SWC性能优化实战与踩坑经验分享

轩辕志煜 优化 阅读 1,075
赞 12 收藏
二维码
手机扫码查看
反馈

我的写法,亲测靠谱

先说结论,SWC真的香。作为一个前端老油条,我从去年开始把几个项目的构建工具从Babel换成了SWC,性能提升肉眼可见。特别是那种动辄上千个文件的大型项目,原本要等30秒的热更新,现在基本控制在5秒内。

SWC性能优化实战与踩坑经验分享

这里分享下我的最佳实践代码:

// swc.config.js
module.exports = {
  jsc: {
    parser: {
      syntax: "ecmascript",
      jsx: true,
      dynamicImport: true,
      privateMethod: true,
    },
    transform: {
      react: {
        runtime: "automatic",
        pragma: "React.createElement",
        pragmaFrag: "React.Fragment",
      },
    },
    target: "es2015",
  },
  module: {
    type: "es6",
  },
};

这个配置看起来简单,但背后踩过的坑可不少。最初我把target设置成”es5″,结果发现很多现代语法被错误转译,尤其是Proxy和Promise相关的代码,调试了大半天才发现问题出在这。建议大家直接用”es2015″,兼容性够用了。

另外那个runtime设为”automatic”也是有讲究的。之前用”classic”模式,每个文件都要手动import React,烦死了。改成自动模式后清爽多了,代码体积也小了一点。

这几种错误写法,别再踩坑了

来说说我踩过的一些典型坑,让大家少走弯路。

第一个常见错误是这样写的:

// 错误示例
module.exports = {
  jsc: {
    parser: {
      syntax: "typescript", // 这里容易出错
      tsx: true,
    },
  },
};

乍一看没啥问题,但如果你的项目同时包含JS和TS文件,这种写法就会导致JS文件解析报错。正确的做法是分开配置:

// 正确写法
const isTsFile = /.tsx?$/.test(filename);
return {
jsc: {
parser: {
syntax: isTsFile ? "typescript" : "ecmascript",
[isTsFile ? "tsx" : "jsx"]: true,
},
},
};
`>

&lt;p&gt;还有个特别隐蔽的坑,就是sourceMaps的配置。很多人直接这么写:&lt;/p&gt;</code></pre>javascript
// 错误写法
module.exports = {
sourceMaps: true, // 看似没问题
};
>
<p>结果打包后的sourcemap完全对不上,调试时定位不到原始代码。后来我发现得这样写才靠谱:</p>
<pre class="pure-highlightjs line-numbers language-javascript"><code class="no-highlight language-javascript">// 正确写法
module.exports = {
sourceMaps: process.env.NODE_ENV === &#039;development&#039; ? &#039;inline&#039; : false,
};
&gt;
&lt;p&gt;开发环境用inline模式,方便调试;生产环境干脆关掉,减少包体积。&lt;/p&gt;

&lt;h2&gt;实际项目中的坑&lt;/h2&gt;
&lt;p&gt;在真实项目中,最容易出问题的就是插件系统。SWC原生插件支持还不够完善,我尝试过自定义一个plugin来处理特定需求,折腾了两天都没搞定。最后还是用rollup-plugin-swc绕过去了:&lt;/p&gt;</code></pre>javascript
// rollup.config.js
import swc from 'rollup-plugin-swc';

export default {
plugins: [
swc({
include: /.[jt]sx?$/,
exclude: /node_modules/,
minify: true,
jsc: {
target: 'es2015',
},
}),
],
};
>
<p>这里要注意include正则表达式,我最初写的是/.js$/,结果ts文件全都被忽略了。改成/.[jt]sx?$/后才正常。</p>

<p>还有个小细节,minify选项千万别滥用。虽然压缩代码很爽,但如果源码里有用eval或者with的(我知道这不好,但有些遗留代码真有),开启minify会直接报错。建议像下面这样分环境处理:</p>
`javascript
const isProduction = process.env.NODE_ENV === 'production';
module.exports = {
minify: isProduction && {
compress: {
unused: true,
dead_code: true,
},
mangle: {
keep_classnames: true,
},
},
};
`>

其他值得注意的地方

说几个零碎但重要的点:

  • 缓存策略:SWC自带缓存功能,但我发现某些情况下反而会导致编译结果不一致。建议在CI环境中禁用缓存,本地开发时再开启。
  • TypeScript支持:官方文档说支持得很好,但实际用下来,对一些高级类型推导还是会出问题。我的解决方案是保留tsc来做类型检查,SWC只负责转译。
  • 多线程优化:记得加上--threads参数,特别是在CI机器上。单核跑真的太慢了。

对了,还有个容易忽略的问题:SWC对Node版本要求比较高。我之前在一个老项目里用Node 12跑SWC,各种奇怪的报错。升级到Node 16后就正常了。建议至少用Node 14以上的版本。

结尾总结

以上是我使用SWC过程中总结的一些实战经验。总的来说,SWC确实是个不错的工具,性能比Babel强太多了。但也不是完美的,比如插件生态还不够丰富,一些边缘case需要自己想办法解决。

我目前的方案可能不是最优解,但至少在实际项目中跑得很稳定。有更好的实践经验欢迎在评论区交流,特别是插件开发这块,如果有人有好的解决方案,希望能分享一下。

本文章不代表JZTHEME立场,仅为作者个人观点 / 研究心得 / 经验分享,旨在交流探讨,供读者参考。
发表评论

暂无评论