0
Fork 0
mirror of https://github.com/withastro/astro.git synced 2024-12-16 21:46:22 -05:00

Preserve generating routes that end with .mjs (#9374)

This commit is contained in:
Bjorn Lu 2023-12-08 23:39:13 +08:00 committed by GitHub
parent 26f7023d69
commit 65ddb02711
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 76 additions and 39 deletions

View file

@ -0,0 +1,5 @@
---
'astro': patch
---
Fixes an issue where prerendered route paths that end with `.mjs` were removed from the final build

View file

@ -198,8 +198,8 @@ class AstroBuilder {
viteConfig,
};
const { internals } = await viteBuild(opts);
await staticBuild(opts, internals);
const { internals, ssrOutputChunkNames } = await viteBuild(opts);
await staticBuild(opts, internals, ssrOutputChunkNames);
// Write any additionally generated assets to disk.
this.timer.assetsStart = performance.now();

View file

@ -1,4 +1,4 @@
import type { Plugin as VitePlugin } from 'vite';
import type { Plugin as VitePlugin, Rollup } from 'vite';
import type { BuildInternals } from './internal.js';
import type { StaticBuildOptions, ViteBuildReturn } from './types.js';
@ -68,7 +68,7 @@ export function createPluginContainer(options: StaticBuildOptions, internals: Bu
};
},
async runPostHook(ssrReturn: ViteBuildReturn, clientReturn: ViteBuildReturn | null) {
async runPostHook(ssrOutputs: Rollup.RollupOutput[], clientOutputs: Rollup.RollupOutput[]) {
const mutations = new Map<
string,
{
@ -76,20 +76,6 @@ export function createPluginContainer(options: StaticBuildOptions, internals: Bu
code: string;
}
>();
const ssrOutputs: RollupOutputArray = [];
const clientOutputs: RollupOutputArray = [];
if (Array.isArray(ssrReturn)) {
ssrOutputs.push(...ssrReturn);
} else if ('output' in ssrReturn) {
ssrOutputs.push(ssrReturn);
}
if (Array.isArray(clientReturn)) {
clientOutputs.push(...clientReturn);
} else if (clientReturn && 'output' in clientReturn) {
clientOutputs.push(clientReturn);
}
const mutate: MutateChunk = (chunk, targets, newCode) => {
chunk.code = newCode;

View file

@ -33,7 +33,7 @@ import { RESOLVED_RENDERERS_MODULE_ID } from './plugins/plugin-renderers.js';
import { RESOLVED_SPLIT_MODULE_ID, RESOLVED_SSR_VIRTUAL_MODULE_ID } from './plugins/plugin-ssr.js';
import { ASTRO_PAGE_EXTENSION_POST_PATTERN } from './plugins/util.js';
import type { StaticBuildOptions } from './types.js';
import { encodeName, getTimeStat } from './util.js';
import { encodeName, getTimeStat, viteBuildReturnToRollupOutputs } from './util.js';
export async function viteBuild(opts: StaticBuildOptions) {
const { allPages, settings } = opts;
@ -103,7 +103,9 @@ export async function viteBuild(opts: StaticBuildOptions) {
// Run client build first, so the assets can be fed into the SSR rendered version.
const clientOutput = await clientBuild(opts, internals, clientInput, container);
await runPostBuildHooks(container, ssrOutput, clientOutput);
const ssrOutputs = viteBuildReturnToRollupOutputs(ssrOutput);
const clientOutputs = viteBuildReturnToRollupOutputs(clientOutput ?? []);
await runPostBuildHooks(container, ssrOutputs, clientOutputs);
settings.timer.end('Client build');
@ -113,23 +115,38 @@ export async function viteBuild(opts: StaticBuildOptions) {
teardown();
}
return { internals };
// For static builds, the SSR output output won't be needed anymore after page generation.
// We keep track of the names here so we only remove these specific files when finished.
const ssrOutputChunkNames: string[] = [];
for (const output of ssrOutputs) {
for (const chunk of output.output) {
if (chunk.type === 'chunk') {
ssrOutputChunkNames.push(chunk.fileName);
}
}
}
export async function staticBuild(opts: StaticBuildOptions, internals: BuildInternals) {
return { internals, ssrOutputChunkNames };
}
export async function staticBuild(
opts: StaticBuildOptions,
internals: BuildInternals,
ssrOutputChunkNames: string[]
) {
const { settings } = opts;
switch (true) {
case settings.config.output === 'static': {
settings.timer.start('Static generate');
await generatePages(opts, internals);
await cleanServerOutput(opts);
await cleanServerOutput(opts, ssrOutputChunkNames);
settings.timer.end('Static generate');
return;
}
case isServerLikeOutput(settings.config): {
settings.timer.start('Server generate');
await generatePages(opts, internals);
await cleanStaticOutput(opts, internals);
await cleanStaticOutput(opts, internals, ssrOutputChunkNames);
opts.logger.info(null, `\n${bgMagenta(black(' finalizing server assets '))}\n`);
await ssrMoveAssets(opts);
settings.timer.end('Server generate');
@ -324,10 +341,10 @@ async function clientBuild(
async function runPostBuildHooks(
container: AstroBuildPluginContainer,
ssrReturn: Awaited<ReturnType<typeof ssrBuild>>,
clientReturn: Awaited<ReturnType<typeof clientBuild>>
ssrOutputs: vite.Rollup.RollupOutput[],
clientOutputs: vite.Rollup.RollupOutput[]
) {
const mutations = await container.runPostHook(ssrReturn, clientReturn);
const mutations = await container.runPostHook(ssrOutputs, clientOutputs);
const config = container.options.settings.config;
const build = container.options.settings.config.build;
for (const [fileName, mutation] of mutations) {
@ -347,7 +364,11 @@ async function runPostBuildHooks(
* For each statically prerendered page, replace their SSR file with a noop.
* This allows us to run the SSR build only once, but still remove dependencies for statically rendered routes.
*/
async function cleanStaticOutput(opts: StaticBuildOptions, internals: BuildInternals) {
async function cleanStaticOutput(
opts: StaticBuildOptions,
internals: BuildInternals,
ssrOutputChunkNames: string[]
) {
const allStaticFiles = new Set();
for (const pageData of eachPageData(internals)) {
if (pageData.route.prerender) {
@ -361,10 +382,8 @@ async function cleanStaticOutput(opts: StaticBuildOptions, internals: BuildInter
const out = ssr
? opts.settings.config.build.server
: getOutDirWithinCwd(opts.settings.config.outDir);
// The SSR output is all .mjs files, the client output is not.
const files = await glob('**/*.mjs', {
cwd: fileURLToPath(out),
});
// The SSR output chunks for Astro are all .mjs files
const files = ssrOutputChunkNames.filter((f) => f.endsWith('.mjs'));
if (files.length) {
await eslexer.init;
@ -394,14 +413,10 @@ async function cleanStaticOutput(opts: StaticBuildOptions, internals: BuildInter
}
}
async function cleanServerOutput(opts: StaticBuildOptions) {
async function cleanServerOutput(opts: StaticBuildOptions, ssrOutputChunkNames: string[]) {
const out = getOutDirWithinCwd(opts.settings.config.outDir);
// The SSR output is all .mjs files, the client output is not.
const files = await glob('**/*.mjs', {
cwd: fileURLToPath(out),
// Important! Also cleanup dotfiles like `node_modules/.pnpm/**`
dot: true,
});
// The SSR output chunks for Astro are all .mjs files
const files = ssrOutputChunkNames.filter((f) => f.endsWith('.mjs'));
if (files.length) {
// Remove all the SSR generated .mjs files
await Promise.all(

View file

@ -1,4 +1,6 @@
import type { Rollup } from 'vite';
import type { AstroConfig } from '../../@types/astro.js';
import type { ViteBuildReturn } from './types.js';
export function getTimeStat(timeStart: number, timeEnd: number) {
const buildTime = timeEnd - timeStart;
@ -52,3 +54,15 @@ export function encodeName(name: string): string {
return name;
}
export function viteBuildReturnToRollupOutputs(
viteBuildReturn: ViteBuildReturn
): Rollup.RollupOutput[] {
const result: Rollup.RollupOutput[] = [];
if (Array.isArray(viteBuildReturn)) {
result.push(...viteBuildReturn);
} else if ('output' in viteBuildReturn) {
result.push(viteBuildReturn);
}
return result;
}

View file

@ -151,6 +151,13 @@ describe('Astro basics', () => {
expect($('body > :nth-child(5)').prop('outerHTML')).to.equal('<textarea>textarea</textarea>');
});
it('Generates pages that end with .mjs', async () => {
const content1 = await fixture.readFile('/get-static-paths-with-mjs/example.mjs');
expect(content1).to.be.ok;
const content2 = await fixture.readFile('/get-static-paths-with-mjs/example.js');
expect(content2).to.be.ok;
});
describe('preview', () => {
it('returns 200 for valid URLs', async () => {
const result = await fixture.fetch('/');

View file

@ -0,0 +1,10 @@
export function getStaticPaths() {
return [
{ params: { file: 'example.mjs' } },
{ params: { file: 'example.js' } },
];
}
export function GET() {
return new Response('console.log("fileContent");')
}