Skip to content

Commit 65ddb02

Browse files
authoredDec 8, 2023
Preserve generating routes that end with .mjs (#9374)
1 parent 26f7023 commit 65ddb02

File tree

7 files changed

+76
-39
lines changed

7 files changed

+76
-39
lines changed
 

‎.changeset/shiny-glasses-care.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'astro': patch
3+
---
4+
5+
Fixes an issue where prerendered route paths that end with `.mjs` were removed from the final build

‎packages/astro/src/core/build/index.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -198,8 +198,8 @@ class AstroBuilder {
198198
viteConfig,
199199
};
200200

201-
const { internals } = await viteBuild(opts);
202-
await staticBuild(opts, internals);
201+
const { internals, ssrOutputChunkNames } = await viteBuild(opts);
202+
await staticBuild(opts, internals, ssrOutputChunkNames);
203203

204204
// Write any additionally generated assets to disk.
205205
this.timer.assetsStart = performance.now();

‎packages/astro/src/core/build/plugin.ts

+2-16
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { Plugin as VitePlugin } from 'vite';
1+
import type { Plugin as VitePlugin, Rollup } from 'vite';
22
import type { BuildInternals } from './internal.js';
33
import type { StaticBuildOptions, ViteBuildReturn } from './types.js';
44

@@ -68,28 +68,14 @@ export function createPluginContainer(options: StaticBuildOptions, internals: Bu
6868
};
6969
},
7070

