标题
安装webpack 和 CLI
# webpack 5 runs on Node.js version 10.13.0+.
npm install webpack webpack-cli -g
# yarn add webpack webpack-cli
Commands
# npx webpack 命令
build | b [option] # 编译打包
configtest | t [config-path] # 验证可配置的webpack.config.js文件内容
info | i [option] # 输出关于系统的信息(OS、CPU、npm/yum/Node、Browsers、Packages)
init | c [option] # 初始化一个webpack的工程
server | s [option] # 运行webpack-dev-server
version | v # 输出webpack CLI的版本信息
watch | w [option] # 运行webpack 监听文件的变化
Flags
列举几个,同时还有Negated Flags, eg --no-color --no-watch
等
Falg/Alias | Type | 描述 |
---|---|---|
–entry | string[] | 程序的入口 |
–config, -c | string[] | webpack配置文件的路径 eg ./webpack.config.js |
–config-name | string | webpack多个配置时,选择配置 |
–node-env | string | 设置process.env.NODE_ENV |
–progress | string、boolean | 输出编译的过程 |
–output-path,-o | string | 设置编译输出的文件目录 eg ./dist |
–hot, -h | boolean | 热模块更新是否启用 |
–color | boolean | console上是否可用color |
–json, -j | string、boolean | 已JSON格式输出到一个文件 |
–analyze | boolean | webpack-bundle-analyzer插件的bundle信息 |
--help=verbose
列出所以的参数
help --entry
具体的–entry参数
Guides
起步
配置最简单的项目
// webpack.config.js
// npx webpack --config webpack.config.js 可以直接执行
// 或者 package.json 中script 中添加 "build": "webpack" 执行build时会默认去执行配置文件 webpack.config.js
const path = require('path')
module.exports = {
mode: 'production',
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
}
}
<!-- /dist/index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script src="bundle.js"></script>
</body>
</html>
在编译结束后发现生成的文件会多一个.LISTENSE.text
后缀的文件(webpack5 自带的terser-webpack-plugin 去压缩JS时,extractComments 属性默认true 会提取当前JS文件中的注释到.LISTENSE.text的文件中
)
Asset Management
- Loading CSS
使用sass
(Dart Sass)时,由于异步回调的开销,默认情况下,同步编译的速度是异步编译速度的两倍。为了避免这种开销,您可以使用fibers
包从同步代码路径中调用异步导入程序。node-sass
不存在这种情况。 - Loading Images
CSS中使用背景和图标等图像或者JSimport MyImage from './image.png'
时,从webpack 5开始,使用内置的Asset Modules
(通过他加载的任何文件,编译时都输出到构建目录),我们也可以轻松地将其合并到我们的系统中
html-loader 会处理同样的方式处理<img src="./my-image.png" />
...
module: {
rules: [
{
test: /\.(png|svg|jpg|jpeg|gif)$/i,
type: 'asset/resource',
}
]
},
...
- Loading Fonts
{
test: /\.(woff|woff2|eot|ttf|otf)$/i,
type: 'asset/resource',
}
- Loading Data
针对 xml文件和 csv(Comma-Separated Values,逗号分隔值)文件,csv-loader/xml-loader
yarm配置文件或者json5,yamljs/json5
const yaml = require('yamljs')
const json5 = require('json5')
{
test: /\.(csv|tsv)$/i,
use: ['csv-loader'],
},
{
test: /\.xml$/i,
use: ['xml-loader'],
},
{
test: /\.yaml$/i,
type: 'json',
parser: {
parse: yaml.parse,
},
},
{
test: /\.json5$/i,
type: 'json',
parser: {
parse: json5.parse,
},
}
js 文件中可以import 以上文件去获取配置文件的属性
Output Management
html-webpack-plugin
将用一个新生成的文件替换我们的index.html文件
Development
mode: 'development',
devtool: 'inline-source-map', // 为了更容易跟踪错误和警告,source-map 将编译后的代码映射回原始源代码
帮助我们在更改时自动编译
- Watch Mode
...
"script": {
"watch": "webpack --watch"
}
...
唯一的缺点:
就是需要手动去刷新页面去看改变的结果
2. webpack-dev-server (常用)
npm install --save-dev webpack-dev-server
// webpack.config.js
...
devServer: {
// 相关属性
hot: true // HMR 热更新
}
...
http://[devServer.host]:[devServer.port]/[output.publicPath]/[output.filename]
3. webpack-dev-middleware
结合express框架,创建服务
配置文件输出中添加publicPath: '/'
, webpack-dev-middleware需要
// server.js
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);
// Tell express to use the webpack-dev-middleware and use the webpack.config.js
// configuration file as a base.
app.use(
webpackDevMiddleware(compiler, {
publicPath: config.output.publicPath,
})
);
// Serve the files on port 3000.
app.listen(3000, function () {
console.log('Example app listening on port 3000!\n');
});
pack.json中添加命令server: node server.js
用以启动服务
Code Splitting
将代码分割成更小的bundles,按需或者并行加载这些包,正确使用对负载的时间有很大的影响
一般有三种方法拆分代码
- Entry Points:使用entry配置手动拆分代码
- Prevent Duplication:用 Entry dependencies 或SplitChunksPlugin进行重复数据删除和拆分
- Dynamic Imports
尽可能避免使用具有多个导入的入口点:entry:{page:[’./analytics’,’./app’]}。这将结果最好通过异步JS去优化和按顺序执行
SplitChunksPlugin
允许我们去提取公共的依赖到一个已存在的entry chunk中或者一个新的chunk中
优化配置optimization.splitChunks
就是SplitChunksPlugin 插件可选的配置
Prefetching/Preloading modules webpack4.6.0+ 支持
- prefetch: 资源可能在在未来的一些导航中需要
- preload: 当前导航将需要的资源
// 例如在点击登录后接下来需要加载登录的组件
import(/* webpackPrefetch: true */ './path/to/LoginModal.js')
preload在父级chunk开始执行;prefetch 在父chunk完成加载后开始执行
preload chunk 有中等优先级,可以立即下载;prefetch chunk 只能等浏览器空闲的时候
浏览器的支持也不同
错误的使用webpackPreload 会影响性能
Bundle Analysis
webpack-chart、webpack-visualizer、webpack-bundle-analyzer、webpack bundle optimize helper
Caching
webpack 提供了一种使用方括号括起来的字符串来替代文件名的模板方法,eg.[name]/[contenthash]
webpack提供了优化功能,可以使用optimization.runtimeChunk
选项将运行时代码拆分为单独的块,将其设置为single
可为所有块创建运行时共享的单个chunk。(参数是string时可选的值为all(chunks能在同步和异步chunks之间共享)、async、initial;)
将第三方库(例如lodash或react)提取到单独的vendor块中也是一个好习惯,因为与我们的本地源代码相比,第三方供应商块发生变化的可能性较小。此步骤将允许客户端从服务器请求的内容更少,以保持最新状态。通过optimization.splitChunks
中的 cacheGroups
去实现(
继承或覆盖splitChunks中的任何选项;但是只能在cacheGroups上配置test,priority(默认-20)和reuseExistingChunk(默认true))。
// webpack.config.js
optimization: {
runtimeChunk: 'single', // 会生成一个在所有生成chunk之前共享的运行时文件 runtime.bundle.js
splitChunks: {
chunks: 'all',
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
chunks: 'initial',
},
elementUI: {
name: 'chunk-elementUI', // split elementUI into a single package
priority: 20, // the weight needs to be larger than libs and app or it will be packaged into libs or app
test: /[\\/]node_modules[\\/]_?element-ui(.*)/
},
commons: {
name: 'chunk-commons',
test: path.join(__dirname,'src/components'),
minChunks: 3,
priority: 5,
reuseExistingChunk: true
}
},
},
},
Authoring Libraries
// webpack.config.js
...
output: {
...
library: {
name: 'libraryCustomName',
type: 'umd'
}
},
externals: {
// 当前库额外的依赖,使用权交给库的使用者
lodash: {
commonjs: 'lodash',
commonjs2: 'lodash',
amd: 'lodash',
root: '_',
},
},
...
Environment Variables
Webpack的环境变量不同于bash和CMD.exe等操作系统shell的环境变量
可以在命令行中--env name=local
或者 --env production
VSCode 编辑器可以在项目根目录下设置.env .env.production
文件去设置不同的环境变量
Build Performance
General
无论开发还是生成都有所帮助
- Loaders
在每个loader处理的时候使用include
去选择实际要做处理的模块 - Bootstrap
每一个loader/plugin都需要启动时间,尽量少使用 - Resolving
提高解析的速度:- resolve.symlinks: false ;不使用npm link 等创建符号链接的操作
- resolve.cacheWithContext: false ;用自定义的解析插件,不存在解析上下文
- 最小化resolve.modules,resolve.extensions,resolve.mainFiles,resolve.descriptionFiles中的项目数量,因为它们增加了文件系统调用的数量
- DLL
使用DllPlugin
将不常更改的代码移动到单独的编译中。尽管这确实会增加构建过程的复杂性,但这将提高应用程序的编译速度 - Smaller = Faster
- Worker Pool
thread-loader
可以将昂贵的loades放到worker pool里面 - Persistent cache
设置cache
属性在配置文件中 - 自定义plugin/loader
- Progress plugin
开发
- Incremental Builds
对于许多watch的文件,这可能会导致大量的CPU负载。您可以使用watchOptions.poll增加轮询间隔 - Compile in Memory
webpack-dev-server、webpack-hot-middleware、webpack-dev-middleware
- stats.toJson speed
stats.toJson() 默认输出大量的数据,除非在增量步骤中有必要,否则请避免检索stats对象的部分。 - Devtool
不同的设置也是不同的性能
大多数清楚eval-cheap-module-source-map
是最好的选择 - Avoid Production Specific Tooling
生成环境中应该避免出现如下的TerserPlugin、[fulgash]/[chunkhash]/[contenthash]
等 - Minimal Entry Chunk
配置optimization.runtimeChunk - Avoid Extra Optimization Steps
这些优化对于较小的代码库是高性能的,但是在较大的代码库中可能会很昂贵
optimization: {
removeAvailableModules: false,
removeEmptyChunks: false,
splitChunks: false,
}
- Output Without Path Info
output: {
pathinfo: false,
}
- Node.js Versions 8.9.10-9.11.1
Map 和Set的性能有点下降,其他版本不影响 - TypeScript Loader
{
loader: 'ts-loader',
options: {
transpileOnly: true, // 提升编译时间
},
}
生产
- Multiple Compilations
parallel-webpack、cache-loader
会有所帮助 - Source Maps
很昂贵,确定真的需要?
node-sass有一个错误,该错误阻止了Node.js线程池中的线程。想使用时设置thread-loader中workerParallelJobs:2
Tree Shaking
为了利用Tree Shaking的优势,你这必须尽心一下操作
- 使用ES2015模块语法(import、export)
- 添加sideEffects 在package.json中
- 使用production模式
Lazy Loading
Shimming
预置依赖
ProvidePlugin
自动加载模块,而不必在任何地方导入或要求它们
// 我们还可以使用ProvidePlugin通过为模块导出一个“数组路径”(例如[module,child,... children?])来配置该模块的单个导出
new webpack.ProvidePlugin({
_map: ['lodash', 'map'],
});
Usage
Web Workers
webpack5 在没有worker-loader的情况下,可以用Web Workers
Asset Modules
Asset Modules 通过添加4种新的模块类型来替换所有这些加载程序:
- asset/resource:以前可以通过使file-loader来实现
- asset/inline:以前可以通过使用url-loader实现
- asset/source:以前可以通过使用raw-loader来实现
- asset:以前可以通过使用具有资产大小限制的url-loader来实现