前言:以下都是自己的总结,或多或少会有错误,若有错误,希望能够指出 聊webpack之前,先来聊一聊前端模块化这个概念
1.前端模块化
- 为什么需要前端模块化: 命名空间的问题,由于没有模块化,那么代码中的变量名、方法名在不知情的情况下很容易被使用者给覆盖,容易造成问题。 难以管理,因为没有模块化,那么代码的管理就非常的重要了 如果只通过script标签加载的话,首先加载的顺序存在限制,有些存在依赖性的文件必须要写在依赖项的后面才行,并且数量众多的script会导致如果其中一个script中出问题了,后面的script都得不到加载。
最早期实现模块化的方式是用一个对象来定义所有需要用到的属性,这样在一定程度上可以解决命名空间的问题,但是他人是可以随意更改你的属性名称。
之后的模块化方案是使用闭包,通过IIFE的闭包,可以有效的创建私有属性,可以把一些不需要向外暴露的属性设置为私有的,仅仅把需要暴露给外界的属性使用return返回给变量接受。好处是解决了命名冲突的问题,但是外界可以修改内部的代码。
一句话总结就是:模块化开发方便代码的管理,提高代码复用性,降低代码耦合,每个模块都会有自己的作用域
- 现在主流的模块化方式:
-
commonjs: CommonJS规范是由node.js来具体实现的。
特点: 由于是使用于服务器端的,所以他仅仅实现了同步加载模块。 导出的模块是浅拷贝的,一旦导出了模块,之后模块内发生的改变都不会影响到该导出的代码。 CommonJS导入支持动态导入:require(
${path}/xx.js
);缺点:由于是同步加载的,所以传统的CommonJS实现不能使用于浏览器端,因为对于node.js而言,模块都存在磁盘上的,使用同步加载的话,速度是非常快的。但是对于浏览器端,模块是被保存在服务器上,那么同步加载的话必然会导致浏览器出现假死的问题。
-
AMD
-
CMD
-
ES6 Module:先ES6模块化是ECMA提出的模块化方式,而并不是民间流传的这些方式。他使用起来非常的简约。 特点:ES6模块导出的值是模块内存的地址,所以如果模块代码发生了改变,那么导出的地方也会发生改变。 ES6模块是编译时输出接口。之所以导出的是值得引用,就是因为JS引擎在对脚本进行静态分析的时候,遇到了import命令之后只会生成一个只读的引用,引用的是模块对象的内存地址;等到真正执行的时候,再根据这个引用去获取具体的值。
-
- Commonjs和Es6 MOdules的区别:
- CommonJS是同步加载的,而ES6 Module是异步加载的;
- CommonJS导出的是值的拷贝,而ES6 Module是导出的值的引用;并且接收的变量不能被重新赋值处理循环依赖的时候两者的方式会不一样;
- CommonJS可以动态加载使用模板字符串即可,但是ES6 Module不行
2.Webpack:
webpack是把项目当作一个整体,通过一个给定的入口文件,开始找到项目的所有依赖的文件,使用loader处理他们,最后打包成一个或多个浏览器可识别的js文件,说白来就是一个打包工具
webpack构建过程:
1.初始化参数:从配置文件和 Shell 语句中读取与合并参数,得出最终的参数;
2.开始编译:用上一步得到的参数初始化 Compiler 对象,加载所有配置的插件,执行对象的 run 方法开始执行编译
3.确定入口:根据配置中的 entry 找出所有的入口文件;
4.编译模块:从入口文件出发,调用所有配置的 Loader 对模块进行翻译,再找出该模块依赖的模块,再递归本步骤直到所有入口依赖的文件都经过了本步骤的处理;
5.完成模块编译:在经过第4步使用 Loader 翻译完所有模块后,得到了每个模块被翻译后的最终内容以及它们之间的依赖关系;
6.输出资源:根据入口和模块之间的依赖关系,组装成一个个包含多个模块的 Chunk,再把每个 Chunk 转换成一个单独的文件加入到输出列表,这步是可以修改输出内容的最后机会;
7.输出完成:在确定好输出内容后,根据配置确定输出的路径和文件名,把文件内容写入到文件系统。
在以上过程中,Webpack 会在特定的时间点广播出特定的事件,插件在监听到感兴趣的事件后会执行特定的逻辑,并且插件可以调用 Webpack 提供的 API 改变 Webpack 的运行结果。
webpack中的插件
- Plugin直译为"插件"。Plugin可以扩展webpack的功能,让webpack具有更多的灵活性。 在 Webpack 运行的生命周期中会广播出许多事件,Plugin 可以监听这些事件,在合适的时机通过 Webpack 提供的 API 改变输出结果
- 常见的插件有:Html-Webpack-plugin,Ugligy-webpack-plugin,Plugin在plugins中单独配置。 类型为数组,每一项是一个plugin的实例,参数都通过构造函数传入。
webpack中的加载器
- Loader直译为"加载器"。Webpack将一切文件视为模块,但是webpack原生是只能解析js文件,如果想将其他文件也打包的话,就会用到loader。 所以Loader的作用是让webpack拥有了加载和解析_非JavaScript文件_的能力。
- 常见的有css-loader,style-loader,file-loader,url-loader,babel-loader,Loader在module.rules中配置,也就是说他作为模块的解析规则而存在。 类型为数组,每一项都是一个Object,里面描述了对于什么类型的文件(test),使用什么加载(loader)和使用的参数(options)
什么是bundle、chunk、module?
- bundle:是由webpack打包出来的文件
- chunk:代码块,一个chunk由多个模块组合而成,用于代码的合并和分割
- module:是开发中的单个模块,在webpack的世界,一切皆模块,一个模块对应一个文件,webpack会从配置的entry中递归开始找出所有依赖的模块