webpack的作用
-
模块打包。可以将不同模块的文件打包整合在一起,并且保证它们之间的引用正确,执行有序。利用打包我们就可以在开发的时候根据我们自己的业务自由划分文件模块,保证项目结构的清晰和可读性。
-
编译兼容。通过
webpack
的Loader
机制,不仅仅可以帮助我们对代码做polyfill
,还可以编译转换诸如.less, .vue, .jsx
这类在浏览器无法识别的格式文件,让我们在开发的时候可以使用新特性和新语法做开发,提高开发效率。 -
能力扩展。通过
webpack
的Plugin
机制,我们在实现模块化打包和编译兼容的基础上,可以进一步实现诸如按需加载,代码压缩等一系列功能,帮助我们进一步提高自动化程度,工程效率以及打包输出的质量。
构建流程
webpack 的运行流程是一个串行的过程,从启动到结束会依次执行以下流程:
-
初始化参数
:从配置文件和 Shell 语句中读取与合并参数,得出最终的参数 -
开始编译
:用上一步得到的参数初始化 Compiler 对象,加载所有配置的插件,执行对象的 run 方法开始执行编译 -
确定入口
:根据配置中的 entry 找出所有的入口文件 -
编译模块
:从入口文件出发,调用所有配置的 Loader 对模块进行翻译,再找出该模块依赖的模块,再递归本步骤直到所有入口依赖的文件都经过了本步骤的处理 -
完成模块编译
:在经过第4步使用 Loader 翻译完所有模块后,得到了每个模块被翻译后的最终内容以及它们之间的依赖关系 -
输出资源
:根据入口和模块之间的依赖关系,组装成一个个包含多个模块的 Chunk,再把每个 Chunk 转换成一个单独的文件加入到输出列表,这步是可以修改输出内容的最后机会 -
输出完成
:在确定好输出内容后,根据配置确定输出的路径和文件名,把文件内容写入到文件系统
在以上过程中,webpack 会在特定的时间点广播出特定的事件,插件在监听到感兴趣的事件后会执行特定的逻辑,并且插件可以调用 Webpack 提供的 API 改变 Webpack 的运行结果。
简单说
-
初始化:启动构建,读取与合并配置参数,加载 Plugin,实例化 Compiler
-
编译:从 Entry 出发,针对每个 Module 串行调用对应的 Loader 去翻译文件的内容,再找到该 Module 依赖的 Module,递归地进行编译处理
-
输出:将编译后的 Module 组合成 Chunk,将 Chunk 转换成文件,输出到文件系统中
其中文件的解析与构建是一个比较复杂的过程,在webpack
源码中主要依赖于compiler
和compilation
两个核心对象实现。
compiler
对象是一个全局单例,他负责把控整个webpack
打包的构建流程。 compilation
对象是每一次构建的上下文对象,它包含了当次构建所需要的所有信息,每次热更新和重新构建,compiler
都会重新生成一个新的compilation
对象,负责此次更新的构建过程。
而每个模块间的依赖关系,则依赖于AST
语法树。每个模块文件在通过Loader
解析完成之后,会通过acorn
库生成模块代码的AST
语法树,通过语法树就可以分析这个模块是否还有依赖的模块,进而继续循环执行下一个模块的编译解析。
Entry
入口起点(entry point) 指示 webpack 应该使用哪个模块,来作为构建其内部依赖图的开始。进入入口起点后,webpack 会找出有哪些模块和库是入口起点(直接和间接)依赖的。对于非代码比如图片、字体依赖也会不断加入到依赖图中。
单入口配置:
entry是一个字符串
module.exports = {
entry: './path/to/my/entry/file.js',
};
多入口配置:
entry是一个对象
// array方式:多入口,所有入口文件最终只会形成一个chunk,输出出去只有一个bundle文件
entry: ["./src/app.js", "./src/search.js"],
// object:多入口,有几个入口文件就形成几个chunk,输出几个bundle文件。此时chunk的名称就是对象
entry: {
app: './src/app.js',
adminApp: './arc/adminApp.js'
}
Output
output 属性告诉 webpack 在哪里输出它所创建的 bundle,以及如何命名这些文件.
基本上,整个应用程序结构,都会被编译到你指定的输出路径的文件夹中。
单入口配置:
const path = require('path');
module.exports = {
entry: './path/to/my/entry/file.js',
output: {
path: path.resolve(__dirname, 'dist'), // 输出文件目录(将来所有资源输出的公共目录,包括css和静态文件等等)
filename: 'bundle.js', // 文件名称(指定名称+目录)
publicPath: "", // 所有资源引入公共路径前缀,一般用于生产环境
},
};
多入口配置:
通过占位符确保文件名称的唯一, name表示打包出来的文件名称
const path = require('path');
module.exports = {
entry: {
app: './src/app.js',
search: './src/search.js'
},
output: {
filename: '[name].js',
path: path.resolve(__dirname, 'dist')
}
};
Loader
webpack开箱即用只支持JS和JSON两种文件类型,通过loader去支持其他文件类型并且把它们转换成有效地模块,并且可以添加到依赖图中。
loader的作用:
1、实现对不同格式的文件的处理,比如说将scss转换为css,或者typescript转化为javascript
2、转换这些文件,从而使其能够被添加到依赖图中
loader是webpack最重要的部分之一,通过使用不同的Loader,我们能够调用外部的脚本或者工具,实现对不同格式文件的处理,loader需要在webpack.config.js里边单独用module进行配置
loader本身是一个函数,接受源文件作为参数,返回转换的结果。
常见的loader
名称 | 描述 |
babel-loader | 转换ES6、ES7等JS新特性语法 |
css-loader | 加载 CSS,支持模块化、压缩、文件导入等特性 |
less-loader | 将less文件转换成css |
ts-loader | 将TS转换成JS |
file-loader | 进行图片、字体等的打包,把文件输出到一个文件夹中,在代码中通过相对 URL 去引用输出的文件(webpack5前使用 ) |
raw-loader | 将文件以字符串的形式导入,即加载文件原始内容(utf-8)(webpack5前使用 ) |
thread-loader | 多进程打包JS和CSS |
url-loader | 与 file-loader 类似,区别是用户可以设置一个阈值,大于阈值会交给 file-loader 处理,小于阈值时返回文件 base64 形式编码 (处理图片和字体)(webpack5前使用 ) |
image-loader | 加载并且压缩图片文件 |
sass-loader | 将scss/sass代码转换成css |
style-loader | 把 CSS 代码注入到 JavaScript 中,通过 DOM 操作去加载 CSS |
post-loader | 扩展 CSS 语法,使用下一代 CSS,可以配合 autoprefixer 插件自动补齐 CSS3 前缀 |
eslint-loader | 通过 ESLint 检查 JS代码 |
tslint-loader | 通过 TSLint检查 TS 代码 |
vue-loader | 加载 Vue.js 单文件组件 |
i18n-loader | 国际化 |
cache-loader | 可以在一些性能开销较大的 Loader 之前添加,目的是将结果缓存到磁盘里 |
svg-inline-loader | 将压缩后的 SVG 内容注入代码中 |
Plugins
插件用于bundle文件的优化,资源管理和环境变量注入,作用于整个构建过程。
常见的Plugins:
名称 | 描述 |
CommonsChunkPlugin | 将chunks相同的模块代码提取成公共js |
clean-webpack-plugin | 清理构建目录(webpack5前使用 ) |
extract-text-webpack-plugin | 将CSS从bundle文件里提取成一个独立的CSS文件(webpack4前使用 ) |
copy-webpack-plugin | 将文件或者文件夹拷贝到构建的输出目录 |
html-webpack-plugin | 创建html文件去承载输出的bundle |
uglify-webpack-plugin | 压缩JS |
webpack-bundle-analyzer | 可视化 Webpack 输出文件的体积 (业务组件、依赖第三方模块) |
mode
模式(mode):指示 Webpack使用相应模式的配置。默认为production
支持以下字符串值:
选项 | 描述 |
---|---|
development | 会将 DefinePlugin 中 process.env.NODE_ENV 的值设置为 development . 为模块和 chunk 启用有效的名。 |
production | 会将 DefinePlugin 中 process.env.NODE_ENV 的值设置为 production 。为模块和 chunk 启用确定性的混淆名称,FlagDependencyUsagePlugin ,FlagIncludedChunksPlugin ,ModuleConcatenationPlugin ,NoEmitOnErrorsPlugin 和 TerserPlugin 。 |
none | 不使用任何默认优化选项 |
webpack系列:
参考资料: