Open6

Denoでブラウザで動かすPreactを開発してみる

oosawyoosawy
oosawyoosawy

まずやりたいことができそうか簡単に試してみる

preactは問題なさそう

main.ts
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,
  ....
}
oosawyoosawy

documentがなくてrenderができない

main.ts
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);
oosawyoosawy

tsconfig.jsonを作ってlibにdomを指定すれば実行はできるようになる

調べてみたらissueを見つけた
https://github.com/denoland/deno/issues/6422

tsconfig.jsonをこのように書いてdeno run --config tsconfig.json main.tsとすると実行できるようになった。

tsconfig.json
{
  "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のコマンドで毎回オプションを指定する必要があるのは、求めていたシンプルさに反する部分があるのでどうにかしたい

oosawyoosawy

画面に描画する部分はDenoで扱わない静的なコードとして管理するのがよさそう

main.tsからAppのほかにpreactのhとrenderをexportとして、HTML側からそれらを使って画面に描画する

この部分のコードはTypeScriptによる型チェックが効かなくなるけど、あまり触らない場所なので規約としてしまってもほとんど影響がないはず

oosawyoosawy

bundleしてブラウザで実行してみる

ここまでのコード

main.ts
import { h, render } from "https://cdn.skypack.dev/preact@10";

export const App = () => h("p", null, "hello world");

export { h, render };
dist/index.html
<body>
  <div id="root"></div>

  <script type="module">
    import { App, h, render } from "./index.js"

    render(h(App), document.getElementById("root"))
  </script>
</body>
  1. main.tsをブラウザ用にbundleする
    deno bundle main.ts dist/index.js

  2. ローカルのファイルだとブラウザに読み込まれないことがあるのでサーバーを起動する
    denoだと標準ライブラリにファイルサーバーがあってとても便利。
    deno run --allow-net --allow-read https://deno.land/std/http/file_server.ts

これで画面にhello worldが表示できた!