diff --git a/apps/analog-app-e2e-cypress/src/e2e/app.cy.ts b/apps/analog-app-e2e-cypress/src/e2e/app.cy.ts
index e0e041ab8..db18dbc1a 100644
--- a/apps/analog-app-e2e-cypress/src/e2e/app.cy.ts
+++ b/apps/analog-app-e2e-cypress/src/e2e/app.cy.ts
@@ -1,10 +1,19 @@
import * as app from '../support/app.po';
describe('My Store', () => {
- beforeEach(() => cy.visit('/'));
-
it(`Given the user has navigated to the home page
Then the app title is visible`, () => {
+ cy.visit('/');
app.getTitle().contains(/my store/i);
});
+
+ it(`Given the user has navigated an invalid page then the page not found title is visible`, () => {
+ cy.visit('/bad');
+ app.get404Title().contains(/page not found/i);
+ });
+
+ it(`Given the user has navigated an invalid nested page then the page not found title is visible`, () => {
+ cy.visit('/shipping/bad');
+ app.getNested404Title().contains(/shipping page not found/i);
+ });
});
diff --git a/apps/analog-app-e2e-cypress/src/support/app.po.ts b/apps/analog-app-e2e-cypress/src/support/app.po.ts
index e6566b7fd..1e77b0203 100644
--- a/apps/analog-app-e2e-cypress/src/support/app.po.ts
+++ b/apps/analog-app-e2e-cypress/src/support/app.po.ts
@@ -1 +1,6 @@
export const getTitle = () => cy.contains('h1', /my store/i);
+
+export const get404Title = () => cy.contains('h2', /page not found/i);
+
+export const getNested404Title = () =>
+ cy.contains('h2', /shipping page not found/i);
diff --git a/apps/analog-app/src/app/cart.service.ts b/apps/analog-app/src/app/cart.service.ts
index 4978de9cd..a10797932 100644
--- a/apps/analog-app/src/app/cart.service.ts
+++ b/apps/analog-app/src/app/cart.service.ts
@@ -7,6 +7,7 @@ import { Product } from './products';
})
export class CartService {
items: Product[] = [];
+ private readonly apiURL = import.meta.env.VITE_ANALOG_PUBLIC_BASE_URL;
constructor(private http: HttpClient) {}
@@ -25,7 +26,7 @@ export class CartService {
getShippingPrices() {
return this.http.get<{ type: string; price: number }[]>(
- '/assets/shipping.json'
+ `${this.apiURL}/assets/shipping.json`
);
}
}
diff --git a/apps/analog-app/src/app/pages/[...slug].page.ts b/apps/analog-app/src/app/pages/[...slug].page.ts
new file mode 100644
index 000000000..00a2c565b
--- /dev/null
+++ b/apps/analog-app/src/app/pages/[...slug].page.ts
@@ -0,0 +1,8 @@
+import { Component } from '@angular/core';
+
+@Component({
+ selector: 'app-page-not-found',
+ standalone: true,
+ template: `
Page Not Found
`,
+})
+export default class PageNotFoundComponent {}
diff --git a/apps/analog-app/src/app/pages/[...slug].server.ts b/apps/analog-app/src/app/pages/[...slug].server.ts
new file mode 100644
index 000000000..a5ab19bf2
--- /dev/null
+++ b/apps/analog-app/src/app/pages/[...slug].server.ts
@@ -0,0 +1,9 @@
+import { PageServerLoad } from '@analogjs/router';
+
+export function load({ params }: PageServerLoad) {
+ console.log('params', params);
+
+ return {
+ loaded: true,
+ };
+}
diff --git a/apps/analog-app/src/app/pages/shipping/[...slug].page.ts b/apps/analog-app/src/app/pages/shipping/[...slug].page.ts
new file mode 100644
index 000000000..051e059d8
--- /dev/null
+++ b/apps/analog-app/src/app/pages/shipping/[...slug].page.ts
@@ -0,0 +1,8 @@
+import { Component } from '@angular/core';
+
+@Component({
+ selector: 'app-shipping-page-not-found',
+ standalone: true,
+ template: ` Shipping Page Not Found
`,
+})
+export default class ShippingPageNotFoundComponent {}
diff --git a/apps/analog-app/src/app/pages/shipping/[...slug].server.ts b/apps/analog-app/src/app/pages/shipping/[...slug].server.ts
new file mode 100644
index 000000000..3df66e3d7
--- /dev/null
+++ b/apps/analog-app/src/app/pages/shipping/[...slug].server.ts
@@ -0,0 +1,9 @@
+import { PageServerLoad } from '@analogjs/router';
+
+export function load({ params }: PageServerLoad) {
+ console.log('slug', params?.['slug']);
+
+ return {
+ loaded: true,
+ };
+}
diff --git a/apps/analog-app/src/public/assets/shipping.json b/apps/analog-app/src/public/assets/shipping.json
index fe51488c7..d8390c4c2 100644
--- a/apps/analog-app/src/public/assets/shipping.json
+++ b/apps/analog-app/src/public/assets/shipping.json
@@ -1 +1,14 @@
-[]
+[
+ {
+ "type": "Overnight",
+ "price": 25.99
+ },
+ {
+ "type": "2-Day",
+ "price": 9.99
+ },
+ {
+ "type": "Postal",
+ "price": 2.99
+ }
+]
diff --git a/apps/analog-app/src/vite-env.d.ts b/apps/analog-app/src/vite-env.d.ts
index 11f02fe2a..c08d88d48 100644
--- a/apps/analog-app/src/vite-env.d.ts
+++ b/apps/analog-app/src/vite-env.d.ts
@@ -1 +1,9 @@
///
+
+interface ImportMetaEnv {
+ readonly VITE_ANALOG_PUBLIC_BASE_URL: string;
+}
+
+interface ImportMeta {
+ readonly env: ImportMetaEnv;
+}
diff --git a/packages/router/src/lib/route-config.ts b/packages/router/src/lib/route-config.ts
index 36fa6a8e0..4d3b83807 100644
--- a/packages/router/src/lib/route-config.ts
+++ b/packages/router/src/lib/route-config.ts
@@ -35,7 +35,9 @@ export function toRouteConfig(routeMeta: RouteMeta | undefined): RouteConfig {
};
if (PAGE_ENDPOINTS[routeConfig[ANALOG_META_KEY].endpointKey]) {
- const { queryParams, fragment: hash, params } = route;
+ const { queryParams, fragment: hash, params, parent } = route;
+ const segment =
+ parent?.url.map((segment) => segment.path).join('/') || '';
const url = new URL('', import.meta.env['VITE_ANALOG_PUBLIC_BASE_URL']);
url.pathname = `/api/_analog${routeConfig[ANALOG_META_KEY].endpoint}`;
url.search = `${new URLSearchParams(queryParams).toString()}`;
@@ -44,6 +46,7 @@ export function toRouteConfig(routeMeta: RouteMeta | undefined): RouteConfig {
Object.keys(params).forEach((param) => {
url.pathname = url.pathname.replace(`[${param}]`, params[param]);
});
+ url.pathname = url.pathname.replace('**', segment);
if ((globalThis as any).$fetch) {
return (globalThis as any).$fetch(url.pathname);
diff --git a/packages/router/src/lib/routes.ts b/packages/router/src/lib/routes.ts
index afe38fb8c..9816fe621 100644
--- a/packages/router/src/lib/routes.ts
+++ b/packages/router/src/lib/routes.ts
@@ -163,6 +163,7 @@ function toRoutes(rawRoutes: RawRoute[], files: Files): Route[] {
// get endpoint path
const rawEndpoint = rawRoute.filename
.replace(/\.page\.ts$/, '')
+ .replace(/\[\.{3}.+\]/, '**') // [...not-found] => **
.split(APP_DIR)[1];
// replace periods, remove (index) paths
diff --git a/packages/vite-plugin-nitro/src/lib/utils/get-page-handlers.ts b/packages/vite-plugin-nitro/src/lib/utils/get-page-handlers.ts
index ed614dba1..fc75fd384 100644
--- a/packages/vite-plugin-nitro/src/lib/utils/get-page-handlers.ts
+++ b/packages/vite-plugin-nitro/src/lib/utils/get-page-handlers.ts
@@ -19,10 +19,10 @@ export function getPageHandlers({ workspaceRoot, rootDir }: GetHandlersArgs) {
const route = endpointFile
.replace(path.resolve(workspaceRoot, rootDir, 'src/app'), '')
.replace(/\.server\.ts$/, '')
- .replace(/\[\.{3}]/g, '**')
- .replace(/\[\.{3}(\w+)]/g, '**:$1')
+ .replace(/\[\.{3}(.+)\]/g, '**:$1')
+ .replace(/\[\.{3}(\w+)\]/g, '**:$1')
.replace(/\/\((.*?)\)$/, '/-$1-')
- .replace(/\[(\w+)]/g, ':$1')
+ .replace(/\[(\w+)\]/g, ':$1')
.replace(/\./g, '/');
return {