Webpack 是一个现代 JavaScript 应用程序的静态模块打包工具。主要针对js、css、html、图片、字体文件,进行压缩、优化、合并等操作,以实现前端项目的工程化。
1. Hello Webpack
1.1. 安装
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 
 | ➜  npm init -y
 
 
 
 ➜  npm i webpack webpack-cli --save-dev
 
 
 "scripts": {
 "build": "webpack"
 },
 
 | 
1.2. 添加源码文件
初始状态下(未进行任何配置),webpack 会查找项目到 /src/index.js 文件作为打包入口,并且输出到 /dist 目录下,所以需要先添加源码文件,才能执行打包操作。
| 12
 
 | console.log(`hello webpack`);
 
 | 
1.3. 执行打包
| 12
 3
 4
 5
 6
 7
 8
 9
 
 | ➜  npm run build
 > webpack-demo1@1.0.0 build /Users/sunqiang/www/learning/webpack/webpack-demo1
 > webpack
 
 [webpack-cli] Compilation finished
 asset main.js 29 bytes [emitted] [minimized] (name: main)
 ./src/index.js 29 bytes [built] [code generated]
 webpack 5.3.2 compiled successfully in 315 ms
 
 | 
2. 核心功能点
2.1. entry、output
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 
 | module.exports = {
 
 entry: './path/to/entry/file.js'
 
 output: {
 filename: 'bundle.js',
 path: path.join(__dirname, 'dist')
 }
 };
 
 
 module.exports = {
 entry: {
 home: './path/to/entry/home.js',
 front: './path/to/entry/front.js'
 },
 output: {
 filename: '[name].js',
 path: path.join(__dirname, 'dist')
 }
 };
 
 | 
2.2. loaders
常用举例:
- bable-loader转换 ES6、ES7 新语法
- css-loader.css 文件的加载和解析
- less-loaderLess 转 CSS
- ts-loader将 TS 转换成 JS
- file-loader进行图片、字体等的打包
- raw-loader将文件以字符串多形式导入
- thread-loader多进程打包 CSS 和 JS
配置示例:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 
 | module.exports = {
 ...
 module: {
 rules: [
 {
 
 test: /\.txt/,
 
 use: 'raw-loader'
 }
 ]
 }
 };
 
 | 
2.3. plugins
用途:
- 用于 bundle 文件的优化,资源管理和环境变量引入(loaders 解决不了的所有事情)
- 作用于整个构建过程
常用举例:
- CommonsChunkPlugin将 chunks 相同的模块代码提取成公共 js
- ClearWebpackPlugin清理构建目录
- ExtracTextWebpackPlugin将 CSS 从 bundle 中提取成一个独立的 CSS 文件
- CopyWebpackPlugin将文件或文件夹拷贝到构建输出目录
- HtmlWebpackPlugin创建 HTML 文件去承载输出的 bundle
- UglifyjsWebpackPlugin压缩 JS
- ZipWebpackPlugin打包出的资源生成一个 zip 包
配置示例:
| 12
 3
 4
 5
 6
 7
 
 | module.exports = {
 ...
 plugins: [
 new HtmlWebpackPlugin({ template: './src/index.html' })
 ]
 };
 
 | 
2.4. mode
需要 Webpack v4+ 版本。
用于指定当前构建环境(可使用 Webpack 内置函数):
- development- 
- 设置 process.env.NODE_ENV的值为development
- 开启 NamedChunksPlugin、NamedModulesPlugin。
 
- production(默认)- 
- 设置 process.env.NODE_ENV的值为production
- 开启 FlagDependencyUsagePlugin、FlagIncludedChunksPlugin、ModuleConcatenationPlugin、NoEmitOnErrorsPlugin、OccurrenceOrderPlugin、SideEffectsFlagPlugin、TerserPlugin。
 
- none
3. 常用配置
3.1. 用 babel 解析 ES6
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 
 | npm i @babel/core @babel/preset-env babel-loader -D
 
 
 {
 "presets": [
 "@babel/preset-env"
 ]
 }
 
 
 module: {
 rules: [
 {
 test: /.js$/,
 use: 'babel-loader'
 }
 ]
 }
 
 | 
3.2. 解析 CSS
说明:
- css-loader加载- .css文件,并且转换成- commonjs对象。
- style-loader将样式通过标签插入到 head 中。
示例:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 
 | npm i style-loader css-loader -D
 
 
 module: {
 rules: [
 {
 test: /.css$/,
 use: [
 'style-loader',
 'css-loader'
 ]
 }
 ]
 }
 
 | 
3.3. 解析 Less
说明:
- less-loader将 less 转为 css
示例:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 
 | npm i less less-loader -D
 
 
 module: {
 rules: [
 {
 test: /.less$/,
 use: [
 'style-loader',
 'css-loader',
 'less-loader'
 ]
 }
 ]
 }
 
 | 
3.4. 解析图片和字体
说明:
- file-loader用于处理文件。
- url-loader在- file-loader的基础上,增加小资源的自动 Base64 处理。
示例:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 
 | npm i file-loader url-loader -D
 
 
 module: {
 rules: [
 {
 test: /.(png|svg|jpg|gif)$/,
 
 use: [
 {
 loader: 'url-loader',
 options: {
 limit: 10240
 }
 }
 ]
 },
 {
 test: /.(woff|woff2|eot|ttf|otf)$/,
 use: 'file-loader'
 }
 ]
 }
 
 | 
