📦

Reactで書けるSSG 改善点と今後について - minista v1

2022/01/18に公開

webコーディングに特化した、Reactで書けるスタティックサイトジェネレーター(以下SSG)ministaのv1をリリースしました!開発経緯と使い方は前回記事の通りなので、今回はv0→v1の主な改善点を振り返りつつ、苦労した点や今後について書きます。

設定のオーバーライド

最初はデフォルトの設定を上書きする術がありませんでしたが、情報提供をきっかけに機能追加できました!ministaはwebpackを利用しており webpack.config.js を読み込みます。それを複数マージできるライブラリ webpack-merge があると。

https://www.npmjs.com/package/webpack-merge

早速、デフォルトとユーザーの webpack.config.js をマージしたところ上手く動きました。深いオブジェクトや関数があっても大丈夫で、スプレッド構文より柔軟な印象。

const webpackConfig = require("./webpack.config")
const userWebpackConfig = fs.existsSync(path.resolve("webpack.config.js") ? require(path.resolve("webpack.config")) : {}

const mergedWebpackConfig = merge(webpackConfig, userWebpackConfig)

これで完了かと思いきや、実際に使ってみるとコケる部分がいくつかあり...。例えば、プラグインの登録は配列になっているので、ユーザーがデフォルトと同じプラグインを使うと重複します。MiniCssExtractPluginなどの設定を上書きしようとしても上手く行きません。

// Error
const mergedWebpackConfig = {
  plugins: [
    new MiniCssExtractPlugin({ filename: "assets/[name].css" }),
    new MiniCssExtractPlugin({ filename: "assets/css/[name].css" }),
  ],
}

なので、重複した場合にエラーとなるプラグインはコンストラクター名でフィルタリングして新しいものを残すようにしました。HtmlWebpackPluginにも似た問題があり、何らかの手違いで書き出し先が重複するとエラーになるため、filenameでフィルタリングしています。

PostCSSとBabelもユーザーコンフィグを参照して設定を切り替える仕様にしました。ただ、こちらはコンフィグファイルの種類が多い...。しかもJSだったりJSONだったり。すべてを網羅するのは冗長に思えたので、対象ファイルはNext.jsに揃えました。

// if javascript
const babelConfigJs = require(path.resolve("babel.config.js"))

// if json
const babelrc = JSON.parse(fs.readFileSync(path.resolve(".babelrc"), "utf8"))

TypeScript(.tsx)にデフォルト対応

やはりTypeScript(.tsx)で書けた方が圧倒的に楽ですよね!僕はコンポーネントが20超えたあたりからprops忘れがち...。エディタの補完に助けられています。string なのか boolean なのか判別しにくい名前をつけて後からぐぬぬとなることもありません。

TypeScript導入はななきさんが行っていたので参考にしました!追加で必要だったのは、何が同封されていると良いのか考えること。上書き可能なローダー設定を入れることで、アップグレードでTypeScriptの設定が競合してもコケない仕様にできました。

納品用サイトマップ

SaaSプロジェクトではテンプレページの目次を含めて納品しています。毎回1から書くと時間を取られるため minista-sitemap というReact Componentsを作成。特長は、無制限の入れ子目次をJSONで作れることと、スタイルがバンドルされないことです。

https://www.npmjs.com/package/minista-sitemap

今後について

v1リリースまで破壊的変更もなく辿り着きました。ほとんどwebpackのおかげです!HTML生成のテンプレにJSXが使えたり、開発と本番で差異なくビルドできるなど、求めていた内容はだいたい盛り込めました。あとは...devサーバーの起動を爆速化したい。

最近話題のViteなどはコンポーネントがいくら増えても秒で立ち上がって理想的です。ministaもesbuildで構文解析をすっ飛ばしたい!そもそもwebpackの場合、起動するときにすべてを1つにバンドルしてメモリに乗せる設計なので厳しいでしょうか?

いえ esbuild-loader というライブラリを作っている人がいました!試しにそこそこ大きい案件(js: 319KB, css: 101KB, components: 38個, pages: 15枚)で使ってみたところ、おおよそ3〜4割ほど速くなりました。※ちなみに swc-loader だと1割高速化

内訳は各要素をゼロにしながら差分を測ったものなので厳密ではありませんが、esbuildがどの部分に効くのかは分かりました。JSX→HTMLの変換にも効いてるのが良いですね。ただ、爆速化とまではいかなかったので、安定性を犠牲にして組み込むかは悩みどころです。

https://www.npmjs.com/package/esbuild-loader

devサーバーとバンドラーをViteに切り替えて、JSX→HTMLの手法を独自に考える方が良いかもしれません。もしくは、近い構成でAstroというフレームワークがありますので、そこに全体JSX対応とヒューマンリーダブルなデータ生成機能を加えるとゴールが近いかも?

...などなど、代替を模索しつつも、実務に耐えうるv1は完成しました🎉 ではまた!

Discussion