mirror of
https://github.com/withastro/astro.git
synced 2024-12-30 22:03:56 -05:00
Implement the Astro.request RFC
This commit is contained in:
parent
e2885df50b
commit
8e2cae4990
14 changed files with 79 additions and 91 deletions
|
@ -5,7 +5,7 @@ import AddToCart from '../../components/AddToCart.svelte';
|
||||||
import { getProduct } from '../../api';
|
import { getProduct } from '../../api';
|
||||||
import '../../styles/common.css';
|
import '../../styles/common.css';
|
||||||
|
|
||||||
const id = Number(Astro.request.params.id);
|
const id = Number(Astro.params.id);
|
||||||
const product = await getProduct(id);
|
const product = await getProduct(id);
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,6 @@ import type * as vite from 'vite';
|
||||||
import type { z } from 'zod';
|
import type { z } from 'zod';
|
||||||
import type { AstroConfigSchema } from '../core/config';
|
import type { AstroConfigSchema } from '../core/config';
|
||||||
import type { AstroComponentFactory, Metadata } from '../runtime/server';
|
import type { AstroComponentFactory, Metadata } from '../runtime/server';
|
||||||
import type { AstroRequest } from '../core/render/request';
|
|
||||||
export type { SSRManifest } from '../core/app/types';
|
export type { SSRManifest } from '../core/app/types';
|
||||||
|
|
||||||
export interface AstroBuiltinProps {
|
export interface AstroBuiltinProps {
|
||||||
|
@ -47,10 +46,14 @@ export interface BuildConfig {
|
||||||
* Docs: https://docs.astro.build/reference/api-reference/#astro-global
|
* Docs: https://docs.astro.build/reference/api-reference/#astro-global
|
||||||
*/
|
*/
|
||||||
export interface AstroGlobal extends AstroGlobalPartial {
|
export interface AstroGlobal extends AstroGlobalPartial {
|
||||||
|
/** get the current canonical URL */
|
||||||
|
canonicalURL: URL;
|
||||||
|
/** get page params (dynamic pages only) */
|
||||||
|
params: Params;
|
||||||
/** set props for this astro component (along with default values) */
|
/** set props for this astro component (along with default values) */
|
||||||
props: Record<string, number | string | any>;
|
props: Record<string, number | string | any>;
|
||||||
/** get information about this page */
|
/** get information about this page */
|
||||||
request: AstroRequest;
|
request: Request;
|
||||||
/** see if slots are used */
|
/** see if slots are used */
|
||||||
slots: Record<string, true | undefined> & { has(slotName: string): boolean; render(slotName: string): Promise<string> };
|
slots: Record<string, true | undefined> & { has(slotName: string): boolean; render(slotName: string): Promise<string> };
|
||||||
}
|
}
|
||||||
|
@ -624,7 +627,7 @@ export interface EndpointOutput<Output extends Body = Body> {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface EndpointHandler {
|
export interface EndpointHandler {
|
||||||
[method: string]: (params: any, request: AstroRequest) => EndpointOutput | Response;
|
[method: string]: (params: any, request: Request) => EndpointOutput | Response;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AstroRenderer {
|
export interface AstroRenderer {
|
||||||
|
|
|
@ -16,6 +16,7 @@ import { createLinkStylesheetElementSet, createModuleScriptElementWithSrcSet } f
|
||||||
import { getOutFile, getOutFolder, getOutRoot } from './common.js';
|
import { getOutFile, getOutFolder, getOutRoot } from './common.js';
|
||||||
import type { PageBuildData, StaticBuildOptions } from './types';
|
import type { PageBuildData, StaticBuildOptions } from './types';
|
||||||
import { getTimeStat } from './util.js';
|
import { getTimeStat } from './util.js';
|
||||||
|
import { createRequest } from '../request.js';
|
||||||
|
|
||||||
// Render is usually compute, which Node.js can't parallelize well.
|
// Render is usually compute, which Node.js can't parallelize well.
|
||||||
// In real world testing, dropping from 10->1 showed a notiable perf
|
// In real world testing, dropping from 10->1 showed a notiable perf
|
||||||
|
@ -195,6 +196,7 @@ async function generatePath(pathname: string, opts: StaticBuildOptions, gopts: G
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
const url = new URL(origin + pathname);
|
||||||
const options: RenderOptions = {
|
const options: RenderOptions = {
|
||||||
legacyBuild: false,
|
legacyBuild: false,
|
||||||
links,
|
links,
|
||||||
|
@ -222,8 +224,7 @@ async function generatePath(pathname: string, opts: StaticBuildOptions, gopts: G
|
||||||
const fullyRelativePath = relPath[0] === '.' ? relPath : './' + relPath;
|
const fullyRelativePath = relPath[0] === '.' ? relPath : './' + relPath;
|
||||||
return fullyRelativePath;
|
return fullyRelativePath;
|
||||||
},
|
},
|
||||||
method: 'GET',
|
request: createRequest(url, new Headers()),
|
||||||
headers: new Headers(),
|
|
||||||
route: pageData.route,
|
route: pageData.route,
|
||||||
routeCache,
|
routeCache,
|
||||||
site: astroConfig.buildOptions.site,
|
site: astroConfig.buildOptions.site,
|
||||||
|
|
|
@ -2,9 +2,9 @@ import type { EndpointHandler } from '../../@types/astro';
|
||||||
import type { RenderOptions } from '../render/core';
|
import type { RenderOptions } from '../render/core';
|
||||||
import { renderEndpoint } from '../../runtime/server/index.js';
|
import { renderEndpoint } from '../../runtime/server/index.js';
|
||||||
import { getParamsAndProps, GetParamsAndPropsError } from '../render/core.js';
|
import { getParamsAndProps, GetParamsAndPropsError } from '../render/core.js';
|
||||||
import { createRequest } from '../render/request.js';
|
|
||||||
|
|
||||||
export type EndpointOptions = Pick<RenderOptions, 'logging' | 'headers' | 'method' | 'origin' | 'route' | 'routeCache' | 'pathname' | 'route' | 'site' | 'ssr'>;
|
export type EndpointOptions = Pick<RenderOptions, 'logging' | 'origin' |
|
||||||
|
'request' | 'route' | 'routeCache' | 'pathname' | 'route' | 'site' | 'ssr'>;
|
||||||
|
|
||||||
type EndpointCallResult =
|
type EndpointCallResult =
|
||||||
| {
|
| {
|
||||||
|
@ -23,9 +23,8 @@ export async function call(mod: EndpointHandler, opts: EndpointOptions): Promise
|
||||||
throw new Error(`[getStaticPath] route pattern matched, but no matching static path found. (${opts.pathname})`);
|
throw new Error(`[getStaticPath] route pattern matched, but no matching static path found. (${opts.pathname})`);
|
||||||
}
|
}
|
||||||
const [params] = paramsAndPropsResp;
|
const [params] = paramsAndPropsResp;
|
||||||
const request = createRequest(opts.method, opts.pathname, opts.headers, opts.origin, opts.site, opts.ssr);
|
|
||||||
|
|
||||||
const response = await renderEndpoint(mod, request, params);
|
const response = await renderEndpoint(mod, opts.request, params);
|
||||||
|
|
||||||
if (response instanceof Response) {
|
if (response instanceof Response) {
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import type { ComponentInstance, EndpointHandler, MarkdownRenderOptions, Params, Props, SSRLoadedRenderer, RouteData, SSRElement } from '../../@types/astro';
|
import type { ComponentInstance, EndpointHandler, MarkdownRenderOptions, Params, Props, SSRLoadedRenderer, RouteData, SSRElement } from '../../@types/astro';
|
||||||
import type { LogOptions } from '../logger.js';
|
import type { LogOptions } from '../logger.js';
|
||||||
import type { AstroRequest } from './request';
|
|
||||||
|
|
||||||
import { renderHead, renderPage } from '../../runtime/server/index.js';
|
import { renderHead, renderPage } from '../../runtime/server/index.js';
|
||||||
import { getParams } from '../routing/index.js';
|
import { getParams } from '../routing/index.js';
|
||||||
|
@ -71,12 +70,11 @@ export interface RenderOptions {
|
||||||
routeCache: RouteCache;
|
routeCache: RouteCache;
|
||||||
site?: string;
|
site?: string;
|
||||||
ssr: boolean;
|
ssr: boolean;
|
||||||
method: string;
|
request: Request;
|
||||||
headers: Headers;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function render(opts: RenderOptions): Promise<{ type: 'html'; html: string } | { type: 'response'; response: Response }> {
|
export async function render(opts: RenderOptions): Promise<{ type: 'html'; html: string } | { type: 'response'; response: Response }> {
|
||||||
const { headers, legacyBuild, links, logging, origin, markdownRender, method, mod, pathname, scripts, renderers, resolve, route, routeCache, site, ssr } = opts;
|
const { legacyBuild, links, logging, origin, markdownRender, mod, pathname, scripts, renderers, request, resolve, route, routeCache, site, ssr } = opts;
|
||||||
|
|
||||||
const paramsAndPropsRes = await getParamsAndProps({
|
const paramsAndPropsRes = await getParamsAndProps({
|
||||||
logging,
|
logging,
|
||||||
|
@ -107,11 +105,10 @@ export async function render(opts: RenderOptions): Promise<{ type: 'html'; html:
|
||||||
pathname,
|
pathname,
|
||||||
resolve,
|
resolve,
|
||||||
renderers,
|
renderers,
|
||||||
|
request,
|
||||||
site,
|
site,
|
||||||
scripts,
|
scripts,
|
||||||
ssr,
|
ssr,
|
||||||
method,
|
|
||||||
headers,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
let page = await renderPage(result, Component, pageProps, null);
|
let page = await renderPage(result, Component, pageProps, null);
|
||||||
|
|
|
@ -29,10 +29,8 @@ export interface SSROptions {
|
||||||
routeCache: RouteCache;
|
routeCache: RouteCache;
|
||||||
/** Vite instance */
|
/** Vite instance */
|
||||||
viteServer: vite.ViteDevServer;
|
viteServer: vite.ViteDevServer;
|
||||||
/** Method */
|
/** Request */
|
||||||
method: string;
|
request: Request;
|
||||||
/** Headers */
|
|
||||||
headers: Headers;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ComponentPreload = [SSRLoadedRenderer[], ComponentInstance];
|
export type ComponentPreload = [SSRLoadedRenderer[], ComponentInstance];
|
||||||
|
@ -65,7 +63,7 @@ export async function preload({ astroConfig, filePath, viteServer }: Pick<SSROpt
|
||||||
|
|
||||||
/** use Vite to SSR */
|
/** use Vite to SSR */
|
||||||
export async function render(renderers: SSRLoadedRenderer[], mod: ComponentInstance, ssrOpts: SSROptions): Promise<RenderResponse> {
|
export async function render(renderers: SSRLoadedRenderer[], mod: ComponentInstance, ssrOpts: SSROptions): Promise<RenderResponse> {
|
||||||
const { astroConfig, filePath, logging, mode, origin, pathname, method, headers, route, routeCache, viteServer } = ssrOpts;
|
const { astroConfig, filePath, logging, mode, origin, pathname, request, route, routeCache, viteServer } = ssrOpts;
|
||||||
const legacy = astroConfig.buildOptions.legacyBuild;
|
const legacy = astroConfig.buildOptions.legacyBuild;
|
||||||
|
|
||||||
// Add hoisted script tags
|
// Add hoisted script tags
|
||||||
|
@ -145,12 +143,11 @@ export async function render(renderers: SSRLoadedRenderer[], mod: ComponentInsta
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
renderers,
|
renderers,
|
||||||
|
request,
|
||||||
route,
|
route,
|
||||||
routeCache,
|
routeCache,
|
||||||
site: astroConfig.buildOptions.site,
|
site: astroConfig.buildOptions.site,
|
||||||
ssr: astroConfig.buildOptions.experimentalSsr,
|
ssr: astroConfig.buildOptions.experimentalSsr,
|
||||||
method,
|
|
||||||
headers,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if (route?.type === 'endpoint' || content.type === 'response') {
|
if (route?.type === 'endpoint' || content.type === 'response') {
|
||||||
|
|
|
@ -1,50 +0,0 @@
|
||||||
import type { Params } from '../../@types/astro';
|
|
||||||
import { canonicalURL as utilCanonicalURL } from '../util.js';
|
|
||||||
|
|
||||||
type Site = string | undefined;
|
|
||||||
|
|
||||||
export interface AstroRequest {
|
|
||||||
/** get the current page URL */
|
|
||||||
url: URL;
|
|
||||||
|
|
||||||
/** get the current canonical URL */
|
|
||||||
canonicalURL: URL;
|
|
||||||
|
|
||||||
/** get page params (dynamic pages only) */
|
|
||||||
params: Params;
|
|
||||||
|
|
||||||
headers: Headers;
|
|
||||||
|
|
||||||
method: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type AstroRequestSSR = AstroRequest;
|
|
||||||
|
|
||||||
export function createRequest(method: string, pathname: string, headers: Headers, origin: string, site: Site, ssr: boolean): AstroRequest {
|
|
||||||
const url = new URL('.' + pathname, new URL(origin));
|
|
||||||
|
|
||||||
const canonicalURL = utilCanonicalURL('.' + pathname, site ?? url.origin);
|
|
||||||
|
|
||||||
const request: AstroRequest = {
|
|
||||||
url,
|
|
||||||
canonicalURL,
|
|
||||||
params: {},
|
|
||||||
headers,
|
|
||||||
method,
|
|
||||||
};
|
|
||||||
|
|
||||||
if (!ssr) {
|
|
||||||
// Headers are only readable if using SSR-mode. If not, make it an empty headers
|
|
||||||
// object, so you can't do something bad.
|
|
||||||
request.headers = new Headers();
|
|
||||||
|
|
||||||
// Disallow using query params.
|
|
||||||
request.url = new URL(request.url);
|
|
||||||
|
|
||||||
for (const [key] of request.url.searchParams) {
|
|
||||||
request.url.searchParams.delete(key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return request;
|
|
||||||
}
|
|
|
@ -3,7 +3,7 @@ import type { AstroGlobal, AstroGlobalPartial, MarkdownParser, MarkdownRenderOpt
|
||||||
import { renderSlot } from '../../runtime/server/index.js';
|
import { renderSlot } from '../../runtime/server/index.js';
|
||||||
import { LogOptions, warn } from '../logger.js';
|
import { LogOptions, warn } from '../logger.js';
|
||||||
import { isCSSRequest } from './dev/css.js';
|
import { isCSSRequest } from './dev/css.js';
|
||||||
import { createRequest } from './request.js';
|
import { canonicalURL as utilCanonicalURL } from '../util.js';
|
||||||
import { isScriptRequest } from './script.js';
|
import { isScriptRequest } from './script.js';
|
||||||
|
|
||||||
function onlyAvailableInSSR(name: string) {
|
function onlyAvailableInSSR(name: string) {
|
||||||
|
@ -26,8 +26,7 @@ export interface CreateResultArgs {
|
||||||
site: string | undefined;
|
site: string | undefined;
|
||||||
links?: Set<SSRElement>;
|
links?: Set<SSRElement>;
|
||||||
scripts?: Set<SSRElement>;
|
scripts?: Set<SSRElement>;
|
||||||
headers: Headers;
|
request: Request;
|
||||||
method: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class Slots {
|
class Slots {
|
||||||
|
@ -72,10 +71,10 @@ class Slots {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createResult(args: CreateResultArgs): SSRResult {
|
export function createResult(args: CreateResultArgs): SSRResult {
|
||||||
const { legacyBuild, markdownRender, method, origin, headers, params, pathname, renderers, resolve, site } = args;
|
const { legacyBuild, markdownRender, origin, params, pathname, renderers, request, resolve, site } = args;
|
||||||
|
|
||||||
const request = createRequest(method, pathname, headers, origin, site, args.ssr);
|
const url = new URL(request.url);
|
||||||
request.params = params;
|
const canonicalURL = utilCanonicalURL('.' + pathname, site ?? url.origin);
|
||||||
|
|
||||||
// Create the result object that will be passed into the render function.
|
// Create the result object that will be passed into the render function.
|
||||||
// This object starts here as an empty shell (not yet the result) but then
|
// This object starts here as an empty shell (not yet the result) but then
|
||||||
|
@ -90,6 +89,8 @@ export function createResult(args: CreateResultArgs): SSRResult {
|
||||||
|
|
||||||
const Astro = {
|
const Astro = {
|
||||||
__proto__: astroGlobal,
|
__proto__: astroGlobal,
|
||||||
|
canonicalURL,
|
||||||
|
params,
|
||||||
props,
|
props,
|
||||||
request,
|
request,
|
||||||
redirect: args.ssr
|
redirect: args.ssr
|
||||||
|
|
32
packages/astro/src/core/request.ts
Normal file
32
packages/astro/src/core/request.ts
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
import type { IncomingHttpHeaders } from 'http';
|
||||||
|
|
||||||
|
type HeaderType = Headers | Record<string, any> | IncomingHttpHeaders;
|
||||||
|
|
||||||
|
export function createRequest(url: URL | string, headers: HeaderType, method: string = 'GET'): Request {
|
||||||
|
let headersObj = headers instanceof Headers ? headers :
|
||||||
|
new Headers(Object.entries(headers as Record<string, any>));
|
||||||
|
|
||||||
|
const request = new Request(url.toString(), {
|
||||||
|
method: method,
|
||||||
|
headers: headersObj
|
||||||
|
});
|
||||||
|
|
||||||
|
Object.defineProperties(request, {
|
||||||
|
canonicalURL: {
|
||||||
|
get() {
|
||||||
|
console.warn(`Astro.request.canonicalURL has been moved to Astro.canonicalURL`);
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
params: {
|
||||||
|
get() {
|
||||||
|
console.warn(`Astro.request.params has been moved to Astro.params`);
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// TODO warn
|
||||||
|
|
||||||
|
return request;
|
||||||
|
}
|
|
@ -10,11 +10,11 @@ import { createSafeError } from '../core/util.js';
|
||||||
import { ssr, preload } from '../core/render/dev/index.js';
|
import { ssr, preload } from '../core/render/dev/index.js';
|
||||||
import { call as callEndpoint } from '../core/endpoint/dev/index.js';
|
import { call as callEndpoint } from '../core/endpoint/dev/index.js';
|
||||||
import * as msg from '../core/messages.js';
|
import * as msg from '../core/messages.js';
|
||||||
|
import { createRequest } from '../core/request.js';
|
||||||
|
|
||||||
import notFoundTemplate, { subpathNotUsedTemplate } from '../template/4xx.js';
|
import notFoundTemplate, { subpathNotUsedTemplate } from '../template/4xx.js';
|
||||||
import serverErrorTemplate from '../template/5xx.js';
|
import serverErrorTemplate from '../template/5xx.js';
|
||||||
import { RouteCache } from '../core/render/route-cache.js';
|
import { RouteCache } from '../core/render/route-cache.js';
|
||||||
import { AstroRequest } from '../core/render/request.js';
|
|
||||||
|
|
||||||
interface AstroPluginOptions {
|
interface AstroPluginOptions {
|
||||||
config: AstroConfig;
|
config: AstroConfig;
|
||||||
|
@ -117,9 +117,19 @@ async function handleRequest(
|
||||||
const site = config.buildOptions.site ? new URL(config.buildOptions.site) : undefined;
|
const site = config.buildOptions.site ? new URL(config.buildOptions.site) : undefined;
|
||||||
const devRoot = site ? site.pathname : '/';
|
const devRoot = site ? site.pathname : '/';
|
||||||
const origin = `${viteServer.config.server.https ? 'https' : 'http'}://${req.headers.host}`;
|
const origin = `${viteServer.config.server.https ? 'https' : 'http'}://${req.headers.host}`;
|
||||||
|
const buildingToSSR = !!config._ctx.adapter?.serverEntrypoint;
|
||||||
const url = new URL(origin + req.url);
|
const url = new URL(origin + req.url);
|
||||||
const pathname = decodeURI(url.pathname);
|
const pathname = decodeURI(url.pathname);
|
||||||
const rootRelativeUrl = pathname.substring(devRoot.length - 1);
|
const rootRelativeUrl = pathname.substring(devRoot.length - 1);
|
||||||
|
if(!buildingToSSR) {
|
||||||
|
// Prevent user from depending on search params when not doing SSR.
|
||||||
|
for(const [key] of url.searchParams) {
|
||||||
|
url.searchParams.delete(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Headers are only available when using SSR.
|
||||||
|
const request = createRequest(url, buildingToSSR ? req.headers : new Headers(), req.method);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (!pathname.startsWith(devRoot)) {
|
if (!pathname.startsWith(devRoot)) {
|
||||||
|
@ -166,10 +176,9 @@ async function handleRequest(
|
||||||
filePath: filePathCustom404,
|
filePath: filePathCustom404,
|
||||||
logging,
|
logging,
|
||||||
mode: 'development',
|
mode: 'development',
|
||||||
method: 'GET',
|
|
||||||
headers: new Headers(Object.entries(req.headers as Record<string, any>)),
|
|
||||||
origin,
|
origin,
|
||||||
pathname: rootRelativeUrl,
|
pathname: rootRelativeUrl,
|
||||||
|
request,
|
||||||
route: routeCustom404,
|
route: routeCustom404,
|
||||||
routeCache,
|
routeCache,
|
||||||
viteServer,
|
viteServer,
|
||||||
|
@ -190,8 +199,7 @@ async function handleRequest(
|
||||||
route,
|
route,
|
||||||
routeCache,
|
routeCache,
|
||||||
viteServer,
|
viteServer,
|
||||||
method: req.method || 'GET',
|
request,
|
||||||
headers: new Headers(Object.entries(req.headers as Record<string, any>)),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Route successfully matched! Render it.
|
// Route successfully matched! Render it.
|
||||||
|
|
|
@ -6,7 +6,7 @@ export async function getStaticPaths() {
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
const { year, slug } = Astro.request.params
|
const { year, slug } = Astro.params
|
||||||
---
|
---
|
||||||
|
|
||||||
<html>
|
<html>
|
||||||
|
@ -14,4 +14,4 @@ const { year, slug } = Astro.request.params
|
||||||
<title>{year} | {slug}</title>
|
<title>{year} | {slug}</title>
|
||||||
</head>
|
</head>
|
||||||
<body></body>
|
<body></body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -8,7 +8,7 @@ export function getStaticPaths() {
|
||||||
params: { pizza: 'grimaldis/new-york' },
|
params: { pizza: 'grimaldis/new-york' },
|
||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
const { pizza } = Astro.request.params
|
const { pizza } = Astro.params
|
||||||
---
|
---
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
|
@ -19,4 +19,4 @@ const { pizza } = Astro.request.params
|
||||||
<body>
|
<body>
|
||||||
<h1>Welcome to {pizza ?? 'The landing page'}</h1>
|
<h1>Welcome to {pizza ?? 'The landing page'}</h1>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -6,7 +6,7 @@ export function getStaticPaths() {
|
||||||
params: { cheese: 'provolone', topping: 'sausage' },
|
params: { cheese: 'provolone', topping: 'sausage' },
|
||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
const { cheese, topping } = Astro.request.params
|
const { cheese, topping } = Astro.params
|
||||||
---
|
---
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
|
@ -18,4 +18,4 @@ const { cheese, topping } = Astro.request.params
|
||||||
<h1>🍕 It's pizza time</h1>
|
<h1>🍕 It's pizza time</h1>
|
||||||
<p>{cheese}-{topping}</p>
|
<p>{cheese}-{topping}</p>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
const val = Number(Astro.request.params.id);
|
const val = Number(Astro.params.id);
|
||||||
---
|
---
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
|
|
Loading…
Reference in a new issue