1.认识 Webpack

Webpack 是什么?

  • 官方的定义
    • Webpack 是一个用于现代 JavaScript 应用程序的 静态模块打包工具。
    • Webpack 处理应用程序时,
    • 它会在内部从一个或多个入口点构建一个 依赖图(dependency graph)
    • 然后将你项目中所需的每一个模块组合成一个或多个 bundles,它们均为静态资源,用于展示你的内容
  • 简单的说
    • 之前
      • 2010年左右,前端当时还是利用 jQuery 进行开发
      • 后端利用 php jsp 等技术将数据库的数据渲染到前端的页面上
      • 前后端开始是耦合的 维护和开发 都是一个不规范 繁琐的流程
    • 现在
      • 当三大框架的横行后 逐渐以MVVM(Model-View-ViewModel)模式来
      • 减少繁琐的 DOM 操作,以数据来驱动视图的变化,更加利于维护和开发
    • 为什么使用
      • 原生js不会提供所有的特性, 因此就需要引入各种插件
      • Webpack就是大一统的集成方案

Webpack 可以做什么

  • 使用Webpack作为前端构建工具通常可以做到以下几个方面的事情
    • 代码转换: TypeScript编译成JavaScriptSCSS编译成CSS等。
    • 文件优化: 压缩JavaScriptCSSHTML代码,压缩合并图片等。
    • 代码分割: 提取多个页面的公共代码、提取首屏不需要执行部分的代码让其异步加载。
    • 模块合并: 在采用模块化的项目里会有很多个模块和文件,需要构建功能把模块分类合并成一个文件。
    • 自动刷新: 监听本地源代码的变化,自动重新构建、刷新浏览器页面,通常叫做模块热替换HMR
    • 代码校验: 在代码被提交到仓库前需要校验代码是否符合规范,以及单元测试是否通过。
    • 自动发布: 更新完代码后,自动构建出线上发布代码并传输给发布系统。

2.搭建 Webpack

搭建基本环境

  • 安装最新的环境, 新建一个文件夹叫 test
  • test 根路径下载基本的依赖
    1
    2
    3
    yarn add webpack webpack-cli --save-dev
    yarn add webpack-dev-server -D
    yarn add html-webpack-plugin --save-dev
  • test/package.json 文件添加启动和打包的 shell 命令
    1
    2
    3
    4
    "scripts": {
    "serve": "webpack serve ",
    "build": "webpack"
    },
  • 新建基本的文件
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    # dist 目录不用手动创建 这个是打包自动生成的
    |-- node_modules
    ├── dist
    │ └── main.js
    ├── public
    │ └── index.html
    ├── package.json
    ├── src
    │ └── index.js
    └── webpack.config.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: {
    filename: 'main.js',
    path: path.resolve(__dirname, 'dist'),
    },
    mode: "development"
    }

测试

此时就完成了基本的搭建,可以来使用shell语句测试一下效果了
  • /src/index.js 写入 console.log('Hello Webpck');
  • 然后在项目根路径执行之前在package.json定义的shell命令
  • yarn build 就在在 /dist/main.js 发现转换后的代码了
  • 但是目前还是不能展示html页面 和 启动服务
  • 在下一阶段就将安装两个必要的插件
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
/*
* ATTENTION: The "eval" devtool has been used (maybe by default in mode: "development").
* This devtool is neither made for production nor for readable output files.
* It uses "eval()" calls to create a separate source file in the browser devtools.
* If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/)
* or disable the default devtool with "devtool: false".
* If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/).
*/
/******/ (() => { // webpackBootstrap
/******/ var __webpack_modules__ = ({

/***/ "./src/index.js":
/*!**********************!*\
!*** ./src/index.js ***!
\**********************/
/***/ (() => {

eval("console.log('Hello Webpck');\n\n//# sourceURL=webpack:///./src/index.js?");

/***/ })

/******/ });
/************************************************************************/
/******/
/******/ // startup
/******/ // Load entry module and return exports
/******/ // This entry module can't be inlined because the eval devtool is used.
/******/ var __webpack_exports__ = {};
/******/ __webpack_modules__["./src/index.js"]();
/******/
/******/ })()
;

