自前のJSXファクトリ関数のimportをRollupに任せる
背景
次のように、JSXのファクトリ関数は自作でき、さまざまな用途に利用できる。
このファクトリ関数をJavaScriptバンドルツールRollupを使って、最近のReactのようにいちいちimportを書かなくていいようにする。
@rollup/plugin-inject は import { Hoge } from "hoge";
を追加するだけなので、自作のファクトリ関数はバンドルしてくれない。(その後に別の処理が必要?)
JSXの処理にはBabelを使用する。Rollupから使うには @rollup/plugin-babel
を入れる。
また、BabelからJSXを変換するため @babel/plugin-transform-react-jsx
を入れる。
npm install --save-dev \
@rollup/plugin-babel \
@babel/core \
@babel/preset-env \
@babel/plugin-transform-react-jsx
今回は自前のファクトリ関数 jsx()
を使用するため、 babel.config.json
に次の記述をする。
{
"presets": ["@babel/preset-env"],
"plugins": [["@babel/plugin-transform-react-jsx", { "pragma": "jsx" }]]
}
実はRollupには最終出力の先頭や末尾にコードを追加するオプションがある。
このオプションに jsx()
の中身を指定すればよさそうだ。
import { babel } from "@rollup/plugin-babel";
const config = {
input: ...,
output: {
format: "es",
intro: `
function jsx(type, props, ...children) {
...
}
`,
},
plugins: [
babel({ babelHelpers: "bundled" }),
],
};
export default config;
Rollupはプラグインを簡単に書くことができ、output.intro
を追加する部分をプラグイン化すると次のようになる。
inject-jsx-runtime.js では jsx()
関数はtoStringメソッドで文字列化して(importなどがあると動かないので注意)……
import { jsx } from "./src/jsx-runtime.js";
const jsxCode = `${jsx.toString()}\n`;
// → function jsx(...) { ... } という文字列になる
export function injectJsxRuntime() {
return {
name: "inject-jsx-runtime",
intro: jsxCode,
};
}
そして rollup.config.js は
import { babel } from "@rollup/plugin-babel";
import { injectJsxRuntime } from "./inject-jsx-runtime.js";
const config = {
...,
plugins: [
babel({ babelHelpers: "bundled" }),
injectJsxRuntime(),
],
};
export default config;
これで出力コードの先頭に function jsx(...) { ... }
が入るようになる。
最近のReactだといちいち import React from "react"
を書かなくていいが、それはプラグイン @babel/plugin-transform-react-jsx のおかげ。
自動でJSX用の宣言をimportしてくれる設定は "runtime": "automatic"
.
プラグインの設定で "importSource": "hoge"
とすると、コードに import { jsx, jsxs, Fragment } from "hoge/jsx-runtime"
を挿入してくれるようだが、プロジェクト内の jsx-runtime.js
を読み込ませる方法は分からなかった。なので "runtime": "classic"
(デフォルト)として動作させることに。
TypeScript (tsc) を使用して型付けも完璧に行うすばらしい記事が公開されました👏