Open22

Deno.cwd()の勉強

hashrockhashrock

storybook alternativeを作ってたんだけどこんがらがってきた…

Deno Deploy上でファイル関連のAPIがどう解釈されてるか復習する。

hashrockhashrock
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>
  );
});
hashrockhashrock

ローカルだとこう。

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:
hashrockhashrock

API Docにはこう書かれている。

https://docs.deno.com/deploy/api/runtime-fs#denocwd

Deno.cwdは、デプロイメントの現在の作業ディレクトリを返します。それはデプロイメントのルートディレクトリのルートにあります。たとえば、GitHubの統合を使用してデプロイした場合、カレントディレクトリはGitHubリポジトリのルートです。

hashrockhashrock

気になったので、一応ファイルリストをwalkで取得してみる。

node_modulesが取れてきてしまったので除外したけど、それ以外は/src/にしかファイルがなさそう。

hashrockhashrock

eszipのサンプルをfreshアプリに対して実行してみたけど動かないな。もっと簡単なやつからやるべきか

hashrockhashrock

まあともかくとして、Deno.cwd()からimportをしたい場合はファイルプロトコル(file://)を足してあげればいいのかな?

hashrockhashrock

サブディレクトリにプロジェクトが置かれていて、Deno.cwd()が一つ上のディレクトリを指しているときにうまく動かない。

プロジェクトのrootを指定するか、islandsの相対パスを指定するか、どっちがいいだろう…?

hashrockhashrock

多分だけどtailwind.config.tsの内容を取得する必要があるケースを考えると、プロジェクトのrootを指定したほうがいいような気がする。import.meta.urlはfresh.config.tsのパスを渡せる(し、どうしてもパスをカスタマイズする必要があれば別のパスを算出して渡せばいい)

tailwind.config.tsの内容を取得したい根拠は下記の通り。ダークモード切り替えUIを作ったとしても、darkMode: 'class'が指定されていなければ意味をなさないので、手動で設定を促すか、無効時はそもそもUIを出さないかのどちらかをしたい。

https://zenn.dev/azukiazusa/articles/bee71756d66679#class

hashrockhashrock

結局何が必要なのか。

  • expandGlobに対して、pathまたはURLオブジェクトがほしい(ワイルドカードを使ったもの)
    • expandGlobで取れてきた絶対パスを相対パスに変換してマッチングをかける
      • 相対パスの変換ロジックはcwdまたはprojectRootのbasepathで置換をかける
  • importに対して、pathパラメータで入ってきた相対パスを絶対パスに変換する
    • cwdまたはprojectRootのbasepathを連結する
hashrockhashrock

かなりいろいろやった。基本的にimport.meta.urlかundefinedしか受け付けないようにした。テストも書いた。安全のため内部的にはURLオブジェクトで扱っている。

相対URLを安全に扱う方法が欲しくなってくるなあ。

  • 相対パスでpluginを使う場合:Deno.cwd()を使えば基本的には動くようになっているはず。
hashrockhashrock

しかしまだ動いてない。

https://hr-fresh-stories-04tcxjx19jvt.deno.dev/stories?path=islands/stories/Button.story.tsx

https://hr-fresh-stories-04tcxjx19jvt.deno.dev/stories-single?path=islands/stories/Button.story.tsx

エラーログ:

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"
}
hashrockhashrock

これは多分 file:///src/www/islands/stories/Button.story.tsx から読みにいかないといけないということだと思うんだけどね…

hashrockhashrock

しかし一応このままで動くはずではある。

  1. www/fresh.config.tsの中で import.meta.url を指定済み
  2. import.meta.urlは file:///src/www/fresh.config.ts になっているはず(要確認)
  3. 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 になるはず

実際そうなってないので調べる。

hashrockhashrock

デバッグ中。

import.meta.url: file:///src/www/fresh.config.ts

いやこれ自体はOKだな。

hashrockhashrock

うーん。デバッグ面倒だなあ。一旦exampleとライブラリのリポジトリ統合して、デバッグ用のブランチ作ろうかな。そしたらrawgitからimportのテストもできるかな?

あとローカルでは起きないというのも面倒だな〜。これもfresh docsでテストするんじゃなくてminimal repro作って実験するようにしたいかな。

あとユニットテストももっと書いて、疑う場所を減らしたいかな。