wip: store propagated scripts separately

This commit is contained in:
bholmesdev 2023-01-30 09:27:12 -05:00
parent a36e8fd912
commit 0577e4e9e4
5 changed files with 98 additions and 20 deletions

View file

@ -75,19 +75,37 @@ export function astroContentProdBundlePlugin({ internals }: { internals: BuildIn
name: 'astro:content-prod-bundle',
async generateBundle(_options, bundle) {
for (const [_, chunk] of Object.entries(bundle)) {
if (chunk.type === 'chunk' && chunk.code.includes(LINKS_PLACEHOLDER)) {
if (
chunk.type === 'chunk' &&
(chunk.code.includes(LINKS_PLACEHOLDER) || chunk.code.includes(SCRIPTS_PLACEHOLDER))
) {
for (const id of Object.keys(chunk.modules)) {
for (const [pageInfo, depth, order] of walkParentInfos(id, this)) {
if (moduleIsTopLevelPage(pageInfo)) {
const pageViteID = pageInfo.id;
const pageData = getPageDataByViteID(internals, pageViteID);
if (!pageData) continue;
console.log({ pageData });
const entryCss = pageData.contentCollectionCss?.get(id);
if (!entryCss) continue;
chunk.code = chunk.code.replace(
JSON.stringify(LINKS_PLACEHOLDER),
JSON.stringify([...entryCss])
);
const entryScripts = pageData.propagatedScripts?.get(id);
if (entryCss) {
chunk.code = chunk.code.replace(
JSON.stringify(LINKS_PLACEHOLDER),
JSON.stringify([...entryCss])
);
}
if (entryScripts) {
console.log({ entryScripts });
chunk.code = chunk.code.replace(
JSON.stringify(SCRIPTS_PLACEHOLDER),
JSON.stringify(
[...entryScripts].map((src) => ({
props: { src, type: 'module' },
children: '',
}))
)
);
}
}
}
}

View file

@ -40,9 +40,10 @@ export function moduleIsTopLevelPage(info: ModuleInfo): boolean {
// This could be a .astro page, a .markdown or a .md (or really any file extension for markdown files) page.
export function* getTopLevelPages(
id: string,
ctx: { getModuleInfo: GetModuleInfo }
ctx: { getModuleInfo: GetModuleInfo },
walkUntil?: (importer: string) => boolean
): Generator<[ModuleInfo, number, number], void, unknown> {
for (const res of walkParentInfos(id, ctx)) {
for (const res of walkParentInfos(id, ctx, walkUntil)) {
if (moduleIsTopLevelPage(res[0])) {
yield res;
}

View file

@ -55,6 +55,7 @@ export async function collectPagesData(
moduleSpecifier: '',
css: new Map(),
contentCollectionCss: new Map(),
propagatedScripts: new Map(),
hoistedScript: undefined,
};
@ -77,6 +78,7 @@ export async function collectPagesData(
moduleSpecifier: '',
css: new Map(),
contentCollectionCss: new Map(),
propagatedScripts: new Map(),
hoistedScript: undefined,
};
}

View file

@ -22,6 +22,7 @@ export interface PageBuildData {
moduleSpecifier: string;
css: Map<string, { depth: number; order: number }>;
contentCollectionCss: Map<string, Set<string>>;
propagatedScripts: Map<string, Set<string>>;
hoistedScript: { type: 'inline' | 'external'; value: string } | undefined;
}
export type AllPagesData = Record<ComponentPath, PageBuildData>;

View file

@ -4,13 +4,24 @@ import type { BuildInternals } from '../../core/build/internal.js';
import type { PluginMetadata as AstroPluginMetadata } from '../../vite-plugin-astro/types';
import { prependForwardSlash } from '../../core/path.js';
import { getTopLevelPages } from './graph.js';
import { getTopLevelPages, moduleIsTopLevelPage, walkParentInfos } from './graph.js';
import { getPageDataByViteID, trackClientOnlyPageDatas } from './internal.js';
import { PROPAGATED_ASSET_FLAG } from '../../content/consts.js';
function isPropagatedAsset(id: string) {
return new URL('file://' + id).searchParams.has(PROPAGATED_ASSET_FLAG);
}
export function vitePluginAnalyzer(internals: BuildInternals): VitePlugin {
function hoistedScriptScanner() {
const uniqueHoistedIds = new Map<string, string>();
const pageScripts = new Map<string, Set<string>>();
const pageScripts = new Map<
string,
{
hoistedSet: Set<string>;
propagatedMapByImporter: Map<string, Set<string>>;
}
>();
return {
scan(this: PluginContext, scripts: AstroPluginMetadata['astro']['scripts'], from: string) {
@ -21,13 +32,36 @@ export function vitePluginAnalyzer(internals: BuildInternals): VitePlugin {
}
if (hoistedScripts.size) {
for (const [pageInfo] of getTopLevelPages(from, this)) {
const pageId = pageInfo.id;
for (const hid of hoistedScripts) {
if (pageScripts.has(pageId)) {
pageScripts.get(pageId)?.add(hid);
} else {
pageScripts.set(pageId, new Set([hid]));
for (const [parentInfo] of walkParentInfos(from, this, function until(importer) {
return isPropagatedAsset(importer);
})) {
if (isPropagatedAsset(parentInfo.id)) {
for (const [nestedParentInfo] of walkParentInfos(from, this)) {
if (moduleIsTopLevelPage(nestedParentInfo)) {
for (const hid of hoistedScripts) {
if (!pageScripts.has(nestedParentInfo.id)) {
pageScripts.set(nestedParentInfo.id, {
hoistedSet: new Set(),
propagatedMapByImporter: new Map(),
});
}
const entry = pageScripts.get(nestedParentInfo.id)!;
if (!entry.propagatedMapByImporter.has(parentInfo.id)) {
entry.propagatedMapByImporter.set(parentInfo.id, new Set());
}
entry.propagatedMapByImporter.get(parentInfo.id)!.add(hid);
}
}
}
} else if (moduleIsTopLevelPage(parentInfo)) {
for (const hid of hoistedScripts) {
if (!pageScripts.has(parentInfo.id)) {
pageScripts.set(parentInfo.id, {
hoistedSet: new Set(),
propagatedMapByImporter: new Map(),
});
}
pageScripts.get(parentInfo.id)?.hoistedSet.add(hid);
}
}
}
@ -35,14 +69,14 @@ export function vitePluginAnalyzer(internals: BuildInternals): VitePlugin {
},
finalize() {
for (const [pageId, hoistedScripts] of pageScripts) {
for (const [pageId, { hoistedSet, propagatedMapByImporter }] of pageScripts) {
const pageData = getPageDataByViteID(internals, pageId);
if (!pageData) continue;
const { component } = pageData;
const astroModuleId = prependForwardSlash(component);
const uniqueHoistedId = JSON.stringify(Array.from(hoistedScripts).sort());
const uniqueHoistedId = JSON.stringify(Array.from(hoistedSet).sort());
let moduleId: string;
// If we're already tracking this set of hoisted scripts, get the unique id
@ -55,13 +89,35 @@ export function vitePluginAnalyzer(internals: BuildInternals): VitePlugin {
}
internals.discoveredScripts.add(moduleId);
pageData.propagatedScripts = propagatedMapByImporter;
// Add propagated scripts to client build,
// but DON'T add to pages -> hoisted script map.
// const flattenedPropagatedScripts = Array.from(propagatedMapByImporter.values())
// .map((s) => Array.from(s))
// .flat();
// const uniquePropagatedId = JSON.stringify(flattenedPropagatedScripts.sort());
// if (uniqueHoistedIds.has(uniquePropagatedId)) {
// moduleId = uniqueHoistedIds.get(uniquePropagatedId)!;
// } else {
// // Otherwise, create a unique id for this set of hoisted scripts
// moduleId = `/astro/hoisted.js?q=${uniqueHoistedIds.size}`;
// console.log('uniquePropagatedId', uniquePropagatedId, moduleId);
// uniqueHoistedIds.set(uniquePropagatedId, moduleId);
// }
for (const propagatedScripts of propagatedMapByImporter.values()) {
for (const propagatedScript of propagatedScripts) {
internals.discoveredScripts.add(propagatedScript);
}
}
// 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);
internals.hoistedScriptIdToHoistedMap.set(moduleId, hoistedSet);
}
}
},