Astro Local Environment Setup

seedlingLast update on Jul 18, 2026
Download .md

Ringkasan

Setup ini diambil dari dua project Astro production:

  • masmuss/pictogrammer — personal website dengan Svelte islands, Biome, Vitest + Playwright
  • masmuss/veka — wiki/content-heavy site dengan MDX, wiki-link, ESLint/Prettier

Keduanya menggunakan Astro 7, Tailwind v4, TypeScript 6, dan Lefthook.


Tools yang Dipakai

ToolFungsiInstalasi
pnpm / BunPackage managerbrew install pnpm / brew install bun
BiomeLinting + formatting (all-in-one)brew install biome
ESLint + PrettierAlternatif: linting + formattingpnpm add -D eslint prettier
LefthookGit hooks managerbrew install lefthook
VitestUnit testingbun add -D vitest
PlaywrightE2E + visual regressionbun add -D @playwright/test
PagefindStatic search indexpnpm add astro-pagefind

1. Package Manager & Scripts

Dua pendekatan yang dipakai:

Pendekatan A: Bun (pictogrammer)

{
  "scripts": {
    "dev": "astro dev --host",
    "build": "astro build",
    "preview": "astro preview",
    "astro": "astro",
    "lint": "biome lint .",
    "format": "biome format --write .",
    "check": "astro check",
    "test": "bun run test:unit:run && CI=true bun run test:e2e",
    "test:unit": "vitest",
    "test:unit:run": "vitest run",
    "test:e2e": "playwright test",
    "test:e2e:ui": "playwright test --ui"
  }
}

Pendekatan B: pnpm (veka/wiki)

{
  "packageManager": "pnpm@11.13.0",
  "scripts": {
    "dev": "astro dev",
    "build": "astro build",
    "preview": "astro preview",
    "astro": "astro",
    "lint": "eslint .",
    "format": "prettier --write .",
    "format:check": "prettier --check .",
    "commitlint": "commitlint",
    "prepare": "lefthook install",
    "preinstall": "npx only-allow pnpm"
  }
}

Rekomendasi: Bun untuk kecepatan install dan monorepo-friendly. pnpm untuk strict dependency resolution. Pilih satu, enforce via preinstall script.


2. Biome (Linting + Formatting)

Biome menggantikan ESLint + Prettier. Konfigurasi dari pictogrammer:

{
  "$schema": "https://biomejs.dev/schemas/2.5.3/schema.json",
  "assist": {
    "actions": { "source": { "organizeImports": "on" } }
  },
  "formatter": {
    "enabled": true,
    "indentStyle": "tab",
    "indentWidth": 2,
    "lineWidth": 80
  },
  "javascript": {
    "formatter": { "trailingCommas": "none" }
  },
  "json": {
    "formatter": { "trailingCommas": "none" }
  },
  "linter": {
    "enabled": true,
    "rules": {
      "preset": "recommended",
      "a11y": { "noSvgWithoutTitle": "off" },
      "suspicious": { "noExplicitAny": "warn" },
      "style": {
        "noParameterAssign": "error",
        "useAsConstAssertion": "error",
        "useSelfClosingElements": "error",
        "noUnusedTemplateLiteral": "error",
        "noInferrableTypes": "error",
        "noUselessElse": "error"
      },
      "nursery": {
        "useSortedClasses": { "level": "warn", "fix": "safe" }
      }
    }
  },
  "vcs": {
    "clientKind": "git",
    "enabled": true,
    "useIgnoreFile": true
  },
  "css": {
    "parser": { "tailwindDirectives": true }
  },
  "overrides": [
    {
      "includes": ["**/*.astro"],
      "linter": {
        "rules": {
          "correctness": {
            "noUnusedVariables": "off",
            "noUnusedImports": "off"
          }
        }
      }
    },
    {
      "includes": ["**/*.svelte"],
      "linter": {
        "rules": {
          "style": { "useConst": "off" },
          "correctness": {
            "noUnusedVariables": "off",
            "noUnusedImports": "off"
          }
        }
      }
    }
  ]
}

Jika pakai ESLint + Prettier (veka/wiki)

// eslint.config.js
import eslintPluginAstro from "eslint-plugin-astro";

export default [
  ...eslintPluginAstro.configs["flat/recommended"],
  {
    ignores: ["dist/", ".astro/", "node_modules/"],
  },
];
// .prettierrc
{
  "plugins": ["prettier-plugin-astro"],
  "overrides": [{ "files": "*.astro", "options": { "parser": "astro" } }]
}

3. Lefthook (Git Hooks)

Pola A: Biome-based (pictogrammer)

# lefthook.yml
pre-commit:
  parallel: true
  commands:
    check:
      glob: "*.{ts,tsx,js,jsx,astro,svelte,css,json,md,mdx}"
      run: bunx biome check --write --no-errors-on-unmatched --files-ignore-unknown=true {staged_files}
    astro-check:
      glob: "*.{ts,tsx,astro}"
      run: bunx astro check

