Open AnnVoV opened 5 years ago
这是一篇阅读笔记,重点推荐阅读下面3篇文章: 1.Predictable long term caching with Webpack https://medium.com/webpack/predictable-long-term-caching-with-webpack-d3eee1d3fa31 2.手摸手合理地带你使用webpack4 上 https://segmentfault.com/a/1190000015919863 3.手摸手带你合理使用webpack4 下 https://segmentfault.com/a/1190000015919928
我的总结:
参考资料: 1.Predictable long term caching with Webpack (重点参考) https://medium.com/webpack/predictable-long-term-caching-with-webpack-d3eee1d3fa31 2.希望做浏览器长缓存?关于Webpack生成的Hash,你应该知道这些 https://segmentfault.com/a/1190000011980729 3.手摸手合理地带你使用webpack4 上 https://segmentfault.com/a/1190000015919863 4.手摸手带你合理使用webpack4 下 (重点参考) https://segmentfault.com/a/1190000015919928 5.webpack4 之SplitChunksPlugin https://juejin.im/post/5af15e895188256715479a9a 6.webpack4 持久缓存小结 https://juejin.im/post/5a705f6cf265da3e36418dc5 7.http1 与 http2 的差别?以及http2的优势 https://medium.com/@factoryhr/http-2-the-difference-between-http-1-1-benefits-and-how-to-use-it-38094fa0e95b 8.如何理解http2 的多路复用 https://segmentfault.com/q/1010000005167289 9.HTTP/2.0 相比1.0有哪些重大改进? https://www.zhihu.com/question/34074946
下面列举一些文中提到的一些问题:
因为新加入了一个模块,导致我们的模块的id顺序已经发生了变化了,所以导致我们打包出来的文件内容都发生了改变,所以我们需要使用另一个插件去替代id来命名的方式
解决方案: 1.在我们的路由里面,我们需要命名chunk 异步组件参考文档: https://router.vuejs.org/zh/guide/advanced/lazy-loading.html
const Foo = () => import(/* webpackChunkName: "group-foo" */ './Foo.vue') const Bar = () => import(/* webpackChunkName: "group-foo" */ './Bar.vue') const Baz = () => import(/* webpackChunkName: "group-foo" */ './Baz.vue')
用这种注释的方式,我们最终得到的组件是以group-foo命名的,并且这3个异步组件打包到了一起
2.我们要开启namedChunks namedModules 让模块依赖不是用id去命名,这样就不会有添加一个组件,其他组件就收到影响的问题了 webpack4 默认在生产环境下开启了namedModules 和 namedChunks,webpack3 我们使用的是 webpack.NamedModulesPlugin 来解决这个问题的
查看文章: https://medium.com/webpack/predictable-long-term-caching-with-webpack-d3eee1d3fa31
将模块的映射列表从app.js 中抽取出来了,只要设置
{ runtimeChuk: true }
其实我们发现打包生成的 runtime.js非常的小,gzip 之后一般只有几 kb,但这个文件又经常会改变,我们每次都需要重新请求它,它的 http 耗时远大于它的执行时间了,所以建议不要将它单独拆包,而是将它内联到我们的 index.html 之中(index.html 本来每次打包都会变)。 这里我选用了 script-ext-html-webpack-plugin,主要是因为它还支持preload和 prefetch,正好需要就不想再多引用一个插件了,你完全可以使用 inline-manifest-webpack-plugin或者 assets-webpack-plugin等来实现相同的效果。
其实我们发现打包生成的 runtime.js非常的小,gzip 之后一般只有几 kb,但这个文件又经常会改变,我们每次都需要重新请求它,它的 http 耗时远大于它的执行时间了,所以建议不要将它单独拆包,而是将它内联到我们的 index.html 之中(index.html 本来每次打包都会变)。
这里我选用了 script-ext-html-webpack-plugin,主要是因为它还支持preload和 prefetch,正好需要就不想再多引用一个插件了,你完全可以使用 inline-manifest-webpack-plugin或者 assets-webpack-plugin等来实现相同的效果。
这个之前也提到了,我们的模块的id 是自增的, 这就导致了,添加一个模块或者删除一个模块,都会影响当前的id, 这就导致了引入一个文件就会使原先的缓存失效了
webpack4里有一个HashedModuleIdsPlugin 这个和 NamedModulesPlugin的区别 NamedModulesPlugin 直接使用了模块的路径作为原先的模块id, 而使用HashedModuleIdsPlugin 会使用hash过的路径作为模块id
NamedModulesPlugin 和 HashedModuleIdsPlugin 原理是相同的,将文件路径作为 id,只不过没有把路径 hash 而已,适用于开发环境方便调试。不建议在生产环境配置,因为这样不仅会增加文件的大小(路径一般偶读比较长),更重要的是为暴露你的文件路径。
同理,我们在固定moduleId的时候,同时也要固定chunkId 因为我们增加chunk 或者减少chunk的时候,也会导致顺序乱掉
它内置的代码分割策略是:
所以有一些小的组件,即使被多个页面进行了引用,但它如果本身比较小(比如只有5k),还是会被分别打包到各自使用的组件中。 【理由】5k的代码在gzip压缩之后,可能只有1.5k左右,你为了这1.5k却要花费额外的http请求,是不值得的
但有些场景下这些规则可能就显得不怎么合理了。比如我有一个管理后台,它大部分的页面都是表单和 Table,我使用了一个第三方 table 组件,几乎后台每个页面都需要它,但它的体积也就 15kb,不具备单独拆包的标准,它就这样被打包到每个页面的 bundle 中了,这就很浪费资源了。这种情况下建议把大部分页面能共用的组件单独抽出来,合并成一个component-vendor.js的包(后面会介绍)。
基础类库 chunk-libs (eg. vue + vue-router + vuex + axios)
UI组件库 (单独抽出来的原因是它比较大,且升级概率高)
自定义组件/函数 提取出app.js 和chunk-commons.js
低频组件 只会在一些特定的业务场景下使用,比如富文本编辑器,js-xlsx 一般这些库的大小也都>30kb 所以webpack默认会把他们独立打包成一个Bundle
业务代码 这个就是由我们的路由,入口文件配置决定的
配置参考:
// ... optimization: { splitChunks: { chunks: 'all', cacheGroups: { // 类似原先的CommonChunksPlugin libs: { name: 'chunk-libs', test: /[\\/]node_modules[\\/]/, priority: 10, // 注意这里的权重 chunks: 'initial', // ?这个配置不了解 有 all async initial }, elementUI: { name: 'chunk-elementUI', priority: 20, // 权重要大于上面的10 test: /[\\/]node_modules[\\/]element-ui[\\/]/, }, commons: { name: 'chunk-commons', test: resolve("src/components"), // 可自定义拓展你的规则 priority: 5, reuseExistingChunk: true } } } }
优化是一个博弈的过程,是让首次加载快一点还是更多的利用cache。拆包的时候不要过分的追求颗粒化,如果什么都单独打成一个bundle,会导致请求过多受到阻塞。但是如果是在http2的情况下,那我们的打包策略又可以有新的改变了
这是一篇阅读笔记,重点推荐阅读下面3篇文章: 1.Predictable long term caching with Webpack https://medium.com/webpack/predictable-long-term-caching-with-webpack-d3eee1d3fa31 2.手摸手合理地带你使用webpack4 上 https://segmentfault.com/a/1190000015919863 3.手摸手带你合理使用webpack4 下 https://segmentfault.com/a/1190000015919928
我的总结:
参考资料: 1.Predictable long term caching with Webpack (重点参考) https://medium.com/webpack/predictable-long-term-caching-with-webpack-d3eee1d3fa31 2.希望做浏览器长缓存?关于Webpack生成的Hash,你应该知道这些 https://segmentfault.com/a/1190000011980729 3.手摸手合理地带你使用webpack4 上 https://segmentfault.com/a/1190000015919863 4.手摸手带你合理使用webpack4 下 (重点参考) https://segmentfault.com/a/1190000015919928 5.webpack4 之SplitChunksPlugin https://juejin.im/post/5af15e895188256715479a9a 6.webpack4 持久缓存小结 https://juejin.im/post/5a705f6cf265da3e36418dc5 7.http1 与 http2 的差别?以及http2的优势 https://medium.com/@factoryhr/http-2-the-difference-between-http-1-1-benefits-and-how-to-use-it-38094fa0e95b 8.如何理解http2 的多路复用 https://segmentfault.com/q/1010000005167289 9.HTTP/2.0 相比1.0有哪些重大改进? https://www.zhihu.com/question/34074946
下面列举一些文中提到的一些问题:
在配置的路由模块里,我们新加一个异步模块,模块的chunkhash都发生了变化
因为新加入了一个模块,导致我们的模块的id顺序已经发生了变化了,所以导致我们打包出来的文件内容都发生了改变,所以我们需要使用另一个插件去替代id来命名的方式
解决方案: 1.在我们的路由里面,我们需要命名chunk 异步组件参考文档: https://router.vuejs.org/zh/guide/advanced/lazy-loading.html
用这种注释的方式,我们最终得到的组件是以group-foo命名的,并且这3个异步组件打包到了一起
2.我们要开启namedChunks namedModules 让模块依赖不是用id去命名,这样就不会有添加一个组件,其他组件就收到影响的问题了 webpack4 默认在生产环境下开启了namedModules 和 namedChunks,webpack3 我们使用的是 webpack.NamedModulesPlugin 来解决这个问题的
当添加了externals 时,0号文件顺序变了,导致vendor又变了
查看文章: https://medium.com/webpack/predictable-long-term-caching-with-webpack-d3eee1d3fa31
webpack4 下面几个配置的区别
RuntimeChunks
将模块的映射列表从app.js 中抽取出来了,只要设置
HashedModuleIdsPlugin
这个之前也提到了,我们的模块的id 是自增的, 这就导致了,添加一个模块或者删除一个模块,都会影响当前的id, 这就导致了引入一个文件就会使原先的缓存失效了
webpack4里有一个HashedModuleIdsPlugin 这个和 NamedModulesPlugin的区别 NamedModulesPlugin 直接使用了模块的路径作为原先的模块id, 而使用HashedModuleIdsPlugin 会使用hash过的路径作为模块id
同理,我们在固定moduleId的时候,同时也要固定chunkId 因为我们增加chunk 或者减少chunk的时候,也会导致顺序乱掉
webpack4 内置的打包策略
它内置的代码分割策略是:
所以有一些小的组件,即使被多个页面进行了引用,但它如果本身比较小(比如只有5k),还是会被分别打包到各自使用的组件中。 【理由】5k的代码在gzip压缩之后,可能只有1.5k左右,你为了这1.5k却要花费额外的http请求,是不值得的
优化分包策略
基础类库 chunk-libs (eg. vue + vue-router + vuex + axios)
UI组件库 (单独抽出来的原因是它比较大,且升级概率高)
自定义组件/函数 提取出app.js 和chunk-commons.js
低频组件 只会在一些特定的业务场景下使用,比如富文本编辑器,js-xlsx 一般这些库的大小也都>30kb 所以webpack默认会把他们独立打包成一个Bundle
业务代码 这个就是由我们的路由,入口文件配置决定的
配置参考:
博弈
优化是一个博弈的过程,是让首次加载快一点还是更多的利用cache。拆包的时候不要过分的追求颗粒化,如果什么都单独打成一个bundle,会导致请求过多受到阻塞。但是如果是在http2的情况下,那我们的打包策略又可以有新的改变了