Start of devapp exploration
This commit is contained in:
parent
8b7cb64dad
commit
4ce0b918b1
5 changed files with 148 additions and 28 deletions
88
packages/astro/src/core/app/dev.ts
Normal file
88
packages/astro/src/core/app/dev.ts
Normal file
|
@ -0,0 +1,88 @@
|
|||
import type { ManifestData, RouteData } from '../../@types/astro';
|
||||
import type { SSRManifest as Manifest } from './types';
|
||||
import { createContainer, type CreateContainerParams } from '../dev/index.js';
|
||||
import { createViteLoader } from '../module-loader/index.js';
|
||||
import { createRouteManifest } from '../routing/index.js';
|
||||
import { createDevelopmentEnvironment, preload, type DevelopmentEnvironment } from '../render/dev/index.js';
|
||||
import { App, MatchOptions } from './index.js';
|
||||
|
||||
export type DevAppParams = Partial<CreateContainerParams> & {
|
||||
root: URL;
|
||||
}
|
||||
|
||||
export class DevApp extends App {
|
||||
#createContainerParams: CreateContainerParams;
|
||||
#manifest: Manifest;
|
||||
#container: Awaited<ReturnType<typeof createContainer>> | null = null;
|
||||
#env: DevelopmentEnvironment | null = null;
|
||||
#root: URL;
|
||||
constructor(params: DevAppParams) {
|
||||
const { root, userConfig } = params;
|
||||
const manifest: Manifest = {
|
||||
adapterName: 'development',
|
||||
base: userConfig?.base,
|
||||
routes: [],
|
||||
markdown: {
|
||||
contentDir: root
|
||||
},
|
||||
pageMap: new Map(),
|
||||
renderers: [],
|
||||
entryModules: {},
|
||||
assets: new Set(),
|
||||
propagation: new Map(),
|
||||
trailingSlash: userConfig?.trailingSlash ?? 'ignore'
|
||||
};
|
||||
super(manifest, true);
|
||||
this.#manifest = manifest;
|
||||
this.#root = root;
|
||||
this.#createContainerParams = params;
|
||||
}
|
||||
|
||||
async load() {
|
||||
const container = this.#container = await createContainer(this.#createContainerParams);
|
||||
this.#manifest.trailingSlash = container.settings.config.trailingSlash;
|
||||
|
||||
const loader = createViteLoader(container.viteServer);
|
||||
|
||||
const routeManifest = createRouteManifest({
|
||||
settings: container.settings,
|
||||
fsMod: this.#createContainerParams.fs
|
||||
}, container.logging);
|
||||
const routes = routeManifest.routes.map(routeData => {
|
||||
return {
|
||||
routeData,
|
||||
file: routeData.component,
|
||||
links: [],
|
||||
scripts: []
|
||||
}
|
||||
});
|
||||
this.updateRoutes(routes);
|
||||
this.#env = createDevelopmentEnvironment(container.settings, container.logging, loader);
|
||||
return this;
|
||||
}
|
||||
|
||||
async close() {
|
||||
await this.#container?.close();
|
||||
}
|
||||
|
||||
async render(request: Request, route?: RouteData | undefined): Promise<Response> {
|
||||
if(!this.#env) {
|
||||
await this.load();
|
||||
}
|
||||
if(!route) {
|
||||
route = this.match(request, { matchNotFound: false });
|
||||
}
|
||||
if(route) {
|
||||
const filePath = new URL(route.component, this.#root);
|
||||
debugger;
|
||||
const [renderers, mod] = await preload({
|
||||
env: this.#env!,
|
||||
filePath
|
||||
});
|
||||
this.#manifest.renderers.length = 0;
|
||||
this.#manifest.renderers.push(...renderers);
|
||||
this.#manifest.pageMap.set(route.component, mod);
|
||||
}
|
||||
return super.render(request, route);
|
||||
}
|
||||
}
|
|
@ -38,8 +38,8 @@ export interface MatchOptions {
|
|||
export class App {
|
||||
#env: Environment;
|
||||
#manifest: Manifest;
|
||||
#manifestData: ManifestData;
|
||||
#routeDataToRouteInfo: Map<RouteData, RouteInfo>;
|
||||
#manifestData: ManifestData = { routes: [] };
|
||||
#routeDataToRouteInfo: Map<RouteData, RouteInfo> = new Map();
|
||||
#encoder = new TextEncoder();
|
||||
#logging: LogOptions = {
|
||||
dest: consoleLogDestination,
|
||||
|
@ -50,10 +50,7 @@ export class App {
|
|||
|
||||
constructor(manifest: Manifest, streaming = true) {
|
||||
this.#manifest = manifest;
|
||||
this.#manifestData = {
|
||||
routes: manifest.routes.map((route) => route.routeData),
|
||||
};
|
||||
this.#routeDataToRouteInfo = new Map(manifest.routes.map((route) => [route.routeData, route]));
|
||||
this.updateRoutes(manifest.routes);
|
||||
this.#env = createEnvironment({
|
||||
adapterName: manifest.adapterName,
|
||||
logging: this.#logging,
|
||||
|
@ -84,6 +81,12 @@ export class App {
|
|||
this.#base = this.#manifest.base || '/';
|
||||
this.#baseWithoutTrailingSlash = removeTrailingForwardSlash(this.#base);
|
||||
}
|
||||
updateRoutes(routes: RouteInfo[]) {
|
||||
this.#manifestData = {
|
||||
routes: routes.map((route) => route.routeData),
|
||||
};
|
||||
this.#routeDataToRouteInfo = new Map(routes.map((route) => [route.routeData, route]));
|
||||
}
|
||||
removeBase(pathname: string) {
|
||||
if (pathname.startsWith(this.#base)) {
|
||||
return pathname.slice(this.#baseWithoutTrailingSlash.length + 1);
|
||||
|
@ -96,7 +99,13 @@ export class App {
|
|||
if (this.#manifest.assets.has(url.pathname)) {
|
||||
return undefined;
|
||||
}
|
||||
let pathname = '/' + this.removeBase(url.pathname);
|
||||
let noBase = this.removeBase(url.pathname);
|
||||
let pathname: string;
|
||||
if(this.#manifest.trailingSlash === 'never' && noBase === '') {
|
||||
pathname = noBase;
|
||||
} else {
|
||||
pathname = prependForwardSlash(noBase);
|
||||
}
|
||||
let routeData = matchRoute(pathname, this.#manifestData);
|
||||
|
||||
if (routeData) {
|
||||
|
|
|
@ -215,6 +215,7 @@ function buildManifest(
|
|||
renderers: [],
|
||||
entryModules,
|
||||
assets: staticFiles.map((s) => settings.config.base + s),
|
||||
trailingSlash: opts.settings.config.trailingSlash,
|
||||
};
|
||||
|
||||
return ssrManifest;
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
export { createContainer, isStarted, runInContainer, startContainer } from './container.js';
|
||||
export { createContainer, isStarted, runInContainer, startContainer, type CreateContainerParams } from './container.js';
|
||||
export { default } from './dev.js';
|
||||
export { createContainerWithAutomaticRestart } from './restart.js';
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import { expect } from 'chai';
|
||||
|
||||
import { runInContainer } from '../../../dist/core/dev/index.js';
|
||||
import { DevApp } from '../../../dist/core/app/dev.js';
|
||||
import { createFs, createRequestAndResponse } from '../test-utils.js';
|
||||
|
||||
const root = new URL('../../fixtures/alias/', import.meta.url);
|
||||
|
@ -16,28 +17,22 @@ describe('base configuration', () => {
|
|||
root
|
||||
);
|
||||
|
||||
await runInContainer(
|
||||
{
|
||||
fs,
|
||||
root,
|
||||
userConfig: {
|
||||
base: '/docs',
|
||||
trailingSlash: 'never',
|
||||
},
|
||||
const app = new DevApp({
|
||||
root,
|
||||
fs,
|
||||
userConfig: {
|
||||
base: '/docs',
|
||||
trailingSlash: 'never',
|
||||
},
|
||||
async (container) => {
|
||||
const { req, res, done } = createRequestAndResponse({
|
||||
method: 'GET',
|
||||
url: '/docs/',
|
||||
});
|
||||
container.handle(req, res);
|
||||
await done;
|
||||
expect(res.statusCode).to.equal(404);
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
const request = new Request(`http://localhost:8080/docs/`);
|
||||
const response = await app.render(request);
|
||||
|
||||
expect(response.status).to.equal(404);
|
||||
});
|
||||
|
||||
it('Requests that exclude a trailing slash 200', async () => {
|
||||
it.only('Requests that exclude a trailing slash 200', async () => {
|
||||
const fs = createFs(
|
||||
{
|
||||
'/src/pages/index.astro': `<h1>testing</h1>`,
|
||||
|
@ -45,6 +40,31 @@ describe('base configuration', () => {
|
|||
root
|
||||
);
|
||||
|
||||
const app = new DevApp({
|
||||
root,
|
||||
fs,
|
||||
userConfig: {
|
||||
base: '/docs',
|
||||
trailingSlash: 'never',
|
||||
},
|
||||
});
|
||||
|
||||
try {
|
||||
const request = new Request(`http://localhost:8080/docs`);
|
||||
|
||||
debugger;
|
||||
const response = await app.render(request);
|
||||
|
||||
expect(response.status).to.equal(200);
|
||||
console.log(await response.text());
|
||||
} finally {
|
||||
await app.close();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
|
||||
await runInContainer(
|
||||
{
|
||||
fs,
|
||||
|
@ -55,7 +75,7 @@ describe('base configuration', () => {
|
|||
},
|
||||
},
|
||||
async (container) => {
|
||||
const { req, res, done } = createRequestAndResponse({
|
||||
const { req, res, done, text } = createRequestAndResponse({
|
||||
method: 'GET',
|
||||
url: '/docs',
|
||||
});
|
||||
|
@ -64,6 +84,8 @@ describe('base configuration', () => {
|
|||
expect(res.statusCode).to.equal(200);
|
||||
}
|
||||
);
|
||||
*/
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
|
|
Loading…
Reference in a new issue