久しぶりにAstro

構築
余談
今の段階ではランタイムはBunを使おうと思ってる
問題が起きたらpnpmにスワップすればいいね。Bunにあんまりメリットはない。
構築
bunx create-astro@latest [your project name]
通常はcreateでいいんだけど、既存プロジェクトなのでbun init
する。
正直、bun init
しても必要のないファイルが作られるだけで、最初からbun add astro
とかでもいい。
それでpackage.json
も自動的に作られるし。
bun add astro
{
"type": "module",
"private": true,
"name": "pages",
"scripts": {
"dev": "astro dev",
"build": "astro build",
"preview": "astro preview"
},
"dependencies": {
"astro": "^5.7.9"
}
}
手順通りにやる。まあ、testとstartはいらないかな
設定
root = true
[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
indent_style = space
indent_size = 4
[{*.html,*.css,*.styl,*.ts,*.js,*.mjs,*.astro,*.md,*.mdx}]
indent_size = 2
[{*.md,*.mdx}]
trim_trailing_whitespace = false
{
"editor.fontFamily": "'Fira Code', 'HackGen35 Console NFJ', monospace",
"editor.fontLigatures": true,
"editor.insertSpaces": true,
"editor.defaultFormatter": "esbenp.prettier-vscode",
"[json]": {
"editor.defaultFormatter": "biomejs.biome"
},
"[jsonc]": {
"editor.defaultFormatter": "biomejs.biome"
},
"[javascript]": {
"editor.defaultFormatter": "biomejs.biome"
},
"[typescript]": {
"editor.defaultFormatter": "biomejs.biome"
},
"[javascriptreact]": {
"editor.defaultFormatter": "biomejs.biome"
},
"[typescriptreact]": {
"editor.defaultFormatter": "biomejs.biome"
},
"[markdown]": {
"editor.defaultFormatter": "DavidAnson.vscode-markdownlint"
},
"[stylus]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"prettier.configPath": "./.prettierrc",
"prettier.ignorePath": "./.prettierignore",
"stylelint.validate": ["css", "postcss", "stylus", "styl"],
"markdownlint.run": "onType"
}
ここはあまり変わらないのでコピってきた。
Stylelintってbunで使えたっけ?
とりあえずnode関係抜きで設定できるのはこれくらいか

フォーマッタ
Biome
bun add -D --exact @biomejs/biome
Biomeを追加する
bunx biome init
bunxというコマンドが無い。bun biome init
とした。
Scoopで入れた影響かな?
{
"$schema": "https://biomejs.dev/schemas/1.9.4/schema.json",
"files": {
"ignore": ["node_modules/**"]
},
"formatter": {
"enabled": true,
"formatWithErrors": true,
"indentStyle": "space",
"indentWidth": 4,
"lineWidth": 120
},
"javascript": {
"formatter": {
"indentWidth": 2
}
},
"json": {
"parser": {
"allowComments": true
}
}
}
Biomeはインデントのスタイルがタブらしい。なんで?
Prettier
bun add -D --exact prettier
Prettierをインストール。Biomeだけだとすべてを網羅できないから。
bun add -D prettier-plugin-astro
Astro用のプラグインも入れる。
{
"printWidth": 120,
"tabWidth": 4,
"astroSkipFrontmatter": true,
"plugins": ["prettier-plugin-astro"]
}
# JS/TS Codes
*.js
*.ts
*.mjs
# JSON files
*.json
*.jsonc
.prettierrc
# Markdown
*.md
*.mdx
とりあえず、Biome優先であとはPrettierに投げる。

Linter
oxlint
bun add -D oxlint
完全な互換性はないけど、速いらしいので使ってみる
{
"plugins": ["oxc", "typescript", "import", "node", "promise", "jsx-a11y"]
}
Stylelint
bun add -D stylelint stylelint-config-html
/** @type {import('stylelint').Config} */
export default {
extends: [
"stylelint-config-html",
"stylelint-config-html/svelte",
"stylelint-config-html/astro"
],
customSyntax: "postcss-html"
};
とりあえずこいつは保留。使うかどうかも分からないんだよね

TypeScript
{
"extends": "astro/tsconfigs/base",
"compilerOptions": {
"module": "nodenext",
"moduleResolution": "nodenext",
"resolveJsonModule": true,
"baseUrl": ".",
"verbatimModuleSyntax": true,
"paths": {
"@/*": ["src/*"],
"@pages/*": ["src/pages/*"],
"@layouts/*": ["src/layouts/*"],
"@styles/*": ["src/styles/*"],
"@components/*": ["src/components/*"],
"@content/*": ["src/content/*"],
"@icons/*": ["src/icons/*"],
"@scripts/*": ["scripts/*"],
}
}
}
言語仕様関係は最新にしておく。CommonJSは読めないから。
bun add -D typescript @types/node
追加する必要はないかもしれない。
ただ、node:pathとか使うときとかに必要だったような気がする。

動作確認
{
"version": "0.2.0",
"configurations": [
{
"name": "Install dependencies",
"type": "node-terminal",
"request": "launch",
"command": "bun i"
},
{
"name": "Launch development server",
"type": "node-terminal",
"request": "launch",
"command": "bun dev"
},
{
"name": "Build",
"type": "node-terminal",
"request": "launch",
"command": "bun build"
},
{
"name": "Preview",
"type": "node-terminal",
"request": "launch",
"command": "bun prev"
}
]
}
---
---
<p>Hello, world!</p>
とりあえず簡単に動かす。
❯ bun dev
$ astro dev
Debugger attached.
01:03:37 [types] Generated 2ms
01:03:37 [content] Syncing content
01:03:37 [content] Synced content
astro v5.7.9 ready in 239 ms
┃ Local http://localhost:4321/
まあ、普通に動く。
こんな速かったっけ?

Tips
import { defineConfig } from "astro/config";
import { getAliases } from "./scripts/alias.ts";
import tsconfig from "./tsconfig.json" with { type: "json" };
export default defineConfig({
vite: {
resolve: {
alias: getAliases(tsconfig.compilerOptions.paths),
},
},
});
import path from 'node:path';
import type { MapLike } from 'typescript';
import type { AliasOptions } from 'vite';
export function getAliases(paths: MapLike<string[]>, alias: AliasOptions = {}): AliasOptions {
let aliasesArray: AliasOptions = alias;
for (const [_alias, _targetPath] of Object.entries(paths)) {
if (_targetPath.length <= 0) {
continue;
}
aliasesArray = {
...aliasesArray,
...{
[_alias]: path.resolve(_targetPath[0]),
},
};
}
return aliasesArray;
}
こうするとtsconfig.jsonで設定したpathsを自動で適用してくれる。
ただ、もしかしたらこれもいらないかもしれない

UnoCSS + daisyUI w/ Astro
bun add unocss daisyui @ameinhardt/unocss-preset-daisy
UnoCSSでもdaisyUIを使うことが出来る。
このプリセット自体は公式によるものではないが、公式ドキュメントで紹介されている。
完全には互換性がないんだとか。
import UnoCSS from 'unocss/astro'
export default defineConfig({
integrations: [UnoCSS()],
import { defineConfig } from 'unocss';
import presetWind4 from "@unocss/preset-wind4";
import { presetDaisy } from "@ameinhardt/unocss-preset-daisy";
export default defineConfig({
presets: [presetDaisy(), presetWind4()],
});
まあ、手順通りにね。presetUnoは無くなった模様。@unocss/preset-wind4ってのがそれになる。
いつも思うけど、daisyUIってほかのコンポーネントライブラリと比べても要素数が少なく綺麗にまとめられていると思う。
daisyはdigital accessible information systemの略で、アクセシビリティの規格らしい

bun add -D sass postcss
bun add postcss-preset-env autoprefixer
import presetEnv from "postcss-preset-env";
import autoprefixer from "autoprefixer";
export default {
plugins: [presetEnv, autoprefixer],
};
とりあえず追加しておく。
SassとかってTailwindCSSとかUnoCSSと併用しない方がいいって言われているけど
完全に分離できるなら話は別なんじゃないかな

import { defineConfig } from 'unocss';
import presetWind4 from "@unocss/preset-wind4";
import { presetDaisy } from "@ameinhardt/unocss-preset-daisy";
export default defineConfig({
presets: [
presetWind4(),
presetDaisy({
styled: false,
themes: ["emerald --default", "dracula --prefersdark"],
}),
],
});
<html data-theme="emerald">
このdata-themeをhtml要素に設定すると、デバイス側のモードがなんであれ、それになる。
<input type="checkbox" value="dracula" class="toggle theme-controller" />
このTheme Controllerを使っていて、気づいたことがある。
data-themeが設定されていない状況で、inputのvalueがdraculaとかダーク系のテーマだとする。
デバイス側のモードがダークモードだとこのトグルは機能しない。
<input
id="theme-controller"
type="checkbox"
value={DARK_THEME}
class="toggle theme-controller"
data-light-theme={LIGHT_THEME}
/>
<script>
const controller = window.document.getElementById("theme-controller");
if (window.matchMedia("(prefers-color-scheme: dark)").matches && controller != null) {
controller.setAttribute("value", controller.dataset.lightTheme ?? "light");
}
</script>
こうした。最初のモードが分かってればいいからね。
もっと良いやり方はあるかもね。