deno-vite-plugin 디버깅 1편

Lee Dogeon @moreal@hackers.pub

일요일인가 봤던 Deno에서 Vite를 쓸 때 라이브러리를 임포트하지 못 하는 문제를 디버깅해서 빌드되도록 만들어봤습니다. 여담에 적혀 있지만 원래 문제와 같은 문제를 해결한 것은 아니지만 일단 글을 적었기에 올려봅니다.


재현 환경 구성하기

제가 이해한 문제를 겪고 있는 구성은 Deno가 런타임이고 SolidStart를 사용하며, deno-vite-plugin라는 Vite Plugin를 사용 중인 것으로 이해했습니다.

공식 사이트에 적혀있는 커맨드 따라 deno run -A npm:create-solid로 생성하고 app.config.ts 파일에 vite: () => ({ plugins: [deno()] }) 같은 설정을 추가하였습니다. deno add jsr:@fedify/fedify 로 라이브러리를 추가해주고 아래와 같이 페이지 코드를 수정해서 Fedify를 import하고 사용하도록 했습니다.

import { Title } from "@solidjs/meta";
import { Note } from "@fedify/fedify"

export default function Home() {
  const note = new Note({
    content: "Hello world!",
  });

  return (
    <main>
      <Title>Hello World</Title>
      <code>{JSON.stringify(note.toJsonLd())}</code>
    </main>
  );
}

그랬더니 deno task build를 할 때 아래와 같은 에러로 실패했습니다.

✗ Build failed in 480ms
Error building router ssr: [commonjs--resolver] Unsupported: {
  "kind": "asserted",
  "specifier": "https://jsr.io/@fedify/fedify/1.7.2/deno.json",
  "local": "/path/to/deno/remote/https/jsr.io/40e42a9e7b255523298a33c95df68bb9298abcd63b8993267883a2a27b2b02a2",
  "size": 4755,
  "mediaType": "Json"
}

원인 찾고 해결해보기

다 넣으면 길기 때문에 주요 에러 메시지만 첨부했지만 stacktrace도 같이 출력되어서 에러를 발생시키는 라인은 쉽게 알 수 있었습니다. 함수 코드가 길어서 핵심만 알 수 있게 좀 자르면:

export async function resolveDeno(id, cwd) {
    // truncated...

    const output = await new Promise((resolve, reject) => {
        execFile(DENO_BINARY, ["info", "--json", id], { cwd }, (error, stdout) => {
      // truncated... 
    });
    // truncated... 
    const json = JSON.parse(output);
    const actualId = json.roots[0];
    const redirected = json.redirects[actualId] ?? actualId;
    const mod = json.modules.find((info) => info.specifier === redirected);
    if (mod === undefined) return null;
    if (isResolveError(mod)) return null;
    if (mod.kind === "esm") {
        return; // truncated... 
    }
    else if (mod.kind === "npm") {
        return; // truncated... 
    }
    else if (mod.kind === "external") {
        // Let vite handle this
        return null
    }
    throw new Error(`Unsupported: ${JSON.stringify(mod, null, 2)}`);
}

돌아가는 방식이 deno info --json <id> 형식으로 커맨드를 돌리고 그 출력을 활용하는데, kind 값이 asserted 일 때가 핸들링 되지 않아서 발생하는 문제였습니다. asserted가 무엇인가 하고 추가적으로 로그를 찍어 어디서 https://jsr.io/@fedify/fedify/1.7.2/deno.json를 임포트 하게 되나 보니 https://jsr.io/@fedify/fedify/1.7.2/runtime/docloader.ts 같은 곳에서 라이브러리 버전 값을 활용하기 위해 불러오고 있었습니다.

// https://jsr.io/@fedify/fedify/1.7.2/runtime/docloader.ts#L4
import metadata from "../deno.json" with { type: "json" };

deno info 커맨드가 출력하는 JSON값이 무엇인지 소스코드를 검색하여 타고 들어가니 deno_graph::ModuleGraph 타입이라는 것을 알았습니다. [deno_graph]라는 별도 저장소가 있어서 들어가서 해당 타입을 찾았고 타고 들어가다 보니 kind: asserted와 관련된 코드는 deno_graph::Module::Json 타입이라는 것도 알 수 있었습니다.

Note

아래 코드는 원본 코드에서 현재 이야기하는 것과 무관한 것들을 모두 제거한 코드입니다.

pub struct ModuleGraph {
  #[serde(rename = "modules")]
  #[serde(serialize_with = "serialize_module_slots")]
  pub(crate) module_slots: BTreeMap<ModuleSpecifier, ModuleSlot>,
}

pub(crate) enum ModuleSlot {
  Module(Module),
}

pub enum Module {
  // todo(#239): remove this when updating the --json output for 3.0
  #[serde(rename = "esm")]
  Js(JsModule),
  // todo(#239): remove this when updating the --json output for 3.0
  #[serde(rename = "asserted")]
  Json(JsonModule),
}

주석이 눈에 들어오는데 이슈 번호를 따라가보니 코멘트가 작성되어 있는데 JSON 모듈도 kind: esm 으로 표시되어야 한다는 이야기 였습니다. (denoland/deno_graph#239, comment)

위 코멘트를 보니 esm으로 취급하게 해도 무관하겠구나 싶어서 로컬에서 asserted의 경우 esm으로 취급하게 만들도록 했더니 원래 발생하던 에러 메시지는 보이지 않게 되었습니다!

    } else if (mod.kind === "asserted") {
        return {
            id: mod.local,
            kind: "esm",
            loader: mod.mediaType,
            dependencies: [],
        };
    }

여담

이후에 import("node:net").isIP 함수 관련하여 에러가 발생했는데 재현 환경 구성할 때 짠 코드가 클라이언트에서 돌 수도 있게끔 되어있는것이 문제였습니다. "use server"를 단 별개 함수로 빼서 클라이언트 코드에 포함되지 않도록 하니 문제는 해결되었습니다.

이 글을 쓰면서 Deno 디스코드 #help에 있는 글을 보니 에러 양상이 달라서 deno task dev 도 돌려보았는데 Deno 디스코드 글과 같이 npm 관련 에러가 여전히 발생했습니다. 이건 나중에 또 보게 되면... 2편으로 적고, 일단 지금 이 글은 적긴 적었으니 올리려고 합니다.

위 deno_graph 저장소 이슈 코멘트가 2023년 3월에 적혔는데 일손이 부족한가 보다 싶었습니다. 😢

1

No comments

If you have a fediverse account, you can comment on this article from your own instance. Search https://hackers.pub/ap/articles/0197ea69-0861-7914-af98-58e1db6ab402 on your instance and reply to it.