🦀

Rust + Webpack = Rspack の紹介

2023/03/13に公開

概要

本記事では、JavaScript モジュールバンドラの一種である、 Rspack について、公式ドキュメントからわかることを要約し、自分なりの所感を付け加えて紹介します。


https://www.rspack.dev/misc/branding.html

※ 本記事は、Webpack に関する最低限の知識を前提としています。
※ 本記事は、2023/03/12 時点の情報であり、古い内容が残っている場合があります

TL;DR;

  • RspackWebpack との互換性とパフォーマンスを両立したモジュールバンドラ
  • Webpack より5~10倍高速
  • Webpack と設定ファイルや loader, plugin に充分な互換性を持つ
  • Webpack の一般的な設定パターンがビルトインで用意されており、シンプルに使える
  • 現在はアーリーステージで、Vue.js のサポートもこれからという状態なので今後に期待

Rspack とは

Webアプリケーション開発において、モジュールバンドルは(今の所)欠かせないツールの1つです。

モジュールバンドルの代表的なツールとして、Webpack が挙げられます。しかし、近年では、プロダクトの大規模化や複雑化に伴い、Webpack では開発サーバーやプロダクションビルドの低速化する問題が浮き彫りとなっています。

この問題に対するアプローチとして、 ViteTurbopack が台頭してきています。

しかし、それらのツールは、Webpack とは全く異なるアプローチを採用しているため、Webpack とは互換性がなく、既存のプロダクトを移行する際に困難を伴うことがあります。

Rspack は、これらの問題に対応するために開発されたツールです。Rust ベースの高速なモジュールバンドラーでありながら、Webpack と互換性を保つように設計されており、既存の設定ファイル、ローダー、プラグインの多くをそのまま活用することができます。

以下は Rspack における設定ファイルの例です。 webpack.config.js に近いことがわかります。

rspack.config.js
module.exports = {
  context: __dirname,
  // エントリーは Webpack と同様にバンドルの開始地点を指定する
  entry: {
    main: "./src/main.jsx"
  },
  // Webpack の HtmlWebpackPlugin にあたる仕組み式ビルトイン化されている(後述)
  // ほか、多数のプラグインにあたる機能がビルトインで提供されており、高速に動作することが期待できる
  builtins: {
    html: [
      {
        template: "./index.html"
      }
    ]
  },
  // ローダーの適用方法は Webpack と同様
  // asset については Webpack 5 時点の最新の仕組みにアラインされている
  module: {
    rules: [
      {
        test: /\.svg$/,
        type: "asset"
      }
    ]
  }
};

発音について

Rspack の発音記号は /'ɑrespæk/ でカタカナにするなら「アーレスペック」に近いようです。
(個人的には Rust + Webpack で「ラスパック」と呼びたくなってしまいます)

Webpack との互換性について

Rspack は、Webpack との互換性を強みとしていますが、ここでいう互換性は以下を指します。

Rspack は 100% の互換性を目指してません。 上記リンクの通り、主要な仕組みを優先して対応し、他はコミュニティからのフィードバックに応じて互換性を広げる方針のようです。

モジュール解決のデフォルトサポート

いくつかのファイル形式については、ローダーの設定を書かずとも自動で適切に変換されるようになりました。以下はその例です。

TypeScript (.ts)

WebpackTypeScript を使用する場合、ts-loaderbabel-loader を使ってトランスパイルする必要がありましたが、 Rspack ではビルトインで TypeScript がサポートされています。

具体的には、Rspack では、.ts ファイルをインポートすると、内部で SWC を用いて高速なトランスパイルをします。

ただし、SWC はトランスパイルのみで、型チェックは行わないため、必要に応じて tsc などを使用する必要があります

JSX (.jsx / .tsx)

RspackJSX もビルトインでサポートしており、babel-loader@babel/preset-react などの設定を行う必要がなく、.jsx .tsx ファイルに対してトランスパイルが自動的に適用されます。

CSS (.css / .module.css)

CSS についても .css .module.css ともにサポートされており、css-loaderstyle-loader を設定する必要がなくなります。

Babel の不要化

Internet Explorer 対応が実質終了した現代においてはその必要性が薄れましたが、従来の Webpack では、Babel 及び babel-loader を用いて、レガシーブラウザ向けに JavaScript コードを変換するのが当たり前でした。

RSpack では、レガシーブラウザ向けのコード変換についてもデフォルトで SWC を使用します。

以下のように設定ファイルの target オプションから、サポートする環境を指定できます。

rspack.config.js
module.exports = {
  target: ['es2015', 'node'],
};

SWC は stage 3 以上の proposal から全てのコードをサポートしており、 preset-env の機能や、 browserslist にも対応しているため、ほとんどのケースで Babel からの置き換えが可能です。