pre-push:
  parallel: false
  commands:
    test:unit:
      run: bun run test:unit:run

Pola B: ESLint/Prettier-based (veka/wiki)

# lefthook.yml
pre-commit:
  parallel: true
  jobs:
    - name: lint
      run: pnpm lint {staged_files}
      glob: "*.{js,ts,mjs,cjs,astro}"
    - name: check
      run: pnpm astro check
    - name: format
      run: pnpm format --check {staged_files}
      glob: "*.{js,ts,mjs,cjs,astro,json,yaml,yml}"

commit-msg:
  jobs:
    - name: commitlint
      run: pnpm commitlint --edit {1}

Install hooks setelah clone:

lefthook install
# atau via prepare script: pnpm install akan otomatis trigger

4. Astro Config

Konfigurasi Astro 7 yang mencakup integrasi, markdown plugins, fonts, dan Vite.

// astro.config.ts
import { unified } from "@astrojs/markdown-remark";
import sitemap from "@astrojs/sitemap";
import svelte from "@astrojs/svelte"; // jika pakai Svelte islands
import mdx from "@astrojs/mdx"; // jika pakai MDX
import tailwindcss from "@tailwindcss/vite";
import { defineConfig, fontProviders } from "astro/config";
import pagefind from "astro-pagefind";
import remarkMath from "remark-math";
import rehypeKatex from "rehype-katex";
import remarkDeflist from "remark-deflist";
import remarkDirective from "remark-directive";
import rehypeExternalLinks from "rehype-external-links";
import { remarkAlert } from "remark-github-blockquote-alert";
import wikiLink from "remark-wiki-link";

export default defineConfig({
  site: "https://example.com",
  trailingSlash: "never",

  // Fonts: Astro 7 built-in font provider
  fonts: [
    {
      provider: fontProviders.google(),
      name: "Geist",
      cssVariable: "--font-sans",
      subsets: ["latin"],
    },
    {
      provider: fontProviders.google(),
      name: "Geist Mono",
      cssVariable: "--font-mono",
      subsets: ["latin"],
    },
  ],

  // Integrations
  integrations: [
    sitemap(),
    svelte(), // framework islands
    mdx(), // MDX support
    pagefind(), // static search
  ],

  // Markdown: remark + rehype plugins
  markdown: {
    processor: unified({
      remarkPlugins: [
        remarkMath,
        remarkDeflist,
        remarkDirective,
        remarkAlert,
        [wikiLink, {/* wiki-link options */}],
      ],
      rehypePlugins: [
        rehypeKatex,
        [
          rehypeExternalLinks,
          { rel: ["noreferrer", "noopener"], target: "_blank" },
        ],
      ],
    }),
    shikiConfig: {
      themes: {
        dark: "github-dark",
        light: "github-light",
      },
      wrap: true,
    },
  },

  // Vite: Tailwind v4 + path alias
  vite: {
    plugins: [tailwindcss()],
    resolve: {
      alias: {
        "@": path.resolve(__dirname, "./src"),
      },
    },
  },
});

Plugin Remark/Rehype yang Sering Dipakai

PluginFungsi
remark-math + rehype-katexRender math (LaTeX)
remark-deflistDefinition list (<dl>)
remark-directiveCustom directive syntax
remark-github-blockquote-alertGitHub-style admonitions
remark-wiki-link[[wikilink]] syntax
rehype-external-linksAuto target="_blank" + rel
rehype-katexRender KaTeX di HTML

5. Content Collections (Astro 5+)

Astro 5+ menggunakan Content Layer API dengan loader:

// src/content.config.ts
import { defineCollection } from "astro:content";
import { glob } from "astro/loaders";
import { z } from "astro/zod";

const blog = defineCollection({
  loader: glob({ pattern: "**/*.{md,mdx}", base: "./src/content/blog" }),
  schema: z.object({
    title: z.string(),
    description: z.string().optional(),
    createdAt: z.date(),
    updatedAt: z.date().optional(),
    tags: z.array(z.string()).default([]),
    isPinned: z.boolean().default(false),
    growthStage: z
      .enum(["seedling", "budding", "evergreen"])
      .default("seedling"),
  }),
});

export const collections = { blog };

Schema Pattern untuk Wiki/Content-heavy

// Growth stage untuk konten
growthStage: z.enum(["seedling", "budding", "evergreen"]).default("seedling");
StageArti
seedlingDraft awal, masih tumbuh
buddingMulai matang, tapi belum lengkap
evergreenKonten stabil dan lengkap

6. TypeScript Config

// tsconfig.json
{
  "extends": "astro/tsconfigs/strict",
  "compilerOptions": {
    "target": "es2020",
    "lib": ["ES2020", "DOM"],
    "paths": {
      "@/*": ["./src/*"]
    },
    "strictNullChecks": true,
    "noUncheckedIndexedAccess": true
  },
  "include": [".astro/types.d.ts", "**/*"],
  "exclude": ["dist"]
}

