原理 :
首先要知道 server 端和 client 端都做了处理工作
1. 第一步,在 webpack 的 watch 模式下,文件系统中某一个文件发生修改, webpack 监听到文件
变化,根据配置文件对模块重新编译打包,并将打包后的代码通过简单的 JavaScript 对象保存在内存中。
2. 第二步是 webpack-dev-server 和 webpack 之间的接口交互,而在这一步,主要是 dev-server 的中间件 webpack-dev-middleware 和 webpack 之间的交互, webpack-dev-middleware 调用
webpack 暴露的 API 对代码变化进行监控,并且告诉 webpack ,将代码打包到内存中。
3. 第三步是 webpack-dev-server 对文件变化的一个监控,这一步不同于第一步,并不是监控代码变化重新打包。当我们在配置文件中配置了devServer.watchContentBase 为 true 的时候, Server
会监听这些配置文件夹中静态文件的变化,变化后会通知浏览器端对应用进行 live reload 。注意,
这儿是浏览器刷新,和 HMR 是两个概念。
4. 第四步也是 webpack-dev-server 代码的工作,该步骤主要是通过 sockjs ( webpack-dev-server
的依赖)在浏览器端和服务端之间建立一个 websocket 长连接,将 webpack 编译打包的各个阶段 的状态信息告知浏览器端,同时也包括第三步中 Server 监听静态文件变化的信息。浏览器端根据
这些 socket 消息进行不同的操作。当然服务端传递的最主要信息还是新模块的 hash 值,后面的步骤根据这一 hash 值来进行模块热替换。
5. webpack-dev-server/client 端并不能够请求更新的代码,也不会执行热更模块操作,而把这些工
作又交回给了 webpack , webpack/hot/dev-server 的工作就是根据 webpack-dev-server/client
传给它的信息以及 dev-server 的配置决定是刷新浏览器呢还是进行模块热更新。当然如果仅仅是
刷新浏览器,也就没有后面那些步骤了。
6. HotModuleReplacement.runtime 是客户端 HMR 的中枢,它接收到上一步传递给他的新模块的
hash 值,它通过 JsonpMainTemplate.runtime 向 server 端发送 Ajax 请求,服务端返回一个
json ,该 json 包含了所有要更新的模块的 hash 值,获取到更新列表后,该模块再次通过 jsonp 请
求,获取到最新的模块代码。这就是上图中 7 、 8 、 9 步骤。
7. 而第 10 步是决定 HMR 成功与否的关键步骤,在该步骤中, HotModulePlugin 将会对新旧模块进行对比,决定是否更新模块,在决定更新模块后,检查模块之间的依赖关系,更新模块的同时更新模块间的依赖引用。
8. 最后一步,当 HMR 失败后,回退到 live reload 操作,也就是进行浏览器刷新来获取最新打包代码
10.如何用webpack来优化前端性能?
用 webpack 优化前端性能是指优化 webpack 的输出结果,让打包的最终结果在浏览器运行快速高效。
压缩代码 : 删除多余的代码、注释、简化代码的写法等等方式。可以利用 webpack 的
UglifyJsPlugin 和 ParallelUglifyPlugin 来压缩 JS 文件, 利用 cssnano ( css-loader?
minimize )来压缩 css
利用CDN 加速 : 在构建过程中,将引用的静态资源路径修改为 CDN 上对应的路径。可以利用
webpack 对于 output 参数和各 loader 的 publicPath 参数来修改资源路径
Tree Shaking: 将代码中永远不会走到的片段删除掉。可以通过在启动 webpack 时追加参数 --
optimize - minimize 来实现
Code Splitting: 将代码按路由维度或者组件分块 (chunk), 这样做到按需加载 , 同时可以充分利用浏览
器缓存
提取公共第三方库 : SplitChunksPlugin 插件来进行公共模块抽取 , 利用浏览器缓存可以长期缓存这
些无需频繁变动的公共代码
11.如何提高webpack的打包速度?
happypack: 利用进程并行编译 loader, 利用缓存来使得 rebuild 更快 , 遗憾的是作者表示已经不会继
续开发此项目 , 类似的替代者是 thread-loader
外部扩展 (externals) : 将不怎么需要更新的第三方库脱离 webpack 打包,不被打入 bundle 中,从而
减少打包时间 , 比如 jQuery 用 script 标签引入
dll: 采用 webpack 的 DllPlugin 和 DllReferencePlugin 引入 dll ,让一些基本不会改动的代码先打包
成静态资源 , 避免反复编译浪费时间
利用缓存 : webpack.cache 、 babel-loader.cacheDirectory 、 HappyPack.cache 都可以利用缓存
提高 rebuild 效率
缩小文件搜索范围 : 比如 babel-loader 插件 , 如果你的文件仅存在于 src 中 , 那么可以 include:
path.resolve(__dirname, 'src') , 当然绝大多数情况下这种操作的提升有限 , 除非不小心 build
了 node_modules 文件
12.如何提高webpack的构建速度?
1. 多入口情况下,使用 CommonsChunkPlugin 来提取公共代码
2. 通过 externals 配置来提取常用库
3. 利用 DllPlugin 和 DllReferencePlugin 预编译资源模块 通过 DllPlugin 来对那些我们引用但是
绝对不会修改的 npm 包来进行预编译,再通过 DllReferencePlugin 将预编译的模块加载进来。 4. 使用 Happypack 实现多线程加速编译
5. 使用 webpack - uglify - parallel 来提升 uglifyPlugin 的压缩速度。 原理上 webpack - uglify -
parallel 采用了多核并行压缩来提升压缩速度
6. 使用 Tree - shaking 和 Scope Hoisting 来剔除多余代码
13.怎么配置单页应用?怎么配置多页应用?
单页应用可以理解为 webpack 的标准模式,直接在 entry 中指定单页应用的入口即可
多页应用的话,可以使用webpack 的 AutoWebPlugin 来完成简单自动化的构建,但是前提是项目的目
录结构必须遵守他预设的规范。 多页应用中要注意的是:
每个页面都有公共的代码,可以将这些代码抽离出来,避免重复的加载。比如,每个页面都引用了
同一套 css 样式表
随着业务的不断扩展,页面可能会不断的追加,所以一定要让入口的配置足够灵活,避免每次添加
新页面还需要修改构建配置