⁉️

どうやって0.00何秒削ったか?

に公開

How did you shave off 0.00 seconds?こちらの私のブログでgoogle翻訳版を取り上げています。

TypeScirptライブラリーということが前提です。
Plumeria CSSのコンパイル速度を極限まで詰めたのでそのために何をしたのか書きたいと思います。

速度が速いRustのバイナリを使う

CSSライブラリの都合上なるべくフレームワークロックインしないようにしています。
globを使い{js,jsx,ts,tsx,vue,svelte}を収集しています。
fs.globが安定してない頃に@rust-gear/globというライブラリーを作成しました。
この時はまだNode.jsのfs.globがstableではなかったので安定版として自作する必要がありました。

Rustのglobsetのクレートを直接napi-rsで呼び出しているため通常のfs.globSyncの2倍から3倍の速度が出すことが出来ました。

dependenciesはこんな感じです。

napi = { version = "2", features = ["tokio_rt"] }
napi-derive = "2.12.2"
globset = "0.4"
ignore = "0.4"
tokio = { version = "1", features = ["rt-multi-thread"] }

JSのV8Engineを直接的に使う

上で集めたコードをメモリで直接実行する必要があります、そのためにJSの最適化されたV8エンジン上で直接的に評価するには次の方法がありました。

  1. await importでNode.jsのV8で評価する
  2. Node module loaderでNode.jsのV8に解釈させる
  3. Node.jsのVMを使ってサンドボックスを作りVMのV8で評価する
  4. evalで直接JSエンジンのV8評価する(セキュリティ上の懸念が指摘されます)
  5. new Functionでscriptを作り直接JSエンジンのV8で評価する

このうちの最後のnew Functionで評価する方法が最終採択に採用されました。
理由としては1と2よりも圧倒的に速い。3よりも高速で評価できる。4より安全に評価できる。でした。

commonjsに全て変換する必要があるためAST parseに@swc/coreが採用されました。
このライブライリもRustで実装されており非常に高速で強力なライブラリーです。

簡単にいうと「rscuteはnew Functionのラッパーです」と言いたいところですが
rscute は new Function をベースにした軽量実行環境で、
TypeScript/ESM を瞬間的に CJS に変換しつつ V8 上で即時評価 できます。

CSSコンパイラーのdependencies

コンパイラーは収集と実行のみを行いコマンドを提供します。

@rust-gear/glob: ファイル収集
@swc/core: ファイルをAST解析するため
rscute: 実行するために
lightningcss: 最終的なCSSの軽量化を担っています
postcss: メディアクエリの最終調整に

3つの Rust ベースのライブラリの高速ランタイムによってPlumeria CSS のコンパイルは
“実質ほぼ1/3秒以下” と言える速度まで到達しました。

次回は、このコンパイラがどんな利点をもたらすのかを紹介します。

Discussion