diff --git a/.changeset/quiet-beds-study.md b/.changeset/quiet-beds-study.md new file mode 100644 index 0000000..49af760 --- /dev/null +++ b/.changeset/quiet-beds-study.md @@ -0,0 +1,5 @@ +--- +"@marko/run": patch +--- + +Fix nested flat routes with layouts being shared diff --git a/packages/run/src/__tests__/fixtures/basic-nested-page/.marko-run/routes.d.ts b/packages/run/src/__tests__/fixtures/basic-nested-page/.marko-run/routes.d.ts new file mode 100644 index 0000000..a8038aa --- /dev/null +++ b/packages/run/src/__tests__/fixtures/basic-nested-page/.marko-run/routes.d.ts @@ -0,0 +1,58 @@ +/* + WARNING: This file is automatically generated and any changes made to it will be overwritten without warning. + Do NOT manually edit this file or your changes will be lost. +*/ + +import { NotHandled, NotMatched, GetPaths, PostPaths, GetablePath, GetableHref, PostablePath, PostableHref, Platform } from "@marko/run/namespace"; +import type * as Run from "@marko/run"; + + +declare module "@marko/run" { + interface AppData extends Run.DefineApp<{ + routes: { + "/foo": Routes["/foo"]; + "/foo/bar": Routes["/foo/bar"]; + } + }> {} +} + +declare module "../src/routes/foo/+page.marko" { + namespace MarkoRun { + export { NotHandled, NotMatched, GetPaths, PostPaths, GetablePath, GetableHref, PostablePath, PostableHref, Platform }; + export type Route = Run.Routes["/foo"]; + export type Context = Run.MultiRouteContext & Marko.Global; + export type Handler = Run.HandlerLike; + /** @deprecated use `((context, next) => { ... }) satisfies MarkoRun.Handler` instead */ + export const route: Run.HandlerTypeFn; + } +} + +declare module "../src/routes/foo/bar+page.marko" { + namespace MarkoRun { + export { NotHandled, NotMatched, GetPaths, PostPaths, GetablePath, GetableHref, PostablePath, PostableHref, Platform }; + export type Route = Run.Routes["/foo/bar"]; + export type Context = Run.MultiRouteContext & Marko.Global; + export type Handler = Run.HandlerLike; + /** @deprecated use `((context, next) => { ... }) satisfies MarkoRun.Handler` instead */ + export const route: Run.HandlerTypeFn; + } +} + +declare module "../src/routes/+layout.marko" { + export interface Input { + renderBody: Marko.Body; + } + namespace MarkoRun { + export { NotHandled, NotMatched, GetPaths, PostPaths, GetablePath, GetableHref, PostablePath, PostableHref, Platform }; + export type Route = Run.Routes["/foo" | "/foo/bar"]; + export type Context = Run.MultiRouteContext & Marko.Global; + export type Handler = Run.HandlerLike; + /** @deprecated use `((context, next) => { ... }) satisfies MarkoRun.Handler` instead */ + export const route: Run.HandlerTypeFn; + } +} + +type Routes = { + "/foo": { verb: "get"; }; + "/foo/bar": { verb: "get"; }; +} diff --git a/packages/run/src/__tests__/fixtures/basic-nested-page/__snapshots__/dev.expected.md b/packages/run/src/__tests__/fixtures/basic-nested-page/__snapshots__/dev.expected.md new file mode 100644 index 0000000..25e33e2 --- /dev/null +++ b/packages/run/src/__tests__/fixtures/basic-nested-page/__snapshots__/dev.expected.md @@ -0,0 +1,6 @@ +# Loading + +```html +/foo/bar page rendered +``` + diff --git a/packages/run/src/__tests__/fixtures/basic-nested-page/__snapshots__/preview.expected.md b/packages/run/src/__tests__/fixtures/basic-nested-page/__snapshots__/preview.expected.md new file mode 100644 index 0000000..25e33e2 --- /dev/null +++ b/packages/run/src/__tests__/fixtures/basic-nested-page/__snapshots__/preview.expected.md @@ -0,0 +1,6 @@ +# Loading + +```html +/foo/bar page rendered +``` + diff --git a/packages/run/src/__tests__/fixtures/basic-nested-page/src/routes/+layout.marko b/packages/run/src/__tests__/fixtures/basic-nested-page/src/routes/+layout.marko new file mode 100644 index 0000000..d55428e --- /dev/null +++ b/packages/run/src/__tests__/fixtures/basic-nested-page/src/routes/+layout.marko @@ -0,0 +1,12 @@ + + + + + @marko/run Test Fixture + + + + <${input.renderBody}/> + + + diff --git a/packages/run/src/__tests__/fixtures/basic-nested-page/src/routes/foo/+page.marko b/packages/run/src/__tests__/fixtures/basic-nested-page/src/routes/foo/+page.marko new file mode 100644 index 0000000..c5f3993 --- /dev/null +++ b/packages/run/src/__tests__/fixtures/basic-nested-page/src/routes/foo/+page.marko @@ -0,0 +1 @@ +-- /foo page rendered diff --git a/packages/run/src/__tests__/fixtures/basic-nested-page/src/routes/foo/bar+page.marko b/packages/run/src/__tests__/fixtures/basic-nested-page/src/routes/foo/bar+page.marko new file mode 100644 index 0000000..1cbaf3f --- /dev/null +++ b/packages/run/src/__tests__/fixtures/basic-nested-page/src/routes/foo/bar+page.marko @@ -0,0 +1 @@ +-- /foo/bar page rendered diff --git a/packages/run/src/__tests__/fixtures/basic-nested-page/test.config.ts b/packages/run/src/__tests__/fixtures/basic-nested-page/test.config.ts new file mode 100644 index 0000000..8871b40 --- /dev/null +++ b/packages/run/src/__tests__/fixtures/basic-nested-page/test.config.ts @@ -0,0 +1 @@ +export const path = '/foo/bar' diff --git a/packages/run/src/__tests__/fixtures/basic-nested-page/tsconfig.json b/packages/run/src/__tests__/fixtures/basic-nested-page/tsconfig.json new file mode 100644 index 0000000..03ff88a --- /dev/null +++ b/packages/run/src/__tests__/fixtures/basic-nested-page/tsconfig.json @@ -0,0 +1,4 @@ +{ + "extends": "../../tsconfig-base.json", + "include": ["src/**/*", ".marko-run/*"], +} \ No newline at end of file diff --git a/packages/run/src/vite/codegen/index.ts b/packages/run/src/vite/codegen/index.ts index 57322ce..88ca921 100644 --- a/packages/run/src/vite/codegen/index.ts +++ b/packages/run/src/vite/codegen/index.ts @@ -153,8 +153,12 @@ export function renderRouteEntry(route: Route, entriesDir: string): string { ); } if (page) { + const pageNameIndex = page.name.indexOf("+page"); + const pageNamePrefix = + pageNameIndex > 0 ? `${page.name.slice(0, pageNameIndex)}.` : ""; + const importPath = route.layouts.length - ? `./${path.posix.join(entriesDir, page.relativePath, "..", "route.marko")}` + ? `./${path.posix.join(entriesDir, page.relativePath, "..", pageNamePrefix + "route.marko")}` : `./${page.importPath}`; imports.writeLines(`import page from '${importPath}${serverEntryQuery}';`); } diff --git a/packages/run/src/vite/plugin.ts b/packages/run/src/vite/plugin.ts index 2e54a6c..8149735 100644 --- a/packages/run/src/vite/plugin.ts +++ b/packages/run/src/vite/plugin.ts @@ -186,29 +186,27 @@ export default function markoRun(opts: Options = {}): Plugin[] { } for (const route of routes.list) { - if (route.handler) { - const exports = await getExportsFromFile( - context, - route.handler.filePath, - ); - route.handler.verbs = []; + const { handler, page, layouts } = route; + if (handler) { + const exports = await getExportsFromFile(context, handler.filePath); + handler.verbs = []; for (const name of exports) { const verb = name.toLowerCase() as HttpVerb; if (name === verb.toUpperCase() && httpVerbs.includes(verb)) { - route.handler.verbs.push(verb); + handler.verbs.push(verb); } } - if (!route.handler.verbs.length) { + if (!handler.verbs.length) { context.warn( - `Did not find any http verb exports in handler '${path.relative(root, route.handler.filePath)}' - expected ${httpVerbs.map((v) => v.toUpperCase()).join(", ")}`, + `Did not find any http verb exports in handler '${path.relative(root, handler.filePath)}' - expected ${httpVerbs.map((v) => v.toUpperCase()).join(", ")}`, ); } } - if (route.page && route.layouts.length) { + if (page && layouts.length) { const relativePath = path.relative( resolvedRoutesDir, - route.page.filePath, + page.filePath, ); const routeFileDir = path.join(entryFilesDir, relativePath, ".."); const routeFileRelativePathPosix = normalizePath( @@ -216,8 +214,13 @@ export default function markoRun(opts: Options = {}): Plugin[] { ); fs.mkdirSync(routeFileDir, { recursive: true }); + + const pageNameIndex = page.name.indexOf("+page"); + const pageNamePrefix = + pageNameIndex > 0 ? `${page.name.slice(0, pageNameIndex)}.` : ""; + fs.writeFileSync( - path.join(routeFileDir, "route.marko"), + path.join(routeFileDir, pageNamePrefix + "route.marko"), renderRouteTemplate(route, (to) => path.posix.join(routeFileRelativePathPosix, to), ), @@ -229,10 +232,11 @@ export default function markoRun(opts: Options = {}): Plugin[] { ); } for (const route of Object.values(routes.special) as Route[]) { - if (route.page && route.layouts.length) { + const { page, layouts, key } = route; + if (page && layouts.length) { const relativePath = path.relative( resolvedRoutesDir, - route.page.filePath, + page.filePath, ); const routeFileDir = path.join(entryFilesDir, relativePath, ".."); const routeFileRelativePathPosix = normalizePath( @@ -241,7 +245,7 @@ export default function markoRun(opts: Options = {}): Plugin[] { fs.mkdirSync(routeFileDir, { recursive: true }); fs.writeFileSync( - path.join(routeFileDir, `route.${route.key}.marko`), + path.join(routeFileDir, `route.${key}.marko`), renderRouteTemplate(route, (to) => path.posix.join(routeFileRelativePathPosix, to), ),