Implement the Astro.request RFC (#2913)

* Implement the Astro.request RFC

* Disable console warnings eslint

* Use our logger

* Adds a changeset

* Fix tests that depend on params, canonicalURL, URL

Co-authored-by: Fred K. Schott <fkschott@gmail.com>
This commit is contained in:
Matthew Phillips 2022-03-29 07:35:03 -04:00 committed by GitHub
parent 030fd48bdd
commit ecc6a4833f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
34 changed files with 135 additions and 121 deletions

View file

@ -0,0 +1,5 @@
---
'astro': minor
---
Implements the Astro.request RFC

View file

@ -4,7 +4,7 @@ import Nav from '../components/Nav.astro';
import authorData from '../data/authors.json'; import authorData from '../data/authors.json';
const { content } = Astro.props; const { content } = Astro.props;
let canonicalURL = Astro.request.canonicalURL; let canonicalURL = Astro.canonicalURL;
--- ---
<html lang={content.lang || 'en'}> <html lang={content.lang || 'en'}>

View file

@ -4,7 +4,7 @@ import Nav from '../components/Nav.astro';
let title = 'About'; let title = 'About';
let description = 'About page of an example blog on Astro'; let description = 'About page of an example blog on Astro';
let canonicalURL = Astro.request.canonicalURL; let canonicalURL = Astro.canonicalURL;
--- ---
<html lang="en"> <html lang="en">

View file

@ -12,7 +12,7 @@ import authorData from '../data/authors.json';
// All variables are available to use in the HTML template below. // All variables are available to use in the HTML template below.
let title = 'Dons Blog'; let title = 'Dons Blog';
let description = 'An example blog on Astro'; let description = 'An example blog on Astro';
let canonicalURL = Astro.request.canonicalURL; let canonicalURL = Astro.canonicalURL;
// Data Fetching: List all Markdown posts in the repo. // Data Fetching: List all Markdown posts in the repo.
let allPosts = await Astro.glob('./post/*.md'); let allPosts = await Astro.glob('./post/*.md');

View file

@ -28,9 +28,9 @@ export async function getStaticPaths({ paginate, rss }) {
} }
// page // page
let title = 'Dons Blog'; const title = 'Dons Blog';
let description = 'An example blog on Astro'; const description = 'An example blog on Astro';
let canonicalURL = Astro.request.canonicalURL; const { canonicalURL } = Astro;
const { page } = Astro.props; const { page } = Astro.props;
--- ---

View file

