浅谈webpack优化
webpack优化方案
1. 优化开发体验
1-1. 加快构建速度
① 缩小文件搜索范围
- 由于 Loader 对文件的转换操作很耗时,需要让尽可能少的文件被 Loader 处理,用include和exclude去缩小;
- resolve.modules用于配置 Webpack 去哪些目录下寻找第三方模块:[path.resolve(__dirname, 'node_modules')](根目录下);
- resolve.mainFields用于配置第三方模块使用哪个入口文件:['mian'];
- resolve.alias配置项通过别名来把原导入路径映射成一个新的导入路径:[path.resolve(__dirname, './node_modules/react/dist/react.min.js')];
- resolve.extensions用于配置在尝试过程中用到的后缀列表:['js', 'json'];
- module.noParse配置项可以让 Webpack 忽略对部分没采用模块化的文件的递归解析处理:[/react\.min\.js$/];
② HappyPack
- HappyPack 的核心原理就是把loader转换任务分解到多个进程去并行处理,从而减少了总的构建时间;
③ ParallelUglifyPlugin
- 压缩js代码需要先把代码解析成用 Object 抽象表示的 AST 语法树,再去应用各种规则分析和处理 AST;
- ParallelUglifyPlugin会开启多个子进程,把对多个文件的压缩工作分配给多个子进程去完成,每个子进程其实还是通过 UglifyJS 去压缩代码,但是变成了并行执行;
1-2. 提升开发效率
① 自动刷新(webpack 模块负责监听文件,webpack-dev-server 模块则负责刷新浏览器)
- 文件监听(--watch或watch: true),原理是定时的去获取这个文件的最后编辑时间,每次都存下最新的最后编辑时间,如果发现当前获取的和最后一次保存的最后编辑时间不一致,就认为该文件发生了变化;
- 优化文件监听:watchOptions: {ignored: /node_modules/};
- 自动刷新原理是往要开发的网页中注入代理客户端代码,通过代理客户端向DevServer 发起的 WebSocket 连接去刷新整个页面;
- devServer.inline是用来控制是否往 Chunk 中注入代理客户端的,默认会注入;在你关闭了 inline 后,DevServer 会自动地提示你通过新网址
http://localhost:8080/webpack-dev-server/
去访问;
② 模块热替换
- 模块热替换的原理和自动刷新原理类似,都需要往要开发的网页中注入一个代理客户端用于连接 DevServer 和网页, 不同在于模块热替换独特的模块替换机制;
2. 优化输出质量
2-1. 减少加载时间
① 区分环境
- process.env.NODE_ENV
② 压缩代码
③ CDN加速
- 针对 HTML 文件:不开启缓存,把 HTML 放到自己的服务器上,而不是 CDN 服务上,同时关闭自己服务器上的缓存。自己的服务器只提供 HTML 文件和数据接口;
- 针对静态的 JavaScript、CSS、图片等文件:开启 CDN 和缓存,上传到 CDN 服务上去,同时给每个文件名带上由文件内容算出的 Hash 值;
④ tree shaking
- 让 Tree Shaking 正常工作的前提是交给 Webpack 的js代码必须是采用 ES6 模块化语法的, 因为 ES6 模块化语法是静态的(导入导出语句中的路径必须是静态的字符串,而且不能放入其它代码块中),这让 Webpack 可以简单的分析出哪些export的被import过了
⑤ 提取公共代码(CommonsChunkPlugin)
⑥ 按需加载
2-2. 提升流畅度
① Prepack
- 通过 Babel 把 JavaScript 源码解析成抽象语法树(AST),以方便更细粒度地分析源码;
- Prepack 实现了一个 JavaScript 解释器,用于执行源码。借助这个解释器 Prepack 才能掌握源码具体是如何执行的,并把执行过程中的结果返回到输出中。
② Scope Hoisting
webpack构建流程
- 初始化(启动构建,读取并合并配置参数,加载plugin,实例化compiler)
- 编译(entry出发,针对每个module引用loader解析,依次找到module依赖,然后递归)
- 输出(对编译后的module组合成chunk,转换成文件,输出)
- 文件变化,转到step2;