3.配置插件

导读

  • 自己可以去npm 搜索各种loader 获取更多具体的配置
  • 这里仅仅配置了我用过的常用配置
  • npm-loader
  • 配置插件章节的项目最终结构

目录结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
.
├── dist
│ ├── index.html
│ ├── main.js
│ └── public
│ ├── assets
│ │ └── images
│ │ └── 99b6d6d0aac2e1ab068e.png
│ └── static
│ └── e7c3da3c784524f42673.html
├── node_modules
├── package.json
├── public
│ ├── avatar.png
│ └── index.html
├── src
│ ├── index.js
│ └── index.less
└── webpack.config.js

index.html

1
2
3
4
5
6
7
8
9
10
./public/index.html
<body>
html5
<img id='im' src="" alt="">
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
</body>

index.js

1
2
3
4
5
6
7
8
# ./src/index.js
import avatar from '../public/avatar.png'
import './index.less'
const im = document.getElementById('im')
im.src = avatar
console.log('Hello Webpck');
const aaaa = () => 10
console.log(aaaa);

index.less

1
2
3
4
5
# ./src/index.less
@myColor: blue;
li{
color: @myColor;
}

webpack.config.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
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# ./webpack.config.js
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
entry: './src/index.js',
output: {
filename: 'main.js',
path: path.resolve(__dirname, 'dist'),
// 指定打包后输出的文件夹 ./dist/public/assets/images
assetModuleFilename: 'public/assets/images/[hash][ext][query]'
},
mode: "development",
devServer: {
// 启动gzip压缩
compress: true,
port: 8088,
open: true
},
plugins: [
new HtmlWebpackPlugin({
template: './public/index.html',
//要生成的文件名 存在内存 目录中不显示
filename: 'index.html',
minify: {
// 移除空格
collapseWhitespace: true,
// 移除注释
removeComments: true
}
})
],
module: {
rules: [
{
test: /\.(?:ico|gif|png|jpg|jpeg)$/i,
type: 'asset/resource',
},
// {
// test: /\.html/,
// type: 'asset/resource',
// generator: {
// filename: 'public/static/[hash][ext][query]' // 单独指定名字
// }
// },
{
test: /\.svg/,
type: 'asset/inline' // inline 的时候不需要指定文件名
},
{
test: /\.txt/,
type: 'asset',
parser: {
dataUrlCondition: {
maxSize: 4 * 1024 // 4kb 指定大小
}
}
},
{
test: /\.js$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env']
}
}
},
{
test: /\.css$/,
use: [
'style-loader',
'css-loader',
'postcss-loader'
]
},
{
test: /\.less$/,
use: [
'style-loader',
'css-loader',
'less-loader',
]
},
{
test: /\.scss$/,
use: [
'style-loader',
'css-loader',
'sass-loader'
]
}
],
},
}

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
# package.json
{
"scripts": {
"serve": "webpack serve",
"build": "webpack"
},
"dependencies": {
"html-webpack-plugin": "^5.5.0",
"webpack": "^5.69.0",
"webpack-cli": "^4.9.2"
},
"devDependencies": {
"@babel/core": "^7.17.4",
"@babel/plugin-proposal-class-properties": "^7.16.7",
"@babel/preset-env": "^7.16.11",
"autoprefixer": "^10.4.2",
"babel-loader": "^8.2.3",
"css-loader": "^6.6.0",
"less": "^4.1.2",
"less-loader": "^10.2.0",
"node-sass": "^7.0.1",
"postcss-loader": "^6.2.1",
"sass-loader": "^12.6.0",
"style-loader": "^3.3.1",
"webpack-dev-server": "^4.7.4"
}
}

webpack-dev-server

  • 这个插件其实就是一个小型的本地服务器
  • 相关配置也比较简单
  • 其他的具体配置后面再说
  • 这时候就可以执行 yarn serve
  • 此时还没有配置解析html的插件 因此先手动跳转到 main.js 测试下
  • http://localhost:8088/main.js
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    yarn add webpack-dev-server -D
    # webpack.config.js
    const path = require('path')
    module.exports = {
    ...
    devServer: {
    // 启动gzip压缩
    compress: true,
    // 打开的端口
    port: 8088,
    // 启动服务后自动打开网页
    open: true
    }
    }

