主要学习一下四种模块加载规范:javascript
前端模块化开发那点历史html
requirejs 为全局添加了 define 函数,你只要按照这种约定的方式书写这个模块便可。前端
define(function () { //Do setup work here return { color: "black", size: "unisize" } });
//my/shirt.js now has some dependencies, a cart and inventory //module in the same directory as shirt.js define(["./cart", "./inventory"], function(cart, inventory) { //return an object to define the "my/shirt" module. return { color: "blue", size: "large", addToCart: function() { inventory.decrement(this); cart.add(this); } } } );
以上示例代码来源于require.js官网java
demo代码详见 https://github.com/BillyQin/jsModule/tree/master/requireJsnode
require.js 为全局添加了define 函数,按照这种约定方式写便可。webpack
这个约定方式就是AMD(The Asyncchronous Module Definition)git
因此AMD规范就是定义了怎么写define函数。只要按照这个规范来写模块和依赖,require.js就能正确解析。es6
demo代码详见 https://github.com/BillyQin/jsModule/tree/master/seaJsgithub
一样的道理,CMD就是Sea.js对模块定义对规范化产出。web
因此CMD的内容就是描述该如何定义模块,如何引入模块,如何导出模块。只要按照这个规范来写模块和依赖,sea.js就能正确解析。
CMD推崇依赖就近
AMD 和 CMD 都是用于浏览器的模块规范,而在服务端(node),则采用CommonJS。
CommonJS和sea.js同样,require的时候才去加载模块文件,加载完再接着执行。
demo代码详见 https://github.com/BillyQin/jsModule/tree/master/commonJs
为何浏览器中不支持 CommonJS 语法呢?
这是由于浏览器环境中并无 module、 exports、 require 等环境变量。
es6定义了新的模块加载方案。
// 导出 const addr = 'China' const year = 2018 export { addr, year }
// 导入 import { addr, year } from './index.js'
和require.js(AMD)一致,将须要使用的模块加载完再执行代码。
CommonJS模块输出值的拷贝, ES6输出值的引用。 CommonJS模块输出值的拷贝, 也就是说,一旦输出一个值,模块内部的变化就影响不到这个值。
CommonJS是运行时加载,ES6是编译时输出接口。 CommonJS加载的是一个对象,就是module.exports属性。该对象只有在脚本运行完成后才会生成。而es6模块不是对象,对外接口只是一种静态定义,在代码静态解析阶段就会生成。
在浏览器不支持es6的时候,若是要使用es6的语法,通常都会在项目里加入babel。
// es6 let firstName = 'Michael'; const lastName = 'Jackson'; var year = 1958; export {firstName, lastName, year};
转换后
Object.defineProperty(exports, "__esModule", { value: true }); var firstName = 'Michael'; var lastName = 'Jackson'; var year = 1958; exports.firstName = firstName; exports.lastName = lastName; exports.year = year;
Babel 只是把 ES6 模块语法转为 CommonJS 模块语法,而浏览器不支持CommonJs。这时候webpack出动。
浏览器不支持CommonJs的本质是由于浏览器环境中并无 module、 exports、 require 等环境变量。 webpack 打包后的文件之因此在浏览器中能运行,就是靠模拟了这些变量的行为。
// commonJs let multiply = require('./multiply') console.log('加载 square 模块') let square = function (num) { return multiply.multiply(num, num) } module.exports = { square: square }
模拟后:
// 包裹一层,注入这些变量 function(module, exports, require) { console.log('加载了 square 模块'); var multiply = require("./multiply"); module.exports = { square: function(num) { return multiply.multiply(num, num); } }; }
整个CommonJs项目改写后
// 自执行函数 (function(modules){ // 存储已加载的模块 var installModules = {} // 关键的require方法 function require(moduleName) { if (installModules.moduleName) { return installModules.moduleName.exports } var module = installModules[moduleName] = { exports: {} } modules[moduleName](module, module.exports, require); return module.exports; } return require('main') })({ 'main': function(module, exports, require) { var addModule = require("./add"); console.log(addModule.add(1, 1)) var squareModule = require("./square"); console.log(squareModule.square(3)); }, './add': function(module, exports, require) { console.log('加载 add 模块') var add = function (x, y) { return x + y } module.exports = { add: add } }, './multiply': function(module, exports, require) { console.log('加载 multiply 模块') var multiply = function (x, y) { return x * y } module.exports = { multiply: multiply } }, './square': function(module, exports, require) { console.log('加载 square 模块') var multiply = require('./multiply') var square = function (num) { return multiply.multiply(num, num) } module.exports = { square: square } } })
原文出处:https://www.cnblogs.com/BillyQin/p/10058454.html