webpack基础
webpack基础参数说明
module.exports = {
entry: './src/index.js', // 入口
output: { // 出口
filename: 'bundle.js',
path: path.resolve(__dirname, './dist'), // 设置绝对路径
clean: true, // 自动清除上次打包出来的文件
// assetModuleFilename: 'images/test.jpg', // 定义静态资源打包的文件路径和文件名
assetModuleFilename: 'images/[contenthash][ext]', // 根据文件内容自动生成一个hash扩展值文件名
},
mode: 'development', // 设置成开发环境
devtool: 'inline-source-map', // 用于设置精准定位错误位置 并且会格式化打包生成的Js文件
plugins: [
new HtmlWebpackPlugin({
template: './index.html', // 指定模板
filename: 'app.html', // 打包出来的静态文件的名字
inject: 'body' // 把文件打包到body里面
})
],
devServer: {
static: './dist'
},
// 定义模块资源
module: {
// type用于定义转换类型
rules: [
// 将.jpg文件转换成链接形式
{
test: /\.jpg$/,
type: 'asset/resource',
generator: {
// filename: 'images/text.jpg' // 这个优先级比assetModuleFilename更高
filename: 'images/[contenthash][ext]' // 这个优先级比assetModuleFilename更高
}
},
{
test: /\.svg$/,
type: 'asset/inline', // 将svg格式装换成base64的文件格式,并且不会在dist打包文件中生成
},
{
test: /\.txt$/,
type: 'asset/source' // 可以导出文件源代码
},
{
test: /\.png/,
type: 'asset' // 设置通用文件资源类型。默认大小是8k,超出这个文件就会生不会生成base64文件,否则就会打包到dist文件中。这个默认大小可以修改,通过parser下面的MaxSize
}
]
}
}
安装
npm install webpack webpack-cli (用于命令行控制webpack)
基本包安装
npm install webpack webpack-cli webpack-dev-server html-webpack-plugin -D
基本安装步骤
1、npm init -y
2、npm install webpack webpack-cli --save-dev
3、修改文件
此时还不能使用webpack,会报错
解决方案: 1、全局安装webpack
2、使用npx webpack
3、找到node_modules/bin/webpacl.cmd文件,复制该文件到该项目根路径下,修改里面的内容
@ECHO off
SETLOCAL
CALL :find_dp0
IF EXIST "%dp0%\node.exe" (
SET "_prog=%dp0%\node.exe"
) ELSE (
SET "_prog=node"
SET PATHEXT=%PATHEXT:;.JS;=;%
)
"%_prog%" "%dp0%\..\webpack\bin\webpack.js" %* // -------- 原先的
"%_prog%" "%dp0%\node_modules\webpack\bin\webpack.js" %* // -------- 修改之后的
ENDLOCAL
EXIT /b %errorlevel%
:find_dp0
SET dp0=%~dp0
EXIT /b
webpack相关命令
《----------npx作用是自己去找相关可以执行命令的文件 ------》
npx webpack -------打包
npx webpack -stats detailed ----- 查看打包相关信息
npx webpack --help
npx webpack --entry ./src/index.js --mode production ------设置入口和模式
npx webpack --watch -------监听文件的变化 自动重新打包编译
将配置文件显示出来
在根目录下创建一个文件 webpack.config.js
const path = require('path')
module.exports = {
entry: './src/index.js', // 入口
output: { // 出口
filename: 'bundle.js',
path: path.resolve(__dirname, './dist') // 设置绝对路径
},
mode: 'none'
}
热更新
!!!本质不是重新打包编译,而是把编译的放到了内存里
安装 npm install webpack-dev-server --save-dev
使用:
npx webpack serve
loader文件解析
webpack默认的只能解析js 和json这样的文件,其他文件的解析都要配置使用相应的loader,在用use设置解析的loader时,它是从右向左解析的。
配置css-loader 解析文件中的css
安装css-loader(用于解析css文件) style-loader(将解析后的css文件添加到样式中)
npm install css-loader style-loader
使用,通过use使用对应的loader来进行解析 从右向左解析
// 定义模块资源
module: {
// type用于定义转换类型
rules: [
...
{
test: /\.css$/,
use: ['style-loader', 'css-loader'] //从右向左解析的,先把css文件解析出来,然后用style-loader加载
}
]
}
加载less
安装
npm install less less-loader
使用
module: {
// type用于定义转换类型
rules: [
...,
{
test: /\.(css|less)$/, // 正则匹配css/less文件
use: ['style-loader', 'css-loader', 'less-loader'] // 从右向左接卸
}
]
}
抽离和压缩css
抽离
将css less文件抽离成单独文件然后引入
安装
npm install mini-css-extract-plugin // 只支持webpack5
使用:引入该插件,然后在plugin中实例化,使用里面带的loader
效果: 会把css和less文件解析后存放在一个单独文件中然后进行引入
const MinCssExtractPlugin = require('mini-css-extract-plugin')
module.exports = {
...
plugins: [
...
new MinCssExtractPlugin({
// 定义文件路径和文件名 ----》 生成styles文件夹,里面内容是hash随机生成,不写的话默认根目录下main.css
filename: 'styles/[contenthash].css'
})
],
devServer: {
static: './dist'
},
// 定义模块资源
module: {
// type用于定义转换类型
rules: [
...
{
test: /\.(css|less)$/,
use: [MinCssExtractPlugin.loader, 'css-loader', 'less-loader']
}
]
}
}
压缩
安装
npm install css-minimizer-webpack-plugin
使用
...
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin')
module.exports = {
...
mode: 'production', // 需设置成开发环境
...
// 通过以下配置进行压缩
optimization: {
minimizer: [
new CssMinimizerPlugin()
]
}
}
csv、tsv、xml数据加载
安装
npm install csv-loader // 解析csv,tsv文件
npm install xml-loader // 解析 xml文件
使用
module: {
// type用于定义转换类型
rules: [
...
{
test: /\.(csv|tsv)$/,
use: "csv-loader"
},
{
test: /\.xml$/,
use: "xml-loader"
}
]
},
babel的使用
将es6代码转化为es5,兼容不同浏览器
安装
babel-loader: 在webpack里应用babel解析es6的桥梁
@babel/core: babe核心模块
@babel/preset-env: babel预设,一组babel插件的集合
npm install babel-loader @babel/core @babel/preset-env
用法
module: {
// type用于定义转换类型
rules: [
...
{
test: /\.js$/,
exclude: /node_modules/, // node_modules中的文件夹不参与转换
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env']
}
}
}
]
},
代码中如果使用了 async await 会报错
regeneratorRuntime is not defined
regeneratorRuntime
是webpack打包生成的全局辅助函数,由babel生成,用于兼容async/await语法
安装
npm install @babel/runtime @babel/plugin-transform-runtime
用法
module: {
rules: [
...
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env'],
plugins: [
[
'@babel/plugin-transform-runtime'
]
]
}
}
}
]
},
当打包文件过大时会报错
entrypoint size limit: The following entrypoint(s) combined asset size exceeds the recommended limit (244 KiB). This can impact web performance.
解决方案:
module.export = {
...
performance: {
maxEntrypointSize: 4000000,
maxAssetSize: 30000000
}
}
maxEntrypointSize: 根据入口起点的最大体积,控制 webpack 何时生成性能提示
maxAssetSize: 此选项根据单个资源体积(单位: bytes),控制 webpack 何时生成性能提示。
代码分离
有三种方式
1、入口起点: 使用entry配置手动地分离代码 (如果配置多个入口,相同文件会参与重复打包)
定义多个入口,但是如果多个入口文件都引入了相同的文件,那么该文件会参与重复打包
module.exports = {
entry: {
index: './src/index.js', // 入口1
another: './src/another-modules.js' // 入口2
},
output: { // 出口
filename: '[name].bundle.js', //根据不同的入口生成不同的文件名
...
},
}
// 最终会打包生成 index.bundle.js + another.bundle.js
2、防止重复打包: 使用Entry dependencies 或者SplitChunksPlugin去重和分离代码
2-1 Entry dependencies
module.exports = {
entry: {
index: {
import: './src/index.js',
dependOn: 'sharedLo' // 从sharedLo这里加载文件,该名字和下面的要同名(自定义名称)
},
another: {
import: './src/another-modules.js',
dependOn: 'sharedLo' // 从sharedLo这里加载文件(同上)
},
sharedLo: 'lodash' // 定义sharedLo抽离的文件chunk名字,用于上面的dependOn名称
}
}
SplitChunks实现模块抽离
module.exports = {
entry: {
index: './src/index.js',
another: './src/another-modules.js'
},
...
optimization: {
...
splitChunks: {
chunks: 'all'
}
},
}
3、动态导入 通过模块的内联函数调用来分离代码
定义引入第三方包的js文件,然后引入该文件,配合上面的入口,将动态和静态资源分别打包引入
function getComponent() {
// 引入
return import('lodash')
.then(({ default: _ }) => {
const element = document.createElement('div')
element.innerHTML = _.join(['hello', 'webpack'], ' ')
return element
})
}
getComponent().then(element => {
document.body.appendChild(element)
})
动态导入应用
1、懒加载
节约网络流量,减少请求,加快初次渲染的速度 ----使用方式基于上面的动态引入
示例自定义一个js文件,点击执行之后再加载
定义了一个math.js的文件,导出两个方法
export const add = (x, y) => {
return x + y
}
export const minus = (x, y) => {
return x- y
}
点击按钮之后再引入,未点击之前不会加载该资源
webpackChunkName: 'math' 是用于定义打包出来的文件名,也可以不写用默认的
const button = document.createElement('button')
button.textContent = '点击执行加载文件'
button.addEventListener('click', () => {
import(/* webpackChunkName: 'math' */'./math.js').then(({add, minus}) => {
console.log(add(4,5))
})
})
document.body.appendChild(button)
2、预获取/预加载模块
预获取(网络空闲时会加载该资源)// 性能更好,会在头部
使用魔法注释 加上webpackPrefetch: true
button.addEventListener('click', () => {
import(/* webpackChunkName: 'math', webpackPrefetch: true */'./math.js').then(({add, minus}) => {
console.log(add(4,5))
})
})
document.body.appendChild(button)
会自动在head中引入以下
<link rel="prefetch" as="script" href="http://localhost:8081/math.bundle.js">
预加载(和懒加载效果类似)
使用魔法注释 加上webpackPreload: true
button.addEventListener('click', () => {
import(/* webpackChunkName: 'math', webpackPreload: true */'./math.js').then(({add, minus}) => {
console.log(add(4,5))
})
})
document.body.appendChild(button)
缓存
为了防止文件更新,但是文件名没有发生变化的情况,此时浏览器就会读取本地缓存的文件,导致发生错误。
所以使用hash来命名输出文件
module.exports = {
output: { // 出口
filename: '[name].[contenthash].js', // 生成hash文件名,文件内容不变,打包出来的文件名不会发生变化,浏览器就会调用该缓存文件
},
}
缓存第三方库
将第三方库(如lodash)提取到单独的vendor chunk文件中。因为他们很少像本地源代码一样频繁修改,所以利用client的长效缓存机制,命中缓存来消除请求,并减少向server获取资源,同时保障client代码和server代码版本一样,我们在optimization.splitChunks添加如下cacheGroup参数并构建
!!!打包出来的文件名不能发生变化,否则会重新请求
module.exports = {
...
optimization: {
...
splitChunks: {
cacheGroups: {
vendor: {
// 将该匹配的文件(第三方库)全部打包到vendors文件中,只要改文件名没有发生变化,就不会重新请求
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
chunks: 'all'
}
}
}
},
}
将所有的js打包到一个文件夹里面
module.exports = {
output: { // 出口
filename: 'script/[name].[contenthash].js', // 全部打包到script中
},
}
拆分开发环境和生产环境配置
定义公共域名/cdn域名
module.exports = {
output: {
...
publicPath: 'http://localhost:8081/'
},
}
打包之后html文件引入的文件就变成http://localhost:8081
<!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">
<title>Document</title>
<link href="http://localhost:8081/styles/2125e8b98edb6a3c5f17.css" rel="stylesheet">
</head>
<body>
<script defer="defer" src="http://localhost:8081/script/vendors.27878cfbf98dddd4c44b.js"></script>
<script defer="defer" src="http://localhost:8081/script/index.a291f4666a680e49dc91.js"></script>
<script defer="defer" src="http://localhost:8081/script/another.60d845548c50ad6eb7f3.js"></script>
</body>
</html>
<script src="./dist/bundle.js"></script>
环境变量
设置环境变量的方式
每一个 --env后面可以设置环境变量。也可以设置自定义键值对
npx webpack --env production --env goal=local
获取设置的变量值
将module设置成函数的形式,可以获取到设置的变量
module.exports = (env) => {
console.log('------', env)
return {
...
mode: env.production ? 'production' : 'development'
}
}
压缩js
如果手动设置了压缩css,此时js就不会自动压缩了
optimization: {
minimizer: [
new CssMinimizerPlugin()
],
},
安装:
npm install terser-webpack-plugin
使用
module.exports = {
...
optimization: {
minimizer: [
new CssMinimizerPlugin(), // 压缩css
new TerserPlugin() // 压缩js
],
},
}
将不同环境变量的配置进行拆分
在根目录下定义config文件夹,里面包含生成环境和开发环境配置
开发环境配置 config/webpack.config.dev.js
// 删除了上面的压缩 写死了mode 修改了打包出来的文件路径 不需要对文件名进行hash处理,不读取缓存
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const MinCssExtractPlugin = require('mini-css-extract-plugin')
module.exports = {
entry: {
index: './src/index.js',
another: './src/another-modules.js'
},
output: { // 出口
filename: 'script/[name].js', // 不需要hash命名文件,不适用缓存
path: path.resolve(__dirname, '../dist'), // 修改打包文件路径
...
},
mode: 'development', // 设置成开发环境
devServer: {
static: './dist'
},
optimization: {
...
// 删除了文件压缩
splitChunks: {
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
chunks: 'all'
}
}
}
},
}
生产环境配置 config/webpack.config.propd.js
// 不需要devserver 修改了打包出来的文件路径
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const MinCssExtractPlugin = require('mini-css-extract-plugin')
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin')
const TerserPlugin = require('terser-webpack-plugin')
module.exports = {
entry: {
index: './src/index.js',
another: './src/another-modules.js'
},
output: { // 出口
filename: 'script/[name].[contenthash].js',
path: path.resolve(__dirname, '../dist'), // !!!!! 修改打包路径
...
},
mode: 'production', // 设置成开发环境
devtool: 'inline-source-map', // 用于设置精准定位错误位置 并且会格式化打包生成的Js文件
....
// 开启本地服务关闭
// devServer: {
// static: './dist'
// },
// 定义模块资源
}
执行不同命令打包不同的文件,这样就可以根据打包生产还是开发环境来使用不同配置文件
使用上面开发环境配置进行打包 (生产环境同理)
npx webpack -c ./config/webpack.config.dev.js
用开发环境配置启动本地项目命令
npx webpack serve -c ./config/webpack.config.dev.js
通过脚本执行相关命令
在package.json中定义脚本指令
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
// !!!webpack server 是会存放在内存里,不会生成打包文件
"start": "webpack serve -c ./config/webpack.config.dev.js",
// !!!webpack 才会生成打包文件
"build": "webpack -c ./config/webpack.config.prod.js"
}
提取公共配置
将开发环境和生成环境公共配置存放在config/webpack.cnfig.common.js文件中
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const MinCssExtractPlugin = require('mini-css-extract-plugin')
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin')
const TerserPlugin = require('terser-webpack-plugin')
module.exports = {
entry: {
index: './src/index.js',
another: './src/another-modules.js'
},
output: { // 出口
path: path.resolve(__dirname, './dist'), // 设置绝对路径
clean: true, // 自动清除上次打包出来的文件
// assetModuleFilename: 'images/test.jpg', // 定义静态资源打包的文件路径和文件名
assetModuleFilename: 'images/[contenthash][ext]', // 根据文件内容自动生成一个hash扩展值文件名
},
plugins: [
new HtmlWebpackPlugin({
template: './index.html', // 指定模板
filename: 'app.html', // 打包出来的静态文件的名字
inject: 'body' // 把文件打包到body里面
}),
new MinCssExtractPlugin({
filename: 'styles/[contenthash].css'
})
],
// 定义模块资源
module: {
// type用于定义转换类型
rules: [
// 将.jpg文件转换成链接形式
{
test: /\.jpg$/,
type: 'asset/resource', // 可以生成一个单独的资源,他是一个文件路径
generator: {
// filename: 'images/text.jpg' // 这个优先级比assetModuleFilename更高
filename: 'images/[contenthash][ext]' // 这个优先级比assetModuleFilename更高
}
},
{
test: /\.svg$/,
type: 'asset/inline', // 将svg格式装换成base64的文件格式,并且不会在dist打包文件中生成
},
{
test: /\.txt$/,
type: 'asset/source' // 导出资源的源代码
},
// {
// type: 'asset' // 通用资源类型,在resource和inline之间自动选择,选择依据是资源的大小, 默认的是8Kb
// }
{
test: /\.(css|less)$/,
use: [MinCssExtractPlugin.loader, 'css-loader', 'less-loader']
},
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env'],
plugins: [
[
'@babel/plugin-transform-runtime'
]
]
}
}
}
]
},
optimization: {
splitChunks: {
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
chunks: 'all'
}
}
}
},
performance: {
maxEntrypointSize: 10000000,
maxAssetSize: 300000000
}
}
把生产环境和开发环境相同的配置删除
开发
module.exports = {
output: { // 出口
filename: 'script/[name].js',
},
mode: 'development', // 设置成开发环境
devtool: 'inline-source-map', // 用于设置精准定位错误位置 并且会格式化打包生成的Js文件
devServer: {
static: './dist'
},
}
生产
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin')
const TerserPlugin = require('terser-webpack-plugin')
module.exports = {
output: { // 出口
filename: 'script/[name].[contenthash].js',
publicPath: 'http://localhost:8081/'
},
mode: 'production', // 设置成开发环境
optimization: {
minimizer: [
new CssMinimizerPlugin(),
new TerserPlugin()
],
},
}
合并配置
安装:
npm install webpack-merge
使用: config/webpack.config.js
// 使用该merge合并,后面的内容覆盖前面的,可以查看该包的示例说明
const { merge } = require('webpack-merge')
const commonConfig = require('./webpack.config.common')
const productionConfig = require('./webpack.config.prod')
const developmentConfig = require('./webpack.config.dev')
module.exports = (env) => {
if (env.production) {
return merge(commonConfig, productionConfig)
}
if (env.development) {
return merge(commonConfig, developmentConfig)
}
return new Error('no match configuration was found')
}
修改package.json
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "webpack serve -c ./config/webpack.config.js --env development",
"build": "webpack serve -c ./config/webpack.config.js --env production"
},
webpack高级应用
提高开发效率和完善团队开发规范
source-map
用于快速定位代码, 有以下7种属性值
eval
开发环境下默认值,可以锁定代码行数
每个module会分装到eval里包裹起来执行,并且会在末尾追加注释//@sourceURL
source-map
生成一个sourecMap文件,会在末尾追加一个注释,可以锁定代码行数
//# sourceMappingURL=main.js.map
hidden-source-map
和source-map一样,但是不会在末尾追加注释,无法锁定代码行数
inline-source-map
生成一个DataUrl形式的sourceMap文件,可以锁定代码行数
会在末尾生成一个注释
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWFpbi5qcyIsIm1hcHBpbmdzIjoiOzs7OztBQUFBO0FBQ0E7QUFDQTtBQUNBLGtCIiwic291cmNlcyI6WyJ3ZWJwYWNrOi8vMDEtc291cmNlLW1hcC8uL2FwcC5qcyJdLCJzb3VyY2VzQ29udGVudCI6WyJjb25zb2xlLmxvZygnaGVsbG8gd2VicGFjaycpXHJcblxyXG5cclxuY29uc29sZS5sb2coJ+esrOS6jOihjCcpIl0sIm5hbWVzIjpbXSwic291cmNlUm9vdCI6IiJ9
eval-source-map
每个module会通过eval()来执行,并且生成一个DataUrl形式的sourceMap,可以锁定代码行数
//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi9hcHAuanMuanMiLCJtYXBwaW5ncyI6IkFBQUE7QUFDQTtBQUNBO0FBQ0EiLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly8wMS1zb3VyY2UtbWFwLy4vYXBwLmpzPzlhNzgiXSwic291cmNlc0NvbnRlbnQiOlsiY29uc29sZS5sb2coJ2hlbGxvIHdlYnBhY2snKVxyXG5cclxuXHJcbmNvbnNvbGUubG9nKCfnrKzkuozooYwnKSJdLCJuYW1lcyI6W10sInNvdXJjZVJvb3QiOiIifQ==\n//# sourceURL=webpack-internal:///./app.js\n");
cheap-source-map
会生成一个没有列信息的sourceMaps文件,不包含loader的sourcemap(比如:不包含babel的sourcemap,如ES6代码经过babel转换后无法定位锁定)
可以锁定代码行数
cheap-module-source-map
生成一个没有列信息的sourcemaps文件,同时loader的sourcemap也被简化为只包含对应行的。
(可以定位到经过转化之后的代码行数)
可以锁定代码行数
注意点
生产环境一般不开启sourcemap功能,主要原因
1、通过bundle和sourcemap文件,可以反编译出源码 ---- 也就是说线上产物有sourcemap文件的话,就意味着有暴露源码的风险
2、sourcemap文件的体积相对比较巨大,这跟我们生产环境的追求不同,生产环境追求更小更轻量的bundle
devServer
开发环境下,我们往往需求启动一个web服务,为了方便模拟一个用户从浏览器访问我们的web服务,读取我们的打包产物,以观测我们的代码在客户端的表现,webpakc内置了这样的功能。
安装
npm install webpack-dev-server
module.exports = {
entry:'./app.js',
mode: 'development',
output: {
publicPath: '/'
},
devServer: {
static: path.resolve(__dirname, './dist'), // 设置静态资源路径
// 该属性用于配置是否在服务器端进行代码压缩,服务器在代码传输到浏览器中数据是压缩了的。提升传输效率
compress: true,
port: 3000, // 设置端口
headers: { // 设置响应头信息
'X-Access-Token': 'abc123'
},
host: '0.0.0.0', // 配置主机
proxy: { // 配置代理
'/api': 'http://localhost:9000'
},
// https: true // 设置成https
http2: true, // 设置成http2
historyApiFallback: true
},
plugins: [
new HtmlWebpackPlugin()
],
}
开启了compress之后,会在响应头中出现该设置
response header: Content-Encoding: gzip
开启代理
如果我们本地有一个ajax请求,但是端口是不一样的
根目录下新建文件 server.js 开启本地服务并监听端口
const http = require('http')
const app = http.createServer((req, res) => {
if(req.url === '/api/hello') {
res.end('hello node')
}
})
app.listen(9000, 'localhost', () => {
console.log('localhost: 9000')
})
在项目js文件中请求
fetch('/api/hello')
.then(response => response.text())
.then(result => {
console.log(result)
})
此时会提示404或者跨域问题。可以通过配置代理的方式解决
module.exports = {
...
devServer: {
...
proxy: {
'/api': 'http://localhost:9000'
},
},
}
配置https
想让我们的http变成https,使用配置
注意: 此时使用http是无法访问我们的服务器的,需要改成Https,由于默认配置使用的是自签名证书,所有有的浏览器会告诉你不安全。但依然可以访问。同时也可以使用我们自己的证书
module.exports = {
devServer: {
...
https: true
},
}
也可以使用http2,这个是本身自带签名证书的
module.exports = {
devServer: {
...
http2: true
},
}
historyApiFallback
如果我们的应用是个SPA单应用,当路由到/some时(可以直接到地址栏里输入),会发现此时刷新页面后控制台会报错。
比如页面访问了https://localhost:3000/home,但是你并没有配置该路由,此时就会报错,通过historyApiFallback可以继续访问自己的根路径
module.exports = {
...
devServer: {
...
historyApiFallback: true
},
}
开发服务器主机
如果你在开发环境中起了devserver服务,并期望你的同事访问它,只需要配置
module.exports = {
...
devServer: {
...
host: '0.0.0.0',
},
}
模块热替换和热加载
module.exports = {
...
devServer: {
hot: true, // 热替换
liveReload: true // 热加载
},
}
css-loader会实现模块热替换配置,js要单独处理
如想要app.js修改之后页面直接改变,则需要 module.hot.accept('./app.js')
if(module.hot) {
module.hot.accept('./app.js')
}
Eslint
安装
npm install eslint
npx eslint --init
webpack中配置eslint webpack.docschina.org/plugins/esl…
npm install eslint-webpack-plugin
用法
const ESLintPlugin = require('eslint-webpack-plugin');
module.exports = {
// ...
plugins: [new ESLintPlugin(options)],
// ...
};
代码中如果有eslint问题未处理,此页面会报错,可以通过devServer配置来处理
module.exports = {
...
devServer: {
client: {
overlay: false, // 设置成false,eslint就只会在控制台报错,不会影响页面
},
},
plugins: [
...
new ESLintPlugin(),
],
};
git-hooks和husky
在代码提交前检查代码eslint规则
www.bilibili.com/video/BV1YU… 视频教程
www.npmjs.com/package/hus… 官方文档链接
模块与依赖
[js, css,less,img,html等文件] -------》 loader + module --------》模块化文件
解析时是通过enhanced-resolve这个包来完成的
模块解析
可以解析 绝对路径 相对路径 第三方包(模块路径)
设置路径别名 文件名不写
const path = require('path')
module.exports = {
...
resolve: {
alias: {
'@': path.resolve(__dirname, './src'),
},
// 如果引入的时候文件名可以不写,先匹配json, 然后是js, vue
extensions: ['.json', 'js', '.vue']
}
}
外部扩展
当使用第三方包的时候,希望该不参与打包(不用npm install方式导入),可以使用外部扩展的方式
以jquery为例
module.exports = {
externalsType: 'script', // 配置以script标签包裹
externals: {
// 参数说明: jquery的cdn链接 暴露出去的名称
jquery: [
'https://cdn.staticfile.org/jquery/1.10.2/jquery.min.js',
'$'
]
}
}
经过这种cdn引入的方式,那么就可以不参与打包,也可以定义一个html模板文件,然后在该文件中引入
<script src="https://cdn.staticfile.org/jquery/1.10.2/jquery.min.js"></script>
依赖图
分析各个模块之前的引用关系
安装
npm install webpack-bundle-analyzer
使用
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer')
module.exports = {
...
plugins: [
...
new BundleAnalyzerPlugin()
],
...
}
用服务器打开在页面中访问即可
npx webpack serve
扩展功能
postCss
是一个用javascript工具和插件转换css代码的工具,比如可以用autoprefixer插件自动获取浏览器的流行度和能够支持的属性,并根据这些数据帮我们自动的为css规则添加前缀,将最新的css语法转换成大多数浏览器都能够理解的语法
即自动的帮我们处理css兼容性问题
安装 style-loader css-loader安装过了得话就不用安了
npm install style-loader css-loader postcss-loader autoprefixer
增加webpack解析配置
module.exports = {
...
module: {
...
rules: [
...
{
test: /\.css$/,
use: ['style-loader', 'css-loader', 'postcss-loader']
},
]
}
}
根目录下新建一个文件postcss.config.js
module.exports = {
plugins: [
require('autoprefixer'),
]
}
在package.json中修改浏览器支持情况
{
...
"browserslist": [
"> 1%", // 浏览器全球使用率大于1%的
"last 2 versions" // 最新两个版本之内的
]
}
此时直接启动项目运行即可看到浏览器兼容处理
例如给body写了一个css
body{
background: red;
display: flex; // 浏览器支持要单独处理
}
解析出来的结果
display: -webkit-box;
display: -ms-flexbox;
display: flex;
让css支持嵌套写法
安装
npm install postcss-nested
配置使用 postcss.config.js
module.exports = {
plugins: [
require('autoprefixer'),
require('postcss-nested') // 支持扩展
]
}
body{
background: red;
display: flex;
.box {
width: 100px;
height: 100px;
background: yellow;
}
}
此时即会和less sass功能同样使用
css模块
css模块:能让你不用担心命名太大众化而造成冲突
使用方式:配置css loader
module.exports = {
...
module: {
// type用于定义转换类型
rules: [
// 将.jpg文件转换成链接形式
{
test: /\.css$/,
use: ['style-loader', {
loader: 'css-loader',
options: {
modules: true
}
}, 'postcss-loader']
},
]
}
}
也可以部分开启css模块模式,比如全局样式可以冠以 .global 前缀,如
*.global.css普通模式
*.css css module模式
module.exports = {
...
// 定义模块资源
module: {
rules: [
// global模式
{
test: new RegExp(`^(?!.*\\.global).*\\.css`),
use: [
{
loader: 'style-loader'
},
{
loader: 'css-loader',
options: {
modules:true,
localIdenName: '[hash:base64:6]'
}
}
],
exclude: [path.resolve(__dirname, '..', 'node_modules')]
},
// 普通模式
{
test: new RegExp(`^(.*\\.global).*\\.css`),
use: [
{
loader: 'style-loader'
},
{
loader: 'css-loader',
}
],
exclude: [path.resolve(__dirname, '..', 'node_modules')]
},
]
}
}
web works
webpack5.x版本中,是自带支持web Worker功能的。
使用方式
const worker = new Worker(new URL('./work.js', import.meta.url))
worker.postMessage({
question: '问题'
})
worker.onmessage = (message) => {
console.log(message)
}
self.onmessage = (message) => {
self.postMessage({
answer: 1111
})
}
typescript
安装
npm install typescript ts-loader
webpack配置
const HtmlWebpackPlugin = require('html-webpack-plugin')
const path = require('path')
module.exports = {
entry: './src/app.ts', // 入口
mode: 'development', // 设置成开发环境
output: { // 出口
filename: 'bundle.js',
path: path.resolve(__dirname, './dist'), // 设置绝对路径
clean: true, // 自动清除上次打包出来的文件
},
// ts解析
module: {
rules: [
{
test: /\.ts$/,
use: 'ts-loader',
exclude: /node_modules/
}
]
},
resolve: {
extensions: ['.ts', '.js'] // 不写文件名时优先找ts文件
}
}
再执行这个会生成一个tsconfig.json配置文件
npx tsc --init
tsconfig.json
{
...
"rootDir": "./src", // ts检查的文件
"outDir": "./dist", // 输出的文件,对应的webpack中的输出文件
}
当我们使用某个第三方包时,也要安装相关的类型文件。具体安装第三方相关依赖查询下列官方文档
官方地址www.typescriptlang.org/dt/search?s…
多页面应用
为了更好的性能,不同的功能模块配置不同的html
const HtmlWebpackPlugin = require('html-webpack-plugin')
const path = require('path')
module.exports = {
entry: {
index: {
import: './src/index.js',
dependOn: 'sharedLo'
},
another: {
import: './src/another-modules.js',
dependOn: 'sharedLo'
},
sharedLo: 'lodash'
},
plugins: [
new HtmlWebpackPlugin({
template: 'index1.html', // 依据哪个模板来生成
filename: 'index1.html', // 生成的文件名
chunks: ['index', 'sharedLo'] // 该页面分别引入哪些上面的chunk
}),
new HtmlWebpackPlugin({
template: 'index2.html', // 依据哪个模板来生成
filename: 'index2.html', // 生成的文件名
chunks: ['another', 'sharedLo'] // 该页面分别引入哪些上面的chunk
}),
],
}
Tree Shaking
没有使用过的代码不参与打包 基于ESM中的module.就算是引用了但是没有使用过也会被摇掉.
缺点: 第三方包引入了但是没有使用也会被打包
module.exports = {
...
optimization: {
usedExports: true
}
}
sideEffects
告诉webpack哪些文件没有副作用,如果没有使用则不参与打包
webpack4.x 默认所有文件都是有副作用的。所以默认是不会进行tree shaking的
webpack5中可以通过设置sideEffects来实现
比如在文件中引入了css,但实际上未使用
import { add } from './math'
import './style.css' // 引入未使用
console.log(add(4, 5))
默认的情况下也会参与打包编译,此时可以通过设置sideEffects
在package.json中 (!!!只要引用了的第三方包依然会参与打包)
{
"name": "05-tree-shaking",
...
"sideEffects": false, // 默认值是true,所有的文件都是有副作用的,设置成false则所有的都没有副作用
}
也可以单独将某些文件副作用去除掉
{
"name": "05-tree-shaking",
...
"sideEffects": ["*.css"], // 意思是.css文件是有副作用的,不能进行tree shaking
}
渐进式网络应用程序PWA
可以使用http-server包来启动项目
安装:
npm install http-server
使用 package.json中定义启动脚本 可以直接npm start启动项目
"scripts": {
"start": "http-server dist"
},
动态打包文件: 每次修改后帮我们重新打包
module.exports = {
...
devServer: {
devMiddleware: {
writeToDisk: true
}
}
}
离线下访问
安装
npm install workbox-webpack-plugin
创建service work
const WorkboxPlugin = require('workbox-webpack-plugin')
module.exports = {
...
plugins: [
...
new WorkboxPlugin.GenerateSW({
clientsClaim: true,
skipWaiting: true
})
],
// 这个是为了能让代码存储到硬盘中
devServer: {
devMiddleware: {
writeToDisk: true
}
}
}
开启service work
if('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker.register('/service-worker.js') // 打包会生成该文件
.then(registration => {
console.log('SW注册成功', registration)
})
.catch(registrationError => {
console.log('SW注册失败', registrationError)
})
})
}
之后启动项目npm start之后,就算结束该项目运行依然可以访问。因为已经缓存到了浏览器中。
缓存访问地址 chrome://serviceworker-internals/
预置依赖Shimming
全局引入第三方依赖
const webpack = require('webpack')
module.exports = {
...
plugins: [
...
new webpack.ProvidePlugin({
_: 'lodash' // 通过 _ 直接使用lodash
})
],
}
// 使用 _.join(['hello', 'shimming'], ' ')
细粒度
一些遗留模块依赖的this指向的是window对象,有些时候可能this指向的module.export,为了解决这个问题将this指向window
安装
npm install imports-loader
使用
module.exports = {
...
module: {
rules: [
{
test: require.resolve('./src/index.js'), // 要关联的文件
use: 'imports-loader?wrapper=window'
}
]
}
}
全局exports
如果引入了一些第三方包,但是不知道这个包是如何导出的,则可以使用这种全局导出
安装
npm install exports-loader
定义文件
const file = 'example test'
const helpers = {
test: function() {
console.log('test something')
},
parse: function() {
console.log('parse something')
}
}
配置全局导出
module.exports = {
...
module: {
rules: [
{
test: require.resolve('./src/globals.js'),
use: 'exports-loader?type=commonjs&exports=file,multiple|helpers.parse|parse'
}
]
}
}
直接使用
const { file, parse } = require('./globals')
console.log(file)
console.log(parse())
加载Polyfills
作用:优雅降级
安装
npm i @babel/polyfill
使用
import '@babel/polyfill'
console.log(Array.from([1,2,3], x => x + x))
按需加载polyfills
安装
npm install babel-loader @babel/core @babel/preset-env core-js@3 -D
配置
module.exports = {
...
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: [['@babel/preset-env', {
targets: [
'last 1 version',
'> 1%'
],
useBuiltIns: 'usage',
corejs: 3
}]],
}
}
}
]
}
}
创建Library
它只能通过被script标签引用而发挥作用,不能运行在Common、AMD、Node.js环境中,我们希望它能够兼容不同的环境,也就是说,用户应该能够通过以下方式使用打包后的库
Common.js module require
AMD module require
script tag,设置type值为umd来实现
配置
const HtmlWebpackPlugin = require('html-webpack-plugin')
const { resolve } = require('path')
const path = require('path')
module.exports = {
...
output: {
path: path.resolve(__dirname, 'dist'),
clean: true,
filename: 'mylib.js',
library: {
name: 'mylib', // 这样这个文件就不会被treeShaking
type: 'umd', // window commongjs umd可以让他支持node和window ,单需要加上下面的globalObject
},
globalObject: 'globalThis' // 需加上该属性
},
}
定义文件 src/index
export const add = (x, y) => {
return x + y
}
使用1,然后通过npx http-server可以在浏览器访问
<!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>
</body>
</html>
<script src="../dist/mylib.js"></script>
<script>
console.log(mylib.add(1, 2))
</script>
使用2 用node执行该文件
const {add} = require('../dist/mylib')
console.log(add(6, 7))
创建一个符合各个环境之间的包
module.exports = {
...
output: {
...
library: {
name: 'webpackNumbers', // 这样这个文件就不会被treeShaking
type: 'umd', // window commongjs
},
globalObject: 'globalThis'
},
// 发布上去之后提示没有lodash文件,待解决
externals: { // 放到这里面让第三方包其不参与打包,减少打包体积
lodash: {
commonjs: 'lodash',
commonjs2: 'lodash',
amd: 'lodash',
root: '_'
}
}
}
自己定义两个方法
import _ from 'lodash'
import numRef from './ref.json'
export function numToWord(num) {
return _.reduce(numRef, (accum, ref) => {
return ref.num === num ? ref.word : accum
}, '')
}
export function wordToNum(word) {
return _.reduce(numRef, (accum, ref) => {
return ref.word === word && word.toLowerCase() ? ref.num : accum
}, -1)
}
使用 node引入自己的包然后使用
const webpackNumbers = require('../dist/webpack-numbers')
console.log(webpackNumbers.numToWord(3))
发布到npm上
把上面自己定义的两个方法(numToWord, wordToNum)发布到npm上
相关代码在 part-2/08-library/-2-webpack-numbers
首先在npm上注册一个自己的账号(这个是我自己的包管理页面)
npm config get registry
这个时候会出来如下一个链接 要保证这个链接是https的,保证是npm的源
在确定了上面npm正确之后
执行
npm adduser
然后输入自己的npm账号密码和邮箱,执行publish之后就可以发布上去了
npm publish
要保证自己的包名是唯一的,否则会发布失败 package.json
{
"name": "webpack-numbers-test-ccczzzjjj", // 包名
"version": "1.0.0", // 版本
"main": "dist/webpack-numbers.js", // 指向你打完包之后的文件路径
}
安装使用
npm install webpack-numbers-test-ccczzzjjj
import { numToWord } from 'webpack-numbers-test-ccczzzjjj'
console.log(11111, numToWord(3))
模块联邦(Module Federation)
可以理解为微前端
目前我们有三个独立的项目 nav search home
实现功能将项目中的组件暴露出来给其他项目使用
nav项目运行在localhost:3003中 (npx webpack serve --port 3003)
home项目运行在localhost: 3001中 (npx webpack serve --port 3001)
search项目运行在localhost: 3002中 (npx webpack serve --port 3002)
在nav项目下有一个文件 src/Header
const Header = () => {
const header = document.createElement('h1')
header.textContent = '公共头'
return header
}
export default Header
这个时候要通过模块联邦将他暴露出去 nav下webpac.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin')
const { ModuleFederationPlugin } = require('webpack').container
module.exports = {
entry: './src/index.js',
mode: 'production',
plugins: [
new HtmlWebpackPlugin(),
new ModuleFederationPlugin({
name: 'nav', // 定义的名称,之后其他项目通过这个来引入
filename: 'remoteEntry.js', // 定义的引入的远端项目文件
remotes: {},
exposes: { // 暴露给别的组件使用
'./Header': './src/Header.js' // 其它项目使用时通过/Header来使用。 后面是文件路径
},
shared: {} // 共享的第三方包 如lodash等
})
]
}
比如现在home项目要使用nav暴露出来的组件 home下webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin')
const { ModuleFederationPlugin } = require('webpack').container
module.exports = {
entry: './src/index.js',
mode: 'production',
plugins: [
new HtmlWebpackPlugin(),
new ModuleFederationPlugin({
name: 'home', // 名称
filename: 'remoteEntry.js', // 远端仓库文件(暴露给其他组件的)
remotes: {
//定义一个nav,他的值是上面定义的name和nav项目的运行地址以及filename的值(看上面配置)
nav: 'nav@http://localhost:3003/remoteEntry.js'
},
exposes: { // 暴露给别的组件的东西(没有的话可不写)
'./HomeList': './src/HomeList.js'
},
shared: {} // 共享的第三方包
})
]
}
使用:home中业务代码,因为这个是异步的并且返回的是一个promise
import('nav/Header').then((Header) => {
const body = document.createElement('div')
body.appendChild(Header.default()) // 通过这个default来取这个组件
document.body.appendChild(body)
})
完整代码地址 part-2/09-module-federation下
通过npx webpack serve --port 3001 3002 3003分别让三个项目跑起来就可以看到效果
提升构建性能
分为两种1、项目性能 (首屏加载时间,页面响应速度) 2、构建时间体积
三种环境 1、通用环境 2、开发环境 3线上环境
通用优化
1、更新webpack版本 和node.js版本
2、将loader应用于最少数量的必要模块 (如下 只解析src下的js文件)
module.exports = {
module: {
rules: [
{
test: /\.js$/,
include: path.resolve(__dirname, 'src'),
loader: 'babel-loader'
}
]
}
}
3、引导(bootstrap)
每个额外的loader/plugin都有其启动时间,尽量少的使用工具
4、解析
- 减少resolve.modules, resolve,extensions,resolve.mainFiles, resolve.descriptionFiles中条目数量,因为他们会增加文件系统调用的次数
- 如果你不使用symlinks(例如 npm link或者yarn link),可以设置resolve.symlinks:false
- 如果你使用自定义resolve plugin规则,并且没有指定context上下文,可以设置resolve.cacheWithContext:false
5、小即是快
减少编译结果的整体大小,以提高构建性能,尽量保持chunk体积小
- 使用数量更少/体积更小的library
- 在多页面应用中使用SplitChunksPlugin,并开启async模式
- 移除未引用的代码
- 只编译你当前正在开发的那些代码
6、持久化缓存
在webpack配置中使用cache选项,使用package.json中的postinstall清除缓存目录
将cache类型设置为内存或文件系统,memory选项很简单,它告诉webpack在内存中存储缓存,不允许额外配置
module.exports = {
...
cache: {
type: 'memory'
}
}
7、自定义plugin/loader
对他们进行概要分析,以免在此处引入性能问题
8、progress plugin
将ProgressPlugin从webpack中删除,可以缩短构建时间。
注意: ProgressPlugin可能不会为快速构建提供太多价值,权衡使用
9、dll
代码路径 part2/10-build-performance/01-dll
DllPlugin 和 DllReferencePlugin 用某种方法实现了拆分 bundles,同时还大幅度提升了构建的速度
使用DllPlugin为更改不频繁的代码生成单独的编译结果,这样可以提高应用程序的编译速度,尽管它增加了构建过程的复杂度
比如要使用jquery,将他解析成单独的chunk
在根目录下新建文件夹 webpack.dll.config.js
const path = require('path')
const webpack = require('webpack')
module.exports = {
mode: 'production',
entry: {
jquery: ['jquery'] // 可以把其他包名字也放进去
},
output: {
filename: '[name].js', // 输出的动态链接库的文件名称,[name] 代表当前动态链接库的名称,
path: path.resolve(__dirname, 'dll'),
library: '[name]_[hash]' //library必须和后面dllplugin中的name一致
},
plugins: [
// 接入 DllPlugin
new webpack.DllPlugin({
// 动态链接库的全局变量名称,需要和 output.library 中保持一致
// 该字段的值也就是输出的 manifest.json 文件 中 name 字段的值
name: '[name]_[hash]',
// 描述动态链接库的 manifest.json 文件输出时的文件名称
path: path.resolve(__dirname, 'dll/manifest.json')
})
]
}
然后执行打包命令
webpack --config ./webpack.dll.config.js
manifest.json文件里,是用来描述对应的dll文件里保存的模块,里面暴露出刚刚构建的所有模块
修改配置文件 webpack.config.js
安装
npm install add-asset-html-webpack-plugin
配置
const HtmlWebpackPlugin = require('html-webpack-plugin')
const webpack =require('webpack')
const path = require('path')
const AddAssetHtmlPlugin =require('add-asset-html-webpack-plugin')
module.exports = {
...
plugins: [
...
new webpack.DllReferencePlugin({
manifest: path.resolve(__dirname, './dll/manifest.json') // 上面生成的文件路径
}),
// 加上这个插件才可以在页面中访问
new AddAssetHtmlPlugin({
// 指向打包出来的文件名路径
filepath: path.resolve(__dirname, './dll/jquery.js'),
publicPath: './' // 当前路径
})
]
}
10、worker池(worker pool)
thread-loader可以将非常消耗资源的loader分流给一个worker pool (和happypack一样)
安装
npm install thread-loader
使用: 比如我们要处理babel-loader
module.exports = {
....
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: [
{
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env']
}
},
// 将babel-loader分配给worker pool
{
loader: 'thread-loader',
options: {
workers: 2 // 定义CPU数量
}
}
]
}
]
}
}
注意: 不要使用太多的worker,因为Nodejs的runtime和loader都有开销,最小化worker和main process主进程之间的模块传输。进程间通讯(IPC inter process communication)是非常消耗资源的
开发环境提升构建性能
1、增量编译
使用webpack的watch mode(监听模式)。而不使用其他工具来watch文件和调用webpack,内置的watch mode会记录时间戳并将此信息传递给compilation以使缓存失效。
在某些配置环境中,watch mode会回退到poll mode(轮询模式),监听太多文件会导致CPU大量负载,这些情况下,可以使用watchOptions.poll来增加轮询的间隔时间
2、在内存中编译
下面几个工具通过在内存中(而不是写入磁盘)编译和serve资源来提高性能
- webpack-dev-server
- webpack-hot-middleware
- webpack-dev-middleware
3、stats.toJson加速
webpack4默认使用stats.toJson()输出大量数据,除非在增量步骤中做必要的统计,否则请避免获取stats对象的部分内容
webpack-dev-server在V3.13.3以后的版本,包含一个重要的性能修复,即最小化每个增量构建步骤中,从stats对象获取的数据量
4、devtool
- eval具有最好的性能,但不能帮你转译代码
- cheap-source-map配置可以提高性能,但是map质量会稍差
- 使用eval-source-map配置进行增量编译
- 大多情况下,最佳选择是eval-cheap-module-source-map
5、避免在生产环境才用到的工具
某些utility、plugin和loader都只能用生产环境,比如在开发环境进行压缩是没有意义的
应该排查以下工具
- TerserPlugin
- [fullhash]/[chunkhash]/[contenthash]
- AggressiveSplittingPlugin
- AggressiveMergingPlugin
- ModuleConcatenationPlugin
6、最小化entry chunk
确保在生成entry chunk时,尽量减少其体积以提高性能
module.exports = {
...
optimization: {
runtimeChunk: true
}
}
7、避免额外的优化步骤
webpack通过执行额外的算法任务,来优化输出结果的体积和加载性能。这些优化适用于小型代码库,但是在大型代码库中却非常消耗性能
module.exports = {
...
optimization: {
removeAvailavleModules: false,
removeEmptyChunks: false,
splitChunks: false
}
}
8、输出结果不携带路径信息
webpack会在输出的bundle中生成路径信息。然而在打包数千个模块的项目中,这会导致垃圾回收性能的压力,在options.output.pathinfo设置中关闭
module.exports = {
...
output: {
pathinfo: false
}
}
9、TypeScript Loader
可以为loader传入transpileOnly选项,以缩短使用ts-loader时的构建时间。使用此选项,会关闭类型检查。如果要再次开启类型检查,请使用ForkTsCheckerWebpackPlugin,使用此插件会将检查过程转移至单独的进程,可以加快Typescript的类型检查和Eslint插入的速度。
module.exports = {
...
module: {
rules: [
{
test: /\.tsx?$/,
use: [
{
loader: 'ts-loader',
options: {
transpileOnly: true
}
}
]
}
]
}
}
生产环境优化
不起用sourceMap
source map相当消耗资源,开发环境模式不要设置source map