ローダーの対応状況

Rspack では、Webpack における主要なローダーの多くがサポートされています。

以下のローダーはそのまま利用可能です。

  • sass-loader
  • less-loader
  • postcss-loader
  • yaml-loader
  • json-loader
  • stylus-loader
  • @mdx-js/loader
  • @svgr/webpack
  • raw-loader
  • url-loader
  • css-loader

以下については注意が必要です。

vue-loader

vue-loader は、Vue.js での開発においては必須と言えるローダーですが、現状はサポートされていません。

詳細は不明ですが、現状の Rspack が提供する API では、vue-loader を動かすことが不可能なようです。

ただし Rspack 側としても、vue-loader のサポートは優先度が高いと判断しているようで、2023年の4月から6月を目処に対応するようです。

なお、 vue-loader を直接使うことは出来ずとも、同等の動作をするローダーを実装することは既に可能なようです。

https://github.com/web-infra-dev/rspack/blob/main/examples/vue/vue-loader.js

babel-loader

babel-loader 自体は対応していますが、パフォーマンス懸念から、推奨されていません。

前述のとおり、Rspack では内部的に SWC を使用した TypeScript のトランスパイルと、レガシーブラウザ向けのコード変換機能を持っているため、ほとんどのケースでは babel-loader は必要ありません。

互換性自体は充分にあるため、上記以外の用途で babel-loader を使用している場合は、継続的に使用することもできます。

プラグインの対応状況

いくつかの主要なプラグインはそのまま利用可能です。

  • DefinePlugin
  • copy-webpack-plugin
  • mini-css-extract-plugin
  • terser-webpack-plugin
  • progressPlugin
  • webpack-bundle-analyzer
  • webpack-stats-plugin
  • tsconfig-paths-webpack-plugin
  • HotModuleReplacementPlugin

また、いくつかのプラグインについては、同等の組み込み機能が用意されている場合があります。

組み込み機能は、設定ファイルの builtins から設定することができます。

開発サーバー

Webpack を用いた開発サーバーを立ち上げる場合、 webpack-dev-server を別途導入しますが、 RSpack では開発用サーバーが組み込みで用意されており、以下コマンドですぐに開発を始めることができます。

$ yarn rspack serve

当然、設定は webpack-dev-server との互換性が充分にあり、 HMRProxy といった機能も使用可能です。

プロダクションビルド

ここでは詳細は割愛しますが、以下のような Webpack ではお馴染みのプロダクションビルド時の最適化についても対応しています。

  • ミニフィケーション
  • コード分割(チャンク化)
  • ツリーシェイキング(デッドコード検出)
  • ソースマップ生成

パフォーマンス

さて、肝心のパフォーマンスですが、RspackWebpack + babel の組み合わせと比較した場合、以下のようなベンチマークが取れたようです。

  • 開発環境の初回起動時: 11倍高速
  • ルートモジュール変更時のHMR: 3倍高速
  • リーフモジュール変更時のHMR: 3倍高速
  • プロダクションビルド: 7倍高速

※ ベンチマーク手法の詳細は Benchmark case 参照

もちろん、 Webpack を使いつつも、 babelSWC に置き換えたり、一部で esbuild を使用するなどでパフォーマンスを改善することは可能です。

とはいえ、コア機能であるモジュール解決やバンドル化、チャンク切り出しなどの仕組みを JavaScript でなく Rust で書くことで、マルチコアCPU による並列化を最大限に生かして効率化できているようです。

まとめと所感

本記事では、Webpack との互換性を持ちつつも Rust によって高速に動作するように書き換えられたモジュールバンドラである、Rspack について紹介しました。

近年では ViteTurbopack など、新たなアプローチによってパフォーマンスを大幅に向上させるツールが台頭していますが、そこに新たな仲間が加わりました。

新規プロダクトについては既に Vite を使えば最高の開発体験を得られているとも言えますが、一方で、Webpack を用いている既存プロダクトを Vite に移行するというのは一筋縄では行かないことがあります。

そういった事情から、いつまでも Webpack を使い続けてしまうプロダクトにとって、 Rspack は一筋の光になりえます。もし Vite と比べて遥かに低コストで移行ができると言うなら、これ以上のソリューションはないでしょう。
(マイグレーションガイド を見る限りは移行コストは低いですが、Webpack の使い方によっては困難にもなりそう)

また、個人的には終わりを迎えてしまった Webpack に関する知識・ノウハウが無駄にならずに今後も活かせる可能性に心躍っています。
(これは逆に早く無くなってほしいという声もありそうですが)

とは言え、自社では Vue.js を使用している都合、vue-loader の完全サポートを待ち望みつつウォッチしていくことになりそうです。

GitHubで編集を提案

Discussion