Denoでブラウザで動かすPreactを開発してみる
まずやりたいことができそうか簡単に試してみる
preactは問題なさそう
import { h } from "https://cdn.skypack.dev/preact@10";
const App = () => h("p", null, "hello world");
console.log(h(App));
{
type: [Function: App],
props: {},
key: undefined,
....
}
documentがなくてrenderができない
import { h, render } from "https://cdn.skypack.dev/preact@10";
const App = () => h("p", null, "hello world");
if ("document" in window) {
render(h(App), document.body);
}
error: TS2584 [ERROR]: Cannot find name 'document'. Do you need to change your target library? Try changing the `lib` compiler option to include 'dom'.
render(h(App), document.body);
tsconfig.jsonを作ってlibにdomを指定すれば実行はできるようになる
調べてみたらissueを見つけた
tsconfig.jsonをこのように書いてdeno run --config tsconfig.json main.ts
とすると実行できるようになった。
{
"compilerOptions: {
"lib": [ "dom", "deno.ns" ]
}
}
deno bundleでも同じようにオプションを指定するとブラウザで動きそうなコードが作れた。
ただVSCode上でエラーが表示されつずける
VSCodeのプラグインと相性が悪いのか、window.document
とアクセスしてる箇所でProperty 'document' does not exist on type 'Window & typeof globalThis'.
というエラーが表示されてしまう。
この問題は上のissueには2月時点でvscode_denoのcanary版で解決されたようなことが書いてあったけど、今の最新版でも解決していなさそう。
それからtsconfig.jsonでも"deno.ns"
と書いている部分がVSCodeでエラーが表示されてしまったり、tsconfig.jsonがあるのとdenoのコマンドで毎回オプションを指定する必要があるのは、求めていたシンプルさに反する部分があるのでどうにかしたい
画面に描画する部分はDenoで扱わない静的なコードとして管理するのがよさそう
main.tsからAppのほかにpreactのhとrenderをexportとして、HTML側からそれらを使って画面に描画する
この部分のコードはTypeScriptによる型チェックが効かなくなるけど、あまり触らない場所なので規約としてしまってもほとんど影響がないはず
bundleしてブラウザで実行してみる
ここまでのコード
import { h, render } from "https://cdn.skypack.dev/preact@10";
export const App = () => h("p", null, "hello world");
export { h, render };
<body>
<div id="root"></div>
<script type="module">
import { App, h, render } from "./index.js"
render(h(App), document.getElementById("root"))
</script>
</body>
-
main.tsをブラウザ用にbundleする
deno bundle main.ts dist/index.js
-
ローカルのファイルだとブラウザに読み込まれないことがあるのでサーバーを起動する
denoだと標準ライブラリにファイルサーバーがあってとても便利。
deno run --allow-net --allow-read https://deno.land/std/http/file_server.ts
これで画面にhello worldが表示できた!