1. 前言
大型webpack项目(例如页面300+,组件1k+), 本地开发、上线build,编译耗时太久的问题会影响我们的开发效率、开发体验。通过打包耗时分析,具体原因是webpack配置的各项loader,其中babel-loader占了80%的耗时时间, babel-loader我们做了ts、react、es6等各种的语法转换。针对分析的结果,在现有webpack打包的配置情况下,替换babel-loader的解决方案: swc-loader
2. 调研
2.1 swc介绍
受限于JS的语言本身效率的问题,近几年前端领域出现了不少工具被Rust
重写,其中就包括编译JS/TS
文件速度比Babel
快不少的SWC
,其所对标的工具就是Babel
。SWC
全称为Speed Web Compiler
,其是基于Rust实现的工具,目前被很多前端知名项目(Next.js、Parcel和Deno)所使用。官方SWC的编译速度相对于Babel可提升近20倍。
swc的详细介绍可参考:https://zhuanlan.zhihu.com/p/437529362
2.2 功能对比
swc-loader vs bable-loader
swc官方对比链接: https://swc.rs/docs/migrating-from-babel
下图是部分功能对比, 通过完整的功能对比, swc-loader可覆盖常用babel-loader插件功能,覆盖总插件80%
通过以上的调研分析,swc-loader替换babel-loader的方案是可行的,且编译效率能得到很大的提升
3. 项目改造
3.1 增加依赖包
@swc/core;@swc/helpers;swc-loader
3.2 打包配置修改
去除之前的babel-loader
替换新的swc-loader配置, 核心代码如下(ts、js类型单独配置: swc的解析配置是区分这两种文件类型,没发合到一起)
const { getTsSwcOptions, getJSSwcOptions } = require("./webpack.swcrc.js");
const swcLoader = "swc-loader";
[
{
test: /.(ts|tsx)$/,
use: [
{
loader: swcLoader,
options: getTsSwcOptions(isDebug, isClient),
},
],
},
{
test: /.(js|jsx|mjs|cjs)$/,
use: [
{
loader: swcLoader,
options: getJSSwcOptions(isDebug, isClient),
},
],
},
];
webpack.swcrc.js 配置如下图
/* eslint-disable no-unused-vars */
// const pkg = require("../package.json");
const getCommon = (isDev = false, isClient = false) => {
const opt = {
jsc: {
// externalHelpers: true,
transform: {
legacyDecorator: true,
decoratorMetadata: true,
react: {
runtime: "automatic", // or classic
throwIfNamespace: true,
useBuiltins: true,
development: isDev,
},
},
loose: true,
parser: {
decorators: true,
dynamicImport: true,
},
target: "es5",
},
};
// 禁止服务端拆分成chunks
if (!isClient) {
opt.module = {
type: "commonjs",
// ignoreDynamic: true,
};
}
// 非本地开发
if (!isDev) {
opt.env = {
mode: "entry",
coreJs: 3,
forceAllTransforms: true,
dynamicImport: true,
// targets: {
// ...(isClient
// ? { browsers: pkg.browserslist }
// : { node: pkg.engines.node.match(/(\d+\.?)+/)[0] }),
// },
};
}
return opt;
};
const getTsSwcOptions = (isDev = false, isClient = false) => {
const com = getCommon(isDev, isClient);
return {
// test: ".(ts|tsx)$",
...com,
jsc: {
...com.jsc,
parser: {
...com.jsc.parser,
syntax: "typescript",
tsx: true,
},
},
};
};
const getJSSwcOptions = (isDev = false, isClient = false) => {
const com = getCommon(isDev, isClient);
return {
// test: ".(js|jsx|mjs|cjs)$",
...com,
jsc: {
...com.jsc,
parser: {
...com.jsc.parser,
syntax: "ecmascript",
jsx: true,
},
},
};
};
module.exports = {
getTsSwcOptions,
getJSSwcOptions,
};
4. 最终效果
测试项目信息: webpack5+; 页面100+; 组件400+
window: DELL i7、16G
Mac: MacBook Pro (15-inch, 2018)
5. 总结
本地启动、热更新都有很明显的效率提升
启动编译效率提升最大
window比mac提升效率更高一些
支持了吗