Codog

关注微信公众号:Codog代码狗

0%

Webpack基础

webpack已基本成为前端资源构建的默认工具

以webpack@4版本说明:

基本概念:

  • mode
    • production: 生产,默认值
    • development: 开发

Loader

用于对模块源代码进行转换,可以在import时预处理文件,至于可以在js中直接import css文件也是loader的功劳。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
module.exports = {
...
module: {
rules: [
{
test: /.scss$/,
use: [
"style-loader",
"css-loader",
"sass-loader"
]
}
]
}
}

会把.scss文件打包到bundle.js文件中,执行时插入style标签。

  • html-loader

  • file-loader

将项目引入的其他文件,比如svg, png之类的打包到dist目录中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
module: {
rules: [
{
test: /\.html$/,
use: ['html-loader']
},
{
test: /\.(svg|png|jpg|gif)$/,
use: {
loader: 'file-loader,
options: {
name: '[name].[hash].[ext],
outputPath: 'imgs'
}
}
}
]
}

自定义输出文件名及路径:

[contentHash]:资源hash,内容变才改变,意味着重新编译不会改变。

1
2
3
4
5
6
7
8
module.exports = {
// ...
output: {
filename: 'main.[contentHash].js',
path: path.resolve(__dirname, 'dist')
}
// ...
}

Plugin

可以自定义webpack构建流程

  • HtmlWebpackPlugin

上面说到可以使每次内容变更都输出带hash的文件名,那么手动添加到模版中就很麻烦了,这个插件可以自动帮我们将编译后的js文件添加到模版末尾。

  • clean-webpack-plugin

清除构建结果,保证build后的dist目录清洁

  • mini-css-extract-plugin

上面说到css-loader会将css代码打包进js文件中,通过style-loader插件在运行时插入style标签到header中。这样的体验不好,会造成闪屏(FOUC: Flash Of Unstyled Content, 无样式内容闪烁)

而且实际项目在编译后css和js代码都是分开的,css写在header中,js写在body结束前。

这个插件实际代替了style-loader的作用,将css-loader的内容单独输出css文件,并在html头部添加link标签引入。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
const MiniCssExtractPlugin = require('mini-css-extract-plugin')

// 修改loader内容
{
test: /.scss$/,
use: [
MiniCssExtractPlugin.loader,
"css-loader",
"sass-loader"
]
}

// 修改Plugin配置,配合HtmlWebpackPlugin自动引用css文件:
plugins: [
new MiniCssExtractPlugin({ filename: "[name].[contentHash].css" }),
new HtmlWebpackPlugin()
]
  • optimize-css-assets-webpack-plugin

压缩css代码。

1
2
3
4
5
6
7
8
9
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin')

modules.exports = {
// ...
optimization: {
minimizer: [new OptimizeCssAssetsWebpackPlugin()]
}
// ...
}

❗️注意:这样css文件得到压缩,但之前压缩的js文件却失效了,因为我们实际覆盖了webpack的optimization方法,所以,要再把它引回来:

1
2
3
4
5
6
7
8
9
10
11
// 安装webpack的时候已经附带安装了,无需再安装
const TerserPlugin = require('terser-webpack-plugin')
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin')

modules.exports = {
// ...
optimization: {
minimizer: [new OptimizeCssAssetsWebpackPlugin(), new TerserPlugin()]
}
// ...
}
  • 压缩html代码

仍然使用HtmlWebpackPlugin插件,但注意此时不再plugins中引入,而是在optimization中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
modules.exports = {
// ...
optimization: {
minimizer: [
new OptimizeCssAssetsWebpackPlugin(),
new TerserPlugin(),
new HtmlWebpackPlugin({
template: './index.html',
minify: {
collapseWhitespace: true,
removeComments: true
}
})
]
}
// ...
}

// ...
  • uglifyjs-webpack-plugin

这里只是压缩了代码,想进一步缩小体积,可以混淆js,将变量、方法进一步缩减。

1
2
3
4
5
6
7
const UglifyJsPlugin = require('uglifyjs-webpack-plugin')

module.exports = {
plugins: [
new UglifyJsPlugin()
]
}

其他

  • webpack-merge
    实际项目中,经常会针对开发环境和生产环境的构建方式进行区分,但二者也有共同部分,这时可以单独分离出webpack.base.js配置文件,然后使用webpack-merge包将二者结合,比如

webpack.dev.js:

1
2
3
4
5
6
7
8
const base = require('./webpack.base.js')
const merge = require('webpack-merge')

module.exports = merge(base, {
plugins: [
// Plugins for dev
]
})
  • webpack-dev-server

构建内容保存在内存中,不会在项目目录单独生成。

  • 多入口

通常用来将三方库文件单独进行打包,避免编译后的main.js体积过大

1
2
3
4
5
6
7
8
9
10
// vendor.js
import 'bootstrap'

// webpack.base.js
module.exports = {
entry: {
main: './src/index.js',
vendor: './src/vendor.js'
}
}

还有其他更多的概念,webpack工作过程、优化、代码分拆之类,这些问题问的频率也较高。

https://iamakulov.com/notes/webpack-front-end-size-caching/?utm_campaign=chrome_series_webpackrealtasks_081117&utm_source=chromedev&utm_medium=yt-desc

参考视频列表:https://www.youtube.com/playlist?list=PLblA84xge2_zwxh3XJqy6UVxS60YdusY8,个人感觉还是不错的,结合代码,从0到1,配合一个小型应用的升级改造介绍了webpack基本概念。