html-webpack-plugin

  • 这个包显然就是用来解析html的
  • 配置后运行 yarn build 就可以在 dist 目录看到打包后的 index.html
  • 同时运行 yarn serve 也可以直接运行解析了
    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
    yarn add html-webpack-plugin -D
    # 在 ./public/index.html 随便写点东西
    <body>
    html5
    <img id='im' src="" alt="">
    </body>
    # webpack.config.js
    const path = require('path')
    const HtmlWebpackPlugin = require('html-webpack-plugin')
    module.exports = {
    entry: './src/index.js',
    output: {
    filename: 'main.js',
    path: path.resolve(__dirname, 'dist'),
    },
    mode: "development",
    devServer: {
    // 启动gzip压缩
    compress: true,
    port: 8088,
    open: true
    },
    plugins: [
    new HtmlWebpackPlugin({
    // 要生成的index.html路径
    template: './public/index.html',
    //要生成的文件名 存在内存 目录中不显示
    filename: 'index.html',
    minify: {
    // 移除空格
    collapseWhitespace: true,
    // 移除注释
    removeComments: true
    }
    })
    ]
    }
    此时我们完成了基本的架构,现在需要配置各种loader来满足项目的需要

Asset Modules

  • Asset Modules 是一种模块,它允许人们在不配置额外加载器的情况下使用资产文件(字体、图标等)
  • webpack5 不需要再去手动下载三个loader
  • webpack 5 之前,通常使用:
    • raw-loader将文件作为字符串导入
    • url-loader将文件作为数据 URI 内联到包中
    • file-loader将文件发送到输出目录
  • Asset Modules 分为4中资源模块
    • asset/resource 将资源分割为单独的文件,并导出url,就是之前的 file-loader的功能
    • asset/inline 将资源导出为dataURL(url(data:))的形式,之前的 url-loader的功能
    • asset/source 将资源导出为源码(source code). 之前的 raw-loader 功能
    • asset 自动选择导出为单独文件或者 dataURL形式(默认为8KB). 之前有url-loader设置asset size limit 限制实现。
  • 当配置完成后运行 yarn build就会发现 图片也被打包进了dist目录
    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
    # 在 ./public 放一张图片 这里选择了avatar.png
    # ./src/index.js
    import avatar from '../public/avatar.png'
    const im = document.getElementById('im')
    im.src = avatar
    console.log('Hello Webpck');
    # webpack.config.js => module.exports.use
    const path = require('path')
    const HtmlWebpackPlugin = require('html-webpack-plugin')
    module.exports = {
    entry: './src/index.js',
    output: {
    filename: 'main.js',
    path: path.resolve(__dirname, 'dist'),
    // 指定打包后输出的文件夹 ./dist/public/assets/images
    assetModuleFilename: 'public/assets/images/[hash][ext][query]'
    },
    mode: "development",
    devServer: {
    // 启动gzip压缩
    compress: true,
    port: 8088,
    open: true
    },
    plugins: [
    new HtmlWebpackPlugin({
    template: './public/index.html',
    //要生成的文件名 存在内存 目录中不显示
    filename: 'index.html',
    minify: {
    // 移除空格
    collapseWhitespace: true,
    // 移除注释
    removeComments: true
    }
    })
    ],
    module: {
    rules: [
    {
    test: /\.(?:ico|gif|png|jpg|jpeg)$/i,
    type: 'asset/resource',
    },
    // {
    // test: /\.html/,
    // type: 'asset/resource',
    // generator: {
    // filename: 'public/static/[hash][ext][query]' // 单独指定名字
    // }
    // },
    {
    test: /\.svg/,
    type: 'asset/inline' // inline 的时候不需要指定文件名
    },
    {
    test: /\.txt/,
    type: 'asset',
    parser: {
    dataUrlCondition: {
    maxSize: 4 * 1024 // 4kb 指定大小
    }
    }
    }
    ],
    },
    }

