Skip to content

Commit

Permalink
Ensure hoisted scripts are deduplicated in build (#3433)
Browse files Browse the repository at this point in the history
* fix(build): ensure hoisted scripts are deduplicated in build

* chore: add changeset
  • Loading branch information
natemoo-re authored May 24, 2022
1 parent 62036ee commit 4ca60e9
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 10 deletions.
5 changes: 5 additions & 0 deletions .changeset/silly-ears-unite.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'astro': patch
---

Fix build issue where hoisted scripts would be duplicated per page
8 changes: 7 additions & 1 deletion packages/astro/src/core/build/internal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@ export interface BuildInternals {
// Pure CSS chunks are chunks that only contain CSS.
pureCSSChunks: Set<RenderedChunk>;

// TODO document what this is
// A mapping of hoisted script ids back to the exact hoisted scripts it references
hoistedScriptIdToHoistedMap: Map<string, Set<string>>;
// A mapping of hoisted script ids back to the pages which reference it
hoistedScriptIdToPagesMap: Map<string, Set<string>>;

// A mapping of specifiers like astro/client/idle.js to the hashed bundled name.
// Used to render pages with the correct specifiers.
Expand Down Expand Up @@ -50,9 +52,13 @@ export function createBuildInternals(): BuildInternals {
// These are for tracking hoisted script bundling
const hoistedScriptIdToHoistedMap = new Map<string, Set<string>>();

// This tracks hoistedScriptId => page components
const hoistedScriptIdToPagesMap = new Map<string, Set<string>>();

return {
pureCSSChunks,
hoistedScriptIdToHoistedMap,
hoistedScriptIdToPagesMap,
entrySpecifierToBundleMap: new Map<string, string>(),

pagesByComponent: new Map(),
Expand Down
23 changes: 21 additions & 2 deletions packages/astro/src/core/build/static-build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export async function staticBuild(opts: StaticBuildOptions) {

// Build internals needed by the CSS plugin
const internals = createBuildInternals();
const uniqueHoistedIds = new Map<string, string>();

const timer: Record<string, number> = {};

Expand Down Expand Up @@ -76,9 +77,27 @@ export async function staticBuild(opts: StaticBuildOptions) {
// Add hoisted scripts
const hoistedScripts = new Set(metadata.hoistedScriptPaths());
if (hoistedScripts.size) {
const moduleId = npath.posix.join(astroModuleId, 'hoisted.js');
internals.hoistedScriptIdToHoistedMap.set(moduleId, hoistedScripts);
const uniqueHoistedId = JSON.stringify(Array.from(hoistedScripts).sort());
let moduleId: string;

// If we're already tracking this set of hoisted scripts, get the unique id
if (uniqueHoistedIds.has(uniqueHoistedId)) {
moduleId = uniqueHoistedIds.get(uniqueHoistedId)!;
} else {
// Otherwise, create a unique id for this set of hoisted scripts
moduleId = `/astro/hoisted.js?q=${uniqueHoistedIds.size}`;
uniqueHoistedIds.set(uniqueHoistedId, moduleId);
}
topLevelImports.add(moduleId);

// Make sure to track that this page uses this set of hoisted scripts
if (internals.hoistedScriptIdToPagesMap.has(moduleId)) {
const pages = internals.hoistedScriptIdToPagesMap.get(moduleId);
pages!.add(astroModuleId);
} else {
internals.hoistedScriptIdToPagesMap.set(moduleId, new Set([astroModuleId]))
internals.hoistedScriptIdToHoistedMap.set(moduleId, hoistedScripts);
}
}

for (const specifier of topLevelImports) {
Expand Down
15 changes: 8 additions & 7 deletions packages/astro/src/core/build/vite-plugin-hoisted-scripts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { viteID } from '../util.js';
import { getPageDataByViteID } from './internal.js';

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

export function vitePluginHoistedScripts(
Expand Down Expand Up @@ -49,12 +49,13 @@ export function vitePluginHoistedScripts(
virtualHoistedEntry(output.facadeModuleId)
) {
const facadeId = output.facadeModuleId!;
const pathname = facadeId.slice(0, facadeId.length - '/hoisted.js'.length);

const vid = viteID(new URL('.' + pathname, astroConfig.root));
const pageInfo = getPageDataByViteID(internals, vid);
if (pageInfo) {
pageInfo.hoistedScript = id;
const pages = internals.hoistedScriptIdToPagesMap.get(facadeId)!;
for (const pathname of pages) {
const vid = viteID(new URL('.' + pathname, astroConfig.root));
const pageInfo = getPageDataByViteID(internals, vid);
if (pageInfo) {
pageInfo.hoistedScript = id;
}
}
}
}
Expand Down

0 comments on commit 4ca60e9

Please sign in to comment.