Webpack 是一个现代 JavaScript 应用程序的静态模块打包工具。主要针对js、css、html、图片、字体文件,进行压缩、优化、合并等操作,以实现前端项目的工程化。
1. Hello Webpack
1.1. 安装
1 2 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
目录下,所以需要先添加源码文件,才能执行打包操作。
1 2
| console.log(`hello webpack`);
|
1.3. 执行打包
1 2 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
1 2 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-loader
Less 转 CSS
ts-loader
将 TS 转换成 JS
file-loader
进行图片、字体等的打包
raw-loader
将文件以字符串多形式导入
thread-loader
多进程打包 CSS 和 JS
配置示例:
1 2 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 包
配置示例:
1 2 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
1 2 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 中。
示例:
1 2 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
示例:
1 2 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 处理。
示例:
1 2 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
。
示例:
1 2 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),而是放在内存中;
示例:
1 2 3 4
| "scripts": { "dev": "webpack-dev-server --open" }
|
1 2 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 服务端);
- 用于更灵活的定制场景;
示例:
1 2 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
配置示例:
1 2 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 预处理器
1 2 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
插件并设置压缩参数
1 2 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 指定的输出目录。
1 2 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 前缀。
1 2 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' ] }) } } } ] } ] }
|