webpack基本配置

webpack配置

webpack 文档

webpack基本配置

安装:

1
2
3
4
5
npm install --save-dev webpack webpack-cli webpack-merge sass-loader node-sass css-loader postcss-loader  mini-css-extract-plugin babel-loader autoprefixer @babel/preset-env @babel/core @babel/plugin-syntax-dynamic-import 
......

# 或指定版本
npm install --save-dev webpack@<version>

package.json:

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
{
"name": "webpack5-demo",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"dev-without-dev-server": "webpack --config build/webpack.dev.js",
"dev": "webpack serve --config build/webpack.dev.js",
"build": "webpack --config build/webpack.prod.js"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"@babel/core": "^7.16.7",
"@babel/preset-env": "^7.16.8",
"autoprefixer": "^10.1.0",
"babel-loader": "^8.2.3",
"clean-webpack-plugin": "^3.0.0",
"file-loader": "^6.2.0",
"html-webpack-plugin": "^4.5.0",
"mini-css-extract-plugin": "^2.4.6",
"optimize-css-assets-webpack-plugin": "^5.0.4",
"postcss-loader": "^6.2.1",
"css-loader": "^6.5.1",
"node-sass": "^7.0.1",
"sass-loader": "^12.4.0",
"style-loader": "^3.3.1",
"terser-webpack-plugin": "^5.0.3",
"url-loader": "^4.1.1",
"webpack": "^5.65.0",
"webpack-cli": "^4.9.1",
"webpack-merge": "^5.8.0",
},
"dependencies": {
"lodash": "^4.17.20"
}
}

折分配置和merge

1.文件: webpack.common.js / webpack.dev.js / webpack.pord.js

2.通过merge把common.js引入到dev.js和pord.js中;

1
2
3
4
5
6
const { merge } = require('webpack-merge');
const common = require('./webpack.common');

module.exports = merge(common, {
mode: 'production',
});

webpack.common.js

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
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const { srcPath, distPath } = require('./paths')

module.exports = {
entry: path.join(srcPath, 'index'),
module: {
rules: [
#// 处理ES6
{
test: /\.js$/,
loader: ['babel-loader'],
include: srcPath,
exclude: /node_modules/ #//排除node_modules文件夹
},
# // {
# // test: /\.vue$/,
# // loader: ['vue-loader'],
# // include: srcPath
# // },
{
test: /\.css$/,
#// loader 的执行顺序是:从后往前
loader: ['style-loader', 'css-loader', 'postcss-loader'] #// 加了 postcss
},
{
test: /\.less$/,
#// 增加 'less-loader' ,注意顺序
loader: ['style-loader', 'css-loader', 'less-loader']
},
# // 直接引入图片 url
# //{
# // test: /\.(png|jpg|jpeg|gif)$/,
# // use: 'file-loader'
# //},
# // 图片 - 考虑 base64 编码的情况
{
test: /\.(png|jpg|jpeg|gif)$/,
use: {
loader: 'url-loader',
options: {
#// 小于 5kb 的图片用 base64 格式产出
#// 否则,依然延用 file-loader 的形式,产出 url 格式
limit: 5 * 1024,

#// 打包到 img 目录下
outputPath: '/img1/',

#// 设置图片的 cdn 地址(也可以统一在外面的 output 中设置,那将作用于所有静态资源)
#// publicPath: 'http://cdn.abc.com'
}
}
},
]
},
plugins: [
#// 生成 index.html
new HtmlWebpackPlugin({
template: path.join(srcPath, 'index.html'),
filename: 'index.html'
})
]
}

paths.js

1
2
3
4
5
6
7
8
9
const path = require('path')

const srcPath = path.join(__dirname, '..', 'src')
const distPath = path.join(__dirname, '..', 'dist')

module.exports = {
srcPath,
distPath
}

