阅读 448

webpack5配置及优化

为什么需要构建工具?

  • 转换es6语法(低版本浏览器不支持)
  • css前缀自动补全,scss/less预处理器编译
  • js/css代码压缩与混淆
  • 图片文件的压缩

构建工具有哪些?

  • grunt
  • gulp
  • fis3
  • rollup
  • parcel
  • webpack
  • vite

相关概念及配置参考

配置文件

webpack 默认配置⽂件:webpack.config.js

可以通过 webpack --config 指定配置⽂件

module.exports = {
    entry: './src/index.js',      // 入口文件
    output: './dist/bundle.js',   // 输出的文件
    mode: 'production',           // 开发环境
    module: {
        rules: [                  // loader配置
            test: /\.txt$/,
            use: 'raw-loader'
        ]
    },
    plugins: [                    // 插件配置 
        new HtmlwebpackPlugin({
            template: './src/index.html'
        })
    ]
}
复制代码

Entry: 打包入口

单文件入口

module.exports = {
    entry: './path/to/my/entry/file.js',
}
复制代码

多文件入口(多页应用)

module.exports = {
    entry: {
        app: './src/app.js',
        adminApp: './src/adminApp.js',
    },
}
复制代码

output:输出

output⽤来告诉webpack如何将编译后的⽂件输出到磁盘

单文件⼊⼝

module.exports = {
    entry: './path/to/my/entry/file.js'
    output: {
        filename: 'bundle.js’,
        path: __dirname + '/dist'
    }
};
复制代码

多文件入口

module.exports = {
    entry: {
        app: './src/app.js',
        search: './src/search.js'
    },
    output: {
        filename: '[name]_[chunkhash:8].js',     // 通过占位符确保文件名唯一
        path: __dirname + '/dist'
    }
};

// 写入到硬盘:./dist/app.js, ./dist/search.js
复制代码

Loaders:加载器

webpack 开箱即用只支持 JS 和 JSON 两种文件类型,通过 Loaders 去支持其它文 件类型并且把它们转化成有效的模块,并且可以添加到依赖图中。

常⻅的 Loaders 有哪些?

名称描述
babel-loader转换ES6、ES7高级js新特性语法
css-loader支持.css文件的加载和解析
less-loader将less文件解析为css
file-loader进行图片、字体的打包
raw-loader将文件以字符串的形式引入
thread-loader多进程打包js和css

loader的用法

module.exports = {
    module: {
        rules: [
            { 
                test: /\.css$/, 
                use: [
                    { 
                        loader: 'style-loader' 
                    },
                    {
                        loader: 'css-loader',
                        options: {
                            modules: true
                        }
                    },
                    { 
                        loader: 'sass-loader'
                    }
                ]
            },
            { 
                test: /\.ts$/, 
                use: 'ts-loader'
            },
        ],
    },
};

复制代码

Plugins: 插件

有些loader处理不了,可以通过插件处理,插件⽤于 bundle ⽂件的优化,资源管理和环境变量注⼊,作⽤于整个构建过程

常⻅的 Plugins 有哪些?

名称描述
CommonsChunkPlugin将chunks相同的模块代码提取为公共的js
CleanWebpackPlugin清理目录插件
ExtraTextWebpackPlugin将css从bunlde文件提取成一个独立的css文件
CopyWebpackPlugin将文件或者文件夹拷贝到构建的输出目录
HtmlWebpackPlugin创建html文件加载输出的bundle文件
UglifyjsWebpackPlugin压缩js

Plugins 的⽤法

const HtmlWebpackPlugin = require('html-webpack-plugin'); // 通过 npm 安装
const webpack = require('webpack'); // 访问内置的插件
const path = require('path');

module.exports = {
    entry: './path/to/my/entry/file.js',
    output: {
        filename: 'my-first-webpack.bundle.js',
        path: path.resolve(__dirname, 'dist'),
    },
    module: {
        rules: [
            {
                test: /\.(js|jsx)$/,
                use: 'babel-loader',
            },
        ],
    },
    plugins: [
        new webpack.ProgressPlugin(),
        new HtmlWebpackPlugin(
            { 
                template: './src/index.html'
            }
        ),
    ],
};
复制代码

Mode: 构建环境

Mode ⽤来指定当前的构建环境是:production、development 还是 none 设置 mode 可以使⽤ webpack 内置的函数,默认值为 production

选项
| 描述 --- | --- `development` | 会将 DefinePlugin 中 process.env.NODE_ENV 的值设置为 development. 为模块和 chunk 启用有效的名。 `production` | 会将 DefinePlugin 中 process.env.NODE_ENV 的值设置为 production。为模块和 chunk 启用确定性的混淆名称,FlagDependencyUsagePlugin,FlagIncludedChunksPlugin,ModuleConcatenationPlugin,NoEmitOnErrorsPlugin 和 TerserPlugin 。 `none` | 不使用任何默认优化选项

Externals: 外部扩展

通过script标签外部链接引入公共库文件,减少打包速度和公共包体积

externals: {
	'vue': 'Vue',
	'element-ui': 'ELEMENT',
	'vue-router': 'VueRouter',
	'vuex': 'Vuex',
	'axios': 'axios'
},
复制代码

resolve:解析文件解析

resolve: {
    // 引入文件时可以不使用后缀
    extensions:['.js', '.json', '.vue'],     
    // 通过别名引入
    alias: {
        '@images': path.resolve(__dirname, './assets/images'),  
        '@style': path.resolve(__dirname, './assets/style'),   
        '@src':  path.resolve(__dirname, './src'), 
    }
}
复制代码

