diff --git a/AGENTS.md b/AGENTS.md
index 7e65a9c0..181203ea 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -46,7 +46,9 @@ console output.
## `src/adapters/`
Framework-specific integrations. One file per framework, with a sibling
-`*.templates.ts` file for generated file content.
+`*.templates.ts` file for generated file content. When an older framework major
+needs different generated code, it gets its own adapter that extends the current
+one, such as `sveltekit2.ts`. Delete it when support for that major ends.
## `src/subprocesses/`
diff --git a/evals/set-up-previews.eval.ts b/evals/set-up-previews.eval.ts
index c004f4c0..6fd43151 100644
--- a/evals/set-up-previews.eval.ts
+++ b/evals/set-up-previews.eval.ts
@@ -37,7 +37,7 @@ it.for(trials)(
await mkdir(new URL("src/routes/", project), { recursive: true });
await writeFile(
new URL("src/routes/+layout.svelte", project),
- "\n\n" +
'\n\t\n\n\n' +
"
KEEP-ME
\n{@render children()}\n",
diff --git a/src/adapters/index.ts b/src/adapters/index.ts
index 2a38dae2..31b938ee 100644
--- a/src/adapters/index.ts
+++ b/src/adapters/index.ts
@@ -18,7 +18,7 @@ import {
writeFileRecursive,
} from "../lib/file";
import { stringify } from "../lib/json";
-import { readPackageJson } from "../lib/packageJson";
+import { getInstalledMajor, readPackageJson } from "../lib/packageJson";
import {
addPreview,
getPreviews,
@@ -63,6 +63,10 @@ export async function getAdapter(): Promise {
return new NuxtAdapter();
}
if ("@sveltejs/kit" in allDependencies) {
+ if ((await getInstalledMajor("@sveltejs/kit")) < 3) {
+ const { SvelteKit2Adapter } = await import("./sveltekit2");
+ return new SvelteKit2Adapter();
+ }
const { SvelteKitAdapter } = await import("./sveltekit");
return new SvelteKitAdapter();
}
diff --git a/src/adapters/sveltekit.templates.ts b/src/adapters/sveltekit.templates.ts
index 77cc8493..c0849ad8 100644
--- a/src/adapters/sveltekit.templates.ts
+++ b/src/adapters/sveltekit.templates.ts
@@ -8,14 +8,14 @@ export function prismicIOFileTemplate({ typescript }: { typescript: boolean }):
return dedent`
import { createClient as baseCreateClient } from "@prismicio/client";
import { type CreateClientConfig, enableAutoPreviews } from '@prismicio/svelte/kit';
- import { env } from '$env/dynamic/public';
+ import { PUBLIC_PRISMIC_ENVIRONMENT } from '$app/env/public';
import prismicConfig from "../../prismic.config.json";
/**
* The project's Prismic repository name.
*/
export const repositoryName =
- env.PUBLIC_PRISMIC_ENVIRONMENT || prismicConfig.repositoryName;
+ PUBLIC_PRISMIC_ENVIRONMENT || prismicConfig.repositoryName;
/**
* Creates a Prismic client for the project's repository. The client is used to
@@ -39,14 +39,14 @@ export function prismicIOFileTemplate({ typescript }: { typescript: boolean }):
return dedent`
import { createClient as baseCreateClient } from "@prismicio/client";
import { enableAutoPreviews } from '@prismicio/svelte/kit';
- import { env } from '$env/dynamic/public';
+ import { PUBLIC_PRISMIC_ENVIRONMENT } from '$app/env/public';
import prismicConfig from "../../prismic.config.json";
/**
* The project's Prismic repository name.
*/
export const repositoryName =
- env.PUBLIC_PRISMIC_ENVIRONMENT || prismicConfig.repositoryName;
+ PUBLIC_PRISMIC_ENVIRONMENT || prismicConfig.repositoryName;
/**
* Creates a Prismic client for the project's repository. The client is used to
@@ -67,15 +67,37 @@ export function prismicIOFileTemplate({ typescript }: { typescript: boolean }):
`;
}
-export function sliceSimulatorPageTemplate(): string {
+export function envVarTemplate(): string {
+ return dedent`
+ PUBLIC_PRISMIC_ENVIRONMENT: {
+ public: true,
+ schema: (value) => value,
+ description: "The Prismic environment to use instead of the production repository.",
+ },
+ `;
+}
+
+export function envFileTemplate(): string {
+ return dedent`
+ import { defineEnvVars } from "@sveltejs/kit/env";
+
+ export const variables = defineEnvVars({
+ ${envVarTemplate()}
+ });
+ `;
+}
+
+export function sliceSimulatorPageTemplate({ extension }: { extension: string }): string {
return dedent`
-
-
+
+ {#snippet children({ slices })}
+
+ {/snippet}
`;
}
@@ -84,7 +106,7 @@ export function previewAPIRouteTemplate({ typescript }: { typescript: boolean })
if (typescript) {
return dedent`
import { redirectToPreviewURL } from '@prismicio/svelte/kit';
- import { createClient } from '$lib/prismicio';
+ import { createClient } from '#lib/prismicio.ts';
import type { RequestHandler } from "./$types";
export const GET: RequestHandler = async ({ fetch, request, cookies }) => {
@@ -97,7 +119,7 @@ export function previewAPIRouteTemplate({ typescript }: { typescript: boolean })
return dedent`
import { redirectToPreviewURL } from '@prismicio/svelte/kit';
- import { createClient } from '$lib/prismicio';
+ import { createClient } from '#lib/prismicio.js';
/* @type {import("./$types").RequestHandler} */
export async function GET({ fetch, request, cookies }) {
@@ -108,9 +130,9 @@ export function previewAPIRouteTemplate({ typescript }: { typescript: boolean })
`;
}
-export function layoutServerTemplate(): string {
+export function layoutServerTemplate({ extension }: { extension: string }): string {
return dedent`
- import { repositoryName } from "$lib/prismicio";
+ import { repositoryName } from "#lib/prismicio.${extension}";
export const prerender = "auto";
@@ -151,7 +173,7 @@ export function pageTemplate({ typescript }: { typescript: boolean }): string {
return dedent`
@@ -184,7 +206,7 @@ export function pageServerTemplate({
if (typescript) {
return dedent`
import type { PageServerLoad } from "./$types";
- import { createClient } from "$lib/prismicio";
+ import { createClient } from "#lib/prismicio.ts";
export const load: PageServerLoad = async ({ params, fetch, cookies }) => {
const client = createClient({ fetch, cookies });
@@ -196,7 +218,7 @@ export function pageServerTemplate({
}
return dedent`
- import { createClient } from "$lib/prismicio";
+ import { createClient } from "#lib/prismicio.js";
/** @type {import("./$types").PageServerLoad} */
export async function load({ params, fetch, cookies }) {
@@ -211,7 +233,7 @@ export function pageServerTemplate({
if (typescript) {
return dedent`
import type { PageServerLoad } from "./$types";
- import { createClient } from "$lib/prismicio";
+ import { createClient } from "#lib/prismicio.ts";
export const load: PageServerLoad = async ({ fetch, cookies }) => {
const client = createClient({ fetch, cookies });
@@ -223,7 +245,7 @@ export function pageServerTemplate({
}
return dedent`
- import { createClient } from "$lib/prismicio";
+ import { createClient } from "#lib/prismicio.js";
/* @type {import("./$types").PageServerLoad} */
export async function load({ fetch, cookies }) {
diff --git a/src/adapters/sveltekit.ts b/src/adapters/sveltekit.ts
index d05f3dc5..d18ee556 100644
--- a/src/adapters/sveltekit.ts
+++ b/src/adapters/sveltekit.ts
@@ -17,6 +17,8 @@ import { addDependencies, getNpmPackageVersion } from "../lib/packageJson";
import { dedent, formatObjectKey } from "../lib/string";
import { checkIsTypeScriptProject, findProjectRoot } from "../project";
import {
+ envFileTemplate,
+ envVarTemplate,
layoutServerTemplate,
pageServerTemplate,
pageTemplate,
@@ -58,9 +60,12 @@ export class SvelteKitAdapter extends Adapter {
new URL(`src/lib/prismicio.${extension}`, projectRoot),
prismicIOFileTemplate({ typescript }),
);
+ if (!(await findSourceFile("src/env"))) {
+ await writeFileRecursive(new URL(`src/env.${extension}`, projectRoot), envFileTemplate());
+ }
await writeFileIfMissing(
new URL("src/routes/slice-simulator/+page.svelte", projectRoot),
- sliceSimulatorPageTemplate(),
+ sliceSimulatorPageTemplate({ extension }),
);
await writeFileIfMissing(
new URL(`src/params/preview.${extension}`, projectRoot),
@@ -87,11 +92,11 @@ export class SvelteKitAdapter extends Adapter {
See for more information.
`,
);
- const serverLayout = await findServerLayout();
+ const serverLayout = await findSourceFile("src/routes/+layout.server");
if (!serverLayout) {
await writeFileRecursive(
new URL(`src/routes/+layout.server.${extension}`, projectRoot),
- layoutServerTemplate(),
+ layoutServerTemplate({ extension }),
);
}
// The generated layout reads repositoryName from the server layout. When an existing
@@ -124,7 +129,29 @@ export class SvelteKitAdapter extends Adapter {
from it first.
`;
- return [await this.getPreviewStep(), homePageStep].filter(Boolean).join("\n\n") || undefined;
+ return (
+ [await this.getEnvStep(), await this.getPreviewStep(), homePageStep]
+ .filter(Boolean)
+ .join("\n\n") || undefined
+ );
+ }
+
+ // The generated Prismic client imports PUBLIC_PRISMIC_ENVIRONMENT, which SvelteKit only
+ // provides when the project's env file declares it.
+ private async getEnvStep(): Promise {
+ const envFile = await findSourceFile("src/env");
+ if (!envFile) return;
+ const contents = await readFile(new URL(envFile, await findProjectRoot()), "utf8");
+ if (contents.includes("PUBLIC_PRISMIC_ENVIRONMENT")) return;
+
+ return dedent`
+ Action required: add PUBLIC_PRISMIC_ENVIRONMENT to ${envFile}.
+
+ Your project does not build until you do this. Add these lines to
+ defineEnvVars({ ... }):
+
+ ${envVarTemplate().replace(/^/gm, " ")}
+ `;
}
private async getPreviewStep(): Promise {
@@ -132,14 +159,15 @@ export class SvelteKitAdapter extends Adapter {
// The layout reads repositoryName from the server layout's data.
const serverLayoutPath =
- (await findServerLayout()) ?? `src/routes/+layout.server.${await getJsFileExtension()}`;
+ (await findSourceFile("src/routes/+layout.server")) ??
+ `src/routes/+layout.server.${await getJsFileExtension()}`;
const serverLayout = await readFile(
new URL(serverLayoutPath, await findProjectRoot()),
"utf8",
).catch(() => "");
const serverLayoutStep =
!serverLayout.includes("repositoryName") &&
- `Return repositoryName from load in ${serverLayoutPath}, creating the file if needed:\n\n${layoutServerTemplate().replace(/^/gm, " ")}`;
+ `Return repositoryName from load in ${serverLayoutPath}, creating the file if needed:\n\n${layoutServerTemplate({ extension: serverLayoutPath.split(".").pop()! }).replace(/^/gm, " ")}`;
return [
dedent`
@@ -219,7 +247,7 @@ export class SvelteKitAdapter extends Adapter {
}
}
-async function deleteStarterHomePage(): Promise {
+export async function deleteStarterHomePage(): Promise {
const path = new URL("src/routes/+page.svelte", await findProjectRoot());
const contents = await readFile(path, "utf8").catch(() => undefined);
if (!STARTER_HOME_PAGES.includes(contents?.replace(/\s/g, "") ?? "")) return;
@@ -227,9 +255,9 @@ async function deleteStarterHomePage(): Promise {
await rm(path);
}
-async function findServerLayout(): Promise {
+export async function findSourceFile(path: string): Promise {
const projectRoot = await findProjectRoot();
- for (const path of ["src/routes/+layout.server.js", "src/routes/+layout.server.ts"]) {
- if (await exists(new URL(path, projectRoot))) return path;
+ for (const extension of ["js", "ts"]) {
+ if (await exists(new URL(`${path}.${extension}`, projectRoot))) return `${path}.${extension}`;
}
}
diff --git a/src/adapters/sveltekit2.templates.ts b/src/adapters/sveltekit2.templates.ts
new file mode 100644
index 00000000..526f1fe4
--- /dev/null
+++ b/src/adapters/sveltekit2.templates.ts
@@ -0,0 +1,56 @@
+import type { DynamicCustomTypeModel } from "@prismicio/types-internal";
+
+import { dedent } from "../lib/string";
+import * as sveltekit from "./sveltekit.templates";
+
+// SvelteKit 2 has no #lib, so it imports from $lib without file extensions.
+function useLib(code: string): string {
+ return code.replace(/#lib\/(\w+)(?:\/index)?\.\w+/g, "$lib/$1");
+}
+
+// SvelteKit 2 has no $app/env.
+export function prismicIOFileTemplate({ typescript }: { typescript: boolean }): string {
+ return sveltekit
+ .prismicIOFileTemplate({ typescript })
+ .replace(
+ "{ PUBLIC_PRISMIC_ENVIRONMENT } from '$app/env/public'",
+ "{ env } from '$env/dynamic/public'",
+ )
+ .replace("PUBLIC_PRISMIC_ENVIRONMENT ||", "env.PUBLIC_PRISMIC_ENVIRONMENT ||");
+}
+
+// @prismicio/svelte v2 passes slices through a slot.
+export function sliceSimulatorPageTemplate(): string {
+ return dedent`
+
+
+
+
+
+ `;
+}
+
+export function previewAPIRouteTemplate({ typescript }: { typescript: boolean }): string {
+ return useLib(sveltekit.previewAPIRouteTemplate({ typescript }));
+}
+
+export function layoutServerTemplate(): string {
+ return useLib(sveltekit.layoutServerTemplate({ extension: "js" }));
+}
+
+export function pageTemplate({ typescript }: { typescript: boolean }): string {
+ return useLib(sveltekit.pageTemplate({ typescript }));
+}
+
+export function pageServerTemplate({
+ model,
+ typescript,
+}: {
+ model: DynamicCustomTypeModel;
+ typescript: boolean;
+}): string {
+ return useLib(sveltekit.pageServerTemplate({ model, typescript }));
+}
diff --git a/src/adapters/sveltekit2.ts b/src/adapters/sveltekit2.ts
new file mode 100644
index 00000000..4f485b93
--- /dev/null
+++ b/src/adapters/sveltekit2.ts
@@ -0,0 +1,160 @@
+import { readFile } from "node:fs/promises";
+
+import type { DynamicCustomTypeModel } from "@prismicio/types-internal";
+
+import { checkSourceContains, getJsFileExtension, type PageFile, writeFileIfMissing } from ".";
+import { exists, writeFileRecursive } from "../lib/file";
+import { addDependencies, getNpmPackageVersion } from "../lib/packageJson";
+import { dedent } from "../lib/string";
+import { checkIsTypeScriptProject, findProjectRoot } from "../project";
+import { deleteStarterHomePage, findSourceFile, SvelteKitAdapter } from "./sveltekit";
+import { rootLayoutTemplate } from "./sveltekit.templates";
+import {
+ layoutServerTemplate,
+ pageServerTemplate,
+ pageTemplate,
+ previewAPIRouteTemplate,
+ prismicIOFileTemplate,
+ sliceSimulatorPageTemplate,
+} from "./sveltekit2.templates";
+
+// SvelteKit 2 projects use @prismicio/svelte v2. Delete this file and sveltekit2.templates.ts
+// when SvelteKit 2 support ends.
+export class SvelteKit2Adapter extends SvelteKitAdapter {
+ async setupProject(): Promise {
+ await addDependencies({
+ "@prismicio/client": `^${await getNpmPackageVersion("@prismicio/client")}`,
+ "@prismicio/svelte": "^2",
+ });
+
+ const projectRoot = await findProjectRoot();
+ const extension = await getJsFileExtension();
+ const typescript = await checkIsTypeScriptProject();
+
+ await writeFileIfMissing(
+ new URL(`src/lib/prismicio.${extension}`, projectRoot),
+ prismicIOFileTemplate({ typescript }),
+ );
+ await writeFileIfMissing(
+ new URL("src/routes/slice-simulator/+page.svelte", projectRoot),
+ sliceSimulatorPageTemplate(),
+ );
+ await writeFileIfMissing(
+ new URL(`src/params/preview.${extension}`, projectRoot),
+ dedent`
+ export function match(param) {
+ return param === 'preview';
+ }
+ `,
+ );
+ await writeFileIfMissing(
+ new URL(`src/routes/api/preview/+server.${extension}`, projectRoot),
+ previewAPIRouteTemplate({ typescript }),
+ );
+ await writeFileIfMissing(
+ new URL("src/routes/[[preview=preview]]/README.md", projectRoot),
+ dedent`
+ This directory adds support for optional \`/preview\` routes. Do not remove this directory.
+
+ All routes within this directory will be served using the following URLs:
+
+ - \`/example-route\` (prerendered)
+ - \`/preview/example-route\` (server-rendered)
+
+ See for more information.
+ `,
+ );
+ const serverLayout = await findSourceFile("src/routes/+layout.server");
+ if (!serverLayout) {
+ await writeFileRecursive(
+ new URL(`src/routes/+layout.server.${extension}`, projectRoot),
+ layoutServerTemplate(),
+ );
+ }
+ // The generated layout reads repositoryName from the server layout. When an existing
+ // server layout does not return it, the setup instructions cover both files instead.
+ const returnsRepositoryName =
+ !serverLayout ||
+ (await readFile(new URL(serverLayout, projectRoot), "utf8")).includes("repositoryName");
+ if (returnsRepositoryName) {
+ await writeFileIfMissing(
+ new URL("src/routes/+layout.svelte", projectRoot),
+ rootLayoutTemplate(),
+ );
+ }
+ await deleteStarterHomePage();
+ }
+
+ async getSetupInstructions(): Promise {
+ const projectRoot = await findProjectRoot();
+
+ // The layout reads repositoryName from the server layout's data.
+ const serverLayoutPath =
+ (await findSourceFile("src/routes/+layout.server")) ??
+ `src/routes/+layout.server.${await getJsFileExtension()}`;
+ const serverLayout = await readFile(new URL(serverLayoutPath, projectRoot), "utf8").catch(
+ () => "",
+ );
+ const previewStep =
+ !(await checkSourceContains("PrismicPreview")) &&
+ [
+ dedent`
+ Action required: add to your root layout.
+
+ Previews do not work until you do this, and the CLI cannot edit your
+ layout for you. Make the change now.
+
+ Change the lines marked - and + in src/routes/+layout.svelte:
+
+
+
+ {@render children()}
+ +
+ `,
+ !serverLayout.includes("repositoryName") &&
+ `Return repositoryName from load in ${serverLayoutPath}, creating the file if needed:\n\n${layoutServerTemplate().replace(/^/gm, " ")}`,
+ "Run `prismic docs view sveltekit` for details.",
+ ]
+ .filter(Boolean)
+ .join("\n\n");
+
+ // The Prismic home page lives in [[preview=preview]], so this page also serves / and wins.
+ const hidesHomePage =
+ (await exists(new URL("src/routes/+page.svelte", projectRoot))) &&
+ (await exists(new URL("src/routes/[[preview=preview]]/+page.svelte", projectRoot)));
+ const homePageStep =
+ hidesHomePage &&
+ dedent`
+ Action required: delete src/routes/+page.svelte.
+
+ It also serves / and hides your Prismic home page in
+ src/routes/[[preview=preview]]/+page.svelte. Move anything you need
+ from it first.
+ `;
+
+ return [previewStep, homePageStep].filter(Boolean).join("\n\n") || undefined;
+ }
+
+ protected async getPageFiles(
+ model: DynamicCustomTypeModel,
+ routePath: string,
+ ): Promise {
+ const routeDirectory = new URL(
+ `src/routes/[[preview=preview]]/${routePath}/`,
+ await findProjectRoot(),
+ );
+ const typescript = await checkIsTypeScriptProject();
+ return [
+ { path: new URL("+page.svelte", routeDirectory), contents: pageTemplate({ typescript }) },
+ {
+ path: new URL(`+page.server.${await getJsFileExtension()}`, routeDirectory),
+ contents: pageServerTemplate({ model, typescript }),
+ },
+ ];
+ }
+}
diff --git a/test/env-set.test.ts b/test/env-set.test.ts
index e80f0cf5..82307411 100644
--- a/test/env-set.test.ts
+++ b/test/env-set.test.ts
@@ -1,6 +1,6 @@
-import { readFile, writeFile } from "node:fs/promises";
+import { mkdir, readFile, writeFile } from "node:fs/promises";
-import { it } from "./it";
+import { it, useSvelteKit } from "./it";
it("supports --help", async ({ expect, prismic }) => {
const { stdout, exitCode } = await prismic("env", ["set", "--help"]);
@@ -30,6 +30,21 @@ it("clears the active environment when setting to production", async ({
expect(after).not.toContain("my-stage-env");
});
+it("asks for the Prismic environment variable in a SvelteKit env file", async ({
+ expect,
+ prismic,
+ project,
+ repo,
+}) => {
+ await useSvelteKit(project);
+ await mkdir(new URL("src/", project), { recursive: true });
+ await writeFile(new URL("src/env.ts", project), "export const variables = {};\n");
+
+ const { stdout, exitCode } = await prismic("env", ["set", repo]);
+ expect(exitCode).toBe(0);
+ expect(stdout).toContain("Action required: add PUBLIC_PRISMIC_ENVIRONMENT to src/env.ts.");
+});
+
it("prints setup instructions", async ({ expect, prismic, repo }) => {
const { stdout, exitCode } = await prismic("env", ["set", repo]);
expect(exitCode).toBe(0);
diff --git a/test/gen-page.test.ts b/test/gen-page.test.ts
index 14dbb262..9d0adfc3 100644
--- a/test/gen-page.test.ts
+++ b/test/gen-page.test.ts
@@ -1,7 +1,7 @@
import { mkdir, writeFile } from "node:fs/promises";
import { sep } from "node:path";
-import { buildCustomType, it, writeLocalCustomType } from "./it";
+import { buildCustomType, it, useSvelteKit, writeLocalCustomType } from "./it";
it("supports --help", async ({ expect, prismic }) => {
const { stdout, stderr, exitCode } = await prismic("gen", ["page", "--help"]);
@@ -22,6 +22,32 @@ it("writes a missing page", async ({ expect, project, prismic }) => {
});
});
+it("writes SvelteKit 3 pages that import from #lib", async ({ expect, project, prismic }) => {
+ await useSvelteKit(project);
+ const customType = buildCustomType({ format: "page", repeatable: false });
+ await writeLocalCustomType(project, customType);
+
+ const { stderr, exitCode } = await prismic("gen", ["page", customType.id]);
+ expect(exitCode, stderr).toBe(0);
+ await expect(project).toHaveFile(
+ `src/routes/[[preview=preview]]/${customType.id.toLowerCase()}/+page.server.js`,
+ { contains: 'import { createClient } from "#lib/prismicio.js";' },
+ );
+});
+
+it("writes SvelteKit 2 pages that import from $lib", async ({ expect, project, prismic }) => {
+ await useSvelteKit(project, "^2.27.0");
+ const customType = buildCustomType({ format: "page", repeatable: false });
+ await writeLocalCustomType(project, customType);
+
+ const { stderr, exitCode } = await prismic("gen", ["page", customType.id]);
+ expect(exitCode, stderr).toBe(0);
+ await expect(project).toHaveFile(
+ `src/routes/[[preview=preview]]/${customType.id.toLowerCase()}/+page.server.js`,
+ { contains: 'import { createClient } from "$lib/prismicio";' },
+ );
+});
+
it("prints the code for an existing page", async ({ expect, project, prismic }) => {
const customType = buildCustomType({ format: "page", repeatable: false });
await writeLocalCustomType(project, customType);
diff --git a/test/gen-setup.test.ts b/test/gen-setup.test.ts
index 6962757f..3fb50ac6 100644
--- a/test/gen-setup.test.ts
+++ b/test/gen-setup.test.ts
@@ -36,23 +36,6 @@ it("skips existing files", { timeout: 30_000 }, async ({ expect, project, prismi
await expect(project).toHaveFile("prismicio.js", { contains: "// custom client file" });
});
-it(
- "generates valid script tags for SvelteKit",
- { timeout: 30_000 },
- async ({ expect, project, prismic }) => {
- // A SvelteKit project generates a file with a ", not the bundler-escaped "<\/script>".
- await expect(project).toHaveFile("src/routes/slice-simulator/+page.svelte", {
- contains: "",
- });
- },
-);
-
it("skips installation with --no-install", async ({ expect, project, prismic }) => {
const { stderr, exitCode, stdout } = await prismic("gen", ["setup", "--no-install"]);
expect(exitCode, stderr).toBe(0);
@@ -166,7 +149,104 @@ it(
const layout = await readFile(new URL("src/routes/+layout.svelte", project), "utf8");
expect(layout).toContain("const { data, children } = $props();");
expect(layout).toContain("");
- expect(layout).not.toContain("$lib/prismicio");
+ expect(layout).not.toContain("#lib/prismicio");
+ },
+);
+
+it(
+ "generates a slice simulator page with a snippet",
+ { timeout: 30_000 },
+ async ({ expect, project, prismic }) => {
+ await useSvelteKit(project);
+
+ const { stderr, exitCode } = await prismic("gen", ["setup", "--no-install"]);
+ expect(exitCode, stderr).toBe(0);
+ const page = await readFile(
+ new URL("src/routes/slice-simulator/+page.svelte", project),
+ "utf8",
+ );
+ // The closing tag must be "", not the bundler-escaped "<\/script>".
+ expect(page).toContain("");
+ expect(page).toContain("import { components } from '#lib/slices/index.js';");
+ expect(page).toContain("{#snippet children({ slices })}");
+ expect(page).not.toContain("let:slices");
+ },
+);
+
+it(
+ "declares the Prismic environment variable in a new SvelteKit env file",
+ { timeout: 30_000 },
+ async ({ expect, project, prismic }) => {
+ await useSvelteKit(project);
+
+ const { stdout, stderr, exitCode } = await prismic("gen", ["setup", "--no-install"]);
+ expect(exitCode, stderr).toBe(0);
+ const env = await readFile(new URL("src/env.js", project), "utf8");
+ expect(env).toContain("PUBLIC_PRISMIC_ENVIRONMENT: {");
+ expect(env).toContain("public: true,");
+ const client = await readFile(new URL("src/lib/prismicio.js", project), "utf8");
+ expect(client).toContain("import { PUBLIC_PRISMIC_ENVIRONMENT } from '$app/env/public';");
+ expect(stdout).not.toContain("PUBLIC_PRISMIC_ENVIRONMENT");
+ },
+);
+
+it(
+ "asks for the Prismic environment variable in an existing SvelteKit env file",
+ { timeout: 30_000 },
+ async ({ expect, project, prismic }) => {
+ await useSvelteKit(project);
+ const env =
+ 'import { defineEnvVars } from "@sveltejs/kit/env";\n' +
+ "export const variables = defineEnvVars({ API_KEY: {} });\n";
+ await mkdir(new URL("src/", project), { recursive: true });
+ await writeFile(new URL("src/env.ts", project), env);
+
+ const { stdout, stderr, exitCode } = await prismic("gen", ["setup", "--no-install"]);
+ expect(exitCode, stderr).toBe(0);
+ expect(await readFile(new URL("src/env.ts", project), "utf8")).toBe(env);
+ await expect(project).not.toHaveFile("src/env.js");
+ expect(stdout).toContain("Action required: add PUBLIC_PRISMIC_ENVIRONMENT to src/env.ts.");
+ expect(stdout).toContain(" PUBLIC_PRISMIC_ENVIRONMENT: {");
+ },
+);
+
+it(
+ "does not ask for the Prismic environment variable when the env file declares it",
+ { timeout: 30_000 },
+ async ({ expect, project, prismic }) => {
+ await useSvelteKit(project);
+ await mkdir(new URL("src/", project), { recursive: true });
+ await writeFile(
+ new URL("src/env.js", project),
+ "export const variables = { PUBLIC_PRISMIC_ENVIRONMENT: { public: true } };\n",
+ );
+
+ const { stdout, stderr, exitCode } = await prismic("gen", ["setup", "--no-install"]);
+ expect(exitCode, stderr).toBe(0);
+ expect(stdout).not.toContain("PUBLIC_PRISMIC_ENVIRONMENT");
+ },
+);
+
+it(
+ "sets up a SvelteKit 2 project with @prismicio/svelte v2",
+ { timeout: 30_000 },
+ async ({ expect, project, prismic }) => {
+ await useSvelteKit(project, "^2.27.0");
+
+ const { stderr, exitCode } = await prismic("gen", ["setup", "--no-install"]);
+ expect(exitCode, stderr).toBe(0);
+ const packageJson = JSON.parse(await readFile(new URL("package.json", project), "utf8"));
+ expect(packageJson.dependencies["@prismicio/svelte"]).toBe("^2");
+ await expect(project).toHaveFile("src/lib/prismicio.js", {
+ contains: "import { env } from '$env/dynamic/public';",
+ });
+ await expect(project).toHaveFile("src/routes/slice-simulator/+page.svelte", {
+ contains: "",
+ });
+ await expect(project).toHaveFile("src/routes/+layout.server.js", {
+ contains: 'import { repositoryName } from "$lib/prismicio";',
+ });
+ await expect(project).not.toHaveFile("src/env.js");
},
);
@@ -179,7 +259,7 @@ it(
const { stderr, exitCode } = await prismic("gen", ["setup", "--no-install"]);
expect(exitCode, stderr).toBe(0);
const serverLayout = await readFile(new URL("src/routes/+layout.server.js", project), "utf8");
- expect(serverLayout).toContain('import { repositoryName } from "$lib/prismicio";');
+ expect(serverLayout).toContain('import { repositoryName } from "#lib/prismicio.js";');
expect(serverLayout).toContain('export const prerender = "auto";');
expect(serverLayout).toContain("return { repositoryName };");
},
@@ -269,7 +349,7 @@ it(
await writeFile(new URL("src/routes/+layout.svelte", project), "{@render children()}");
await writeFile(
new URL("src/routes/+layout.server.js", project),
- 'import { repositoryName } from "$lib/prismicio";\nexport const load = () => ({ repositoryName });',
+ 'import { repositoryName } from "#lib/prismicio.js";\nexport const load = () => ({ repositoryName });',
);
const { stdout, stderr, exitCode } = await prismic("gen", ["setup", "--no-install"]);
@@ -567,3 +647,67 @@ it(
expect(stdout).not.toContain("delete src/routes/+page.svelte");
},
);
+
+// SvelteKit 2 projects use their own adapter, which copies this setup logic.
+
+it(
+ "deletes the SvelteKit starter home page in a SvelteKit 2 project",
+ { timeout: 30_000 },
+ async ({ expect, project, prismic }) => {
+ await useSvelteKit(project, "^2.27.0");
+ await mkdir(new URL("src/routes/", project), { recursive: true });
+ await writeFile(new URL("src/routes/+page.svelte", project), SVELTEKIT_STARTER_HOME_PAGE);
+
+ const { stderr, exitCode } = await prismic("gen", ["setup", "--no-install"]);
+ expect(exitCode, stderr).toBe(0);
+ await expect(project).not.toHaveFile("src/routes/+page.svelte");
+ },
+);
+
+it(
+ "asks to delete a changed home page in a SvelteKit 2 project",
+ { timeout: 30_000 },
+ async ({ expect, project, prismic }) => {
+ await useSvelteKit(project, "^2.27.0");
+ await mkdir(new URL("src/routes/[[preview=preview]]/", project), { recursive: true });
+ await writeFile(new URL("src/routes/+page.svelte", project), "