Deno で https:// から import しても動くモジュールにする
Deno Advent Calendar 2022 の9日目の記事です
https:// から import できるのはとても便利
Deno は Node.js とは違い, 直接 https://
から始まるURLでTypeScript のコードを import して実行することができます.
import { serve } from "https://deno.land/std@0.167.0/http/server.ts";
serve(() => {
return new Response("今の時刻は" + new Date().toISOString() + "です");
});
package.json
が不要で手軽ですね. import する URL は https://deno.land
のオリジンである必要もなく, HTTP としてWebに公開していれば, どこからでも import できます. npm registry などにアップロードする必要はありません.
1番手軽に公開できるのは GitHub でしょう.
GitHub ではファイルのページの Raw ボタンから移動できる コードだけを返すURLを用意してくれています.
例 https://raw.githubusercontent.com/narumincho/deno-https-import-test/main/sampleServer.ts
ただ この URL には commit hash が入っていないため, main ブランチのファイルを変更したら内容が変わってしまいます. Deno は 1度 import したものはキャッシュされ, 更新するのが少し面倒なのと, デプロイ時に内容が変わってしまうと開発時に動いたものと変わってしまうので, 「Copy Permalink」でコピーした commit hash が含まれる URL のページを開き「Raw」ボタンでURLを得るのが良いでしょう.
import { main } from "https://raw.githubusercontent.com/narumincho/deno-https-import-test/01c08b708bb21abdcda420eb1673a91ea1997678/sampleServer.ts";
main();
https://raw.githubusercontent.com/narumincho/deno-https-import-test/01c08b708bb21abdcda420eb1673a91ea1997678/sampleServer.ts
のコードを確認すると次のように相対パスで指定してますが, うまく取得してくれます.
また, Deno Doc に URL を入れるとそのモジュールのドキュメントを表示してくれます. API ドキュメントの仕組みをわざわざ用意しなくて良いですね.
この https://
で始まるURL で import して動かせる機能ですが, うまく動かない場合があります.
import map を使っている場合
import map を使っているコード
使う側
import { startUseImportMapHttpServer } from "https://raw.githubusercontent.com/narumincho/deno-https-import-test/d9c961328aff4e3512a550ac022fbccebdd988df/useImportMap.ts";
startUseImportMapHttpServer();
このコードを実行するとこのような import のパスが解決できないというエラーが発生します. (たまたま同じ指定の import map を使っていればエラーは発生しない)
PS C:\Users\narum\Documents\GitHub\deno-https-import-test> deno run --allow-net=:8000 ./start.ts
error: Relative import path "std/http/server.ts" not prefixed with / or ./ or ../
at https://raw.githubusercontent.com/narumincho/deno-https-import-test/d9c961328aff4e3512a550ac022fbccebdd988df/useImportMap.ts:1:23
GitHub で公開したコードを直接使いたいときには import map を使わずに直接 import するモジュールを指定するのが良いでしょう.
ファイル読み取りをしている場合
今度は HTTP サーバーで画像を返す例です
-
import.meta.resolve
を使っている理由は, このファイルを基準とした相対パスで指定するためです. そうしないとカレントディレクトリ基準になってしまいます -
new URL
を使っている理由は,file://
から始まる文字列には複数の解釈があるためみたいです. 関連 issue ↓
使う側
import { startDenoImageServer } from "https://raw.githubusercontent.com/narumincho/deno-https-import-test/83d95134eafb394556f3b39de6255a7caf0bcd2a/imageServerUseReadFile.ts";
startDenoImageServer();
クローンして動かせば問題なく動くのですが, GitHub の https://
でimportするコードでは このようなエラーメッセージが表示され うまく動きません
PS C:\Users\narum\Documents\GitHub\deno-https-import-test> deno run --allow-net=:8000 ./start.tserror: Uncaught (in promise) TypeError: Must be a file URL.
throw new TypeError("Must be a file URL.");
^
at fromFileUrl (https://deno.land/std@0.167.0/path/win32.ts:968:11) at startDenoImageServer (https://raw.githubusercontent.com/narumincho/deno-https-import-test/7c9a2c1caed59fcec84a794f266f23a59b84b111/imageServerUseReadFile.ts:9:5) at file:///C:/Users/narum/Documents/GitHub/deno-https-import-test/start.ts:3:1
Deno.readFile
ではなく fetch
を使うことで対処できます. fetch
は https://
から始まるURL以外にも, import.meta.url
などで取得できる file://
から始まるURLにも対応しています.
ちなみにHTTPの POST メソッドでファイルの保存はできません. できるのは HTTPのGETメソッドだけです
import { startDenoImageServer } from "https://raw.githubusercontent.com/narumincho/deno-https-import-test/83d95134eafb394556f3b39de6255a7caf0bcd2a/imageServerUseFetch.ts";
startDenoImageServer();
これで, https://
から始まるURLで import しても動くようになりました
また, 実行時に画像を取得するコードになっているため実行には
deno run --allow-net=:8000,raw.githubusercontent.com ./start.ts
のように --allow-net
フラグに raw.githubusercontent.com
の指定を加える必要があります. (:8000
の指定はHTTPサーバーの起動のため)
このフラグの指定をしなくて済み, またネットに接続していないときでも動作するようにするために画像をコードに埋め込むようにしてみます
この記事も似たようなことをしています
png ファイルを json ファイルに変換して保存するコード
json ファイルになった deno.png
埋め込まれた json を import して動作するサーバーのコード
import { startDenoImageServer } from "https://raw.githubusercontent.com/narumincho/deno-https-import-test/83d95134eafb394556f3b39de6255a7caf0bcd2a/imageServerUseJsonImport.ts";
startDenoImageServer();
これで, --allow-net
に余計な指定をしなくて済むようになりました
deno run --allow-net=:8000 ./start.ts
欠点は画像を変更したときに変更を反映させるために jsonに変換するスクリプトを実行して GitHub にアップロードする手間があることです. そこを自動化するのはまた今度ー
Discussion