`
seavers
  • 浏览: 170022 次
  • 来自: ...
社区版块
存档分类
最新评论

mini javascript loader

阅读更多

自己写的一个mini 且 simple 的 javascript loader

功能特点
  • 异步并行载入js, 每个js只加载一次
  • 支持模块依赖, 未检测循环依赖
  • 支持别名
  • 兼容ie6+ , firefox, chrome ...
  • API : 
  •     define.alias['modName'] = 'http://path/to/mods/root/dir'
        define(deps, callback)   其中 callback(dep1, dep2, dep3...)
        require(deps, callback)   其中 callback(dep1, dep2, dep3...)




define = (function() {
	
	var modules = {};
	var modulesCallbacks = {};
	var alias = window.alias || {};

	function map(arr, callback) {
		var ret = [];
		for(var i = 0; i < arr.length; i++) {
			ret.push(callback(arr[i], i, arr));
		}
		return ret;
	}
	function isString(obj) {
		return typeof(obj) == 'string';
	}
	function isArray(obj) {
		return Object.prototype.toString.call(obj) == '[object Array]';
	}
	function isFunction(obj) {
		return typeof(obj) == 'function';
	}
	function mix(src, dst) {
		for(var key in dst) {
			src[key] = dst[key];
		}
	}
	function getScript(url, callback) {
		var node = document.createElement("script");
		node.async = true;
		if (document.addEventListener) {
			node.addEventListener('load', callback);
		} else {
			node.onreadystatechange = function () {
				if(node.readyState == 'loaded' || node.readyState == 'complete') {
					callback && callback();
				}
			}
		}
		node.src = url;

		var head = document.head || document.getElementsByTagName('head')[0] || document.documentElement;
		head.insertBefore(node, head.firstChild);
		return node;
	}

	function getCurrentScript() {
		
		//firefox4 and opera
		if (document.currentScript) {
			return document.currentScript;
		} else if (document.attachEvent) {
			//ie6-9 得到当前正在执行的script标签
			var scripts = document.getElementsByTagName('script');
			for (var i = scripts.length - 1; i > -1; i--) {
				if (scripts[i].readyState === 'interactive') {
					return scripts[i];
				}
			}
		} else {
			// 参考 https://github.com/samyk/jiagra/blob/master/jiagra.js
			// chrome and firefox4以前的版本
			var stack;
			try {
				makeReferenceError
			} catch (e) {
				stack = e.stack;
			}
			if (!stack)
				return undefined;
			// chrome uses at, ff uses @

			var e = stack.indexOf(' at ') !== -1 ? ' at ' : '@';
			while (stack.indexOf(e) !== -1) {
				stack = stack.substring(stack.indexOf(e) + e.length);
			}
			stack = stack.replace(/:\d+:\d+$/ig, "");

			var scripts = document.getElementsByTagName('script');
			for (var i = scripts.length - 1; i > -1; i--) {
				if (scripts[i].src === stack) {
					return scripts[i];
				}
			}
		}
	}

	function getScriptWithCache(url, callback) {
		var scripts = this._scripts = this._scripts || {};
		var cache = scripts[url];
		if (cache === true) {
			callback && callback();
			return ;
		} else if (isArray(cache)) {
			cache.push(callback);
			return ;
		} else {
			scripts[url] = [callback];
		}

		getScript(url, function() {
			var callbacks = scripts[url] || [];
			scripts[url] = true;
			for(var i = 0; i < callbacks.length; i++) {
				callbacks[i] && callbacks[i]();
			}
		});		
	}

	function getModule(mod, callback) {
		if (!modules[mod]) {
			modulesCallbacks[mod] = modulesCallbacks[mod] || [];
			modulesCallbacks[mod].push(callback);

			getScriptWithCache(mod);
		} else {
			callback && callback(modules[mod]);
		}
	}

	function getModules(mods, callback) {
		if (mods == undefined || mods.length == 0) {
			callback && callback();
			return ;
		}
		var c = 0;

		var ret = [];
		map(mods, function(mod, i) {
			getModule(mod, function(obj) {
				ret[i] = obj;

				if (++c == mods.length) {
					callback && callback(ret);
				}
			});
		});
	}

	function define(deps, callback) {
		var container = this;

		if (!isString(deps) && !isArray(deps)) {
			callback = deps;
			deps = [];
		}
		var current = getCurrentScript();
		var url = current && current.src;

		deps = deps || [];
		if (isString(deps)) {
			deps = deps.split(',');
		}
		var allDeps = map(deps, tran);				//全部转换映射

		getModules(allDeps, function(mods) {
			var ret = isFunction(callback) ? callback.apply(undefined, mods||[]) : callback;
			modules[url] = modules[url] || {}
			mix(modules[url], ret);

			container != window && (mix(container, ret));

			if (modulesCallbacks[url]) {
				for(var i = 0; i < modulesCallbacks[url].length; i++) {
					modulesCallbacks[url][i](ret);
				}
			}
		});

		return container;
	}

	function tran(dep) {
		for(var key in alias) {
			dep = dep.replace(new RegExp('^' + key), alias[key]);		//TODO
		}
		return dep + '.js';
	}

	define.alias = alias;
	return define;
})();









测试用例

//上述代码保存为 http://localhost/loader/loader.js


<!-- index.htm -->
<script src="loader.js"></script>

<script>
define.alias['ok'] = 'http://localhost/loader/';
define(['ok/mod1', 'ok/mod2'], function(Mod1, Mod2) {
	console.log('execute index ', Mod1, Mod2);
});
</script>






//   http://localhost/loader/mod1.js
require(['ok/mod2'], function(Mod2) {
	console.log('mod1 index ', Mod2);

	return {
		mod1: 'this is mod1'
	}
});




//   http://localhost/loader/mod2.js
define(function() {
	console.log('mod2 index ');

	return {
		'hello' : 'world'
	}
});






补: 其它用法
//mod3.js
//功能模块1
define({
    sayHello : function() {
       console.log('hello');
    }
});

//功能模块2, 模块2没支持!!!
define(function() {
    return {
        sayWorld : function() {
           console.log('world');
        }
    }
});





App = {define : define, require: define};
App.define.alias['ok'] = 'http://lhj/loader';
App.define({
      showMsg : function(msg) {
          console.log(msg);
      }
});

App.define(function(Mod3) {
      return {
          say : function() {
				App.require('ok/Mod3', function(Mod3) {
	                  return Mod3.sayHello() + ' ' + '';//Mod3.sayWorld();
				});
          }
      }
});

App.showMsg(123);
App.say();


分享到:
评论

相关推荐

    mini-program-webpack-loader:基于 webpack 的小程序构建工具

    mini-program-webpack-loader基于 webpack 4.0 的小程序打包工具。项目依赖 async/await, Set/Map, spread 等 es6+ 语法安装 $ npm i mini-program-webpack-loader --dev介绍该工具主要解决小程序难以集成更多的成熟...

    svgo-loader::framed_picture::evergreen_tree:常绿svgo-loader更换

    用于webpack的svgo加载程序 @hyperbola/svgo-loader是零依赖性,常绿替代 。...带有asset模块const svgToMiniDataURI = require ( "mini-svg-data-uri" ) ;module . exports = { ... , module : { rules : [ { test :

    轻量级CSS提取插件-javascript

    异步加载 无重复编译(性能) 更易于使用 特定于 CSS 入门 首先,您需要安装 mini-css-extract-plugin: npm install --save- dev mini-css-extract-plugin 建议将 mini-css-extract-plugin 与 css-loader 结合起来...

    mini-css-class-name:最小大小的唯一CSS类名称生成器

    mini-css-class-name 最小大小的唯一CSS类名称生成器。 它可以与和生态系统一起使用。安装npm i mini-css-class-name --save-dev# oryarn add mini-css-class-name -D如何使用const miniClassName = require ( "mini...

    glivera-webpack-template

    webpack-plugin css-loader css-mqpacker cssnano file-loader gulp gulp-cheerio gulp-replace gulp-svg-sprite gulp-svgmin html-webpack-plugin mini-css-extract-plugin node-sass postcss-loader pug pug-...

    jsvideo

    npm install @babel/core babel-loader @babel/preset-env @babel/preset-react --save-dev npm install webpack webpack-cli html-webpack-plugin html-loader webpack-dev-server --save-dev npm install mini-css...

    reactjs-practico:关于Platzi的React JS实践课程的注释和回购

    -save-devnpm install webpack-dev-server --save-devnpm install mini-css-extract-plugin css-loader node-sass sass-loader --save-devnpm install eslint babel-eslint eslint-config-airbnb eslint-p

    Webpack4-WEB:这是一个框架无关的基于Webpack4构建的前端开发脚手架

    npm init -y// 初始化npm i webpack webpack-cli -D// webpack 核心npm i html-webpack-plugin html-loader -D// 动态生成html插件npm i mini-css-extract-plugin -D // 动态生成css文件插件npm i style-loader css-...

    htmlcsswebpack:HTML CSS Webpack only网站样板

    mini-css-extract-plugin :Webpack 4的ExtractTextPlugin。 normalize.cs :标准化CSS optimize-css-assets-webpack-plugin :最小化生成CSS。 pug和pug-loader :编译.pug文件导入的.html。 style-loader :...

    react-template-from-scratch

    React模板该模板已使用webpack和babel从头开始可用脚本Start :启动webpack-dev-server Build :在dist文件夹中构建开发包分行master :仅支持javascript typescript :也支持打字稿Webpack加载器babel-loader mini-...

    evaluate_news_nlp

    npm i -D @ babel / core @ babel / preset-env babel-loader -npm i -D样式加载器node-sass css-loader sass-loader -npm i -D clean-webpack-plugin -npm I -D html-webpack-plugin -npm i -D mini-css-extract-pl

    顶石

    顶石项目 这是我的Fron-End Nano-Degree的最终项目。 在这个项目中,我将使用多个API来创建旅行应用。 这将在计划旅行的时间和希望到达的目的地收集天气。 许可 该项目中使用的照片均为png格式。... mini-css-extract

    example-webpack-plugin-github-action:Github Action的@ relative-ciagent Webpack插件设置示例

    Javascript :使用@babel/preset-env和@babel/preset-react CSS : postcss ( autoprefixer , cssnano ), css-modules , mini-css-extract 资产: public : copy-webpack-plugin src : file-loader ...

    example-cli-github-action-pull-request:Github Action的@ relative-ciagent CLI设置示例

    Javascript :使用@babel/preset-env和@babel/preset-react CSS : postcss ( autoprefixer , cssnano ), css-modules , mini-css-extract 资产: public : copy-webpack-plugin src : file-loader ...

    mina-webpack:Mina单文件组件符合Webpack

    entry-webpack-plugin \ @tinajs/mina-runtime-webpack-plugin \ @tinajs/mina-loader \ @tinajs/wxs-loader 最简单的用法webpack.config.js : const webpack = require ( "webpack" ) ;const MinaEntryPlugin = r

    testing-netlify

    dev-server尚未100%与webpack 5兼容解决方案: target: 'web',位于webpack.config.js 修复错误后,删除target键以重新启用默认行为等待webpack-dev-server v4mini-css-extract-plugin 最好的做法是使用重复CSS / ...

    vue-template

    Oncomouse的Vue模板 一个功能全面的Vue.js模板。 与vue-cli一起使用。 特征: ... mini-css-extract-plugin 在构建时提取静态CSS文件 复制webpack插件将静态资产存储在./assets 友好错误Webpack插件

    webpack4-react-starter:Webpack 4 教程:零配置 基础实现, 复杂实现还需要使用webpack.config.js

    但是要实现复杂的工程还是要config定义比较好package.json -&gt; scripts -&gt;webpack --mode development ./src/index.js --output ./dist/main.js --module-bind js=babel-loader 参数描述mode 编译模式 development ...

    Portfolio-React

    我的个人投资组合 :house_with_garden: 该项目旨在展示我的经验,特色项目,研究,文章并提供我的所有联系方式。 如何运行项目。 运行命令npm run install初始化项目依赖... mini-css-extract-plugin 1.3.3 不用叉子了:

    评价新闻新闻

    npm i -D @ babel / core @ babel / preset-env babel-loader npm i -D样式加载器节点ass css加载器sass加载器 npm i -D clean-webpack-plugin npm i -D html-webpack-plugin npm i -D mini-css-extract-plugin ...

Global site tag (gtag.js) - Google Analytics