babel-loader

  • babel-loader 用于转化和识别高级语法
  • 当配置完成后运行 yarn build 可以查看 ./dist/main.js 后可以发现
    • 代码已经将箭头函数转换成了es5
    • var aaaa = function aaaa() {\n return 10;\n};\n\nconsole.log(aaaa);
    • 然后注销掉 babel-loader 的规则 重新打包
    • 你会发现 main.js 中还是箭头函数 这就是 babel-loader 的作用之一
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      npm install -D babel-loader @babel/core @babel/preset-env 
      在 ./src/index.js 加入一个 es6 箭头函数
      const aaaa = () => 10
      console.log(aaaa);
      # webpack.config.js => module.exports.module.rules.xxx
      {
      test: /\.js$/,
      exclude: /(node_modules|bower_components)/,
      use: {
      loader: 'babel-loader',
      options: {
      presets: ['@babel/preset-env']
      }
      }
      },

css,sass,less,postcss loader

  • sass less 大家都知道是css的预编译语言就不用多说了
  • postcss 是用于自动添加css的兼容前缀
  • 接下来就一次性安装多个loader
    • 不过注意 node-sass 的上游依赖需要手动配置镜像或代理 否则一直可能下载失败node-sass配置镜像
  • 配置完成后 就可以看到less-loader生效了
  • 其他的loader,可以自己测试下,这里就不测试了
    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
    yarn add style-loader css-loader -D 
    yarn add less-loader less -D
    yarn add sass-loader node-sass -D
    yarn add postcss-loader autoprefixer -D
    # ./public/index.html
    ul>li{$}*3
    # ./src/index.js
    import './index.less'
    # ./src/index.less
    @myColor: blue;
    li{
    color: @myColor;
    }
    # webpack.config.js => module.exports.module.rules.xxx
    {
    test: /\.css$/,
    use: [
    'style-loader',
    'css-loader',
    'postcss-loader'
    ]
    },
    {
    test: /\.less$/,
    use: [
    'style-loader',
    'css-loader',
    'less-loader',
    ]
    },
    {
    test: /\.scss$/,
    use: [
    'style-loader',
    'css-loader',
    'sass-loader'
    ]
    }

4. configuration

版本事项

以下的这些配置基于 webpack 4.x, 当使用webpack5 时可能有一些变动

webpack4.x
webpack5

entry

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 新建目录src
默认入口: ./src/index.js
#
多入口打包
entry: {
'jquery': './src/index.js',
'angular': './src/2.js'
},
# 根目录创建webpack.config.js
// entry: string 生成一个chunk 输出一个 bundle
// entry: sring[] 生成一个chunk 输出一个 bundle
// entry: object 有几个入口文件就生成几个 chunk 和 bundle
module.exports = {
entry: "./src/main.js",
}

output

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
  默认出口: ./dist/main.js
#
module.exports = {
output: {
path: path.join(__dirname, "dist"),
filename: "bundle.js",
// 资源公众路径前缀
// images/a.jpg => /images/a.jpg
publicPath: '/',
chunkFilename: 'js/[name]_chunk.js',
// 整个库向外保留的变量名
library: '[name]'
// 变量名添加到顶级作用域 global
libraryTarget: 'window'
},
}

mode

1
2
3
module.exports = {
mode: 'development production'
}

devServer

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
module.exports = {
port: 5000,
host: 'localhost',
open: true,
hot: true,
proxy: {
/*
本地 :5000 端口服务器接受到 /api/xxx 的请求
就会把请求转发到另外一个服务器 :3000
*/
'/api': {
target: 'http://localhost:3000',
// 请求路径重写:将 /api/xxx --> /xxx (去掉/api)
pathRewrite: {
'^/api': ''
}
}
}

// 不显示服务器日志信息
clientLogLevel: 'none',
// 除了一些基本启动信息以外,其他内容都不要显示
quiet: true,
// 如果报错 不要全屏提示
overlay: false
// 启动gzip压缩
compress: true,
watchContentBase: true,
watchOptions: {
// 忽略文件
ignored: /node_modules/
},

# 4.0 webpack
// 影响本地资源的访问 express.static
// 是对 output 打包文件物理存储位置的映射
publicPath: "/assets/",
// html页面的路径 (默认就是项目根路径)
// 初始相对路径是webpack.config 如果dist和他同级
// contentBase: './dist'
contentBase: resolve(__dirname, 'dist')
// 监视 contentBase 目录下的所有文件 文件变化就会 reload
# 5.0 webpack
// 默认指定为 public 目录
static: { //false
directory: path.join(__dirname, 'assets'),
publicPath: '/index.html',
}
}

