新一代的編譯工具 SWC
最近前端圈掀起了一陣 rust 風,凡是能用 rust 重寫的前端工具就用 rust 重寫,今天介紹的工具就是通過 rust 實現的 bable:swc,一個將 ES6 轉化為 ES5 的工具。
而且在 swc 的官網,很直白說自己和 babel 對標, swc
和 babel
命令可以相互替換,並且大部分的 babel 外掛也已經實現。
使用 rust 的一個優勢就是快,比如我們之前的一個專案,將 babel 替換成 swc 後,編譯速度從原來的 7 秒提升到了 1 秒,效率直接爆炸。
swc 與 babel 一樣,將命令列工具、編譯核心模組分化為兩個包。
-
@swc/cli
類似於@babel/cli
; -
@swc/core
類似於@babel/core
;
npm i -D @swc/cli @swc/core
通過如下命令,可以將一個 ES6 的 JS 檔案轉化為 ES5。
npx swc source.js -o dist.js
下面是 source.js
的程式碼:
const start = () => { console.log('app started') }
程式碼中囊括了 ES6 的兩個特性, const 宣告
和 箭頭函式
。經過 swc 轉化後,這兩個特性分別被轉化成了 var 宣告
和 function 匿名函式
。
swc 與 babel 一樣,支援類似於 .babelrc
的配置檔案: .swcrc
,配置的格式為 JSON。
{ "jsc": { // 編譯規則 "target": "es5", // 輸出js的規範 "parser": { // 除了 ecmascript,還支援 typescript "syntax": "ecmascript", // 是否解析jsx,對應外掛 @babel/plugin-transform-react-jsx "jsx": false, // 是否支援裝飾器,對應外掛 @babel/plugin-syntax-decorators "decorators": false, // 是否支援動態匯入,對應外掛 @babel/plugin-syntax-dynamic-import "dynamicImport": false, // …… // babel 的大部分外掛都能在這裡找到對應配置 }, "minify": {}, // 壓縮相關配置,需要先開啟壓縮 }, "env": { // 編譯結果相關配置 "targets": { // 編譯結果需要適配的瀏覽器 "ie": "11" // 只相容到 ie 11 }, "corejs": "3" // corejs 的版本 }, "minify": true // 是否開啟壓縮 }
babel 的外掛系統被 swc 整合成了 jsc.parser
內的配置,基本上大部分外掛都能照顧到。而且,swc 還繼承了壓縮的能力,通過 minify
屬性開啟, jsc.minify
用於配置壓縮相關的規則,更詳細的配置可檢視 文件 。
通過在 node.js 程式碼中,匯入 @swc/core
模組,可以在 node.js 中呼叫 api 直接進行程式碼的編譯,這對 CLI 工具的開發來說是常規操作。
// swc.mjs import { readFileSync } from 'fs' import { transform } from '@swc/core' const run = async () => { const code = readFileSync('./source.js', 'utf-8') const result = await transform(code, { filename: "source.js", }) // 輸出編譯後代碼 console.log(result.code) } run()
除了將程式碼轉義,swc 還提供了一個簡易的打包能力。我們新建一個 src
資料夾,在裡面新建兩個檔案: index.js
、 utils.js
。
// src/index.js import { log } from './utils.js' const start = () => log('app started') start()
// src/utils.js export const log = function () { console.log(...arguments) } export const errorLog = function () { console.error(...arguments) }
可以看到 index.js
匯入了 utils.js
中的一個方法,然後我們新建一個 spack.config.js
檔案,該檔案是 swc 打包的配置檔案。
// spack.config.js module.exports = { entry: { // 打包的入口 web: __dirname + "/src/index.js", }, output: { // 打包後輸出的資料夾 path: __dirname + "/dist", }, };
然後在命令列執行:
$ npx spack
打包成功後,會在 dist
目錄輸出一個 web.js
檔案。
可以看到,不僅將 index.js
、 utils.js
打包成了一個檔案,還進行了 tree shaking
,將 utils.js
中沒有使用的 errorLog
方法刪掉了。
babel 畢竟經過了這麼多年的發展,不管是 bug 輸了,還是社群活躍度都遠遠優於 swc。所以,如果是小產品試水還是可以試一下 swc 的,舊專案如果已經使用了 babel 還是不建議進行遷移。
在使用的過程,還是發現了一些小問題。比如,如果我使用了 async function
,swc 會自動匯入 regenerator-runtime
模組。
// 編譯前,有個 async 方法 const start = async () => { console.log('app started') }
呼叫 swc 編譯後,程式碼如下:
這個結果看起來是沒問題的,但是 swc 與 babel 類似,也有 helpers(@swc/helpers),同時提供了 externalHelpers
開關, 如果把 externalHelpers
設定為 true
,swc 會將一些工具類,通過模組的形式匯入。
// .swcrc { "jsc": { "externalHelpers": true } }
而 externalHelpers
的預設值是 false
,那這個時候, regenerator-runtime
,到底是通過模組的形式匯入,還是把整個程式碼寫入到檔案?
swc 正好有個 issue [https://github.com/swc-project/swc/issues/1461] 在討論這個問題。
除了上面說的這個問題,其實還有一點,就是作者覺得之前的架構有問題,正在加緊重寫 2.0 版本,感覺可以期待一下,另外提一句,swc 的作者是一個 97 年的韓國小哥,目前大學都還沒畢業,最後我也只能說一句:牛逼!
- 詳解 Webpack devtools
- 什麼是 LFU 演算法?
- 什麼是 LFU 演算法?
- 關於 Promise 的執行順序
- 關於 Promise 的執行順序
- 新一代的編譯工具 SWC
- 介紹一個請求庫 — Undici
- 你給開源專案提過 PR 嗎?
- Go 語言的模組化
- MobX 上手指南
- 介紹兩種 CSS 方法論
- 普通打工人的2020丨掘金年度徵文
- Node.js 服務效能翻倍的祕密(二)
- Node.js 服務效能翻倍的祕密(一)
- 我是如何閱讀原始碼的
- Vue3 Teleport 元件的實踐及原理
- Vue3 模板編譯優化
- 小程式依賴分析實踐
- React 架構的演變 - Hooks 的實現
- Vue 3 的組合 API 如何請求資料?