3.5. 文件监听
注意:这种方式,浏览器不会自动刷新,可参见下一节通过「热更新」来实现。
作用:在发现源码发生变化时,自动重新构建新的输出文件。
方式:
- 一、启动 webpack 命令时,追加 --watch参数。
- 二、在 webpack.config.js配置文件中增加watch: true。
示例:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 
 | module.exports = {
 
 watch: true,
 
 watchOptions: {
 
 ignored: /node_modules/,
 
 aggregateTimeout: 300,
 
 
 poll: 1000
 }
 }
 
 | 
3.6. 热更新
方式一:WDS(webpack-dev-server)
说明:
- 不刷新浏览器;
- 不输出文件(没有磁盘 I/O),而是放在内存中;
示例:
| 12
 3
 4
 
 | "scripts": {
 "dev": "webpack-dev-server --open"
 }
 
 | 
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 
 | const webpack = require('webpack);
 
 // ...
 
 mode: 'development', // 注意:热更新仅用于生产环境
 plugins: [
 new webpack.HotModuleReplacementPlugin() // webpack 内置插件
 ],
 devServer: {
 contentBase: './dist', //
 hot: true // 开启热更新
 }
 
 | 
方式二:WDM(webpack-dev-middleware)
说明:
- 将 webpack 输出文件传输给服务器(Node.js 服务端);
- 用于更灵活的定制场景;
示例:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 
 | const express = require('express');const webpack = require('webpack');
 const webpackDevMiddleware = require('webpack-dev-middleware');
 
 const app = express();
 const config = require('./webpack.config.js');
 const compiler = webpack(config);
 
 app.use(webpackDevMiddleware(compiler, {
 publicPath: config.output.publicPath
 }));
 
 app.licten(3000, function() {
 console.log('App listening on port 3000. \n');
 });
 
 | 
3.7. 文件指纹(文件后缀)
三种方式:
- Hash:与整个项目的构建相关,只要项目文件修改,整个项目构建的 hash 值就会改变。
- Chunkhash:跟 webpack 打包的 chunk(模块)有关,不同的 entry 会产生不同的 chunkhash 值。
- Contenthash:根据文件内容来定义 hash文件内容不变,这 contenthash 不变。
占位符说明:
- [ext]资源后缀名
- [name]文件名
- [path]文件现对路径
- [folder]文件所在文件夹
- [contenthash]文件内容 hash,默认 md5 生成
- [hash]生成的 hash 值
- [emoji]一个随机指代文件内容的 emoji
配置示例:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 
 | const MiniCssExtractPlugin = require('mini-css-extract-plugin');
 
 module.exports = {
 entry: {
 app: 'app.js',
 search: 'search.js'
 },
 output: {
 filename: '[name]_[chunkhash].js',
 path: __dirname + '/dist'
 },
 plugins: [
 new MiniCssExtractPlugin({
 filename: '[name]_[contenthash:8].css'
 })
 ],
 module: {
 rules: [
 {
 test: /\.(png|svg|jpg|gif)$/,
 use: [
 {
 loader: 'file-loader',
 options: {
 name: 'img/[name]_[hash:8].[ext]'
 }
 }
 ]
 },
 
 
 
 
 
 
 
 
 
 
 
 
 {
 test: /.(woff|woff2|eot|ttf|otf)$/,
 use: [
 {
 loader: 'file-loader',
 options: {
 name: 'img/[name]_[hash:8].[ext]'
 }
 }
 ]
 },
 {
 test: /.css$/,
 use: [
 MiniCssExtractPlugin.loader,
 'css-loader'
 ]
 },
 {
 test: /.less$/,
 use: [
 MiniCssExtractPlugin.loader,
 'css-loader',
 'less-loader'
 ]
 }
 ]
 }
 };
 
 | 
3.8. 代码压缩
3.8.1. js 文件
uglifyjs-webpack-plugin 内置
3.8.2. css 文件
optimize-css-assets-webpack-pugin 插件 + cssnano 预处理器
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 
 | 
 
 const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-pugin');
 
 
 plugins: [
 new OptimizeCSSAssetsPlugin({
 assetNameRegExp: /\.css$/g,
 cssProcessor: require('cssnano')
 })
 ]
 
 
 | 
3.8.3. html 文件
html-webpack-plugin 插件并设置压缩参数
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 
 | 
 
 const HtmlWebpackPlugin = require('html-webpack-plugin');
 
 
 
 plugins: [
 
 new HtmlWebpackPlugin({
 template: path.join(__dirname, 'src/search.html'),
 filename: 'search.html',
 chunks: ['search'],
 inject: true,
 minify: {
 html5: true,
 collapseWhitespace: true,
 preserveLineBreaks: false,
 minifyCSS: true,
 minifyJS: true,
 removeComments: false
 }
 })
 ]
 
 
 
 | 
3.9. 自动清理构建目录
使用插件 webpack-clean-plugin,默认删除 output 指定的输出目录。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 
 | 
 
 const CleanWebpackPlugin = require('clean-webpack-plugin);
 
 // ...
 
 plugins: [
 new CleanWebpackPlugin()
 ]
 
 // ...
 
 | 
3.10. CSS3 前缀自动补全
PostCSS autoprefixer 插件,属于打包完成后的后置处理,补全 CSS3 前缀。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 
 | 
 
 
 
 
 module: {
 rules: [
 {
 test: /.less$/,
 use: [
 MiniCssExtractPlugin.loader,
 'css-loader',
 'less-loader',
 {
 loader: 'postcss-loader',
 options: {
 plugins: () => {
 require('autoprefixer')({
 browsers: [
 'last 2 version',
 '>1%',
 'ios 7'
 ]
 })
 }
 }
 }
 ]
 }
 ]
 }
 
 
 
 |