这个文章就是为了教大家怎么升级到webpack5 以及 怎么去最大程度的优化配置,使得构建速度得到提升。项目用的就是【章节1】和【章节2】的例子。
【章节4】原项目升级到webpack5并进行配置优化
【章节5】创建项目的一些想法
流程比较长,这是个通用流程,有不懂的地方可以加我微信,能帮则帮。
一、前言
可以升了wepack5 再 做commit 预处理的方案,也可以先commit 预处理 再来 升webpack5,我这是后者。
基础工程:https://gitee.com/huqinggui/webpack5_base.git
clone 下来后需要切换到webpack4-d2分支
git clone https://gitee.com/huqinggui/webpack5_base.git -b webpack4
cd webpack5_base
npm install
项目体积越大越能看见差异,最好是编译几分钟以上的项目,如果是1分钟以内的就没必要升级webpack5了(需要用到webpack5联邦模块的例外),我这个工程我大概构建速度20s,代码量几乎没有,我硬装了6个ui组件库进去,采用的vue-cli的形式的,默认时优化了的,内置的webpack4。本次示例将升级到webpack5,并且我门手动配置webpack5,看下他能达到什么程度。
看我用了这6个ui组件,就将几乎0代码量的工程整到了20s启动和构建,可见效率是很低的。
二、添加webpack5相关依赖 和建立webpack配置目录
注意:我会固定版本,是为了避免出现版本不兼容情况,你们可以不带版本,如果报错换成对应版本即可,当然版本越高越好!以前的webpack的配置也要注意下,因为存在一些特殊配置在src里用了,所以我们对应的需要在webpack里做相应的配置!
"webpack": "^5.83.1", // webpack5
"webpack-cli": "^5.1.1",// webpack5 版本的 cli
"webpack-dev-server": "^4.15.0", // 开法环境server服务
"webpack-merge": "^5.8.0",// 合并配置用
"webpackbar": "^5.0.2" // 进度条
执行:
npm install -D webpack@5.83.1 webpack-cli@5.1.1 webpack-dev-server@4.15.0 webpack-merge@5.8.0 webpackbar@5.0.2
项目根目录下新建webpack目录,这里存放webpack配置文件。
目录结构如图:
// 目录结构
webpack
config // 环境配置
config.js
index.js
lib // webpack工具
alias.js
cdn.js
console.js // 没有实际作用为了在终端打印好看东西
rules.js
utils.js
dev-server.js // 启动服务
webpack.config.analyzer.js // 包分析配置
webpack.config.common.js // 启动 和 build 公用配置
webpack.config.dev.js // 启动配置
webpack.config.prod.js // build 配置
webpack.config.speed.js // 速度分析
三、package.json脚本更改
"dev": "cross-env NODE_ENV=dev node ./webpack/dev-server.js",
"sit": "cross-env NODE_ENV=sit node ./webpack/dev-server.js",
"pre": "cross-env NODE_ENV=pre node ./webpack/dev-server.js",
"prod": "cross-env NODE_ENV=prod node ./webpack/dev-server.js",
"build": "cross-env NODE_ENV=production webpack --config ./webpack/webpack.config.prod.js",
"build:analyzer": "cross-env NODE_ENV=production webpack --config ./webpack/webpack.config.analyzer.js",
"build:speed": "cross-env NODE_ENV=production webpack --config ./webpack/webpack.config.speed.js",
从脚本上看:
- cross-env设置了dev(开发)、sit(测试)、pre(预生产)、prod(生产)四个环境的启动环境变量
- cross-env设置了一个production(生产)构建变量
- build的入口文件是./webpack/webpack.config.prod.js,其他的是./webpack/dev-server.js
- 添加了包分析脚本(build:analyzer) 和速 度分析脚本(build:speed)
npm i -D cross-env@7.0.3
四、补充对应文件里的代码内容—启动
dev-server.js
const Webpack = require('webpack');
const WebpackDevServer = require('webpack-dev-server');
const getWebpackConfig = require('./webpack.config.dev.js'); //开发配置
const localIPv4 = WebpackDevServer.internalIPSync('v4'); // 获取ipv4地址
const compiler = Webpack(getWebpackConfig(localIPv4));
const devServerOptions = { ...getWebpackConfig(localIPv4).devServer };
const devServer = new WebpackDevServer(devServerOptions, compiler);
devServer.startCallback(() => {}); // 启动
config/config.js
const getConfig = (env) => {
return {
dev: {
envName: '开发环境',
proxy: 'http://xxxxx',
PORT: 8088,
},
sit: {
envName: '测试环境',
proxy: 'http://xxxx',
PORT: 8089,
},
pre: {
envName: '预生产环境',
proxy: 'http://xxxxx',
PORT: 8090,
},
prod: {// 不到万不得已 禁止使用!!!
envName: '生产环境',
proxy: 'xxxxx',
PORT: 8091,
},
// build
production: {
envName: '生产环境',
},
}[env];
};
module.exports = (env) => getConfig(env);
可见:
- 启动环境的 四个环境名和接口代理地址 及端口号
- 生产环境的环境名
config/index.js
"use strict";
const path = require("path");
const env = process.env.NODE_ENV;
const envConfig = require("./config")(env); // 当前启动环境
module.exports = {
// 构建配置
build: {
index: path.resolve(__dirname, "../../dist/index.html"),
assetsRoot: path.resolve(__dirname, "../../dist"),
assetsSubDirectory: "static",
assetsPublicPath: "/", // 对应router 的 base
productionSourceMap: false,
productionGzip: true,
productionGzipExtensions: ["js", "css"],
bundleAnalyzerReport: process.env.npm_config_report,
},
// 启动配置
dev: {
envToStart: envConfig.envName, // 启动环境
port: envConfig.PORT,
autoOpenBrowser: true,
assetsSubDirectory: "static",
assetsPublicPath: "/",
devtool: "eval-cheap-module-source-map",
proxyTable: {
"/ins/web": {
target: envConfig.proxy,
// ws: true, //如果要代理 websockets,配置这个参数
// secure: false, // 如果是https接口,需要配置这个参数
logLevel: "silent", // 不显示终端提示
changeOrigin: true, //是否跨域
pathRewrite: {
"^/ins/web/": "/ins/web/",
},
},
},
},
};
console.log(
"\x1b[36m%s\x1b[0m",
`【${envConfig.envName}】webpack正在努力为您构建中................`
);
可见:
- 从config里拿了代理地址和环境名
- 区分了构建时的配置和启动时的配置
webpack.config.dev.js
const { merge } = require("webpack-merge");
const FriendlyErrorsPlugin = require("@soda/friendly-errors-webpack-plugin");
const colors = require("ansicolors");
const { resolvePath, assetsPath } = require("./lib/utils.js");
const config = require("./config/index");
const rules = require("./lib/rules.js");
const common = require("./webpack.config.common.js");
// 忽略不安全警告. https需要
process.env["NODE_TLS_REJECT_UNAUTHORIZED"] = "0";
// webpack-dev-server 配置
const devServer = {
https: false, // 是否https启动
hot: true, // 热更新
host: "localhost",
port: config.dev.port,
compress: true, //采用gzip压缩
open: config.dev.autoOpenBrowser, // 自动打开
client: {
logging: "error",
progress: false, // 自带进度显示
overlay: false, // 编译错误浏览器全屏覆盖
progress: false, // 浏览器中显示编译进度
},
historyApiFallback: true, // 解决前端路由刷新404问题
static: resolvePath("./dist/"),
proxy: config.dev.proxyTable, // 代理配置
};
// webpack 配置
const getDevWebpackConfig = (ipv4) => {
return merge(common, {
mode: "development",
devtool: config.dev.devtool,
stats: "errors-only",
output: {
filename: "js/[name].js", // 本地无需hash
publicPath: config.dev.assetsPublicPath,
assetModuleFilename: assetsPath("images/[name][ext]"),
},
optimization: {
nodeEnv: process.env.NODE_ENV,
runtimeChunk: "single",
},
module: { rules: rules() },
devServer: devServer,
plugins: [
new FriendlyErrorsPlugin({
// 自定义控制台输出
compilationSuccessInfo: {
messages: [
`【${config.dev.envToStart}】App running at:`,
`- Local: ` +
colors.blue(
`http${devServer.https ? "s" : ""}://${devServer.host}:${
config.dev.port
}`
),
`- Network: ` +
colors.blue(
`http${devServer.https ? "s" : ""}://${ipv4}:${config.dev.port}`
),
],
},
clearConsole: true, // 清除控制台
additionalFormatters: [
(errors) => ({
title: "Compiled failed that affect everything",
log: `${errors.map((e) => e.message).join("\n")}`,
}),
],
additionalTransformers: [(error) => error],
}),
],
});
};
module.exports = (ipv4) => getDevWebpackConfig(ipv4);
引入了三个包:
- webpack-merge:合并webpack5配置
- @soda/friendly-errors-webpack-plugin:自定义控制台输出
- ansicolors:终端颜色控制
npm install -D webpack-merge@5.8.0 @soda/friendly-errors-webpack-plugin@1.8.1 ansicolors@0.3.2
引入了webpack公用方法resolvePath
引入了构建规则lib/rules.js
引入了公共配置文件webpack.config.common.js
webpack.config.common.js
const { ProvidePlugin } = require("webpack");
const { VueLoaderPlugin } = require("vue-loader");
const HtmlPlugin = require("html-webpack-plugin"); // 将打包出的静态文件插入到 HTML 模板中
const CopyWebpackPlugin = require("copy-webpack-plugin"); // 复制文件到指定目录
const WebpackBar = require("webpackbar");
const { resolvePath } = require("./lib/utils.js");
const config = require("./config/index");
const configType = process.env.NODE_ENV === "production" ? "build" : "dev";
const alias = require("./lib/alias.js");
module.exports = {
entry: ["./src/main.js"],
output: {
clean: true,
path: resolvePath("./dist/"),
},
resolve: {
alias,
extensions: [".js", ".ts", ".vue", ".json"],
},
plugins: [
new HtmlPlugin({
title: "webpack5-demo",
inject: "head",
filename: "index.html",
template: resolvePath("./public/index.html"),
}),
// 解决 static 下的资源找不到问题
new CopyWebpackPlugin({
patterns: [
{
from: resolvePath("./static/"),
to: config[configType].assetsSubDirectory,
},
],
}),
new ProvidePlugin({ process: require.resolve("process/browser") }),
new WebpackBar({
// color: "#85d", // 默认green,进度条颜色支持HEX
basic: false, // 默认true,启用一个简单的日志报告器
profile: false, // 默认false,启用探查器。
}),
new VueLoaderPlugin(),
],
};
npm i -D vue-loader@15.9.8 html-webpack-plugin@5.5.0 copy-webpack-plugin@6.4.1
lib/alias.js
const { resolvePath } = require("./utils.js");
module.exports = {
'vue$': 'vue/dist/vue.esm.js',// 解决el-table无法渲染数据
"@": resolvePath("./src"),
"@api": resolvePath("./src/api-new"),
"@assets": resolvePath("./src/assets"),
"@static": resolvePath("../static"),
"@components": resolvePath("./src/components"),
"@router": resolvePath("./src/router"),
"@lib": resolvePath("./src/lib"),
"@views": resolvePath("./src/views"),
};
lib/utils.js
const path = require("path");
const config = require("../config/index");
const resolvePath = (_path) => {
return path.resolve(process.cwd(), _path);
};
const assetsPath = (_path) => {
const assetsSubDirectory =
process.env.NODE_ENV === "production"
? config.build.assetsSubDirectory
: config.dev.assetsSubDirectory;
return path.posix.join(assetsSubDirectory, _path);
};
module.exports = {
resolvePath,
assetsPath,
};
lib/rule.js
const { assetsPath } = require("./utils.js");
const common = [
{
test: /\.vue$/,
loader: "vue-loader",
},
{
test: /\.js$/,
exclude: /node_modules/,
use: [
{
loader: "babel-loader",
options: {},
},
],
},
{
test: /\.txt$/,
type: "asset/source",
},
{
test: /\.(png|svg|gif|jpe?g|webp)$/,
type: "asset/resource",
parser: { dataUrlCondition: { maxSize: 5 * 1024 } },
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/,
type: "asset/resource",
generator: { filename: assetsPath("font/[name]-[contenthash:8][ext]") },
},
];
const dev = [
{
test: /\.css$/i,
use: ["style-loader", "css-loader"],
},
{
test: /\.s[ac]ss$/i,
use: ["style-loader", "css-loader", "sass-loader"],
},
{
test: /\.less$/i,
use: ["style-loader", "css-loader", "less-loader"],
},
];
const prod = [
{
test: /\.css$/i,
use: ["css-loader"],
},
{
test: /\.s[ac]ss$/i,
use: ["css-loader", "sass-loader"],
},
{
test: /\.less$/i,
use: ["css-loader", "less-loader"],
},
];
module.exports = (env) => common.concat(env === "prod" ? prod : dev);
这里用了几个包:
- babel-loader :js编译用的
- style-loader、css-loader、less、less-loader:css编译用的
npm i -D babel-loader@8.2.4 style-loader@3.3.1 css-loader@6.7.1 less@4.1.3 less-loader@5.0.0
如过项目里用了sass请自行 安装 sass 和sass-loader。安装需对应node版本。
通过以上配置我们已经可以启动项目了。
五、验证项目启动
验证结果:
开发 测试 预生产 生产 都可以启动!
六、补充对应文件里的代码内容—build构建
webpack.config.prod.js
const { merge } = require("webpack-merge");
const rules = require("./lib/rules.js");
const config = require("./config/index");
const { assetsPath } = require("./lib/utils.js");
const common = require("./webpack.config.common.js");
module.exports = merge(common, {
mode: "production",
devtool: false,
stats: "errors-only", // 只显示错误信息
output: {
path: config.build.assetsRoot,
filename: assetsPath("js/[name]-[contenthash:8].js"),
assetModuleFilename: assetsPath("images/[name]-[contenthash:8][ext]"),
publicPath: config.build.assetsPublicPath,
chunkFilename: assetsPath("chunk/[name]-[contenthash:8].js"),
},
module: { rules: rules("prod") },
});
升级以后构建速度为29s,对比vuecli创建的webpack4项目来说确实确实慢些,毕竟我们还没做任何的优化处理,接下来我们看看怎么优化!
七、包分析plugin 和 速度分析plugin
npm i -D webpack-bundle-analyzer@4.5.0 speed-measure-webpack-plugin@1.5.0
webpack.config.analyzer.js
const { merge } = require("webpack-merge");
const { BundleAnalyzerPlugin } = require("webpack-bundle-analyzer");
// 生产配置
const prod = require("./webpack.config.prod.js");
const result = merge(prod, {
plugins: [
new BundleAnalyzerPlugin({ openAnalyzer: true }),
],
});
module.exports = result;
webpack.config.speed.js
// 使用此功能需要关闭webpack5缓存
const { merge } = require('webpack-merge');
const SpeedMeasurePlugin = require('speed-measure-webpack-plugin');
// 生产配置
const prod = require('./webpack.config.prod.js');
const result = merge(prod, {
plugins: [new SpeedMeasurePlugin()],
});
module.exports = result;
npm run build:analyzer
npm run build:speed
这么一来webpack5 的项目就非常完善了,接着呢我们就要做点配置来优化一下项目!
八、优化 npm run build速度和 产出文件大小
优化思路很重要,我们从什么角度优化呢,产出文件大小决定着用户加载资源的大小,所以这个是肯定要解决的,那怎噩梦解决呢?
压缩
compression-webpack-plugin
npm i -D compression-webpack-plugin@10.0.0
webpack.config.prod.js
const CompressionWebpackPlugin = require("compression-webpack-plugin"); // 为输出文件启用 Gzip 压缩并生成相应的 .gz 文件
optimization: {
minimize: true,
minimizer: [
// 开启gzip压缩
new CompressionWebpackPlugin({
filename: "[path][base].gz",
algorithm: "gzip",
test: /\.js$|\.css$|\.html$/,
threshold: 10240,
minRatio: 0.8,
deleteOriginalAssets: false, // 是否删除源文件
}),
],
},
添加完后我们npm run build试试
惊人的5s就构建好了,再看看代码体积
.gz局势压缩后的文件,1.3m,秀儿!
分包
我们来试试分包
webpack.config.prod.js
optimization: {
nodeEnv: "production",
runtimeChunk: "single",
splitChunks: {
chunks: "all", // 同时分割同步和异步代码,推荐。
cacheGroups: {
// 公用模块抽离
common: {
chunks: "initial",
minSize: 0, // 大于0个字节
minChunks: 2, // 抽离公共代码时,这个代码块最小被引用的次数
},
element: {
test: /[\\/]node_modules[\\/](element-ui)[\\/]/,
name: "element", // 将这个缓存组命名为 element
chunks: "all",
},
// 第三方库抽离
vendor: {
priority: 1, // 权重
test: /node_modules/,
chunks: "initial",
minSize: 0, // 大于0个字节
minChunks: 2, // 在分割之前,这个代码块最小应该被引用的次数
},
},
},
},
npm run build试试,速度略有提升
再看看包体积
包的体积也有减小,cacheGroups 可以自定义选择抽离哪些代码组成一个文件。我这里抽出了elementui,同时他还会根据模块自己抽离出来。
babel-loader 是不是 可以被替换?(esbuild)
可以!现在有了esbuilder 可以替代babel-loader更高速度的编译js,底层是go,速度杠杠的,vite的底层就是他
npm i -D esbuild-loader@3.0.1
lib/rules.js
- {
- test: /\.js$/,
- exclude: /node_modules/,
- use: [
- {
- loader: "babel-loader",
- options: {},
- },
- ],
- },
+ {
+ test: /\.(js|jsx|ts|tsx)$/,
+ exclude: /node_modules/,
+ use: [
+ {
+ loader: 'esbuild-loader', // 代替 babel-loader 提升速度
+ options: {
+ target: 'es2015', // 目标版本.
+ loader: 'jsx', // 指定loader例如 jsx/ts/tsx
+ },
+ },
+ ],
+ },
webpack.config.prod
+ const { EsbuildPlugin } = require("esbuild-loader"); // 替代 terser-webpack-plugin 和 css-minimizer-webpack-plugin 压缩代码
optimization: {
minimizer: [
+ // js css处理
+ new EsbuildPlugin({
+ target: "es2015",
+ css: true,
+ minify: true,
+ minifyWhitespace: true, // 去掉空格
+ minifyIdentifiers: true, // 缩短标识符
+ minifySyntax: true, // 缩短语法
+ legalComments: "none", // 去掉注释
+ exclude: /node_modules/,
+ }),
],
},
看着好像提升很小,实际上是因为代码量太少了,如果是正常的项目是非常巨大的提升的!
产出的js也被压缩了,那么他的大小?
也变小了!!!
将css从js提出来
尽管做了上面这些,但是呢我发现js里有css,那么肯定是不好的
所以我们把它提取出来。
npm i -D mini-css-extract-plugin@2.7.6
const MiniCssExtractPlugin = require("mini-css-extract-plugin"); // 将 CSS 从 JavaScript 中提取出来作为单独的 CSS 文件
optimization: {
minimizer: [
+ new MiniCssExtractPlugin({
+ filename: assetsPath("style/[name]-[contenthash:8].css"),
+ }), // 样式内容将打包成一个或多个单独的CSS文件
],
},
lib/rules.js
+ const MiniCssExtractPlugin = require('mini-css-extract-plugin');
- const prod = [
- {
- test: /\.css$/i,
- use: ["css-loader"],
- },
- {
- test: /\.s[ac]ss$/i,
- use: ["css-loader", "sass-loader"],
- },
- {
- test: /\.less$/i,
- use: ["css-loader", "less-loader"],
- },
- ];
+ const prod = [
+ {
+ test: /\.css$/i,
+ use: [MiniCssExtractPlugin.loader, "css-loader"],
+ },
+ {
+ test: /\.s[ac]ss$/i,
+ use: [MiniCssExtractPlugin.loader, "css-loader", "sass-loader"],
+ },
+ {
+ test: /\.less$/i,
+ use: [MiniCssExtractPlugin.loader, "css-loader", "less-loader"],
+ },
+ ];
npm run build看看
css都被i提取到了style目录下,js文件也变小了,构建速度没什么变化
多线程构建
有些babel处理的东西非常大,就会非常耗时,thread-loader 将这些耗时的任务放到 worker 池中,利用多线程并发执行任务,从而提高构建速度。
注意:thread-loader用了如果变慢了,说明你的代码量太少了,编译时间还没启动一个线程花的时间多。
本文只是例子,对于正常的项目,强烈推荐使用多线程!
npm i -D thread-loader@4.0.2
lib/rules.js
{
test: /\.vue$/,
- loader: "vue-loader",
+ use: [
+ "thread-loader", // 多线程
+ {
+ loader: 'vue-loader',
+ options: {
+ compilerOptions: {
+ cacheDirectory: true,
+ preserveWhitespace: false,
+ },
+ },
+ },
+ ],
},
{
test: /\.(js|jsx|ts|tsx)$/,
exclude: /node_modules/,
use: [
+ 'thread-loader', // 多线程
{
loader: "esbuild-loader", // 代替 babel-loader 提升速度
options: {
target: "es2015", // 目标版本.
loader: "jsx", // 指定loader例如 jsx/ts/tsx
},
},
],
},
oneOf
当我们使用多个 loader 时,Webpack 需要对每个文件都执行所有的 loader,这会导致编译速度变慢。为了提高编译速度,我们可以使用 oneOf 配置项来优化 loader 的执行顺序。 oneOf 配置项允许我们在多个 loader 中选择一个匹配的 loader,并只对该文件执行该 loader,从而减少不必要的 loader 执行,提高编译速度。
部分包放cdn
lib/cdn.js
module.exports = [
{
name: "vue",
library: "Vue",
js: "https://file.tuns.com.cn/npm/vue@2.7.14/dist/vue.min.js",
css: "",
},
{
name: "vue-router",
library: "VueRouter",
js: "https://file.tuns.com.cn/npm/vue-router@3.6.5/dist/vue-router.min.js",
css: "",
},
{
name: "vuex",
library: "Vuex",
js: "https://file.tuns.com.cn/npm/vuex@3.6.2/dist/vuex.min.js",
css: "",
},
{
name: "axios",
library: "axios",
js: "https://file.tuns.com.cn/npm/axios@0.17.1/dist/axios.min.js",
css: "",
},
{
name: "element-ui",
library: "ELEMENT",
js: "https://file.tuns.com.cn/npm/element-ui@2.15.13/lib/index.js",
css: "https://file.tuns.com.cn/npm/element-ui@2.15.13/lib/theme-chalk/index.css",
},
{
name: "echarts",
library: "echarts",
js: "https://file.tuns.com.cn/npm/echarts@3.8.5/dist/echarts.min.js",
css: "",
},
];
lib/utils.js
+ const cdn = require("./cdn");
// 组装externals
const getExternals = () => {
let externals = {};
for (const {name, library} of cdn) {
// externals[name] = [js || css, library];
// 将 ${name} 转换为 ${library}
externals[name] = `${library}`;
}
return externals;
};
// 组装index.html 的 css 和 js
const getCdnConfig = () => {
let cdnConfig = {
js: [],
css: [],
};
cdn.forEach((config) => {
if (config.js) cdnConfig.js.push(config.js);
if (config.css) cdnConfig.css.push(config.css);
});
return cdnConfig;
};
module.exports = {
resolvePath,
assetsPath,
+ getExternals,
+ getCdnConfig,
};
webpack.config.common.js
- const { resolvePath } = require("./lib/utils.js");
+ const {
+ resolvePath,
+ getExternals,
+ getCdnConfig,
+ } = require("./lib/utils.js");
module.exports = {
...
+ externals: getExternals(),
plugins: [
new HtmlPlugin({
title: "webpack5-demo",
inject: "head",
filename: "index.html",
template: resolvePath("./public/index.html"),
+ cdnConfig: getCdnConfig(), // 自动将cdn 注入到index.html
}),
],
...
}
根目录/public/index.html
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="/favicon.ico">
<title><%= htmlWebpackPlugin.options.title %></title>
<!-- 使用CDN的CSS文件 -->
<% for (var i in htmlWebpackPlugin.options.cdnConfig && htmlWebpackPlugin.options.cdnConfig.css) { %>
<link href="<%= htmlWebpackPlugin.options.cdnConfig.css[i] %>" rel="external nofollow preload" as="style" />
<link href="<%= htmlWebpackPlugin.options.cdnConfig.css[i] %>" rel="external nofollow stylesheet" />
<% } %>
</head>
<body>
<noscript>
<strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
<!-- 使用CDN的JS文件 -->
<% for (var i in htmlWebpackPlugin.options.cdnConfig && htmlWebpackPlugin.options.cdnConfig.js) { %>
<script src="<%= htmlWebpackPlugin.options.cdnConfig.js[i] %>" rel="external nofollow preload" as="script"></script>
<% } %>
</html>
npm run build试一下
速度再次提升,只需要3.68s了,那我们再看下dist的index.html看下cdn是否打上去了,
可以看见 js 和css 都打进去了
包的体积也再次减少,说明配置了cdn东西是不会被编译的,这样就极大的减少了构建时间,我要是把剩下的几个ui组件都放cdn,信不信,我只要1.5s就能构建好!
cache缓存
webpack.config.common.js
可以提升热更新速度和二次编译速度
看,多快乐!我们再看看启动速度
非常的快,这就是缓存的好处。
九、前后分析
注意:以下对比均在优化后,真实测试
代码量极少
只引入了6个组件库的情况:
版本 | 启动速度 | 二次启动速度 | 构建速度 | 二次构建速度 |
webpack4 | 10s | 10s | 20s | 二20s |
webpack5 | 4s | 0.8s | 3s | 1s |
代码量多
完完整维护了5年的项目:
版本 | 启动速度 | 二次启动速度 | 构建速度 | 二次构建速度 |
webpack4 | 120s | 120s | 140s | 140s |
webpack5 | 24s | 4s | 26s | 3s |
升上去做了优化还是很有效果的,超级快,快来吧!
十、案例地址
webpack4:
git clone https://gitee.com/huqinggui/webpack5_base.git -b webpack4
cd webpack5_base
npm install
webpack5:
git clone https://gitee.com/huqinggui/webpack5_base.git -b up-webpack5
cd webpack5_base
npm install