target:打包输出的目标

v5版本默认打包输出的是带有箭头函数的自执行函数,兼容性不好,需要设置为

    // webpack 将生成 web 平台的运行时代码,并且只使用 ES5 相关的特性。 
    target: [
        'web', 
        'es5'
    ]
复制代码

模块热更新

适用于开发环境development ,使用webpack-dev-server

注意webpack v5版本需要安装4.0以前的版本,4.0后的版本去掉了contentBase

devServer: {
    contentBase: path.join(__dirname, './dist'),
    host: 'localhost',
    port: '9000',
    open: true,    // 打开浏览器
    hot: true,     // 启动模块热更新
}
复制代码

文件的压缩

html压缩

HtmlWebpackPlugin 简化了 HTML 文件的创建

const HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
    plugins: [
        new HtmlWebpackPlugin({
            template: path.resolve(__dirname, 'src/index.html'),  // 模版入口
            filename: 'index.html',
            chunks: ['main'],
            inject: true,
            minify: {
                html5: true,
                collapseWhitespace: true,
                preserveLineBreaks: false,
                minifyCSS: true,
                minifyJS: true,
                removeComments: false
            } 
        })  
    ]
};
复制代码

js压缩与加密

TerserPlugin插件使用 terser 来压缩 JavaScript。

const TerserPlugin = require("terser-webpack-plugin");

module.exports = {
    optimization: {
        minimize: true,
        minimizer: [
            new TerserPlugin()
        ],
    },
};
复制代码

js加密插件webpack-obfuscator

css压缩

CssMinimizerWebpackPlugin插件使用 cssnano 优化和压缩 CSS。

optimization: {
    minimizer: [
        new CssMinimizerPlugin({
            parallel: true,   // 启动多线程压缩
            minimizerOptions: {
                preset: ["advanced"],  // cssnano https://cssnano.co/docs/optimisations/
            }
        }),
    ],
},
复制代码

图片压缩

image-webpack-loader 插件进行压缩

// 解析图片
{
	test: /\.(jpg|jpeg|png|gif|svg)$/i,
	type: 'asset/resource', // v5 内置模块解析静态资源
	generator: {
			filename: 'static/images/[contenthash][ext][query]'
	},
	use: [
		// 图片压缩
		{
			loader: 'image-webpack-loader',
			options: {
				mozjpeg: {
					progressive: true,
				},
				// optipng.enabled: false will disable optipng
				optipng: {
					enabled: false,
				},
				pngquant: {
					quality: [0.65, 0.90],
					speed: 4
				},
				gifsicle: {
					interlaced: false,
				},
				// the webp option will enable WEBP
				webp: {
					quality: 75
				}
			}
		}
	]
}
复制代码

css自动添加前缀

PostCSS 插件 autoprefixer ⾃动补⻬ CSS3 前缀 根据 Can I Use 规则( caniuse.com/

const autoprefixer = require('autoprefixer')

// 解析scss
{
    test: /\.(s[ac]ss|css)$/i,
    use: [
        MiniCssExtractPlugin.loader
        'css-loader',
        'sass-loader',
        {
            loader: 'postcss-loader',
            // 也可以提取到到postcss.config.js
            options: {
                postcssOptions: {
                    plugins: [
                        autoprefixer
                    ]
                }
            }
        }
    ]
}
复制代码

增加.browserslistrc文件,添加浏览器规则

last 2 version
> 1%
ie > 8
复制代码

js公共包的分离

splitChunks配置中设置分割规则

splitChunks: {
    cacheGroups: {
        commons: {
            test: /[\\/]node_modules[\\/]/,
            name: 'vendors',
            chunks: 'all',
        }
    }
}
复制代码

css文件抽离

MiniCssExtractPlugin插件会将 CSS 提取到单独的文件中,为每个包含 CSS 的 JS 文件创建一个 CSS 文件。

const MiniCssExtractPlugin = require("mini-css-extract-plugin");

module.exports = {
    plugins: [new MiniCssExtractPlugin()],
        module: {
        rules: [
            {
                test: /\.css$/i,
                use: [
                    MiniCssExtractPlugin.loader, 
                    "css-loader"
                ],
            },
        ],
    },
};

复制代码

动态按需加载

js懒加载,common.js的require.ensure,es6的动态import(需要babel插件转换)

{
    "plugins": ["@babel/plugin-syntax-dynamic-import"],
    ...
}
复制代码

tree shaking(摇树优化)

1 个模块可能有多个⽅法,只要其中的某个⽅法使⽤到了,则整个⽂件都会被打到 bundle ⾥⾯去,tree shaking 就是只把⽤到的⽅法打⼊ bundle ,没⽤到的⽅法会在 uglify 阶段被擦除掉。

webpack 默认⽀持,production mode的情况下默认开启

构建优化显示

统计信息 stats 设置成 errors-only

使⽤ friendly-errors-webpack-plugin 插件

plugins: [
  new FriendlyErrorsWebpackPlugin()
],
stats: 'errors-only'
复制代码

多进程/多实例构建

使用官方推荐thread-loader,需将此 loader 放置在其他 loader 之前。放置在此 loader 之后的 loader 会在一个独立的 worker 池中运行。

请仅在耗时的操作中使用此 loader!

module.exports = {
    module: {
        rules: [
            {
                test: /\.js$/,
                include: path.resolve('src'),
                use: [
                    "thread-loader",
                    // 耗时的 loader (例如 babel-loader)
                ],
            },
        ],
    },
};
复制代码

构建包依赖分析

webpack-bundle-analyzer插件分析体积

文章分类
前端
文章标签