Deno2.0でSvelte5の開発環境を構築したメモ
Deno上でSvelteを開発してみたくなったので、試しに最小限で構築してみた備忘メモです。私はSSGしか使用していないためSSGが前提の構成になっています。もともとnpx sv create
の中の選択肢にdeno
が出てくるようになったので、対応したのかなぁと思っていました。最初にdeno run -A npm:sv create
を試してみたところ普通に構築できました。それはそれで互換性があるということで非常に良いことなのですが、構成があまりにもNode.jsなので気持ち的に何か違いました。せっかくDenoを使用するので、せめて見た目だけでもDenoプロジェクトのようにしたいと思い色々変更した結果です。VSCodeのDevContainerを使用しています。
(2025-03-17追記)
いちいちプロジェクトを構成するのが面倒なので、自分で使う用にjsr:@scirexs/sv
パッケージを作成しました。最低限のセットアップではないですが、不要なものを削除すれば誰でも使用できる気がします。
結論
DevContainerの設定
FROM mcr.microsoft.com/vscode/devcontainers/base:debian
ENV DENO_INSTALL=/deno
RUN mkdir -p /deno \
&& curl -fsSL https://deno.land/x/install/install.sh | sh \
&& chown -R vscode /deno
ENV PATH=${DENO_INSTALL}/bin:${PATH} \
DENO_DIR=${DENO_INSTALL}/.cache
{
"name": "deno_${localWorkspaceFolderBasename}",
"build": {
"dockerfile": "Dockerfile",
},
"runArgs": ["--name", "vsc-${localWorkspaceFolderBasename}"],
"customizations": {
"vscode": {
"extensions": [
"denoland.vscode-deno",
"svelte.svelte-vscode",
],
"settings": {
"deno.enable": true,
"deno.disablePaths": [
"./.svelte-kit",
"./.vite",
"./build",
"./node_modules"
],
},
},
},
}
プロジェクト構成
結果のプロジェクト構成は以下(node_modulesと隠しディレクトリは省略)。スクリプトで生成しているファイルの大半はsv
で生成されるファイルと同じ内容になっている。別途切り出して都度コピー等した方が管理しやすくなると思われる。
$ tree .
.
├── deno.json
├── src
│ ├── app.html
│ ├── lib
│ └── routes
│ ├── +layout.ts
│ └── +page.svelte
├── static
│ └── favicon.png
├── svelte.config.mjs
├── tsconfig.json
└── vite.config.ts
setup script
cat << EOF > ./deno.json
{
"nodeModulesDir": "auto",
"tasks": {
"dev": "deno run -A npm:vite --open",
"build": "deno run -A npm:vite build",
"preview": "deno run -A npm:vite preview --open",
"prepare": "deno run -A npm:@sveltejs/kit/svelte-kit sync || echo ''",
"check": "deno run -A npm:@sveltejs/kit/svelte-kit sync && deno run -A npm:svelte-check --tsconfig ./tsconfig.json",
"check:watch": "deno run -A npm:@sveltejs/kit/svelte-kit sync && deno run -A npm:svelte-check --tsconfig ./tsconfig.json --watch"
}
}
EOF
deno add npm:vite
deno add npm:@deno/vite-plugin
deno add npm:@sveltejs/vite-plugin-svelte
deno add npm:@sveltejs/kit
deno add npm:svelte
deno add npm:svelte-check
deno add npm:@sveltejs/adapter-static
mkdir -p ./src/routes
mkdir -p ./src/lib
mkdir ./static
cat << EOF > ./vite.config.ts
import { sveltekit } from "@sveltejs/kit/vite";
import { defineConfig } from "vite";
import deno from "@deno/vite-plugin";
export default defineConfig({
plugins: [
deno(),
sveltekit()
]
});
EOF
cat << EOF > ./svelte.config.mjs
import adapter from "@sveltejs/adapter-static";
import { vitePreprocess } from "@sveltejs/vite-plugin-svelte";
/** @type {import("@sveltejs/kit").Config} */
const config = {
preprocess: vitePreprocess(),
kit: {
adapter: adapter({
pages: "build",
assets: "build",
fallback: undefined,
precompress: false,
strict: true
})
}
};
export default config;
EOF
cat << EOF > ./tsconfig.json
{
"extends": "./.svelte-kit/tsconfig.json",
"compilerOptions": {
"allowJs": true,
"checkJs": true,
"strict": true
}
}
EOF
echo "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgAQMAAABJtOi3AAAAA1BMVEUAAACnej3aAAAAAXRSTlMAQObYZgAAAAtJREFUCNdjGAUkCQABLAABwXDTkAAAAABJRU5ErkJggg==" | base64 -d > ./static/favicon.png
cat << EOF > ./src/app.html
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
%sveltekit.head%
</head>
<body data-sveltekit-preload-data="hover">
<div style="display: contents">%sveltekit.body%</div>
</body>
</html>
EOF
cat << EOF > ./src/routes/+page.svelte
<h1>Welcome to SvelteKit</h1>
<p>Visit <a href="https://svelte.dev/docs/kit">svelte.dev/docs/kit</a> to read the documentation</p>
EOF
echo "export const prerender = true;" > ./src/routes/+layout.ts
contents by file
{
"nodeModulesDir": "auto",
"tasks": {
"dev": "deno run -A npm:vite --open",
"build": "deno run -A npm:vite build",
"preview": "deno run -A npm:vite preview --open",
"prepare": "deno run -A npm:@sveltejs/kit/svelte-kit sync || echo ''",
"check": "deno run -A npm:@sveltejs/kit/svelte-kit sync && deno run -A npm:svelte-check --tsconfig ./tsconfig.json",
"check:watch": "deno run -A npm:@sveltejs/kit/svelte-kit sync && deno run -A npm:svelte-check --tsconfig ./tsconfig.json --watch"
}
}
import { sveltekit } from "@sveltejs/kit/vite";
import { defineConfig } from "vite";
import deno from "@deno/vite-plugin";
export default defineConfig({
plugins: [
deno(),
sveltekit()
]
});
import adapter from "@sveltejs/adapter-static";
import { vitePreprocess } from "@sveltejs/vite-plugin-svelte";
/** @type {import("@sveltejs/kit").Config} */
const config = {
preprocess: vitePreprocess(),
kit: {
adapter: adapter({
pages: "build",
assets: "build",
fallback: undefined,
precompress: false,
strict: true
})
}
};
export default config;
{
"extends": "./.svelte-kit/tsconfig.json",
"compilerOptions": {
"allowJs": true,
"checkJs": true,
"strict": true
}
}
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
%sveltekit.head%
</head>
<body data-sveltekit-preload-data="hover">
<div style="display: contents">%sveltekit.body%</div>
</body>
</html>
<h1>Welcome to SvelteKit</h1>
<p>Visit <a href="https://svelte.dev/docs/kit">svelte.dev/docs/kit</a> to read the documentation</p>
export const prerender = true;
使い方
コマンド実行
npm run xxx
ではなくdeno task xxx
を実行する。
-
npm run dev
->deno task dev
バージョンアップ
# confirm latest version
deno outdated
# update based on version range
deno outdated --update
# force update to latest
deno outdated --update --latest
キャッシュ削除
deno clean
その他
-
sv
を使用しない理由-
package.json
等のDenoでは不要なファイルが生成されるため - 色々試しているうちに直接設定ファイルを作成した方が早い&クリーンになると判断した
-
-
tsconfig.json
が残っている理由-
deno.json
に統合したかったが、extends
に対応していないため断念した -
deno.json
で設定できないオプションは削除
-
-
svelte-kit sync
がnpm:@sveltejs/kit/svelte-kit sync
の理由-
svelte-kit
パッケージは内容が何もなかったため - 切り離す予定があるのか、統合されたのかは不明
- そのため今後変更する必要があるかもしれない
-
-
svelte.config.js
をmjs
にする理由-
js
のままでpackage.json
がない場合、svelte-language-serverがうまく動作しない -
package.json
に{ "type": "module" }
を指定すれば解決する- が、そのためだけの
package.json
は置きたくない
- が、そのためだけの
- これと同等の指定となるように
svelte.config.js
をsvelte.config.mjs
に変更する- 拡張子を
mjs
とした場合、svelte-kit sync
が動作しない-
svelte-kit sync
内で対象ファイル名がsvelte.config.js
固定のため -
svelte-kit sync
を実行する場合は実行前に以下のような処置が必要-
svelte-kit sync
内の固定値を2か所変更する - 一時的に
mjs
をjs
に置換する -
js
のハードリンクを作成する 等
-
-
- 拡張子を
-
雑記
起動中のviteを終わるためにq + Enter
してもプロンプトが戻ってこない場合があるのは何なんでしょうか。
あとdeno.json
の中で"lock": false
を記載していないとパッケージをバージョンアップするとTypeErrorが出たりするので、この方法だと完全互換とまではいかないようです。全パッケージをremoveしてnode_modules
ディレクトリを完全に削除した後に再度addすれば直るようです。面倒なのでjsr:@scirexs/reinstall
を作成しました。
それでも@tailwindcss/vite
はViteが競合してエラーが出る場合があるようなので、./node_modules/.deno/@tailwindcss+vite@x.y.z/node_modules/vite
のsymlinkを修正する必要があるようです。
Discussion