项目初始化

安装webpack、webpack-cli

1
npm i webpack webpack-cli -D

新建src/index.js文件,根目录新建webpack.config.js

1
2
3
4
5
6
7
8
9
10
11
// webpack.config.js

const path = require('path')

module.exports = {
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'build.js'
}
}

loader的使用

css处理

postcss-loader,一般配合 Autoprefixer 使用,自动获取浏览器的流行度和能够支持的属性,并根据这些数据帮你自动为 CSS 规则添加前缀

1
2
npm i style-loader css-loader postcss-loader -D
npm i autoprefixer -D

新建 postcss.config.js 配置文件

1
2
3
4
5
6
module.exports = {
//...
plugins: [
require('autoprefixer')
]
}

webpack.config.js:

1
2
3
4
5
6
7
8
9
10
module.exports = {
//...
module: {
rules: [
{
test: /\.css$/, use: ['style-loader', 'css-loader', 'postcss-loader']
}
]
}
}

打包less/sass、scss文件类似,只需安装 less-loader/sass-loader 即可。less-loader/sass-loader 放在 postcss-loader 之后

sass-loader requires you to install either Dart Sass or Node Sass on your own (more documentation can be found below).

文件处理

图片

背景图片使用 type 设置打包类型;src 使用 require('./assets/img.png').default,webpack 默认使用 esModule 引用图片对象而不是图片路径

type 设置 asset/resource 会生成图片原文件,asset/inline 会打包成 base64 格式,通过 parser/dataUrlCondition/maxSize 判断是否转为 base64 格式

1
2
3
{
test: /\.(png|svg|gif|jpe?g)$/, type: 'asset/resource'
}

webpack5.x 已弃用 url-loader、file-loader,踩半天坑才查到。https://webpack.docschina.org/guides/asset-modules/

可通过 file-loader 的 options 来设置打包图片的路径和名称

url-loader 会将图片打包为 base64 的格式,可减少请求次数,如果图片过大会影响打包体积,通过设置 limit 根据文件大小来判断是否转为 base64格式

5.x版本通过设置 generator 自定义文件输出名

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
module.exports = {
//...
module: {
rules: [
{
test: /\.css$/, use: ['style-loader', 'css-loader', 'postcss-loader']
},
{
test: /\.(png|svg|gif|jpe?g)$/,
type: 'asset/resource',
generator: {
filename: 'img/[hash][ext][query]'
},
parser: {
dataUrlCondition: {
maxSize: 24 * 1024
}
}
}
]
}
}

图标字体类似

babel

安装

1
npm i babel-loader @babel/core @babel/preset-env

规则

1
2
3
4
5
6
7
8
9
10
module.exports = {
//...
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: ['babel-loader']
}
]
}

新建 babel.config.json 文件

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

加载 vue 文件

1
npm i -D vue vue-loader vue-template-compiler

App.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<template>
<div>
<h2 class="title">{{title}}</h2>
</div>
</template>

<script>
export default {
name: "App",
data() {
return {
title: 'title'
}
},
}
</script>

<style scoped>
.title {
color: red;
}
</style>

index.js

1
2
3
4
5
6
import Vue from 'vue'
import App from './App.vue'

new Vue({
render: h => h(App)
}).$mount('#app')

此时打包会报错

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
File was processed with these loaders:
* ./node_modules/vue-loader/lib/index.js
You may need an additional loader to handle the result of these loaders.
|
> <div>
| <h2 class="title">{{title}}</h2>
| </div>
@ ./src/App.vue 1:0-94 11:2-8 12:2-17
@ ./src/index.js 2:0-28 5:13-16

ERROR in ./src/App.vue
Module Error (from ./node_modules/vue-loader/lib/index.js):
vue-loader was used without the corresponding plugin. Make sure to include VueLoaderPlugin in your webpack config.
@ ./src/index.js 2:0-28 5:13-16

1 error has detailed information that is not shown.
Use 'stats.errorDetails: true' resp. '--stats-error-details' to show it.

需要配合 VueLoaderPlugin 使用

1
2
3
const VueLoaderPlugin = require('vue-loader/lib/plugin-webpack5.js')

new VueLoaderPlugin()

如需使用 css 预编译器编写 vue 代码,需要安装相应的 loader

常用插件

https://webpack.docschina.org/plugins/

html-webpack-plugin

清空 dist 文件目录

clean-webpack-plugin

自定义打包 html 模板

DefinePlugin

定义全局变量,import { DefinePlugin } from ‘webpack’

copy-webpack-plugin

拷贝文件或者是整个目录到输出文件夹,https://webpack.docschina.org/plugins/copy-webpack-plugin/

uglifyjs-webpack-plugin

压缩 js 代码体积,https://www.npmjs.com/package/uglifyjs-webpack-plugin

proxy 代理

对于跨域的请求可以用 devServer/proxy 来解决

安装 webpack-dev-server,webpack.config.js 做以下配置,这样就可以友好的请求网址了

1
2
3
4
5
6
7
8
9
10
11
12
module.exports = {
//...
devServer: {
proxy: {
'/api': {
target: 'https://api.github.com',
pathRewrite: { '^/api': '' },
changeOrigin: true
}
}
}
};

开发/生产环境配置

1
npm i -D webpack-merge

新建 webpack.common.js、webpack.dev.js、webpack.prod.js 文件

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
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const CopyWebpackPlugin = require('copy-webpack-plugin')

module.exports = {
entry: './src/index.js',
output: {
path: path.join(__dirname, 'dist'),
filename: 'js/main.js',
publicPath: '/'
},
plugins: [
new HtmlWebpackPlugin({ template: path.join(__dirname, 'public/index.html') }),
new CopyWebpackPlugin({
patterns: [
{
from: 'public',
globOptions: {
ignore: ['**/index.html']
}
}
]
})
],
module: {
rules: [
{
test: /\.css$/, use: ['style-loader', 'css-loader', 'postcss-loader']
},
{
test: /\.(png|svg|gif|jpe?g)$/,
type: 'asset/resource',
generator: {
filename: 'img/[hash][ext][query]'
},
parser: {
dataUrlCondition: {
maxSize: 24 * 1024
}
}
},
{
test: /\.js$/,
exclude: /node_modules/,
use: ['babel-loader']
}
]
}
}

webpack.dev.js

1
2
3
4
5
6
7
8
9
10
const {merge} = require('webpack-merge')
const common = require('./webpack.common.js')

module.exports = merge(common, {
mode: 'development',
devtool: 'source-map',
devServer: {
hot: true
}
})

webpack.prod.js

1
2
3
4
5
6
7
8
9
10
11
12
13
const {merge} = require('webpack-merge')
const common = require('./webpack.common.js')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const UglifyjsWebpackPlugin = require('uglifyjs-webpack-plugin')

module.exports = merge(common, {
mode: 'production',
performance: false,
plugins: [
new CleanWebpackPlugin(),
new UglifyjsWebpackPlugin()
]
})