diff --git a/CHANGES.md b/CHANGES.md index d86cad0c8..9dad6ef81 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -329,10 +329,14 @@ To be released. ### @fedify/init + - Supported [SvelteKit] as a web framework option in `fedify init` [[#892]] + - Fixed `fedify init`'s hydration test validation to run `format` before `format:check`, which previously caused the entire test suite to fail when the package manager is `npm` or `pnpm`: [[#950]] [[#952] by Jang Hanarae] +[SvelteKit]: https://kit.svelte.dev/ +[#892]: https://github.com/fedify-dev/fedify/issues/892 [#950]: https://github.com/fedify-dev/fedify/issues/950 [#952]: https://github.com/fedify-dev/fedify/pull/952 @@ -5930,7 +5934,6 @@ Released on November 30, 2024. - Let the `fedify lookup` command take multiple arguments. [[#173], [#186] by PGD] -[SvelteKit]: https://kit.svelte.dev/ [#162]: https://github.com/fedify-dev/fedify/issues/162 [#170]: https://github.com/fedify-dev/fedify/issues/170 [#171]: https://github.com/fedify-dev/fedify/issues/171 diff --git a/docs/tutorial/microblog.md b/docs/tutorial/microblog.md index ff1d72e43..616dc8576 100644 --- a/docs/tutorial/microblog.md +++ b/docs/tutorial/microblog.md @@ -169,6 +169,7 @@ Select *Hono*, *npm*, *in-process*, and *in-memory* in order: Express Nuxt SolidStart + SvelteKit ? Choose the package manager to use diff --git a/packages/init/README.md b/packages/init/README.md index 82d8046c8..beb361081 100644 --- a/packages/init/README.md +++ b/packages/init/README.md @@ -26,7 +26,7 @@ Supported options The initializer supports the following project configurations: - **Web frameworks**: Bare-bones, [Astro], [Elysia], [Express], [Hono], - [Next.js], [Nitro], [Nuxt], [SolidStart] + [Next.js], [Nitro], [Nuxt], [SolidStart], [SvelteKit] - **Package managers**: Deno, pnpm, Bun, Yarn, npm - **Key-value stores**: In-Memory, Deno KV, Redis, PostgreSQL - **Message queues**: In-Process, Deno KV, Redis, PostgreSQL, AMQP @@ -39,6 +39,7 @@ The initializer supports the following project configurations: [Nitro]: https://nitro.build/ [Nuxt]: https://nuxt.com/ [SolidStart]: https://start.solidjs.com/ +[SvelteKit]: https://svelte.dev/ Installation diff --git a/packages/init/src/const.ts b/packages/init/src/const.ts index b4120a80d..af5cc2e71 100644 --- a/packages/init/src/const.ts +++ b/packages/init/src/const.ts @@ -15,6 +15,7 @@ export const WEB_FRAMEWORK = [ "express", "nuxt", "solidstart", + "sveltekit", ] as const; /** All supported message queue backend identifiers. */ export const MESSAGE_QUEUE = Object.keys(mq) as readonly (keyof typeof mq)[]; diff --git a/packages/init/src/templates/sveltekit/hooks.server.ts.tpl b/packages/init/src/templates/sveltekit/hooks.server.ts.tpl new file mode 100644 index 000000000..47a60734e --- /dev/null +++ b/packages/init/src/templates/sveltekit/hooks.server.ts.tpl @@ -0,0 +1,7 @@ +import { fedifyHook } from "@fedify/sveltekit"; +import { sequence } from "@sveltejs/kit/hooks"; +import federation from "$lib/federation"; + +export const handle = sequence( + fedifyHook(federation), +); diff --git a/packages/init/src/test/action.ts b/packages/init/src/test/action.ts index 8b64f7d1f..555dd6d17 100644 --- a/packages/init/src/test/action.ts +++ b/packages/init/src/test/action.ts @@ -1,6 +1,6 @@ import { pipe, tap, when } from "@fxts/core"; -import { set } from "../utils.ts"; import type { TestInitCommand } from "../command.ts"; +import { set } from "../utils.ts"; import { checkRequiredDbs } from "./db.ts"; import { fillEmptyOptions } from "./fill.ts"; import runTests from "./run.ts"; diff --git a/packages/init/src/test/lookup.ts b/packages/init/src/test/lookup.ts index e8ea62acb..a86be4d69 100644 --- a/packages/init/src/test/lookup.ts +++ b/packages/init/src/test/lookup.ts @@ -32,6 +32,7 @@ const BANNED_LOOKUP_REASONS: Record = { "solidstart,deno,*,*": "Error occurred while loading submodules in Deno", "astro,deno,*,*": "Astro doesn't support remote packages in Deno", "nuxt,deno,*,*": "Nuxt doesn't support remote packages in Deno", + "sveltekit,deno,*,*": "SvelteKit doesn't support remote packages in Deno", }; const BANNED_LOOKUP_CASES: LookupCasePattern[] = Object.keys( BANNED_LOOKUP_REASONS, diff --git a/packages/init/src/test/port.ts b/packages/init/src/test/port.ts index a4bde934e..f82f5fb9d 100644 --- a/packages/init/src/test/port.ts +++ b/packages/init/src/test/port.ts @@ -132,9 +132,12 @@ export async function replacePortInApp( return; } - if (wf === "astro") { - // Insert server.port into the Astro config - const configPath = join(dir, "astro.config.ts"); + if (wf === "astro" || wf === "sveltekit") { + // Insert server.port into the Astro or Vite config + const configPath = join( + dir, + wf === "astro" ? "astro.config.ts" : "vite.config.ts", + ); const content = await readFile(configPath, "utf8"); await writeFile( configPath, diff --git a/packages/init/src/types.ts b/packages/init/src/types.ts index 33406f9dd..b750bd76a 100644 --- a/packages/init/src/types.ts +++ b/packages/init/src/types.ts @@ -11,13 +11,13 @@ import type { RequiredNotNull } from "./utils.ts"; /** Supported package manager identifiers: `"deno"`, `"pnpm"`, `"bun"`, `"yarn"`, `"npm"`. */ export type PackageManager = typeof PACKAGE_MANAGER[number]; -/** Supported web framework identifiers: `"hono"`, `"nitro"`, `"next"`, `"elysia"`, `"astro"`, `"express"`. */ +/** Supported web framework identifiers: `"bare-bones"`, `"hono"`, `"nitro"`, `"next"`, `"elysia"`, `"astro"`, `"express"`, `"nuxt"`, `"solidstart"`, `"sveltekit"`. */ export type WebFramework = typeof WEB_FRAMEWORK[number]; -/** Supported message queue identifiers: `"denokv"`, `"redis"`, `"postgres"`, `"amqp"`. */ +/** Supported message queue identifiers: `"in-process"`, `"redis"`, `"postgres"`, `"mysql"`, `"amqp"`, `"denokv"`. */ export type MessageQueue = typeof MESSAGE_QUEUE[number]; -/** Supported key-value store identifiers: `"denokv"`, `"redis"`, `"postgres"`. */ +/** Supported key-value store identifiers: `"in-memory"`, `"redis"`, `"postgres"`, `"mysql"`, `"denokv"`. */ export type KvStore = typeof KV_STORE[number]; /** A mapping from each {@link MessageQueue} identifier to its description. */ diff --git a/packages/init/src/webframeworks/mod.ts b/packages/init/src/webframeworks/mod.ts index eccde686c..086b1df31 100644 --- a/packages/init/src/webframeworks/mod.ts +++ b/packages/init/src/webframeworks/mod.ts @@ -8,6 +8,7 @@ import next from "./next.ts"; import nitro from "./nitro.ts"; import nuxt from "./nuxt.ts"; import solidstart from "./solidstart.ts"; +import sveltekit from "./sveltekit.ts"; /** * Registry of all supported web framework configurations. @@ -26,6 +27,7 @@ const webFrameworks: WebFrameworks = { nitro, nuxt, solidstart, + sveltekit, } as const; export default webFrameworks; diff --git a/packages/init/src/webframeworks/sveltekit.ts b/packages/init/src/webframeworks/sveltekit.ts new file mode 100644 index 000000000..dc88d52e6 --- /dev/null +++ b/packages/init/src/webframeworks/sveltekit.ts @@ -0,0 +1,63 @@ +import { PACKAGE_MANAGER } from "../const.ts"; +import deps from "../json/deps.json" with { type: "json" }; +import { PACKAGE_VERSION, readTemplate } from "../lib.ts"; +import type { PackageManager, WebFrameworkDescription } from "../types.ts"; +import { defaultDenoDependencies, defaultDevDependencies } from "./const.ts"; +import { getInstruction, getNodeBunDevToolTasks } from "./utils.ts"; + +const sveltekitDescription: WebFrameworkDescription = { + label: "SvelteKit", + packageManagers: PACKAGE_MANAGER, + defaultPort: 5173, + init: async ({ packageManager: pm, testMode }) => ({ + command: Array.from(getInitCommand(pm)), + dependencies: { + "@fedify/sveltekit": PACKAGE_VERSION, + ...(pm === "deno" ? defaultDenoDependencies : {}), + }, + devDependencies: { + ...defaultDevDependencies, + "typescript": deps["npm:typescript"], + "@types/node": deps["npm:@types/node@25"], + }, + federationFile: "src/lib/federation.ts", + loggingFile: "src/lib/logging.ts", + env: testMode ? { HOST: "127.0.0.1" } : {} as Record, + files: { + "src/hooks.server.ts": await readTemplate("sveltekit/hooks.server.ts"), + }, + tasks: getNodeBunDevToolTasks(pm), + instruction: getInstruction(pm, 5173), + }), +}; + +export default sveltekitDescription; + +/** + * Returns the shell command array to scaffold a new SvelteKit project + * in the current directory using the given package manager. + */ +function* getInitCommand(pm: PackageManager) { + yield* getSvelteKitInitCommand(pm); + yield* [ + ".", + "--template", + "minimal", + "--types", + "ts", + "--no-add-ons", + "--no-dir-check", + "--no-download-check", + "--install", + pm, + ]; +} + +const getSvelteKitInitCommand = (pm: PackageManager): string[] => + pm === "bun" + ? ["bunx", "sv", "create"] + : pm === "deno" + ? ["deno", "run", "-A", "npm:sv", "create"] + : pm === "npm" + ? ["npx", "sv", "create"] + : [pm, "dlx", "sv", "create"];