Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix script injection during build #12392

Merged
merged 16 commits into from
Nov 14, 2024
5 changes: 5 additions & 0 deletions .changeset/slimy-pets-lick.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'astro': patch
---

Fixes an issue where scripts were not correctly injected during the build. The issue was triggered when there were injected routes with the same `entrypoint` and different `pattern`
2 changes: 1 addition & 1 deletion packages/astro/src/core/build/plugins/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export function registerAllPlugins({ internals, options, register }: AstroBuildP
if (options.settings.config.experimental.directRenderScript) {
register(pluginScripts(internals));
} else {
register(pluginHoistedScripts(options, internals));
register(pluginHoistedScripts(internals));
}
register(pluginSSR(options, internals));
register(pluginSSRSplit(options, internals));
Expand Down
38 changes: 14 additions & 24 deletions packages/astro/src/core/build/plugins/plugin-hoisted-scripts.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,14 @@
import type { BuildOptions, Rollup, Plugin as VitePlugin } from 'vite';
import type { AstroSettings } from '../../../@types/astro.js';
import { viteID } from '../../util.js';
import type { BuildInternals } from '../internal.js';
import { getPageDataByViteID } from '../internal.js';
import { getPageDatasByHoistedScriptId } from '../internal.js';
import type { AstroBuildPlugin } from '../plugin.js';
import type { StaticBuildOptions } from '../types.js';
import { shouldInlineAsset } from './util.js';

function virtualHoistedEntry(id: string) {
return id.startsWith('/astro/hoisted.js?q=');
}

export function vitePluginHoistedScripts(
settings: AstroSettings,
internals: BuildInternals,
): VitePlugin {
let assetsInlineLimit: NonNullable<BuildOptions['assetsInlineLimit']>;
Expand Down Expand Up @@ -73,23 +69,18 @@ export function vitePluginHoistedScripts(
shouldInlineAsset(output.code, output.fileName, assetsInlineLimit);
let removeFromBundle = false;
const facadeId = output.facadeModuleId!;
const pages = internals.hoistedScriptIdToPagesMap.get(facadeId)!;
for (const pathname of pages) {
const vid = viteID(new URL('.' + pathname, settings.config.root));
const pageInfo = getPageDataByViteID(internals, vid);
if (pageInfo) {
if (canBeInlined) {
pageInfo.hoistedScript = {
type: 'inline',
value: output.code,
};
removeFromBundle = true;
} else {
pageInfo.hoistedScript = {
type: 'external',
value: id,
};
}
for (const pageData of getPageDatasByHoistedScriptId(internals, facadeId)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As you noticed from the Github bot comments, settings isn't used anymore, so we can remove it

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed. Thanks.

if (canBeInlined) {
pageData.hoistedScript = {
type: 'inline',
value: output.code,
};
removeFromBundle = true;
} else {
pageData.hoistedScript = {
type: 'external',
value: id,
};
}
}

Expand All @@ -103,15 +94,14 @@ export function vitePluginHoistedScripts(
}

export function pluginHoistedScripts(
options: StaticBuildOptions,
internals: BuildInternals,
): AstroBuildPlugin {
return {
targets: ['client'],
hooks: {
'build:before': () => {
return {
vitePlugin: vitePluginHoistedScripts(options.settings, internals),
vitePlugin: vitePluginHoistedScripts(internals),
};
},
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,6 @@
---
---
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width" />
<title>Routing</title>
</head>
<body>
<h1>to-inject.astro</h1>
</body>
</html>
<h1>to-inject.astro</h1>
<script>
console.log('to-inject.astro');
</script>
26 changes: 24 additions & 2 deletions packages/astro/test/reuse-injected-entrypoint.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,13 @@ const routes = [
description: 'matches /injected-a to to-inject.astro',
url: '/injected-a',
h1: 'to-inject.astro',
scriptContent: 'console.log("to-inject.astro");',
},
{
description: 'matches /injected-b to to-inject.astro',
url: '/injected-b',
h1: 'to-inject.astro',
scriptContent: 'console.log("to-inject.astro");',
},
{
description: 'matches /dynamic-a/id-1 to [id].astro',
Expand Down Expand Up @@ -60,7 +62,7 @@ describe('Reuse injected entrypoint', () => {
await fixture.build();
});

routes.forEach(({ description, url, fourOhFour, h1, p, htmlMatch }) => {
routes.forEach(({ description, url, fourOhFour, h1, p, htmlMatch, scriptContent }) => {
const isEndpoint = htmlMatch && !h1 && !p;

it(description, async () => {
Expand All @@ -85,6 +87,15 @@ describe('Reuse injected entrypoint', () => {
if (htmlMatch) {
assert.equal(html, htmlMatch);
}

if (scriptContent) {
const scriptTags = $('script[type="module"]').toArray();
const scriptFound = scriptTags.some((script) => {
const scriptText = $(script).text();
return scriptText.includes(scriptContent.trim());
});
assert(scriptFound, `Expected script content to be injected in SSG ${url}`);
}
});
});
});
Expand All @@ -105,7 +116,7 @@ describe('Reuse injected entrypoint', () => {
await devServer.stop();
});

routes.forEach(({ description, url, fourOhFour, h1, p, htmlMatch }) => {
routes.forEach(({ description, url, fourOhFour, h1, p, htmlMatch, scriptContent }) => {
// checks URLs as written above
it(description, async () => {
const html = await fixture.fetch(url).then((res) => res.text());
Expand All @@ -127,6 +138,17 @@ describe('Reuse injected entrypoint', () => {
if (htmlMatch) {
assert.equal(html, htmlMatch);
}

if (scriptContent) {
const scriptTags = $('script[type="module"]').toArray();
const scriptFound = scriptTags.some((script) => {
const scriptSrc = $(script).attr('src');
return (
scriptSrc && scriptSrc.includes('/to-inject.astro?astro&type=script&index=0&lang.ts')
);
});
assert(scriptFound, `Expected script content to be injected in dev ${url}`);
}
});
});
});
Expand Down
Loading