从前端打包的历史谈起
在很长的一段前端历史里,是不存在打包这个说法的。那个时候页面基本是纯静态的或者服务端输出的, 没有 AJAX,也没有 jquery。Google 推出 Gmail 的时候(2004 年),XMLHttpRequest, 也就是我们俗称的 AJAX被拾起的时候,前端开发者开始往页面里插入各种库和插件,我们的 js 文件程指数倍的开始增加了。JSMin、YUI Compressor、Closure Compiler、UglifyJS 等 js 文件压缩合并工具陆陆续续诞生了。压缩工具是有了,但我们得要执行它,最简单的办法呢,就是 windows 上搞个 bat 脚本,mac / linux 上搞个 bash 脚本,哪几个文件要合并在一块的,哪几个要压缩的,发布的时候运行一下脚本,生成压缩后的文件。
这时候commonJS出现了,如果想在a.js引入b.js和c.js,大概语法是
var b = require(./b.js);
var c = require(./c.js);
b.js和c.js导出方式是大概这样的
exports.add = function(a, b) {
return a+b;
}
然后再a.js中可以使用b模块的add方法
var n = b.add(5, 8);
// b.js
module.exports = {
add(a, b){
return a+b;
}
}
// or
exports.add = function(a,b) {
return a+b;
}
// a.js
var b = require('./b.js');
var n = b.add(5,8);
上述代码中, module.exports 和 exports 很容易混淆,下面看下大致的内部实现
var module = require('./b.js');
module.add
// 包装了一层立即执行函数,防止全局变量污染,重要的是module,module是node独有的一个变量
module.exports = {
add: function(a,b) {
return a+b;
}
}
// 基本实现
var module = {
exports: {} // exports是个空对象
}
var exports = module.exports
var load = function(module) {
// 需要导出的东西
var add = function(a, b) {
return a+b;
}
module.exports = add;
return module.exports;
}
module.exports和exports用法一模一样,但是不能对exports直接赋值,没有任何效果。
但是commonJS是node独有的规范,浏览器中并不适用,因为require()的返回是同步的,服务器加载资源的时候并不能异步的读取。在浏览器中如果使用这种方式就会堵塞js脚本的执行,所以浏览器中只能使用Browserify解析。Browserify和webpack几乎同时出现,简单介绍下Browserify: 其目的是让前端也能使用commonJS的语法来加载js,它会从入口js开始,把所有的require()调用文件打包并合并到一个文件,这样就解决了异步加载的问题。但是对比webpack,他的缺点也是明显的:
1.不支持按需加载,Browserify不支持把代码打包成多个文件。
2.对非js文件的加载不够完善,比如html中的img标签,只能转成Data URI的形式,并不能替换为打包后的路径。在配合gulp或者grunt使用时增加了难度。
3.只支持commonJS规范,不支持后续介绍的AMD和ES6 Module。
所以webpack一统了天下。
于是,在commonJS的基础上,2011又出现了 Asynchronous Module Definition,也是就是AMD规范,AMD规范使用异步回调的语法来并行下载多个依赖项,基本语法如下
require(['./b.js', './c.js'], function(b,c){
var n = b.add(5,8);
console.log(c)
})
同时,导出的时候也需要使用异步回调的方式,比如,c模块又依赖了d.js
defined(['./d'], function(d){
return d.PI
})
总结下AMD: 定义模块使用defined()函数,引入使用reqire()函数,两者的区别是,前者必须要在回调函数中返回一个值作为导出的东西,后者确不需要任何导出,同时也无法作为被依赖项被其他文件导入,因此一般用于入口文件。
AMD是由RequireJS提出的。如果想了解可以查看其文档。但是现在基本已经被淘汰了。
js的模块化问题解决后,css模块化也被各种各样的css预处理器所处理: less、sass、stylus、scss等等。
后来有了ES6规范,提出了模块化的概念,配合babel可以直接使用 ES6模块化
// b.js
export function a() {}
export function b() {}
// c.js
export default function() {}
// a.js
import {a, b} from './b.js'
import ModuleC from './c.js'
对于commonJS和ES6 module 的区别简单总结如下:
1. 前者支持动态导入,也就是可以这样写 require(`${path}/b.js`), 后者目前不支持,但是已有提案。
2. 前者是同步导入,因为用于服务器,文件都在本地,同步导入即使卡主主线程也影响不大;后者是异步导入,因为用于浏览器,需要从服务器下载文件,如果使用同步导入会影响页面渲染。
3. 前者在导出时是值拷贝,就算导出的值发生变化了,导入的值也不会改变。所以如果导入结束后想更新值,必须重新导入一次;后者才用的是实时绑定的方式, 导入导出的值都指向同一个内存地址,所以导入值会跟随导出值变化。
4. ES6 module 会编译成为 require/exports 来执行。
模块化是指把一个复杂的系统分解到一个一个的模块。模块化开发的优点:代码复用,让我们更方便地进行代码管理、同时也便于后面代码的修改和维护。一个单独的文件就是一个模块,是一个单独的作用域,只向外暴露特定的变量和函数。
CommonJS 是服务器端的模块化方案,nodeJs 就采用了这种方案。在 CommonJS 规范中,一个文件即一个模块,用module.exports和exports定义模块输出的接口,用require加载模块。在 requireJS 中用define定义模块,require载入模块,require.config用来配置路径。ES6 Module 主要使用export输出,import加载。
AMD 是 RequireJS 给出的模块加载方案。 支持递归依赖解析、模块异步加载,夜兼容 CommonJS 可以在 Node.js 里用。 虽然目前已经不再流行,很多站点更倾向于编写 ES Modules 并直接 Webpack 打包, 但 AMD 是完整的
CommonJS 模块输出的是一个值的拷贝,ES6 模块输出的是值的引用。CommonJS 模块是运行时加载,ES6 模块是编译时输出接口。export通过接口,输出的是同一个值。不同的脚本加载这个接口,得到的都是同样的实例。
本文包含两部分,第一部分通过简明的描述介绍什么是 CommonJS、AMD、CMD、UMD、ES Module 以及它们的常见用法,第二部分则根据实际问题指出在正常的 webpack 构建过程中该如何指定打包配置中的模块化参数。
这篇文章主要介绍了css模块化方案,css的模块化方案可能和js的一样多,下面简单介绍几种主要的模块方案,非常具有实用价值,需要的小伙伴可以参考下。css的模块化方案可能和js的一样多,下面简单介绍几种主要的模块方案
在模块化规范形成之前,JS开发者使用Module设计模式来解决JS全局作用域的污染问题。Module模式最初被定义为一种在传统软件工程中为类提供私有和公有封装的方法。在JavaScript中,Module模式使用匿名函数自调用 (闭包)来封装
众所周知,早期 JavaScript 原生并不支持模块化,直到 2015 年,TC39 发布 ES6,其中有一个规范就是 ES modules(为了方便表述,后面统一简称 ESM)。但是在 ES6 规范提出前,就已经存在了一些模块化方案
CommonJS 模块输出的是值的拷贝,也就是说,一旦输出一个值,模块内部的变化就影响不到这个值。ES6 Modules 的运行机制与 CommonJS 不一样。JS 引擎对脚本静态分析的时候,遇到模块加载命令import,就会生成一个只读引用。
模块化的开发方式可以提高代码复用率,方便进行代码的管理。通常一个文件就是一个模块,有自己的作用域,只向外暴露特定的变量和函数。目前流行的js模块化规范有CommonJS、AMD、CMD以及ES6的模块系
内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!