webpack.dev.js

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
const path = require('path')
const webpack = require('webpack')
const webpackCommonConf = require('./webpack.common.js')
const { merge } = require('webpack-merge')
const { srcPath, distPath } = require('./paths')

module.exports = merge(webpackCommonConf, {
mode: 'development',
plugins: [
new webpack.DefinePlugin({
#// window.ENV = 'development'
ENV: JSON.stringify('development')
})
],
devServer: {
port: 8080,
progress: true, #// 显示打包的进度条
contentBase: distPath, #// 根目录
open: true, #// 自动打开浏览器
compress: true, #// 启动 gzip 压缩

#// 设置代理(2种方式)
proxy: {
# //1. 将本地 /api/xxx 代理到 localhost:3000/api/xxx
'/api': 'http://localhost:3000',

#//2. 将本地 /api2/xxx 代理到 localhost:3000/xxx
'/api2': {
target: 'http://localhost:3000',
pathRewrite: {
'/api2': ''
}
}
}
}
})

webpack.pord.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
const path = require('path')
const webpack = require('webpack')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const webpackCommonConf = require('./webpack.common.js')
const { merge } = require('webpack-merge')
const { srcPath, distPath } = require('./paths')

module.exports = merge(webpackCommonConf, {
mode: 'production',
output: {
filename: 'bundle.[contenthash:8].js', #// 打包代码时,加上 hash 戳
path: distPath,
#// publicPath: 'http://cdn.abc.com' #// 修改所有静态文件 url 的前缀(如 cdn 域名),这里暂时用不到
},
plugins: [
new CleanWebpackPlugin(), #// 会默认清空 output.path 文件夹
new webpack.DefinePlugin({
#// window.ENV = 'production'
ENV: JSON.stringify('production')
})
]
})

启动本地服务

npm run dev
npm run build

package.json

1
2
3
4
5
6
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"devBuild": "webpack --config build/webpack.dev.js", #// webpack文件放在build文件夹
"dev": "webpack-dev-server --config build/webpack.dev.js",
"build": "webpack --config build/webpack.prod.js"
},

处理ES6 (编译成ES5,兼容浏览器)

  1. loader: [‘babel-loader’]
  2. .babelrc: “presets”: [“@babel/preset-env”]

webpack.common.js

1
2
3
4
5
6
{
test: /\.js$/,
loader: ['babel-loader'],
include: srcPath,
exclude: /node_modules/ #//排除node_modules文件夹
},

.babelrc

1
2
3
{
"presets": ["@babel/preset-env"]
}

处理CSS 或 SCSS

index.js 引入 css
1
import './style/style1.css'
webpack.common.js
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
  # // 处理css
{
test: /\.css$/,
loader: [
MiniCssExtractPlugin.loader, #// 注意,这里不再用 style-loader (<style>插入CSS方法);
'css-loader', #// css语法解析
'postcss-loader' #// 浏览器前缀
]
},

# // 处理scss
# // const globImporter = require('node-sass-glob-importer'); #//Sass@import语句的工具
{
test: /\.scss$/,
use: [
MiniCssExtractPlugin.loader,
{
loader: 'css-loader',
options: {
url: false,
},
},
'postcss-loader',
{
loader: 'sass-loader',
options: {
sassOptions: {
importer: globImporter(),
},
},
},
],
},
plugins: [
new MiniCssExtractPlugin(),
new StyleLintPlugin({
context: 'src',
configFile: path.resolve(__dirname, './.stylelintrc.json'),
files: ['**/*.scss'],
fix: false,
cache: true,
emitErrors: true,
failOnError: false,
}),
new ESLintPlugin(),
],
引用css前缀插件

安装autoprefixer: npm install –save-dev autoprefixer
引用css前缀插件: postcss.config.js

1
2
3
module.exports = {
plugins: [require('autoprefixer')] #// autoprefixer 增加前缀插件
}