module

noParse

1
2
3
4
5
6
7
8
module.exports = {
// 防止 webpack 解析这些文件
// 这些文件内不能含有 import require define
// 可以提高性能
module: {
noParse: /jquery|lodash/
}
}

rules

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
module.exports = {
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
},
{
test: /\.js$/
// 排除 node_modules 下的js文件
exclude: /node_modules/,
// 只检查 src 下的js文件
include: resolve(__dirname, 'scr'),
// pre:优先执行 post:延后执行
enforce: 'pre',
loader: 'eslint-loader',
options: { }
},
{
// 当规则匹配时 只使用第一个成功的匹配规则
oneOf: [
{

}
]
}
]
}
}
oneOf
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
// 当规则匹配时 只使用第一个成功的匹配规则
module.exports = {
module:{
rules:[
{
oneOf: [
{
test: /\.(jpg|png|gif)/,
loader: 'url-loader',
options: {
limit: 8 * 1024,
name: '[hash:10].[ext]',
outputPath: 'imgs',
esModule: false
}
},
{
test: /\.html$/,
loader: 'html-loader'
},
{
exclude: /\.(js|css|less|html|jpg|png|gif)/,
loader: 'file-loader',
options: {
outputPath: 'media'
}
}
]
}
]
}
}

resolve

alias

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
const path = require('path') 
module.exports = {
resolve: {
alias: {
'@': path.resolve(__dirname, 'src'),
'@/components':
path.resolve(__dirname, '..', 'src/components'),
'@/utils':
path.resolve(__dirname, '..', 'src/utils'),
'@/services':
path.resolve(__dirname, '..', 'src/services'),
'@/models':
path.resolve(__dirname, '..', 'src/models'),
'@/pages':
path.resolve(__dirname, '..', 'src/pages'),
}
}
}

extensions modules

1
2
3
4
5
6
7
8
9
10
11
module.exports = {
resolve: {
// 配置省略文件路径的后缀名
extensions: ['.js','.json','.jsx','.css']
// 告诉 webpack 解析模块去找那个目录
modules: [
resolve(__dirname, '../../node_modules'),
'node_modules'
]
}
}

plugins

1
2
3
4
5
module.exports = {
plugins: [

]
}

externals

1
2
3
4
5
6
7
8
9
10
11
// 拒绝 jqery 被打包
module.exports = {
externals: {
jquery: 'jQuery'
},
plugins: [
new webpack.ProvidePlugin({
$: "jquery",
}),
]
}

Optimization

splitChunks

1
2
3
4
5
6
7
8
9
// 将 node_modules 中代码打包进一个 chunk 
// 自动分析多入口 chunk 有没有公共文件 有的话会打包成单独一个 chunk
module.exports = {
optimization: {
splitChunks: {
chunks: 'all async'
},
},
}

devtool

source-map

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
module.exports = {
devtool: 'cheap-module-source-map'
}
#
source-map: 一种 提供源代码到构建后代码映射 技术 (如果构建后代码出错了,通过映射可以追踪源代码错误)

[inline-|hidden-|eval-][nosources-][cheap-[module-]]source-map