7. Testing

Unit Test (Vitest)

// vitest.config.ts
import path from "node:path";
import { getViteConfig } from "astro/config";

export default getViteConfig({
  test: {
    globals: true,
    environment: "node",
    include: ["tests/unit/**/*.{test,spec}.{js,ts}"],
  },
  resolve: {
    alias: {
      "@": path.resolve(__dirname, "./src"),
    },
  },
});

Jalankan: bun run test:unit atau vitest

E2E Test (Playwright + Visual Regression)

// playwright.config.ts
import { defineConfig, devices } from "@playwright/test";

export default defineConfig({
  testDir: "./tests/e2e",
  fullyParallel: true,
  forbidOnly: !!process.env.CI,
  retries: process.env.CI ? 2 : 0,
  use: {
    baseURL: "http://localhost:4321",
    trace: "on-first-retry",
  },
  expect: {
    toHaveScreenshot: {
      maxDiffPixelRatio: 0.05,
      threshold: 0.2,
    },
  },
  projects: [{ name: "chromium", use: { ...devices["Desktop Chrome"] } }],
  webServer: {
    command: "bun run build && bun run preview",
    url: "http://localhost:4321",
    reuseExistingServer: !process.env.CI,
    timeout: 180 * 1000,
  },
});

Jalankan: bun run test:e2e atau playwright test


8. CI/CD (semantic-release)

Digunakan di kedua project untuk otomatisasi versioning dan changelog:

// package.json
{
  "devDependencies": {
    "@semantic-release/changelog": "^6.0.3",
    "@semantic-release/commit-analyzer": "^13.0.1",
    "@semantic-release/git": "^10.0.1",
    "@semantic-release/github": "^11.0.2",
    "@semantic-release/release-notes-generator": "^14.0.3",
    "semantic-release": "^25.0.7"
  },
  "release": {
    "branches": ["main"],
    "plugins": [
      "@semantic-release/commit-analyzer",
      "@semantic-release/release-notes-generator",
      "@semantic-release/changelog",
      "@semantic-release/git",
      "@semantic-release/github"
    ]
  }
}

Trigger via GitHub Actions atau manual: npx semantic-release


9. Project Structure

Dua pendekatan struktur folder:

Pola A: Feature-based (pictogrammer)

  • project
    • src
      • assets/ # Static assets, styles, images, fonts
      • components/ # Shared UI components (.astro/.svelte)
      • config/ # Site config constants
      • content/ # Content collections (blog, projects, etc.)
      • layouts/ # Page layouts
      • lib/ # Utils, schemas, helpers
      • pages/ # File-based routing
      • plugins/ # Custom remark plugins
      • types.ts
      • content.config.ts
    • tests
      • unit
      • e2e
    • public/ # Static files (served as-is)

Pola B: Flat (veka/wiki)

  • project
    • src
      • assets
      • components
        • shell/ # Header, footer, sidebar
        • layout/ # Layout components
        • shared/ # Button, Card, Badge
        • wiki/ # Wiki-specific components
      • content/wiki/ # Wiki pages (nested dirs)
      • layouts
      • lib/ # Utils, custom plugins
      • pages
      • content.config.ts
    • public

Quick Start (Proyek Baru)

# 1. Create project
pnpm create astro@latest my-site -- --template minimal
# atau: bun create astro@latest my-site
cd my-site

# 2. Install core dependencies
pnpm add @astrojs/mdx @astrojs/sitemap @tailwindcss/vite tailwindcss astro-pagefind
pnpm add -D @astrojs/check typescript

# 3. Install tooling (pilih salah satu)
# Opsi A: Biome
pnpm add -D @biomejs/biome lefthook
# Opsi B: ESLint + Prettier
pnpm add -D eslint eslint-plugin-astro prettier prettier-plugin-astro lefthook

# 4. Jika perlu Svelte islands
pnpm add @astrojs/svelte svelte

# 5. Jika perlu testing
pnpm add -D vitest @playwright/test

# 6. Setup git hooks
pnpm lefthook install

# 7. Start dev server
pnpm dev

Perbandingan Dua Setup

Aspekpictogrammerveka/wiki
Package managerBunpnpm
Lint/FormatBiomeESLint + Prettier
Framework islandsSvelte 5N/A (pure Astro + Lucide)
TestingVitest + Playwright (visual)N/A
ContentBlog, projects, experiencesWiki pages
Markdown pluginsdirective, admonitions, deflist, supersub, github-cardmath, wiki-link, deflist, alert
CI/CDsemantic-releasesemantic-release + commitlint
FontsiA Writer Quattro + IBM Plex MonoGeist + Geist Mono + Spectral

Referensi: masmuss/pictogrammer, masmuss/veka