处理图片

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
# // 图片 - 考虑 base64 编码的情况
{
test: /\.(png|jpg|jpeg|gif)$/,
use: {
loader: 'url-loader',
options: {
#// 小于 5kb 的图片用 base64 格式产出
#// 否则,依然延用 file-loader 的形式,产出 url 格式
limit: 5 * 1024,

#// 大于 5kb打包到 img 目录下
outputPath: '/img1/',

#// 设置图片的 cdn 地址(也可以统一在外面的 output 中设置,那将作用于所有静态资源)
#// publicPath: 'http://cdn.abc.com'
}
}
},
#// 或url-loader推荐webpack5使用内置的资源模块(asset):https://webpack.docschina.org/guides/asset-modules/
# //小于8kb输入data URI,否则输出文件路径
{
test: /\.(png|svg|jpg|gif)$/,
type: 'asset',
parser: {
dataUrlCondition: {
maxSize: 8 * 1024, #// 小于 8kb 的图片用 base64 格式产出
},
},

webpack高级配置

webpack配置多入口

产出多个html页面,每个页面对应一个js文件.
(1). entry 入口多个
(2). output 输出’[name].js’
(3). plugins 生成多个

webpack.common.js:

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

const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const { srcPath, distPath } = require('./paths')

module.exports = {
# //1. 入口
entry: {
index: path.join(srcPath, 'index.js'),
other: path.join(srcPath, 'other.js')
},
# // 2. 输出
output: {
filename: '[name].js', # // name 即多入口时 entry 的 key
# // filename: '[name].[contentHash:8].js', // 打包代码时,加上 hash 戳, content变了hash变, content不变,hash不变
chunkFilename: '[name].bundle.js',
path: distPath,
clean: true,
},
module: {
rules: [
{
test: /\.js$/,
loader: ['babel-loader'],
include: srcPath,
exclude: /node_modules/
},
{
test: /\.css$/,
#// loader 的执行顺序是:从后往前
loader: ['style-loader', 'css-loader', 'postcss-loader'] #// 加了 postcss
},
]
},
#// 3. 生成多个,每个实例建一个
plugins: [
# new CleanWebpackPlugin(), #// 会默认清空 output.path (dist)文件夹

#// 多入口 - 生成 index.html
new HtmlWebpackPlugin({
template: path.join(srcPath, 'index.html'),
filename: 'index.html',
#// chunks 表示该页面要引用哪些 chunk (即上面的 index 和 other),默认全部引用
chunks: ['index'] #// 只引用 index.js
}),
#// 多入口 - 生成 other.html
new HtmlWebpackPlugin({
template: path.join(srcPath, 'other.html'),
filename: 'other.html',
chunks: ['other'] #// 只引用 other.js
})
]
}

webpack如何抽离压缩css文件

(1). 用插件加载:MiniCssExtractPlugin
(2). plugins里面: new MiniCssExtractPlugin 生成CSS路径
(3). optimization 压缩文件
(4). 单个js文件里引入所需要的css: import ‘./style/style1.css’

安装:

1
npm install --save-dev mini-css-extract-plugin optimize-css-assets-webpack-plugin node-sass-glob-importer

webpack.common.js:

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
72
73
74
const MiniCssExtractPlugin = require('mini-css-extract-plugin');   #//css提取插件
const TerserJSPlugin = require('terser-webpack-plugin'); #//压缩插件
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin') #//压缩和优化CSS
const globImporter = require('node-sass-glob-importer'); #//Sass@import语句的工具

module.exports = merge(webpackCommonConf, {
mode: 'production',
output: {
......
},
module: {
rules: [
#// 抽离 css
{
test: /\.css$/,
loader: [
MiniCssExtractPlugin.loader, #// 注意,这里不再用 style-loader (<style>加载CSS方法);
'css-loader', #// css语法解析
'postcss-loader' #// 浏览器前缀
]
},
#// 抽离 less --> css
{
test: /\.less$/,
loader: [
MiniCssExtractPlugin.loader, #// 注意,这里不再用 style-loader
'css-loader',
'less-loader',
'postcss-loader'
]
},
#// 抽离 sass --> css
{
test: /\.scss$/,
use: [
MiniCssExtractPlugin.loader,
{
loader: 'css-loader',
options: {
url: false,
},
},
'postcss-loader',
{
loader: 'sass-loader',
options: {
sassOptions: {
importer: globImporter(),
},
},
},
],
},

]
},
plugins: [
new CleanWebpackPlugin(), #// 会默认清空 output.path 文件夹
new webpack.DefinePlugin({
#// window.ENV = 'production'
ENV: JSON.stringify('production')
}),

#// 抽离 css 文件
new MiniCssExtractPlugin({
filename: 'css/main.[contentHash:8].css'
})
],

optimization: {
#// 压缩 css
minimizer: [new TerserJSPlugin({}), new OptimizeCSSAssetsPlugin({})],
}
})

webpack如何抽离公共代码和第三方代码

(1). splitChunks分割代码块
(2). cacheGroups缓存分组
(3). plugins 多入口,chunks配置要引入的模块

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
entry: {
index: path.join(srcPath, 'index.js'),
other: path.join(srcPath, 'other.js')
},
plugins: [
// 多入口 - 生成 index.html
new HtmlWebpackPlugin({
template: path.join(srcPath, 'index.html'),
filename: 'index.html',
// chunks 表示该页面要引用哪些 chunk (即上面的 index 和 other),默认全部引用
chunks: ['index', 'vendor', 'common'] #// 要考虑代码分割
}),
// 多入口 - 生成 other.html
new HtmlWebpackPlugin({
template: path.join(srcPath, 'other.html'),
filename: 'other.html',
chunks: ['other', 'common'] #// chunks 引用考虑代码分割
})
],
optimization: {
// 压缩 css
minimizer: [new TerserJSPlugin({}), new OptimizeCSSAssetsPlugin({})],

// 分割代码块
splitChunks: {
chunks: 'all',
/**
* initial 入口 chunk,对于异步导入的文件不处理
async 异步 chunk,只对异步导入的文件处理
all 全部 chunk
*/

// 缓存分组
cacheGroups: {
// 第三方模块
vendor: {
name: 'vendor', #// chunk 名称
priority: 1, #// (数字越大越高)主权限更高,优先抽离,重要!!!
test: /node_modules/,
minSize: 0, #// 大小限制 可写..kb
minChunks: 1 #// 最少复用过几次
},

// 公共的模块
common: {
name: 'common', #// chunk 名称
priority: 0, #// 优先级
minSize: 30kb, #// 公共模块的大小限制
minChunks: 2 #// 公共模块最少复用过几次
}
}
}
}

webpack如何实现异步加载JS

index.js:

1
2
3
4
5
6
7
// 引入动态数据 - 懒加载dynamic-data.js文件, webpack默认支持的方式
setTimeout(() =>{
// vue react 异步组件
import('./dynamic-data.js').then(res => {
console.log(res.default.message); #// 注意这里的default
})
},1500);

dynamic-data.js内容

1
2
3
export default {
message: 'this is dynamic data'
}

webpack处理JSx

安装@babel/preset-react
babel-preset-react

1
npm install --save-dev @babel/preset-react

.babelrc

1
2
3
{
"presets": ["@babel/preset-react"]
}

webpack处理Vue

安装vue-loader

1
npm i vue-loader --save-dev

webpack.common.js
rules:[]里加上:

1
2
3
4
5
6
// 与babel-loader同理
{
test: /\.vue$/,
loader: ['vue-loader'],
include: srcPath,
},

module chunk bundle 的区别

module:
各个源码文件(图片,JS,CSS…能被引入的文件或文件名), webpack中一切皆模块;

chunk:
分析多模块合并成一个集合,如:
entry import() //文件引入
splitChunk // 分割代码块

bundle:
最终的输出文件

module chunk bundle 的区别