Deno.cwd()の勉強
storybook alternativeを作ってたんだけどこんがらがってきた…
Deno Deploy上でファイル関連のAPIがどう解釈されてるか復習する。
import { defineRoute } from "$fresh/server.ts";
export default defineRoute(async (req, ctx) => {
const cwd = Deno.cwd();
const filePath = new URL(req.url, `file://${cwd}`).pathname;
const importMeta = import.meta;
return (
<div class="page">
<h1>Hello World</h1>
<p>Current working directory: {cwd}</p>
<p>Requested file path: {filePath}</p>
<p>import.meta.url: {importMeta.url}</p>
<p>import.meta.main: {importMeta.main}</p>
</div>
);
});
ローカルだとこう。
Current working directory: /Users/hashrock/code/study/study-deno-deploy-cwd
Requested file path: /
import.meta.url: file:///Users/hashrock/code/study/study-deno-deploy-cwd/routes/index.tsx
import.meta.main:
デプロイしてみる。
Current working directory: /src
Requested file path: /
import.meta.url: file:///src/routes/index.tsx
import.meta.main:
API Docにはこう書かれている。
Deno.cwdは、デプロイメントの現在の作業ディレクトリを返します。それはデプロイメントのルートディレクトリのルートにあります。たとえば、GitHubの統合を使用してデプロイした場合、カレントディレクトリはGitHubリポジトリのルートです。
気になったので、一応ファイルリストをwalkで取得してみる。
node_modulesが取れてきてしまったので除外したけど、それ以外は/src/にしかファイルがなさそう。
eszip viewerでの勉強もしてみたいかも。
eszipのサンプルをfreshアプリに対して実行してみたけど動かないな。もっと簡単なやつからやるべきか
まあともかくとして、Deno.cwd()からimportをしたい場合はファイルプロトコル(file://)を足してあげればいいのかな?
できた!
サブディレクトリにプロジェクトが置かれていて、Deno.cwd()が一つ上のディレクトリを指しているときにうまく動かない。
プロジェクトのrootを指定するか、islandsの相対パスを指定するか、どっちがいいだろう…?
多分だけどtailwind.config.tsの内容を取得する必要があるケースを考えると、プロジェクトのrootを指定したほうがいいような気がする。import.meta.urlはfresh.config.tsのパスを渡せる(し、どうしてもパスをカスタマイズする必要があれば別のパスを算出して渡せばいい)
tailwind.config.tsの内容を取得したい根拠は下記の通り。ダークモード切り替えUIを作ったとしても、darkMode: 'class'
が指定されていなければ意味をなさないので、手動で設定を促すか、無効時はそもそもUIを出さないかのどちらかをしたい。
file://
形式にするにはこれを使うべきっぽい
結局何が必要なのか。
- expandGlobに対して、pathまたはURLオブジェクトがほしい(ワイルドカードを使ったもの)
- expandGlobで取れてきた絶対パスを相対パスに変換してマッチングをかける
- 相対パスの変換ロジックはcwdまたはprojectRootのbasepathで置換をかける
- expandGlobで取れてきた絶対パスを相対パスに変換してマッチングをかける
- importに対して、pathパラメータで入ってきた相対パスを絶対パスに変換する
- cwdまたはprojectRootのbasepathを連結する
かなりいろいろやった。基本的にimport.meta.urlかundefinedしか受け付けないようにした。テストも書いた。安全のため内部的にはURLオブジェクトで扱っている。
相対URLを安全に扱う方法が欲しくなってくるなあ。
- 相対パスでpluginを使う場合:Deno.cwd()を使えば基本的には動くようになっているはず。
deno.land/x/からインポートするとうまく動かなくて、原因としてはURL.pathnameプロパティはschemeを含まないこと、あとはdeno.land/x/に置いたコードから絶対パスを参照することでhttps://deno.land/
を見に行ってしまうことがわかった。
修正:
しかしまだ動いてない。
エラーログ:
TypeError: module not found: 'file:///src/islands/stories/Button.story.tsx'
at async GET (https://deno.land/x/fresh_stories@0.0.10/routes/stories-single.tsx:26:21)
at async handler (file:///src/src/server/context.ts:284:14)
at async ext:deno_http/00_serve.js:459:18 {
code: "ERR_MODULE_NOT_FOUND"
}
これは多分 file:///src/www/islands/stories/Button.story.tsx
から読みにいかないといけないということだと思うんだけどね…
しかし一応このままで動くはずではある。
-
www/fresh.config.ts
の中でimport.meta.url
を指定済み - import.meta.urlは
file:///src/www/fresh.config.ts
になっているはず(要確認) - baseLocationは
file:///src/www/
になる(はず)
const storyPath = "file://" + join(Deno.cwd(), path);
const story = await import(
storyPath
);
- storyPath:
file:///src/www/islands/stories/Button.story.tsx
になるはず
実際そうなってないので調べる。
デバッグ中。
import.meta.url: file:///src/www/fresh.config.ts
いやこれ自体はOKだな。
うーん。デバッグ面倒だなあ。一旦exampleとライブラリのリポジトリ統合して、デバッグ用のブランチ作ろうかな。そしたらrawgitからimportのテストもできるかな?
あとローカルでは起きないというのも面倒だな〜。これもfresh docsでテストするんじゃなくてminimal repro作って実験するようにしたいかな。
あとユニットテストももっと書いて、疑う場所を減らしたいかな。