71-
async runPostHook(ssrReturn: ViteBuildReturn, clientReturn: ViteBuildReturn | null) {
71+
async runPostHook(ssrOutputs: Rollup.RollupOutput[], clientOutputs: Rollup.RollupOutput[]) {
7272
const mutations = new Map<
7373
string,
7474
{
7575
targets: BuildTarget[];
7676
code: string;
7777
}
7878
>();
79-
const ssrOutputs: RollupOutputArray = [];
80-
const clientOutputs: RollupOutputArray = [];
81-
82-
if (Array.isArray(ssrReturn)) {
83-
ssrOutputs.push(...ssrReturn);
84-
} else if ('output' in ssrReturn) {
85-
ssrOutputs.push(ssrReturn);
86-
}
87-
88-
if (Array.isArray(clientReturn)) {
89-
clientOutputs.push(...clientReturn);
90-
} else if (clientReturn && 'output' in clientReturn) {
91-
clientOutputs.push(clientReturn);
92-
}
9379

9480
const mutate: MutateChunk = (chunk, targets, newCode) => {
9581
chunk.code = newCode;

‎packages/astro/src/core/build/static-build.ts

+36-21
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ import { RESOLVED_RENDERERS_MODULE_ID } from './plugins/plugin-renderers.js';
3333
import { RESOLVED_SPLIT_MODULE_ID, RESOLVED_SSR_VIRTUAL_MODULE_ID } from './plugins/plugin-ssr.js';
3434
import { ASTRO_PAGE_EXTENSION_POST_PATTERN } from './plugins/util.js';
3535
import type { StaticBuildOptions } from './types.js';
36-
import { encodeName, getTimeStat } from './util.js';
36+
import { encodeName, getTimeStat, viteBuildReturnToRollupOutputs } from './util.js';
3737

3838
export async function viteBuild(opts: StaticBuildOptions) {
3939
const { allPages, settings } = opts;
@@ -103,7 +103,9 @@ export async function viteBuild(opts: StaticBuildOptions) {
103103
// Run client build first, so the assets can be fed into the SSR rendered version.
104104
const clientOutput = await clientBuild(opts, internals, clientInput, container);
105105

106-
await runPostBuildHooks(container, ssrOutput, clientOutput);
106+
const ssrOutputs = viteBuildReturnToRollupOutputs(ssrOutput);
107+
const clientOutputs = viteBuildReturnToRollupOutputs(clientOutput ?? []);
108+
await runPostBuildHooks(container, ssrOutputs, clientOutputs);
107109

108110
settings.timer.end('Client build');
109111

@@ -113,23 +115,38 @@ export async function viteBuild(opts: StaticBuildOptions) {
113115
teardown();
114116
}
115117

116-
return { internals };
118+
// For static builds, the SSR output output won't be needed anymore after page generation.
119+
// We keep track of the names here so we only remove these specific files when finished.
120+
const ssrOutputChunkNames: string[] = [];
121+
for (const output of ssrOutputs) {
122+
for (const chunk of output.output) {
123+
if (chunk.type === 'chunk') {
124+
ssrOutputChunkNames.push(chunk.fileName);
125+
}
126+
}
127+
}
128+
129+
return { internals, ssrOutputChunkNames };
117130
}
118131

119-
export async function staticBuild(opts: StaticBuildOptions, internals: BuildInternals) {
132+
export async function staticBuild(
133+
opts: StaticBuildOptions,
134+
internals: BuildInternals,
135+
ssrOutputChunkNames: string[]
136+
) {
120137
const { settings } = opts;
121138
switch (true) {
122139
case settings.config.output === 'static': {
123140
settings.timer.start('Static generate');
124141
await generatePages(opts, internals);
125-
await cleanServerOutput(opts);
142+
await cleanServerOutput(opts, ssrOutputChunkNames);
126143
settings.timer.end('Static generate');
127144
return;
128145
}
129146
case isServerLikeOutput(settings.config): {
130147
settings.timer.start('Server generate');
131148
await generatePages(opts, internals);
132-
await cleanStaticOutput(opts, internals);
149+
await cleanStaticOutput(opts, internals, ssrOutputChunkNames);
133150
opts.logger.info(null, `\n${bgMagenta(black(' finalizing server assets '))}\n`);
134151
await ssrMoveAssets(opts);
135152
settings.timer.end('Server generate');
@@ -324,10 +341,10 @@ async function clientBuild(
324341

325342
async function runPostBuildHooks(
326343
container: AstroBuildPluginContainer,
327-
ssrReturn: Awaited<ReturnType<typeof ssrBuild>>,
328-
clientReturn: Awaited<ReturnType<typeof clientBuild>>
344+
ssrOutputs: vite.Rollup.RollupOutput[],
345+
clientOutputs: vite.Rollup.RollupOutput[]
329346
) {
330-
const mutations = await container.runPostHook(ssrReturn, clientReturn);
347+
const mutations = await container.runPostHook(ssrOutputs, clientOutputs);
331348
const config = container.options.settings.config;
332349
const build = container.options.settings.config.build;
333350
for (const [fileName, mutation] of mutations) {
@@ -347,7 +364,11 @@ async function runPostBuildHooks(
347364
* For each statically prerendered page, replace their SSR file with a noop.
348365
* This allows us to run the SSR build only once, but still remove dependencies for statically rendered routes.
349366
*/
350-
async function cleanStaticOutput(opts: StaticBuildOptions, internals: BuildInternals) {
367+
async function cleanStaticOutput(
368+
opts: StaticBuildOptions,
369+
internals: BuildInternals,
370+
ssrOutputChunkNames: string[]
371+
) {
351372
const allStaticFiles = new Set();
352373
for (const pageData of eachPageData(internals)) {
353374
if (pageData.route.prerender) {
@@ -361,10 +382,8 @@ async function cleanStaticOutput(opts: StaticBuildOptions, internals: BuildInter
361382
const out = ssr
362383
? opts.settings.config.build.server
363384
: getOutDirWithinCwd(opts.settings.config.outDir);
364-
// The SSR output is all .mjs files, the client output is not.
365-
const files = await glob('**/*.mjs', {
366-
cwd: fileURLToPath(out),
367-
});
385+
// The SSR output chunks for Astro are all .mjs files
386+
const files = ssrOutputChunkNames.filter((f) => f.endsWith('.mjs'));
368387

369388
if (files.length) {
370389
await eslexer.init;
@@ -394,14 +413,10 @@ async function cleanStaticOutput(opts: StaticBuildOptions, internals: BuildInter
394413
}
395414
}
396415

397-
async function cleanServerOutput(opts: StaticBuildOptions) {
416+
async function cleanServerOutput(opts: StaticBuildOptions, ssrOutputChunkNames: string[]) {
398417
const out = getOutDirWithinCwd(opts.settings.config.outDir);
399-
// The SSR output is all .mjs files, the client output is not.
400-
const files = await glob('**/*.mjs', {
401-
cwd: fileURLToPath(out),
402-
// Important! Also cleanup dotfiles like `node_modules/.pnpm/**`
403-
dot: true,
404-
});
418+
// The SSR output chunks for Astro are all .mjs files
419+
const files = ssrOutputChunkNames.filter((f) => f.endsWith('.mjs'));
405420
if (files.length) {
406421
// Remove all the SSR generated .mjs files
407422
await Promise.all(

‎packages/astro/src/core/build/util.ts

+14
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1+
import type { Rollup } from 'vite';
12
import type { AstroConfig } from '../../@types/astro.js';
3+
import type { ViteBuildReturn } from './types.js';
24

35
export function getTimeStat(timeStart: number, timeEnd: number) {
46
const buildTime = timeEnd - timeStart;
@@ -52,3 +54,15 @@ export function encodeName(name: string): string {
5254

5355
return name;
5456
}
57+
58+
export function viteBuildReturnToRollupOutputs(
59+
viteBuildReturn: ViteBuildReturn
60+
): Rollup.RollupOutput[] {
61+
const result: Rollup.RollupOutput[] = [];
62+
if (Array.isArray(viteBuildReturn)) {
63+
result.push(...viteBuildReturn);
64+
} else if ('output' in viteBuildReturn) {
65+
result.push(viteBuildReturn);
66+
}
67+
return result;
68+
}

‎packages/astro/test/astro-basic.test.js

+7
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,13 @@ describe('Astro basics', () => {
151151
expect($('body > :nth-child(5)').prop('outerHTML')).to.equal('<textarea>textarea</textarea>');
152152
});
153153

154+
it('Generates pages that end with .mjs', async () => {
155+
const content1 = await fixture.readFile('/get-static-paths-with-mjs/example.mjs');
156+
expect(content1).to.be.ok;
157+
const content2 = await fixture.readFile('/get-static-paths-with-mjs/example.js');
158+
expect(content2).to.be.ok;
159+
});
160+
154161
describe('preview', () => {
155162
it('returns 200 for valid URLs', async () => {
156163
const result = await fixture.fetch('/');
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
export function getStaticPaths() {
2+
return [
3+
{ params: { file: 'example.mjs' } },
4+
{ params: { file: 'example.js' } },
5+
];
6+
}
7+
8+
export function GET() {
9+
return new Response('console.log("fileContent");')
10+
}

0 commit comments

Comments
 (0)
Please sign in to comment.