@ -17,7 +17,7 @@ const githubEditUrl = CONFIG.GITHUB_EDIT_URL && CONFIG.GITHUB_EDIT_URL + current
<html dir={content.dir ?? 'ltr'} lang={content.lang ?? 'en-us'} class="initial"> <html dir={content.dir ?? 'ltr'} lang={content.lang ?? 'en-us'} class="initial">
<head> <head>
<HeadCommon /> <HeadCommon />
<HeadSEO {content} canonicalURL={Astro.request.canonicalURL} /> <HeadSEO {content} canonicalURL={Astro.canonicalURL} />
<title>{content.title ? `${content.title} 🚀 ${CONFIG.SITE.title}` : CONFIG.SITE.title}</title> <title>{content.title ? `${content.title} 🚀 ${CONFIG.SITE.title}` : CONFIG.SITE.title}</title>
<style> <style>
body { body {

View file

@ -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);
--- ---

View file

@ -4,7 +4,6 @@ import type * as vite from 'vite';
import { z } from 'zod'; import { 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 {
@ -51,10 +50,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> };
} }
@ -632,7 +635,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 {

View file

@ -10,6 +10,7 @@ import { call as callEndpoint } from '../endpoint/index.js';
import { RouteCache } from '../render/route-cache.js'; import { RouteCache } from '../render/route-cache.js';
import { createLinkStylesheetElementSet, createModuleScriptElementWithSrcSet } from '../render/ssr-element.js'; import { createLinkStylesheetElementSet, createModuleScriptElementWithSrcSet } from '../render/ssr-element.js';
import { prependForwardSlash } from '../path.js'; import { prependForwardSlash } from '../path.js';
import { createRequest } from '../request.js';
export class App { export class App {
#manifest: Manifest; #manifest: Manifest;
@ -17,6 +18,7 @@ export class App {
#routeDataToRouteInfo: Map<RouteData, RouteInfo>; #routeDataToRouteInfo: Map<RouteData, RouteInfo>;
#routeCache: RouteCache; #routeCache: RouteCache;
#encoder = new TextEncoder(); #encoder = new TextEncoder();
#logging = defaultLogOptions;
constructor(manifest: Manifest) { constructor(manifest: Manifest) {
this.#manifest = manifest; this.#manifest = manifest;
@ -63,7 +65,7 @@ export class App {
const result = await render({ const result = await render({
legacyBuild: false, legacyBuild: false,
links, links,
logging: defaultLogOptions, logging: this.#logging,
markdownRender: manifest.markdown.render, markdownRender: manifest.markdown.render,
mod, mod,
origin: url.origin, origin: url.origin,
@ -81,8 +83,7 @@ export class App {
routeCache: this.#routeCache, routeCache: this.#routeCache,
site: this.#manifest.site, site: this.#manifest.site,
ssr: true, ssr: true,
method: info.routeData.type === 'endpoint' ? '' : 'GET', request,
headers: request.headers,
}); });
if (result.type === 'response') { if (result.type === 'response') {
@ -100,15 +101,14 @@ export class App {
}); });
} }
async #callEndpoint(request: Request, routeData: RouteData, mod: ComponentInstance): Promise<Response> { async #callEndpoint(request: Request, _routeData: RouteData, mod: ComponentInstance): Promise<Response> {
const url = new URL(request.url); const url = new URL(request.url);
const handler = mod as unknown as EndpointHandler; const handler = mod as unknown as EndpointHandler;
const result = await callEndpoint(handler, { const result = await callEndpoint(handler, {
headers: request.headers,
logging: defaultLogOptions, logging: defaultLogOptions,
method: request.method,
origin: url.origin, origin: url.origin,
pathname: url.pathname, pathname: url.pathname,
request,
routeCache: this.#routeCache, routeCache: this.#routeCache,
ssr: true, ssr: true,
}); });

View file

@ -17,6 +17,7 @@ import { getOutFile, getOutFolder } from './common.js';
import { eachPageData, getPageDataByComponent } from './internal.js'; import { eachPageData, getPageDataByComponent } from './internal.js';
import type { PageBuildData, SingleFileBuiltModule, StaticBuildOptions } from './types'; import type { PageBuildData, SingleFileBuiltModule, 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
@ -164,6 +165,7 @@ async function generatePath(pathname: string, opts: StaticBuildOptions, gopts: G
} }
} }
const url = new URL(origin + pathname);
const options: RenderOptions = { const options: RenderOptions = {
legacyBuild: false, legacyBuild: false,
links, links,
@ -191,8 +193,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, headers: new Headers(), logging }),
headers: new Headers(),
route: pageData.route, route: pageData.route,
routeCache, routeCache,
site: astroConfig.buildOptions.site, site: astroConfig.buildOptions.site,

View file

@ -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 {

View file

@ -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);

View file

@ -28,10 +28,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];
@ -64,7 +62,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
@ -144,12 +142,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') {

View file

@ -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;
}

View file

@ -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

View file

@ -0,0 +1,44 @@
import type { IncomingHttpHeaders } from 'http';
import type { LogOptions } from './logger';
import { warn } from './logger.js';
type HeaderType = Headers | Record<string, any> | IncomingHttpHeaders;
export interface CreateRequestOptions {
url: URL | string;
headers: HeaderType;
method?: string;
logging: LogOptions;
}
export function createRequest({
url,
headers,
method = 'GET',
logging
}: CreateRequestOptions): 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() {
warn(logging, 'deprecation', `Astro.request.canonicalURL has been moved to Astro.canonicalURL`);
return undefined;
}
},
params: {
get() {
warn(logging, 'deprecation', `Astro.request.params has been moved to Astro.params`);
return undefined;
}
}
});
return request;
}

View file