source-map:外部
错误代码准确信息 和 源代码的错误位置
inline-source-map:内联
只生成一个内联source-map
错误代码准确信息 和 源代码的错误位置
hidden-source-map:外部
错误代码错误原因,但是没有错误位置
不能追踪源代码错误,只能提示到构建后代码的错误位置
eval-source-map:内联
每一个文件都生成对应的source-map,都在eval
错误代码准确信息 和 源代码的错误位置
nosources-source-map:外部
错误代码准确信息, 但是没有任何源代码信息
cheap-source-map:外部
错误代码准确信息 和 源代码的错误位置
只能精确的行
cheap-module-source-map:外部
错误代码准确信息 和 源代码的错误位置
module会将loader的source map加入

内联 和 外部的区别:1. 外部生成了文件,内联没有 2. 内联构建速度更快

开发环境:速度快,调试更友好
速度快(eval>inline>cheap>...)
eval-cheap-souce-map
eval-source-map
调试更友好
souce-map
cheap-module-souce-map
cheap-souce-map

--> eval-source-map / eval-cheap-module-souce-map

生产环境:源代码要不要隐藏? 调试要不要更友好
内联会让代码体积变大,所以在生产环境不用内联
nosources-source-map 全部隐藏
hidden-source-map 只隐藏源代码,会提示构建后代码错误信息

--> source-map / cheap-module-souce-map

4. demo

css抽离

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
plugins: [
new MiniCssExtractPlugin({
// 对输出的css文件进行重命名
filename: 'css/built.css'
}),
// 压缩css
new OptimizeCssAssetsWebpackPlugin()
]

#
{
test: /\.css$/,
use: [ 'file-loader']
['file-loader?name=[name].bundle[hash].css']
},

js抽离

1
2
3
4
output: {
filename: 'js/[name].js',
path: path.resolve(__dirname, 'dist'),
},

js语法检查

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#
eslint eslint-loader
package.json 中添加
// 排除第三方库 只检查自己的代码
"eslintConfig": { "extends": "airbnb-base"}
#
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'eslint-loader',
options: {
// 自动修复eslint的错误
fix: true
}
}
]
}

代码切割

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
1. 多入口 自动打包多个文件
entry: {
'jquery': './src/index.js',
'angular': './src/2.js'
},
2. 异部的chunk
require.ensure([],function(_require){
_require('./xxx')
})
import('./2.css').then(() => {
...
})
}
#
3.
optimization: {
splitChunks: {
chunks: 'all'
}
}
#
externals: {
jquery: 'jQuery'
}
cdn

dll

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
#
硬链接一个 包,再手动scrit引入这个包 之后webpack就不用编译了
#
yarn add add-asset-html-webpack-plugin
webpack --config webpack.config.dll.js && webpack
# 文件路径
webpack.config.js
webpack.config.dll.js
dist
index.html
src
public
dll
jquery
manifest.json
# webpack.config.js
const path = require('path')
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const AddAssetHtmlPlugin = require('add-asset-html-webpack-plugin');
module.export = {
...
externals: {
jquery: 'jQuery'
},
plugins:[
new HtmlWebpackPlugin({
template: './index.html',
filename: 'index.html',
minify: { removeComments: true }
}),
// 告诉webpack哪些库不参与打包,同时使用时的名称也得变~
new webpack.DllReferencePlugin({
manifest: resolve(__dirname, 'dll/manifest.json')
}),
// 将某个文件打包输出去,并在html中自动引入该资源
new AddAssetHtmlPlugin({
filepath: path.resolve(__dirname, 'dll/jquery.js'),
publicPath: '../dll',
outputPath: 'vendor',
}),
]
}
# webpack.config.dll.js
const path = require('path');
const webpack = require('webpack')
module.exports = {
entry: {
jquery: ['jquery'],
},
output: {
filename: '[name].js',
path: path.resolve(__dirname, 'dll'),
library: '[name]_[hash]'
},
plugins: [
// 打包生成一个 manifest.json --> 提供和jquery映射
new webpack.DllPlugin({
// 映射库的暴露的内容名称 和 library 相同
name: '[name]_[hash]',
path: path.join(__dirname, 'dll/manifest.json'),
})
],
mode: 'production'
};
1
2
3
4
5
6
externals: {
jquery: 'jQuery'
},
new webpack.ProvidePlugin({
$: path.resolve(path.join(__dirname, 'dll/jquery.js'))
}),