🪺

Denoを使用したSvelteでLucideアイコンを使用するメモ

に公開


最近Svelteを使用する際はほぼ常にDeno上で使用しているのですが、その環境で開発しているとLucideアイコンが使用できないことに気づきました。特殊なものを除き、ビジュアルデザイン素人が都度AIにSVGを描いてもらうのは避けたいと思ったため、どうにか使用できるようにした内容を備忘のために残しておきます。

前提

$ deno -v
deno 2.2.11
$ grep -E "npm:svelte@|npm:vite@" deno.json
    "svelte": "npm:svelte@^5.28.1",
    "vite": "npm:vite@^6.3.2"

起こった問題

deno add npm:@lucide/svelteしているプロジェクトでSvelteコンポーネントとしてのアイコンを使用すると、deno run -A npm:vite --openコマンド実行時に以下エラーとなる。

[vite] (ssr) Error when evaluating SSR module /src/routes/+page.svelte: Unexpected token '<' at file:///workspaces/svelte/node_modules/.deno/@lucide+svelte@0.501.0/node_modules/@lucide/svelte/dist/Icon.svelte:1:1
      at async SSRCompatModuleRunner.directRequest (file:///workspaces/svelte/node_modules/.deno/vite@6.3.2/node_modules/vite/dist/node/module-runner.js:1233:24)
      at async SSRCompatModuleRunner.cachedRequest (file:///workspaces/svelte/node_modules/.deno/vite@6.3.2/node_modules/vite/dist/node/module-runner.js:1180:76)
      at async eval (/workspaces/svelte/src/routes/+page.svelte, <anonymous>:3:600)
      at async ESModulesEvaluator.runInlinedModule (file:///workspaces/svelte/node_modules/.deno/vite@6.3.2/node_modules/vite/dist/node/module-runner.js:1062:5)
      at async SSRCompatModuleRunner.directRequest (file:///workspaces/svelte/node_modules/.deno/vite@6.3.2/node_modules/vite/dist/node/module-runner.js:1284:61)
      at async SSRCompatModuleRunner.directRequest (file:///workspaces/svelte/node_modules/.deno/vite@6.3.2/node_modules/vite/dist/node/chunks/dep-DG3BLbPj.js:25271:23)

対応検討

  • Vite上のSSRの過程でエラーが起きているようだ
    • 同じ構成のNode.js上では同じように使用してもエラーにはならない
    • ViteがDeno互換対応している部分でエラーになっているように思える
      • 最初の<でUnexpected tokenなのでIcon.svelteをsvelteとして解釈できていない?
  • Viteについて今から詳細実装を確認する気になれないため、回避策の模索に決定
  • いくつか試した結果エラーにならないのはlucide-staticだけだった
    • しかしGuideに書いてあるようにそのままは使用したくない
    • そこでVanillaJS用のシンプルなlucideパッケージをベースに若干手を加える事にした
    • 事前にsvelteをjsに変換する事も考えたが、開発体験が微妙なため見送った

問題の解決

lucide内で実行されている内容に沿ってデータを取り扱い、Snippetとして出力するアダプタ関数をパッケージとして作成した。最初に準備としてcreateRawSnippetを引数に指定するのは、このパッケージ内にsvelteパッケージを内包させたくないため。
https://jsr.io/@scirexs/lucide

雑記

思わぬところでつまずきました。やはりまだ完全互換とまではいかないようですね。

参考文献

Discussion