wip stable url

This commit is contained in:
bluwy 2023-08-14 21:15:02 +08:00
parent 40efae6550
commit dc1e82d622
16 changed files with 81 additions and 16 deletions

View file

@ -107,6 +107,7 @@ export class App {
},
routeCache: new RouteCache(this.#logging),
site: this.#manifest.site,
base: this.#manifest.base,
ssr: true,
streaming,
});

View file

@ -526,6 +526,7 @@ async function generatePath(
},
routeCache,
site: manifest.site,
base: manifest.base,
ssr,
streaming: true,
});

View file

@ -13,6 +13,7 @@ import { AstroCookies, attachCookiesToResponse } from '../cookies/index.js';
import { AstroError, AstroErrorData } from '../errors/index.js';
import { warn } from '../logger/core.js';
import { callMiddleware } from '../middleware/callMiddleware.js';
import { createRouteUrl } from '../routing/url.js';
const clientAddressSymbol = Symbol.for('astro.clientAddress');
const clientLocalsSymbol = Symbol.for('astro.locals');
@ -31,6 +32,7 @@ type CreateAPIContext = {
request: Request;
params: Params;
site?: string;
routeUrl: URL;
props: Record<string, any>;
adapterName?: string;
};
@ -44,6 +46,7 @@ export function createAPIContext({
request,
params,
site,
routeUrl,
props,
adapterName,
}: CreateAPIContext): APIContext {
@ -62,7 +65,7 @@ export function createAPIContext({
},
});
},
url: new URL(request.url),
url: routeUrl,
get clientAddress() {
if (!(clientAddressSymbol in request)) {
if (adapterName) {
@ -102,11 +105,18 @@ export async function callEndpoint<MiddlewareResult = Response | EndpointOutput>
ctx: RenderContext,
onRequest?: MiddlewareHandler<MiddlewareResult> | undefined
): Promise<EndpointCallResult> {
const routeUrl = createRouteUrl(ctx.route, {
params: ctx.params,
base: env.base,
site: env.site ?? new URL(ctx.request.url).origin,
});
const context = createAPIContext({
request: ctx.request,
params: ctx.params,
props: ctx.props,
site: env.site,
routeUrl,
adapterName: env.adapterName,
});

View file

@ -29,6 +29,7 @@ function createContext({ request, params }: CreateContext) {
params: params ?? {},
props: {},
site: undefined,
routeUrl: new URL(request.url)
});
}

View file

@ -10,6 +10,7 @@ import type {
} from '../@types/astro';
import { callMiddleware } from './middleware/callMiddleware.js';
import { renderPage } from './render/core.js';
import { createRouteUrl } from './routing/url.js';
type EndpointResultHandler = (
originalRequest: Request,
@ -95,11 +96,18 @@ export class Pipeline {
mod: Readonly<ComponentInstance>,
onRequest?: MiddlewareHandler<MiddlewareReturnType>
): Promise<Response | EndpointCallResult> {
const routeUrl = createRouteUrl(renderContext.route, {
params: renderContext.params,
base: env.base,
site: env.site ?? new URL(renderContext.request.url).origin,
});
const apiContext = createAPIContext({
request: renderContext.request,
params: renderContext.params,
props: renderContext.props,
site: env.site,
routeUrl,
adapterName: env.adapterName,
});

View file

@ -11,6 +11,7 @@ import { attachCookiesToResponse } from '../cookies/index.js';
import { callEndpoint, createAPIContext, type EndpointCallResult } from '../endpoint/index.js';
import { callMiddleware } from '../middleware/callMiddleware.js';
import { redirectRouteGenerate, redirectRouteStatus, routeIsRedirect } from '../redirects/index.js';
import { createRouteUrl } from '../routing/url.js';
import type { RenderContext } from './context.js';
import type { Environment } from './environment.js';
import { createResult } from './result.js';
@ -37,11 +38,18 @@ export async function renderPage({ mod, renderContext, env, cookies }: RenderPag
if (!Component)
throw new Error(`Expected an exported Astro component but received typeof ${typeof Component}`);
const routeUrl = createRouteUrl(renderContext.route, {
params: renderContext.params,
base: env.base,
site: env.site ?? new URL(renderContext.request.url).origin,
});
const result = createResult({
adapterName: env.adapterName,
links: renderContext.links,
styles: renderContext.styles,
logging: env.logging,
routeUrl,
params: renderContext.params,
pathname: renderContext.pathname,
componentMetadata: renderContext.componentMetadata,
@ -93,11 +101,18 @@ export async function tryRenderRoute<MiddlewareReturnType = Response>(
mod: Readonly<ComponentInstance>,
onRequest?: MiddlewareHandler<MiddlewareReturnType>
): Promise<Response | EndpointCallResult> {
const routeUrl = createRouteUrl(renderContext.route, {
params: renderContext.params,
base: env.base,
site: env.site ?? new URL(renderContext.request.url).origin,
});
const apiContext = createAPIContext({
request: renderContext.request,
params: renderContext.params,
props: renderContext.props,
site: env.site,
routeUrl,
adapterName: env.adapterName,
});

View file

@ -26,6 +26,10 @@ export interface Environment {
* Used for `Astro.site`
*/
site?: string;
/**
* Used to derive `Astro.url`
*/
base?: string;
/**
* Value of Astro config's `output` option, true if "server" or "hybrid"
*/

View file

@ -36,6 +36,10 @@ export interface CreateResultArgs {
* Used for `Astro.site`
*/
site: string | undefined;
/**
* Used for `Astro.url`. A stable route usually derived from `RouteData`.
*/
routeUrl: URL;
links?: Set<SSRElement>;
scripts?: Set<SSRElement>;
styles?: Set<SSRElement>;
@ -126,7 +130,6 @@ class Slots {
export function createResult(args: CreateResultArgs): SSRResult {
const { params, request, resolve, locals } = args;
const url = new URL(request.url);
const headers = new Headers();
headers.set('Content-Type', 'text/html');
const response: ResponseInit = {
@ -195,7 +198,7 @@ export function createResult(args: CreateResultArgs): SSRResult {
props,
locals,
request,
url,
url: args.routeUrl,
redirect(path, status) {
// If the response is already sent, error as we cannot proceed with the redirect.
if ((request as any)[responseSentSymbol]) {

View file

@ -2,4 +2,5 @@ export { createRouteManifest } from './manifest/create.js';
export { deserializeRouteData, serializeRouteData } from './manifest/serialization.js';
export { matchAllRoutes, matchRoute } from './match.js';
export { getParams } from './params.js';
export { createRouteUrl } from './url.js';
export { validateDynamicRouteModule, validateGetStaticPathsResult } from './validation.js';

View file

@ -0,0 +1,24 @@
import type { Params, RouteData } from '../../@types/astro.js';
import { joinPaths } from '../path.js';
interface CreateUrlOptions {
params?: Params;
site?: string;
base?: string;
}
export function createRouteUrl(route: RouteData, options: CreateUrlOptions) {
const site = options.site ?? 'http://localhost:4321';
const base = options.base ?? '/';
// Tests don't implement generate, do a dirty skip here
if (route.generate == null) {
return new URL(base, site);
}
const pathnameWithoutBase = route.generate(options.params);
// If the pathname is empty (root without trailing slash), return it as is so the final
// URL also doesn't have a trailing slash
const pathname = pathnameWithoutBase === '' ? '' : joinPaths(base, pathnameWithoutBase);
return new URL(pathname, site);
}

View file

@ -25,6 +25,7 @@ export function createDevelopmentEnvironment(
resolve: createResolve(loader, settings.config.root),
routeCache: new RouteCache(logging, mode),
site: manifest.site,
base: manifest.base,
ssr: isServerLikeOutput(settings.config),
streaming: true,
});

View file

@ -29,7 +29,7 @@ describe('getStaticPaths - build calls', () => {
const html = await fixture.readFile('/food/tacos/index.html');
const $ = cheerio.load(html);
expect($('#url').text()).to.equal('/blog/food/tacos/');
expect($('#url').text()).to.equal('/blog/food/tacos');
});
});

View file

@ -24,16 +24,16 @@ describe('Astro Global', () => {
await devServer.stop();
});
it('Astro.request.url', async () => {
it('Astro.url', async () => {
const res = await await fixture.fetch('/blog/?foo=42');
expect(res.status).to.equal(200);
const html = await res.text();
const $ = cheerio.load(html);
expect($('#pathname').text()).to.equal('/blog/');
expect($('#pathname').text()).to.equal('/blog');
expect($('#searchparams').text()).to.equal('{}');
expect($('#child-pathname').text()).to.equal('/blog/');
expect($('#nested-child-pathname').text()).to.equal('/blog/');
expect($('#child-pathname').text()).to.equal('/blog');
expect($('#nested-child-pathname').text()).to.equal('/blog');
});
it('Astro.glob() returned `url` metadata of each markdown file extensions DOES NOT include the extension', async () => {

View file

@ -38,7 +38,7 @@ describe('Prerender', () => {
const $ = cheerio.load(html);
expect($('#props').text()).to.equal('10');
expect($('#url').text()).to.equal('/blog/food/tacos/');
expect($('#url').text()).to.equal('/blog/food/tacos');
});
});
@ -169,7 +169,7 @@ describe('Prerender', () => {
const $ = cheerio.load(html);
expect($('#props').text()).to.equal('10');
expect($('#url').text()).to.equal('/blog/food/tacos/');
expect($('#url').text()).to.equal('/blog/food/tacos');
});
});

View file

@ -50,8 +50,8 @@ describe('Using Astro.request in SSR', () => {
const html = await response.text();
const $ = cheerioLoad(html);
expect($('#origin').text()).to.equal('http://example.com');
expect($('#pathname').text()).to.equal('/subpath/request/');
expect($('#request-pathname').text()).to.equal('/subpath/request/');
expect($('#pathname').text()).to.equal('/subpath/request');
expect($('#request-pathname').text()).to.equal('/subpath/request');
});
it('public file is copied over', async () => {

View file

@ -18263,25 +18263,21 @@ packages:
file:packages/astro/test/fixtures/css-assets/packages/font-awesome:
resolution: {directory: packages/astro/test/fixtures/css-assets/packages/font-awesome, type: directory}
name: '@test/astro-font-awesome-package'
version: 0.0.1
dev: false
file:packages/astro/test/fixtures/multiple-renderers/renderers/one:
resolution: {directory: packages/astro/test/fixtures/multiple-renderers/renderers/one, type: directory}
name: '@test/astro-renderer-one'
version: 1.0.0
dev: false
file:packages/astro/test/fixtures/multiple-renderers/renderers/two:
resolution: {directory: packages/astro/test/fixtures/multiple-renderers/renderers/two, type: directory}
name: '@test/astro-renderer-two'
version: 1.0.0
dev: false
file:packages/astro/test/fixtures/solid-component/deps/solid-jsx-component:
resolution: {directory: packages/astro/test/fixtures/solid-component/deps/solid-jsx-component, type: directory}
name: '@test/solid-jsx-component'
version: 0.0.0
dependencies:
solid-js: 1.7.6
dev: false