🐥
Denoとdeno_emitを使ってReactをコンパイルする
概要
Denoとdeno_emitを使ってシンプルにReactをコンパイルする方法をまとめる。
環境
- deno@1.41.1
- deno_emit@0.38.2
- react@18.2.0
ファイル構成
.
├── app.tsx
├── deno.jsonc
├── deno.lock
├── deps.ts
├── index.html // 最終的に表示するHTML
├── index.js // Reactのtsxをコンパイルして生成するJavaScript
├── index.tsx
└── build.ts
対象のReactファイル(app.tsx)をコンパイルして、index.jsに出力。
index.htmlからそれを読み込む。
HTML
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Deno React Samp</title>
</head>
<body>
<div id="root"></div>
<script src="index.js" defer></script>
</body>
</html>
対象のReactファイル
deps.ts
export * as ReactDOM from "https://esm.sh/react-dom@18.2.0";
export * as React from "https://esm.sh/react@18.2.0";
app.tsx
import { React } from "./deps.ts";
export default function App() {
return (
<div>
<h1>Hello, world</h1>
</div>
);
}
ビルドスクリプト
build.ts
import { bundle } from "https://deno.land/x/emit@0.38.2/mod.ts";
const url = new URL("./index.tsx", import.meta.url);
const result = await bundle(url, {
minify: false,
});
console.log(result.code);
await Deno.writeTextFile("./index.js", result.code);
deno_reactは、シンプルにTypeScriptをJavaScriptにコンパイル(トランスパイル)するためのtranspile
関数と、依存関係を全てバンドルするための bundle
関数を提供している。
今回はReactの依存コードも全てindex.jsに含めるためにbundle関数を使用。
設定
deno.jsonc
{
"tasks": {
"build": "deno run --allow-net --allow-env --allow-read --allow-write build.ts"
},
"compilerOptions": {
// Deno.xxxを認識するためにdeno.nsが必要
// documentなどを認識するためにdomが必要
"lib": ["deno.ns", "dom", "esnext"]
},
"imports": {
// react/jsx-runtimeを自動でimportするため必要
"react/": "https://esm.sh/react@18.2.0/"
}
}
Deno自体は、jsxをサポートしており、jsxのランタイムはデフォルトで、reactが使われるようになっている。
ReactはReact17以降、jsへの変換方法を刷新していて、 react/jsx-runtime
というモジュールが使われる。
どのモジュールを使ってImportするかは、jsxImportSource
で指定する。
// この記述をファイルの先頭に書くことで、どのソースからjsxをコンパイルするか指定できる
/** @jsxImportSource https://esm.sh/preact */
export function App() {
return (
<div>
<h1>Hello, world!</h1>
</div>
);
}
deno.json
の imports
に記載することでこの @jsxImportSource
は省略できる。
ビルド
deno run --allow-net --allow-env --allow-read --allow-write build.ts
気になっていること
deno_emitのビルドだとimportsによるモジュール解決ができない?
deps.ts
export * as ReactDOM from "https://esm.sh/react-dom@18.2.0";
export * as React from "https://esm.sh/react@18.2.0";
depsにかかれているimportをdeno.jsonのimportに書きURL表記を省略しようとしたが、deno_emitでのビルドでエラーが出てしまったため、URL表記に戻した。
Reactのimportを省略できない
imports
に reactを書くことで、 @jsxImportSource
を省略できるが、deno_emitでビルドするとReactのコードを一緒にバンドルしてくれず、
import { React } from "./deps.ts";
は書く必要があった。
Discussion