近年来前端技术如雨后春笋般蓬勃发展, 我们也在这个潮流下不断地学习成长前端技术的不断发展, 给我们提供了许多的便利例如: JSX 的出现为我们提供了一个清晰直观的方式来描述组件树, LESS/SASS 的出现提高了我们书写 CSS 的能力, AMD/CommonJS/ES6 的出现为我们模块化开发提供了便利然而, 我们需要使用其它工具将这些工具转化成原生语言以运行在浏览器上为了能够更好的将这些不同的资源整合到一起, 我们就需要一个打包工具, webpack 就是这个需求下的产物
webpack 可以看做是模块打包机它做的事情是: 分析你的项目结构, 找到 JavaScript 模块以及其它的一些浏览器不能直接运行的拓展语言(Scss,TypeScript 等), 并将其打包为合适的格式以供浏览器使用目前, webpack 总共发布了三个稳定版本从 17 年八月底开始, 经历了长达五个月的开发周期, webpack 团队通过增加大量新特性 bug 修复问题改善并于近期发布了 webpack 4.0.0 的 beta 版本如果你对 webpack 感兴趣, 下面我们就来学习一下 webpack 4.0.0-beta.0 的新特性
P.S. 以下所有代码演示代码都是基于 webpack 4.0.0-beta.0
1 安装 webpack v4.0.0-beta.0
如果你使用 yarn:
yarn add webpack@next webpack - cli--dev
如果你使用 npm:
npm install webpack@next webpack - cli--save - dev
2webpack 4.0.0.beta.0 新特性介绍
下面是一些你肯定会感兴趣的新特性如果阅读完本章后还觉得不过瘾, 你可以再这查看完整的 changelog
本章将从以下几部分来介绍 webpack 4.0.0-beta.0
2.1 环境
webpack 运行环境升级已经不支持 Node.js 4 版本源码升级到更高的 ECMAScript 版本
根据 webpack package.json 配置中显示 Node.js 最低支持版本: node: >=6.11.5
2.2 模块
webpack 模块类型及 .mjs 的支持:
长久以来, JS 是 webapck 中唯一的模块类型正因此, 开发者无法有效地打包其它类型的文件目前, webpack 实现了五种模块类型, 它们各有自己的优势, 可按需要使用(后面会详细说明)
javascript/auto: (webpack3 中默认)支持所有的 JS 模块系统: CommonJSAMDESM
javascript/esm: EcmaScript 模块, 所有其他模块系统不可用(.mjs 文件中默认)
javascript/dynamic: 不支持 CommonJS 和 EcmaScript 模块
json: JSON 数据, 可以通过 require 和 import 导入(.json 文件默认)
webassembly / experimental
: WebAssembly 模式(目前处于实验性阶段,.wasm 文件默认)
用法:
module.rules 中的 type 就是新增加的属性, 用来支持不同的模块类型
- module: {
- rules: [{
- test: /\.special\.json$/,
- type: "javascript/auto",
- use: "special-loader"
- }]
- }
此外, 现在 webpack 按照 .wasm, .mjs, .js, 以及 .json 等扩展名的顺序来解析
javascript/esm 相比于 javascript/auto 处理 ESM 更加严格:
具体表现在两个方面: 1. 导入的名称必须存在于导入的模块中 2. 动态的模块 (非 ESM, 例如 CommonJS) 只能通过默认 import 导入, 其他所有 (包括命名空间导入) 的导入都会报错
2.3 用法
必须在 开发或者生产 中选择一种模式(这里有一种隐藏模式 none, 可以禁用一切功能)
1)生产模式不支持监听, 开发模式针对快速增量重建进行了优化
2)生产模式同样支持模块串联, 即变量提升(此功能在 webpack 3 中已经实现)
3)开发模式下支持注释和提示, 并且支持 eval 的 source map
将 CLI 移动到 webpack-cli 中, 你需要通过安装 webpack-cli 使用 CLI
你可以使用 optimization.* 标志来配置自己的自定义模式
webpackInclude 和 webpackExclude 可以通过神奇的注释来支持 import() , 他们允许在使用动态表达式时过滤文件
使用 System.import() 会发出警告:
1)可以使用 Rule.parser.system:true 关闭警告
2)你也可以使用 Rule.parser.system:false 关闭 System.import()
对于迁移到新的插件系统的插件 ProgressPlugin 现在显示插件名称
webpack 现在可以本地处理 JSON 如果用 loader 转换 json 为 js, 需要设置: type:javascript/auto 当然, 不用 loader webpack 依然可以正常工作
2.4 配置
删除了一些常用内置插件:
1)NoEmitOnErrorsPlugin -> optimization.noEmitOnErrors (生产模式默认)
2)ModuleConcatenationPlugin -> optimization.concatenateModules (生产模式默认)
3)NamedModulesPlugin -> optimization.namedModules (开发模式默认)
删除了常用的 CommonsChunkPlugin -> optimization.splitChunks 对于那些需要细粒度控制缓存策略的人, 可以通过 optimization.splitChunks 和 optimization.runtimeChunk 现在可以使用 module.rules[].resolve 来配置解析它与全局配置合并
optimization.minimize 用于控制 minimizing 的开关 生产模式默认为开, 开发模式默认为关
optimization.minimizer 用于配置 minimizers 和选项
许多支持占位符的配置选项现在也支持函数形式
错误的 options.dependencies 配置现在会抛出异常
sideEffects 可以通过 module.rules 覆盖
添加 output.globalObject 配置选项以允许在运行时选择全局对象引用
无需显式设置 entry 和 output 属性, webpack 默认设置 entry 属性为./src,output 的属性为./dist
移除 module.loaders
2.5 优化
uglifyjs-webpack-plugin 升级到了 v 1, 并且支持 ES6 语法
可以在 package.json 中配置 sideEffects:false 当设置这个字段之后, 标识在使用的库里没有任何副作用这意味着 webpack 可以从代码中安全地清除任何 re-exports
使用 JSONP 数组来代替 JSONP 函数 > 异步支持
引入新的 optimization.splitChunks 选项
webpack 可以删除无用代码, 之前是由 Uglify 删除无用的代码, 现在 webpack 也可以删除无用的代码这可以有效防止在 import 无用的代码之后发生的崩溃
以下是一些内部优化:
1)用 tap 调用替换 plugin 调用(新的插件系统)
2)将许多废弃的插件迁移到新的插件系统 API
3)为 json 模块添加 buildMeta.exportsType:default
4)删除了 Parser (parserStringArray, parserCalculatedStringArray) 中未使用的方法
2.6 性能
默认情况, UglifyJS 默认缓存和并行化(并未完全实现缓存和并行化, webpack5 的里程碑)
发布了一个新版本的插件系统, 所以事件钩子和处理程序变的单一化
多个性能改进, 特别是更快的增量重建
改进了 RemoveParentModluesPlugin 的性能
2.7 不兼容的改变(插件 loader 相关)
新的插件系统:
1)插件方法是向后兼容的
2)插件现在应该这样使用
- Compiler.hooks.xxx.tap( < plugin name > , fn)
- Chunk.chunks / parents / blocks
不再是数组在内部使用一个集合, 并且有方法来访问它
Parser.scope.renames
和
Parser.scope.definitions
不再是对象 / 数组, 而是 Map/Set
解析器使用 StackedSetMap(类似于 LevelDB 的数据结构)而不是数组
在应用插件时不再设置 Compiler.options
所有模块的构造参数都发生了变化
将 options 合并到 ContextModule 和
resolveDependencies
的 options 对象中.
更改并重命名 import() 的依赖关系
将 Compiler.resolvers 移入可通过插件访问的
Compiler.resolverFactory
中
Dependency.isEqualResource
已被替换为
Dependency.getResourceIdentifier
Template 方法都是静态的
已经添加了一个新的 RuntimeTemplate 类, outputOptions 和 requestShortener 已经被移动到这个类中
1)已经更新了许多方法来代替 RuntimeTemplate 的使用
2)我们计划将访问运行时的代码移动到这个新类中
Module.meta 已被 Module.buildMeta 所取代
已添加 Module.buildInfo 和 Module.factoryMeta
Module 的一些属性已经被移动到新的对象中
添加指向上下文选项的
loaderContext.rootContext
loaders 可以使用它来创建相对于应用程序根目录的东西
当启用 HMR 时, 将 this.hot 标志添加到 loader 上下文中
buildMeta.harmony 已被替换为
buildMeta.exportsType:namespace
chunk 图已经改变:
之前: Chunks 的连接与嵌套依赖关系有关
现在: ChunksGroups 的连接与引用依赖有关, 按照顺序串联
之前: AsyncDependenciesBlocks 按顺序引用 Chunks 列表
现在: AsyncDependenciesBlocks 引用一个 ChunkGroup
注意: 以上内容都是关于 loadersplugins 重大的变化
3 重点更新详解
3.1 更好的默认值
直到今日, webpack 总是要求显式地设置 entry 和 output 属性 webpack 4.0.0-beta.0 中, webpack 会自动设定你的 entry 属性为 ./src 以及 output 的属性为 ./dist
这意味着您不再需要配置文件来启动 webpack 接下来我们为你演示 webpack 4.0.0-beta.0 的便捷操作:
1 我们需要安装好 webpack 之后, 在 package.json 中添加如下脚本即可启动:
- "scripts": { "build": "webpack"
- },
2 在工程中添加简单示例代码如下图(整个工程没有 webpack 配置文件, 即可运行打包):
3 打包过程中我们发现有新特性的提示:
- WARNING in configuration The 'mode'option has not been set.Set 'mode'option to 'development'or 'production'to enable defaults
- for this environment.
这就是我们下节要说的内容模式设置
注意: 入口默认为 ./src 如果缺少此文件夹会报错!
- > webpack --mode production
- ERROR in Entry module not found: Error: Can't resolve'./src'in'D:\workspace\github\Webpack-Example'
3.2 模式设置
以往的项目使用 webpack3 脚手架生成项目初始模板都会有两个甚至三个配置文件, 比如
- webpack.base.conf.js
- webpack.prod.conf.js
- webpack.dev.conf.js
而现在可以做到一个配置文件都不需要, 直接在启动命令中传入参数
--mode development | production
达到区分不同模式的效果
接下来修改 package.json 设置不同的模式:
- "scripts": { "dev": "webpack --mode development",
- "build": "webpack --mode production"
- },
重新执行 npm run dev 或 npm run build 即可看到不同的打包结果:
我们可以看到两种模式的结果完全不同, 下面我们会更深入的按照我们真实的需求来讲解一些常用配置
接下来这个配置是最常用到的, 我们使用 webpack 的主要目的之一就是为了更好的支撑前段模块化的能力, 既然需要模块化当然少不了代码分割, 目前代码分割有以下几种:
通过 entry 分割不同入口, 常用于多页应用;
通过 CommonsChunkPlugin 插件来分割不同功能模块;
通过动态 import 来分割
下面我们主要讲解 webpack 4.0.0-beta.0 版本的重大变化删除了 CommonsChunkPlugin 插件
3.3 删除 CommonsChunkPlugin
webpack 4.0.0-beta.0 删除了 CommonsChunkPlugin, 以支持两个新的选项(
optimization.splitChunks
和
- optimization.runtimeChunk
- )
从 webpack 4.0.0-beta.0 开始分割 Chunk 将不在使用 CommonsChunkPlugin 插件, 而是使用 optimization 配置项, 具体的实现原理可以参考 CommonsChunkPlugin
由于还没有正式官方文档出来, 以下是我们通过实践出的 optimization 配置方法:
其中用到了新增的 splitChunks 属性, 此属性看字面意思就明白是分割代码块的选项, 其下可配置项已在下面示例代码中列出(有兴趣的朋友可以自行实践):
- entry: {
- vendor: ['lodash']
- },
- ...
- optimization: {
- splitChunks: {
- chunks: "initial", // 必须三选一: "initial" | "all"(默认就是 all) | "async"
- minSize: 0, // 最小尺寸, 默认 0
- minChunks: 1, // 最小 chunk , 默认 1
- maxAsyncRequests: 1, // 最大异步请求数, 默认 1
- maxInitialRequests : 1, // 最大初始化请求书, 默认 1
- name: function(){}, // 名称, 此选项可接收 function
- cacheGroups:{ // 这里开始设置缓存的 chunks
- priority: 0, // 缓存组优先级
- vendor: { // key 为 entry 中定义的 入口名称
- chunks: "initial", // 必须三选一: "initial" | "all" | "async"(默认就是异步)
- test: /react|lodash/, // 正则规则验证, 如果符合就提取 chunk
- name: "vendor", // 要缓存的 分隔出来的 chunk 名称
- minSize: 0,
- minChunks: 1,
- enforce: true,
- maxAsyncRequests: 1, // 最大异步请求数, 默认 1
- maxInitialRequests : 1, // 最大初始化请求书, 默认 1
- reuseExistingChunk: true // 可设置是否重用该 chunk(查看源码没有发现默认值)
- }
- }
- }
- },
以上就是
optimization.splitChunks
的所有可用的配置项属性
总结
以上就是我们初步整理的关于 webpack 4.0.0-beta.0 的新特性, 包含了一部分的官方更新日志的翻译, 还有我们自己试验的一些属性当然如果你有兴趣, 也可以等到正式的官方文档发布之后进行实践
如果上面的信息不能够完全满足你的兴趣, 还请关注官方日志在未来不到一个月的时间里, webpack 将对插件加载器以及整个生态系统进行更加严格的测试, 并发布最终的官方稳定版本如果你喜欢 webpack, 你可以参与使用 webpack 4.0.0-beta.0 测试阶段发现解决的问题越多, 正式版本才会更加稳定
示例代码
京东前端
- webpack 4 betatry it today! . Sean T. Larkin
- webpack v4.0.0-beta.0 release . Tobias Koppers
- webpack 4.0.0-alpha.5 feedback . Tobias Koppers
来源: https://juejin.im/entry/5a7abcc26fb9a063523ddbaf