webpack5发布简译

2020 年真是多事之秋,疫情啊、牛市啊就这样措不及防地来了。。。 前端里也是,被社区推动着学习,之前不小心在 twitter 上刷到 React 17 发布,看完后幸好没什么大改动(hooks 就已经喝够一壶了)。接着掘金里狂刷 Vue 3.0 发布,大航海时代神马的醉了,不过幸好主技术栈不是它 😉。然后当一名老 webpack 配置工程师去官网查文档的时候,纳尼,webpack 5 发布了! 简译于官方文档,加入一些自己的理解(&吐槽),不保证原汁原味,建议查阅官网。 webpack 5 发布(2020-10-10) 距离 2018 年 2 月的 webpack 4 发布已有两年,老实说挺不容易的,因为 webpack 主要都是作者在维护。很多人都不喜欢 breaking changes,特别是 webpack 这种只要能用就行了就不会花时间改它,但是没有 breaking changes 就意味着没法儿进行大更新和优化。 扯了一阵犊子,也确实该优化下了,这启动速度,还有君不见很多神奇的 bug。 这个主要的版本修改了一些默认的配置,以及向未来看齐。 不得不说,很多发布文章都一样,又臭又长,看完就跟没看一样,等着哪天用着不对劲了才发现这个东东改了。。 这次发布主要内容: 打包优化,基于持久缓存 (Persistent Caching)。没用过 cache-loader 直接略过。 长期缓存优化,基于更好的算法。Long Term Cacheing,听名词可能不太懂,主要是指打包出来的文件名称是一致的,这样利于浏览器的缓存机制,比如一个单独提取出来的第三方库,每次打包出来名称都一样的话用户只需要第一次访问下载就行了。 打包后的文件大小优化,基于更好的 Tree Shaking,代码生成的算法也优化了。 提升 web 平台的兼容性。 清理内部结构。略过 一些 breaking changes 和未来的新功能。 接下来喜闻乐见的这个版本主要改了啥。用到的要改的 😫 主要改动 Major Changes 移除的一些东西: v4 所有的弃用项都被移除了。 新的弃用项。包括 require.include,没用过略过。 Node.js Polyfills 被移除了。比如 crypto 模块等 长期缓存 Long Term Cacheing,新的默认算法: module.exports = { optimization: { // v4 - chunkIds: "size", - moduleIds: "size", - mangleExports: "size", // v5 + chunkIds: "deterministic", + moduleIds: "deterministic", + mangleExports: "deterministic", }, }; v4 版本一般都是 contenthash + HashedModuleIdsPlugin 来做长期缓存。 真正的内容哈希。webpack 5 使用真正的文件内容生成哈希,以前只基于内部结构。因此当注释或变量名称改变时会影响长期缓存。压缩了的话没啥变化,甭管。 开发环境新的默认 Chunk ID 命名算法,主要跟动态引入的模块生成后的文件名相关,以前是生成的数字,现在基于其内容,import(/* webpackChunkName: "name" */ 'module') 这种。(生产环境建议继续这样写) Module Federation 重点!这应该算的上 webpack 5 最大的特性了,让不同项目里的模块能一起工作,说个微前端就都懂了 😂 简单的例子: // 项目 app_remote 的配置 module.exports = { plugins: [ new ModuleFederationPlugin({ name: 'app_remote', library: { type: 'var', name: 'app_remote' }, filename: 'remoteEntry.js', exposes: { './Button': './src/Button.jsx', }, shared: ['react', 'react-dom'], }), ], }; 使用时,先引入 remoteEntry.js,再定义插件,最后代码中使用: <!-- index.html --> <script src="http://localhost:8002/remoteEntry.js"></script> // webpack.config.js module.exports = { plugins: [ new ModuleFederationPlugin({ name: 'app', remotes: { app_remote: 'app_remote', // 或者 app_remote: 'app_remote@http://localhost:8002/remoteEntry.js', }, shared: ['react', 'react-dom'], }), new HtmlWebpackPlugin({ template: './index.html' }), ], }; import React from 'react'; // 从 app_remote 项目中引入的模块 const Button = React.lazy(() => import('app_remote/Button')); export default function Page () { return ( <div> <h1>Page title</h1> <React.Suspense fallback="Loading..."> <Button /> </React.Suspense> </div> ); } 功能确实强大,不过作为使用者,感觉可能会有许多问题,比如: webpack 打包模式不同难以调试。app_remote 线上只是生产环境,而本地开发 app 一般都是 development mode,如果说 app_remote 也在本地克隆下来启动,但 remotes 一多总不可能逐个启动吧。 第三方库版本问题?抑或者 remotes 可用性? 组件使用者的体验。框架一般都有文档能查阅,这个上哪搞?给项目里的组件写文档能给烦死。 平时最多的是写业务,如果产品临时把这个项目的业务流程改了,涉及到共用的业务组件咋办。 唉~光是 react、vue 不同的特性就让微前端像是个梦了,何况跨平台乎。不过有这么多大佬推动着前端发展,还是被学习好了 😂 接着 webpack 的改动,一些 web 平台新特性: JSON modules 对齐规范,没有 named exports 又是几个意思。。。貌似之前就能直接导入,内置了 json-loader import.meta。模块的基本信息,目前只规范了个 url 模块绝对地址 资源模块新写法,new URL('./assets/image.png', import.meta.url)。原生的写法 原生 Worker 支持,包括 new Worker/SharedWorker/ navigator.serviceWorker.register。webpack 会单独打包这些文件:new Worker(new URL('./worker.js', import.meta.url))。也是原生写法,要浏览器支持 URI 协议支持,包括 data:、file://、http(s)://。比如:import x from 'data:text/javascript,export default 32'。 Async modules 支持。不会,略过 新的 external 类型,promise/import/script。script 能通过 <script> 标签加载,可以不用写到 html 里了。 Node.js 生态新特性。略过 一些开发体验的优化。target 可以指定多个且指定版本,比如:target: ['web', 'es2020'];Stats 输出信息优化;Progress 进度信息优化,插件还加了个百分比选项;自动定义多个 runtime 在同个页面下时,之前会有冲突;自动定义 output.publicPath 如果没设置的话;可生成 ts 类型文件。 一些打包优化: tree-shaking。包括了嵌套模块,模块内部,以及 CommonJS 模块。 模块副作用分析。以前需要在 package.json 中手动定义 sideEffects,现在基于源代码自动标记这些模块。 优化每次打包 Module Concatenation 代码生成优化 splitChunks.minSize 可指定不同类型 性能优化。文件系统的持久缓存、文件生成。这块不会翻,高级用户还是直接看文档好了 🙄 一直以来存在的问题。没碰到过,略过 实验性性功能。详情请看 experiments。Top-Level-Await 了解一下,基本上是未来的规范: import React from 'react'; // Stage 3 proposal // 顶层作用域直接使用 await const x = await import('x'); 最小的 Node.js 版本 6 -> 10.13.0。 一些配置的改动。只列举写常见的,如果启动出问题的话直接去官网查好了: entry: {} 可以通过插件添加入口文件 target 上文提过的支持数组和版本,默认 browerslist 如果有的话 cache 新的 filesystem 类型 output.filename 可以是个函数。顶一下,可以自定义生成的文件名称。之前在 webpack 4 文档里查到这个选项,开心地试了,but 并不能用,后来才在 issue 里找到这是 webpack 5 里的功能,吐槽下文档,ca optimization.moduleIds: 'deterministic' 添加的默认项 module.rules loaders 被删除了,用 use optimization.splitChunks.cacheGroups.vendors 重命名成 defaultVendors etc... loader 相关的改动。写过 loader 的可以关注下。 内部细节的改动。插件应用的顺序改了,依赖的 tapable 升级,分析模块依赖用的 ModuleGraph 和 ChunkGraph 改动了,最后顺带提下,文件监听系统重构改用 node 原生的 fs 了,不知道是好是坏啊。。。更多的看不动了 😱 做为一名老 webpack 配置工程师,基本上就到此为止了,看过源码的大佬们可以详查之。 次要改动 Minor Changes 可在乎~(太多了...很多都是和常用配置没啥关系的) 最后总结一下,看完过会儿就等于没看一样。 现在基本上都是用脚手架了,诸如 create-react-app 这种,有大佬在调 webpack 配置,省得翻文档了。2020 年了也衍生了几个基于 esm 的打包工具,比如 snowpack、esbuild,据说打包速度贼快,阔以试试。 参考链接 Webpack 5 release (2020-10-10) module-federation | webpack Webpack 5 Module Federation: A game-changer in JavaScript architecture module-federation/module-federation-examples - Github


JavaScript全屏阅读

下一篇:打酱油

上一篇:钢铁是怎样炼成的

Ctrl + Enter