@ -1,6 +1,5 @@
import shorthash from 'shorthash'; import shorthash from 'shorthash';
import type { AstroComponentMetadata, AstroGlobalPartial, EndpointHandler, Params, SSRElement, SSRLoadedRenderer, SSRResult } from '../../@types/astro'; import type { AstroComponentMetadata, AstroGlobalPartial, EndpointHandler, Params, SSRElement, SSRLoadedRenderer, SSRResult } from '../../@types/astro';
import type { AstroRequest } from '../../core/render/request';
import { escapeHTML, HTMLString, markHTMLString } from './escape.js'; import { escapeHTML, HTMLString, markHTMLString } from './escape.js';
import { extractDirectives, generateHydrateScript, serializeProps } from './hydration.js'; import { extractDirectives, generateHydrateScript, serializeProps } from './hydration.js';
import { serializeListValue } from './util.js'; import { serializeListValue } from './util.js';
@ -388,7 +387,7 @@ export function defineScriptVars(vars: Record<any, any>) {
} }
// Renders an endpoint request to completion, returning the body. // Renders an endpoint request to completion, returning the body.
export async function renderEndpoint(mod: EndpointHandler, request: AstroRequest, params: Params) { export async function renderEndpoint(mod: EndpointHandler, request: Request, params: Params) {
const chosenMethod = request.method?.toLowerCase() ?? 'get'; const chosenMethod = request.method?.toLowerCase() ?? 'get';
const handler = mod[chosenMethod]; const handler = mod[chosenMethod];

View file

@ -14,6 +14,7 @@ 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 { fixViteErrorMessage } from '../core/errors.js'; import { fixViteErrorMessage } from '../core/errors.js';
import { createRequest } from '../core/request.js';
interface AstroPluginOptions { interface AstroPluginOptions {
config: AstroConfig; config: AstroConfig;
@ -116,9 +117,24 @@ 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,
headers: buildingToSSR ? req.headers : new Headers(),
method: req.method,
logging
});
try { try {
if (!pathname.startsWith(devRoot)) { if (!pathname.startsWith(devRoot)) {
@ -165,10 +181,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,
@ -189,8 +204,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.

View file

@ -17,6 +17,7 @@ import { getAstroPageStyleId, getAstroStyleId } from '../vite-plugin-build-css/i
import { addRollupInput } from './add-rollup-input.js'; import { addRollupInput } from './add-rollup-input.js';
import { findAssets, findExternalScripts, findInlineScripts, findInlineStyles, getAttributes, getTextContent } from './extract-assets.js'; import { findAssets, findExternalScripts, findInlineScripts, findInlineStyles, getAttributes, getTextContent } from './extract-assets.js';
import { hasSrcSet, isBuildableImage, isBuildableLink, isHoistedScript, isInSrcDirectory } from './util.js'; import { hasSrcSet, isBuildableImage, isBuildableLink, isHoistedScript, isInSrcDirectory } from './util.js';
import { createRequest } from '../core/request.js';
// This package isn't real ESM, so have to coerce it // This package isn't real ESM, so have to coerce it
const matchSrcset: typeof srcsetParse = (srcsetParse as any).default; const matchSrcset: typeof srcsetParse = (srcsetParse as any).default;
@ -87,8 +88,11 @@ export function rollupPluginAstroScanHTML(options: PluginOptions): VitePlugin {
astroConfig, astroConfig,
filePath: new URL(`./${component}`, astroConfig.projectRoot), filePath: new URL(`./${component}`, astroConfig.projectRoot),
logging, logging,
headers: new Headers(), request: createRequest({
method: 'GET', url: new URL(origin + pathname),
headers: new Headers(),
logging,
}),
mode: 'production', mode: 'production',
origin, origin,
pathname, pathname,

View file

@ -25,7 +25,7 @@ describe('Astro.*', () => {
expect($('#nested-child-pathname').text()).to.equal('/'); expect($('#nested-child-pathname').text()).to.equal('/');
}); });
it('Astro.request.canonicalURL', async () => { it('Astro.canonicalURL', async () => {
// given a URL, expect the following canonical URL // given a URL, expect the following canonical URL
const canonicalURLs = { const canonicalURLs = {
'/index.html': 'https://mysite.dev/blog/', '/index.html': 'https://mysite.dev/blog/',

View file

@ -10,7 +10,7 @@ export function getStaticPaths({ paginate }) {
{params: {calledTwiceTest: 'c'}}, {params: {calledTwiceTest: 'c'}},
]; ];
} }
const { params } = Astro.request; const { params } = Astro;
--- ---
<html> <html>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -1,5 +1,5 @@
--- ---
import NestedChild from './NestedChild.astro'; import NestedChild from './NestedChild.astro';
--- ---
<div id="child-pathname">{Astro.request.url.pathname}</div> <div id="child-pathname">{new URL(Astro.request.url).pathname}</div>
<NestedChild /> <NestedChild />

View file

@ -1 +1 @@
<div id="nested-child-pathname">{Astro.request.url.pathname}</div> <div id="nested-child-pathname">{new URL(Astro.request.url).pathname}</div>

View file

@ -4,7 +4,7 @@ const { content } = Astro.props;
<html> <html>
<head> <head>
<title>{content.title}</title> <title>{content.title}</title>
<link rel="canonical" href={Astro.request.canonicalURL.href}> <link rel="canonical" href={Astro.canonicalURL.href}>
</head> </head>
<body> <body>
<slot></slot> <slot></slot>

View file

@ -4,10 +4,10 @@ import Child from '../components/Child.astro';
<html> <html>
<head> <head>
<title>Test</title> <title>Test</title>
<link rel="canonical" href={Astro.request.canonicalURL.href}> <link rel="canonical" href={Astro.canonicalURL.href}>
</head> </head>
<body> <body>
<div id="pathname">{Astro.request.url.pathname}</div> <div id="pathname">{new URL(Astro.request.url).pathname}</div>
<a id="site" href={Astro.site}>Home</a> <a id="site" href={Astro.site}>Home</a>
<Child /> <Child />

View file

@ -4,7 +4,7 @@ export async function getStaticPaths({paginate}) {
return paginate(data, {pageSize: 1}); return paginate(data, {pageSize: 1});
} }
const { page } = Astro.props; const { page } = Astro.props;
const { params, canonicalURL} = Astro.request; const { params, canonicalURL} = Astro;
--- ---
<html> <html>

View file

@ -3,10 +3,10 @@
<html> <html>
<head> <head>
<title>Test</title> <title>Test</title>
<link rel="canonical" href={Astro.request.canonicalURL.href}> <link rel="canonical" href={Astro.canonicalURL.href}>
</head> </head>
<body> <body>
<div id="pathname">{Astro.request.url.pathname}</div> <div id="pathname">{new URL(Astro.request.url).pathname}</div>
<a id="site" href={Astro.site}>Home</a> <a id="site" href={Astro.site}>Home</a>
</body> </body>
</html> </html>

View file

@ -11,7 +11,7 @@ export async function getStaticPaths({paginate}) {
}); });
} }
const { page, filter } = Astro.props; const { page, filter } = Astro.props;
const { params, canonicalURL} = Astro.request; const { params, canonicalURL} = Astro;
--- ---
<html> <html>

View file

@ -4,7 +4,7 @@ export async function getStaticPaths({paginate}) {
return paginate(data, {pageSize: 1}); return paginate(data, {pageSize: 1});
} }
const { page } = Astro.props; const { page } = Astro.props;
const { params, canonicalURL} = Astro.request; const { params, canonicalURL} = Astro;
--- ---
<html> <html>

View file

@ -4,7 +4,7 @@ export async function getStaticPaths({paginate}) {
return paginate(data, {pageSize: 1}); return paginate(data, {pageSize: 1});
} }
const { page } = Astro.props; const { page } = Astro.props;
const { params, canonicalURL} = Astro.request; const { params, canonicalURL} = Astro;
--- ---
<html> <html>

View file

@ -1,5 +1,5 @@
--- ---
const val = Number(Astro.request.params.id); const val = Number(Astro.params.id);
--- ---
<html> <html>
<head> <head>