模块化就是根据文件划分的形式,将每个功能及其相关的数据放在一个JS中,每个JS文件就是一个单独的模块,在需要时再去引入。
这样的模块化有一个缺点就是:模块都是在全局中,容易造成全局变量污染,命名冲突;而且模块与模块之间并没有依赖关系,维护困难。
webpack是一个前端应用程序静态打包工具,它的目标是实现前端项目的模块化,皆在更高效地管理和维护项目中的每一个资源
静态模块是指开发阶段可以被webpack直接引用的资源(可以直接被获取打包进bundle.js的资源)。当webpack处理项目时,它会在内部构建一个依赖图,此依赖图对应项目所需的每个模块,并生成一个或多个bundle


webpack的构建流程是一个串行的过程,它的工作流程就是将各个插件串联起来。
webpack的构建流程分为以下三步:
Shell语句中读取参数、合并参数,并初始化需要使用的插件和配置插件等执行环境所需要的参数。Entry触发,针对每个Module串行调用对应的Loader编译文件内容,再找到该Module依赖的Module,递归地进行编译处理。Module组合成Chunk,把Chunk转换成文件,输出到文件系统var path = require('path');
var node_modules = path.resolve(__dirname, 'node_modules');
var pathToReact = path.resolve(node_modules, 'react/dist/react.min.js');
module.exports = {
// 入口文件,是模块构建的起点,同时每一个入口文件对应最后生成的一个 chunk。
entry: './path/to/my/entry/file.js',
// 文件路径指向(可加快打包过程)。
resolve: {
alias: {
'react': pathToReact
}
},
// 生成文件,是模块构建的终点,包括输出文件与输出路径。
output: {
path: path.resolve(__dirname, 'build'),
filename: '[name].js'
},
// 这里配置了处理各模块的 loader ,包括 css 预处理 loader ,es6 编译 loader,图片处理 loader。
module: {
loaders: [
{
test: /\.js$/,
loader: 'babel',
query: {
presets: ['es2015', 'react']
}
}
],
noParse: [pathToReact]
},
// webpack 各插件对象,在 webpack 的事件流中执行对应的方法。
plugins: [
new webpack.HotModuleReplacementPlugin()
]
};
Shell命令中读取、合并参数,写到Options对象中Compiler对象,加载所有配置的插件,调用Compiler的run方法来启动webpack的构建流程entry,确定入口文件Module调用对应的Loader编译文件内容,再找到该Module依赖的Module,递归进行编译,得到每个Module之间的依赖关系Chunk,再把每个Chunk转换成一个单独的文件加入到输出列表在上述过程中,webpack会在特定的时间点广播出特定的事件,插件在监听到感兴趣的事件后会执行特定的逻辑,并且插件可以调用webpack提供的API改变webpack的运行结果。
对于不同类型的资源,webpack有对应模块加载器loader。
css-loader:加载CSS。只负责加载CSS文件,如果样式生效,还需要style-loader配合style-loader:将css-loader生成的内容用style标签注入到页面的head中module.exports = {
module: {
rules: [
{
test: /\.css$/,
use: [
{ loader: 'style-loader' },
{
loader: 'css-loader',
options: {
modules: true
}
},
{ loader: 'sass-loader' }
]
}
]
}
};
多个`loader`的加载方式是从右到左,从下到上
less-loader/sass-loader:解析less、sass为cssts-loader:将TS转换为JSbabel-laoder:将ES6解析为ES5eslint-loader:检查JS代码规范file-loader:将文件输出到指定目录,并将该资源的地址返回url-loader:与file-loader类似,但遇到图片格式的文件可以选择性的把图片转成base64格式的字符串,并打包到js中。对小体积的图片合适,对大图片不合适。provider-plugin:将指定的模块暴露到全局,使用时就不需要再import或者requirehtml-webpack-plugin:在打包结束后,自动生成一个html文件,将打包生成的js模块引入到该html中hot-module-replacement-plugin:热更新。通过监听本地代码的变化,自动构建,自动刷新页面uglifyjs-webpack-plugin:压缩JS代码,去掉console.log()、注释等代码,减少文件的字节数,提升构建效率mini-css-extract-plugin:提取CSS,实现按需加载webpack-parallel-uglify-plugin:多核压缩,提升压缩速度loader运行在打包文件之前。plugin在整个编译周期内都起作用。webpack会在特定的时间点广播特定的事件,plugin会监听这些事件,对感兴趣的事件进行执行。plugin还可以调用wepack提供的API来改变webpack的执行结果。loader是文件加载器,能够加载资源文件,并对这些文件进行处理plugin扩展了webpack的功能,例如打包优化、压缩代码等module:webpack可以解析的模块,多个module之间存在依赖关系chunk:包含一个或多个module,代码分割加载的就是chunkbundle:包含一个或多个chunk,是webpack最终打包出来的代码文件我们写的源文件module传送到webpack进行打包时,webpack会根据module之间的依赖关系生成chunk文件,webpack会对这些chunk文件进行操作,比如实现按需加载。webpack处理好chunk后最终输出bundle文件,bundle由一个或多个chunk文件构成,bundle包含了经过加载和编译最终生成的源文件,可以直接在浏览器中运行。
AST,分为两个阶段,词法分析和语法分析
tokens流tokens流转换成AST@babel/traverse方法对AST进行遍历,完成对AST节点的替换、删除或增加操作,返回转换后的AST@babel/generator将AST转换成字符串形式的代码Tree-Shaking主要从以下三个方面进行优化:
首先,Tree-Shaking分为以下两步:
Make阶段:收集导出的变量并记录到模块依赖图**ModuleGraph**中Seal阶段:遍历**ModuleGraph**标记模块导出有没有被使用Terser删除掉没有被用到的导出语句webpack Complier对象将源代码与HMR Runtime一起编译成bundle文件,HMR Runtime是一个socket服务器,会被注入到浏览器,更新文件的变化websocket连接,客户端运行的HRM Runtime,服务器端运行的是HRM Serverwebpack监听文件的变化,如果发生变化,重新编译打包后再推送给客户端,编译生成唯一的hash值,这个hash值用来作为下一次热更新的标识manifest(包含了hash和chunkId,用来说明变化的内容)和chunk.jshashajax请求,根据hash获取包含变化内容的manifest文件manifest替换掉旧的内容实现局部更新UglifyJsPlugin 和 ParallelUglifyPlugin 来压缩JS⽂件css-minimizer-webpack-plugin压缩cssCDN上对应的路径,提高对静态资源的访问速度chunk分为更小的chunk,对css提取到单独的文件中,控制资源加载的优先级,实现按需加载,提高首屏渲染速度import加载,将import放到异步回调函数中,异步函数执行后再去加载webpack的打包webpack-uglify-parallel 来提升 uglifyPlugin 的压缩速度。 原理上 webpack-uglify-parallel采⽤了多核并⾏压缩来提升压缩速度Tree-shaking来剔除多余代码webpack.cache、happypack.cache、babel-loader.cacheDirctory都可以提高二次构建的速度hash一般结合CDN缓存来使用,通过webpack构建之后,生成对应文件名自动带上对应的MD5值,如果文件内容改变的话,那么对应文件哈希值也会改变,对应的HTML引用的URL地址也会发生改变,触发CDN回源,进行更新CDN节点缓存。
chunkhash是根据chunk来生成hash值的,chunkhash实现了模块的异步加载。
chunkhash存在一个问题,就是当在一个JS中引入CSS,编译后它们的hash是相同的,而且只要js发生改变 ,关联css的hash也会改变。
这个时候可以使用mini-css-extract-plugin里的contenthash值,保证css所处的模块里就算其他文件内容改变,只要css内容不变,那么不会重复构建。
CSS Modules是以模块化的形式引入CSS,使用CSS Modules可以防止样式覆盖,防止CSS命名冲突,做到样式隔离。
{
test: /\.css$/,
loaders: [
'style-loader',
'css-loader?modules'
}
.color {
color: red;
}
// 整体引入
import modules from './modules.css'
// 按需引入
import { color } from './modules.css'
class Cssmodules extends React.Component {
render() {
return (
基本用法
这是整体引入的红色文字
这是通过按需引入红色文字
)
}
}
作用域分为局部作用域和全局作用域。像上面那样不管是modules.color还是color都属于局部作用。在DOM中,对应的类名会变成一个唯一的hash字符串,只有在当前作用域才有效,这也是一个模块化的体现。
如果想要申明全局作用域,需要在前面加上:global关键字