このメモは、WXT + Svelte を使った Chrome Extension 開発の初期ベースラインを作るための手順を、日本語でまとめたものです。 特定プロジェクト固有の実装内容ではなく、開発を始める前段の共通セットアップに絞っています。
- WXT + Svelte の Chrome Extension 雛形
- Node バージョンの固定
pnpmベースの依存管理- Prettier による format 環境
- ESLint による lint 環境
svelte-checkによる typecheckvitestによるテスト基盤- VS Code 保存時の format / lint fix 設定
- macOS 想定
miseが使えることpnpmが使えること- Chrome が使えること
Node は LTS 系に固定しておくのが無難です。
このメモでは mise.toml で以下のように 24 を固定します。
[tools]
node = "24"空ディレクトリを作って移動します。
mkdir my-chrome-extension
cd my-chrome-extensionGit を初期化します。
git initプロジェクトローカルで Node 24 を固定します。
mise use node@24mise.toml が生成され、node = "24" が記録されます。
補足:
- ローカルに奇数系 Node が入っていても、ツール互換性を考えると LTS 系に揃えた方が安定です
mise WARN gpg not foundは環境によって出ることがありますが、この作業自体では致命的ではありません
WXT の scaffold は wxt init を使います。
空ディレクトリなら、そのままルートに生成できます。
pnpm dlx wxt@latest init . --template svelte --pm pnpmすでに docs/ などのファイルを置いていて、ルートが非空ディレクトリになっている場合は wxt init . が abort します。
その場合はいったん一時ディレクトリに生成してからコピーします。
pnpm dlx wxt@latest init tmp/wxt-starter --template svelte --pm pnpm
cp -R tmp/wxt-starter/. .補足:
wxt init .は非空ディレクトリだと止まります- 一時ディレクトリ経由にすると、既存の
docs/やメモを残したまま scaffold を取り込めます mvではなくcpにしておくと、問題時に生成物を退避として残せます
pnpm installこの時点では最低限の WXT / Svelte 雛形が入り、package.json には以下のような基本 script が入ります。
devbuildzipcheckpostinstall
最初に svelte-check を実行すると、./.wxt/tsconfig.json が未生成で失敗するケースがありました。
そのため、一度 wxt prepare を明示実行して型関連の生成物を作っておきます。
pnpm exec wxt prepareformat / lint / test 基盤を整えるため、以下を追加します。
pnpm add -D eslint @eslint/js typescript-eslint eslint-plugin-svelte globals prettier prettier-plugin-svelte vitest各パッケージの役割:
eslint: lint 本体@eslint/js: ESLint 公式の基本ルールtypescript-eslint: TypeScript 向け parser / rule セットeslint-plugin-svelte: Svelte ファイル向け lintglobals: browser / node / webextensions の globals 設定prettier: format 本体prettier-plugin-svelte: Svelte を Prettier で整形するためのプラグインvitest: テストランナー
方針は以下です。
- できるだけ Prettier のデフォルトを使う
- Svelte 向け整形は
prettier-plugin-svelteに寄せる - 明示設定は最小限にする
printWidthは120- クォートは
singleQuote: true
.prettierrc.json:
{
"plugins": ["prettier-plugin-svelte"],
"printWidth": 120,
"singleQuote": true
}.prettierignore:
.git
.wxt
coverage
dist
node_modules
tmp
方針は以下です。
- ESLint の公式推奨をベースにする
- TypeScript は型情報付き推奨ルールまで入れる
- Svelte は
eslint-plugin-svelteの flat config 推奨を使う - Prettier と競合する Svelte ルールは
flat/prettierで抑える
eslint.config.js:
import js from '@eslint/js';
import { defineConfig } from 'eslint/config';
import svelte from 'eslint-plugin-svelte';
import globals from 'globals';
import tseslint from 'typescript-eslint';
const sharedGlobals = {
...globals.browser,
...globals.node,
...globals.webextensions,
};
export default defineConfig(
{
ignores: ['.wxt/**', 'coverage/**', 'dist/**', 'eslint.config.js', 'node_modules/**', 'tmp/**'],
},
js.configs.recommended,
...tseslint.configs.recommendedTypeChecked,
...svelte.configs['flat/recommended'],
...svelte.configs['flat/prettier'],
{
files: ['**/*.{js,mjs,cjs,ts,mts,cts}'],
languageOptions: {
globals: sharedGlobals,
parserOptions: {
projectService: true,
},
},
},
{
files: ['**/*.svelte', '**/*.svelte.{js,ts}'],
languageOptions: {
globals: sharedGlobals,
parserOptions: {
extraFileExtensions: ['.svelte'],
parser: tseslint.parser,
projectService: true,
},
},
},
);補足:
.svelteに TypeScript を含む場合、parser: tseslint.parserを明示しないと ESLint が落ちるケースがありましたrecommendedTypeCheckedを使うならprojectService: trueを合わせるのが前提です
元の check は typecheck へ変更し、以下を追加します。
{
"scripts": {
"dev": "wxt",
"dev:firefox": "wxt -b firefox",
"build": "wxt build",
"build:firefox": "wxt build -b firefox",
"zip": "wxt zip",
"zip:firefox": "wxt zip -b firefox",
"format": "prettier . --write",
"format:check": "prettier . --check",
"lint": "eslint .",
"lint:fix": "eslint . --fix",
"typecheck": "svelte-check --tsconfig ./tsconfig.json",
"test": "vitest run",
"verify": "pnpm format:check && pnpm lint && pnpm typecheck && pnpm test",
"fix": "pnpm format && pnpm lint:fix && pnpm typecheck && pnpm test",
"postinstall": "wxt prepare"
}
}使い分け:
pnpm format: format 実行pnpm format:check: format 差分の有無だけ確認pnpm lint: lint 確認pnpm lint:fix: 自動修正つき lintpnpm typecheck: Svelte / TypeScript の型確認pnpm test: テスト実行pnpm verify: CI 的な一括確認pnpm fix: 手元でまとめて整える
最初は疎通確認だけのテストを 1 本置きます。
tests/smoke.test.ts:
import { describe, expect, it } from 'vitest';
describe('smoke', () => {
it('runs the test suite', () => {
expect(true).toBe(true);
});
});目的:
vitest自体が動くことを先に確認する- 本体ロジック未実装でも
testコマンドを成立させる
保存時に format と ESLint fix をかけます。
.vscode/settings.json:
{
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit"
},
"eslint.validate": ["javascript", "typescript", "svelte"],
"[javascript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[json]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[markdown]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[svelte]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
"[typescript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
}
}推奨拡張:
.vscode/extensions.json
{
"recommendations": ["svelte.svelte-vscode", "dbaeumer.vscode-eslint", "esbenp.prettier-vscode"]
}.vscode/settings.json を Git 管理するために .gitignore も以下のようにします。
.vscode/*
!.vscode/extensions.json
!.vscode/settings.json以下を実行して、format / lint / typecheck / test が通ることを確認します。
pnpm verify期待値:
format:checkが通るlintが通るsvelte-checkが 0 errors / 0 warningsvitestの smoke test が通る
この時点では WXT のスターター popup が表示できれば OK です。
pnpm devその後 Chrome で以下を実施します。
chrome://extensionsを開く- 右上のデベロッパーモードをオン
- 「パッケージ化されていない拡張機能を読み込む」を選ぶ
.output/chrome-mv3を指定する
この時点では WXT + Svelte のスターター UI が見えれば正常です。 まだアプリ固有の処理は未実装で問題ありません。
mise.tomlpackage.jsonpnpm-lock.yaml.prettierrc.json.prettierignoreeslint.config.js.vscode/extensions.json.vscode/settings.jsontests/smoke.test.tswxt.config.tssrc/entrypoints/popup/*
このベースラインの次にやると自然なのは以下です。
- スターター UI の撤去
- popup を実アプリ向けの骨組みに変更
- ファイル読み込みやアプリ固有ロジックの追加
- ドメインロジックのテスト追加
- build / zip / CI の整備