0
Fork 0
mirror of https://github.com/withastro/astro.git synced 2025-03-10 23:01:26 -05:00

fix(page-data): add key to allPages (#10625)

* fix(page-data): add key to allPages

* add fryuni's test

* replaced object.entries(allpages)

* tmp: change pagesByComponents by pagesByKeys

* fix pagesByKeys.get() in plugin-ssr & plugin-manifest

* remove logs

* remove useless generators

* another useless generator

* use null byte in key

* tmp function in pipeline.ts

* refactor getVirtualModulePageName

* refactor getPageKeyFromVirtualModulePageName

* clean & comments

* better key and fix build

* utils: add makePageDataKey

* fix(pipeline): retrieveRoutesToGenerate for ssr

* internals: getPageData function

* tmp(ssr-split-manifest): fix test ?

* fix?: ssr clean static output

* internals: getPageDatasWithPublicKey

* internals: getPageDatasByHoistedScriptId & getPagesDatasByComponent

* remove broken & useless virtualModuleNameFromResolvedId

* chore: changeset

* fix: sanitize slashes in filepaths

* Revert "fix: sanitize slashes in filepaths"

This reverts commit 5c3a75fac8.

* fix?: remove route from virtual module name

* fix: concat & array.from

* update changeset

* clean unnecessary change

* remove unnecessary pageInfo

* add return types to utils functions

* revert a comment deletion

* fix cleanStaticOutput

* changes from ematipico review

* moving a todo outside jsdoc (cc @ematipico )

* Update .changeset/great-turtles-greet.md

Co-authored-by: Sarah Rainsberger <sarah@rainsberger.ca>

* Update .changeset/great-turtles-greet.md

Co-authored-by: Sarah Rainsberger <sarah@rainsberger.ca>

* chore: fix merge conflicts

* fix: incorrect function

* remove logs

* revert: codepoint change

---------

Co-authored-by: Princesseuh <3019731+Princesseuh@users.noreply.github.com>
Co-authored-by: Sarah Rainsberger <sarah@rainsberger.ca>
Co-authored-by: Emanuele Stoppa <my.burning@gmail.com>
This commit is contained in:
Goulven CLEC'H 2024-05-08 12:33:19 +02:00 committed by GitHub
parent 61f47a6842
commit 698c2d9bb5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
20 changed files with 550 additions and 217 deletions

View file

@ -0,0 +1,5 @@
---
"astro": minor
---
Adds the ability for multiple pages to use the same component as an `entrypoint` when building an Astro integration. This change is purely internal, and aligns the build process with the behaviour in the development server.

View file

@ -42,7 +42,7 @@ import { createRequest } from '../request.js';
import { matchRoute } from '../routing/match.js';
import { getOutputFilename, isServerLikeOutput } from '../util.js';
import { getOutDirWithinCwd, getOutFile, getOutFolder } from './common.js';
import { cssOrder, getPageDataByComponent, mergeInlineCss } from './internal.js';
import { cssOrder, mergeInlineCss } from './internal.js';
import { BuildPipeline } from './pipeline.js';
import type {
PageBuildData,
@ -51,6 +51,8 @@ import type {
StylesheetAsset,
} from './types.js';
import { getTimeStat, shouldAppendForwardSlash } from './util.js';
import { getVirtualModulePageName } from './plugins/util.js';
import { ASTRO_PAGE_MODULE_ID } from './plugins/plugin-pages.js';
function createEntryURL(filePath: string, outFolder: URL) {
return new URL('./' + filePath + `?time=${Date.now()}`, outFolder);
@ -200,7 +202,6 @@ async function generatePage(
// prepare information we need
const { config, internals, logger } = pipeline;
const pageModulePromise = ssrEntry.page;
const pageInfo = getPageDataByComponent(internals, pageData.route.component);
// Calculate information of the page, like scripts, links and styles
const styles = pageData.styles
@ -209,7 +210,7 @@ async function generatePage(
.reduce(mergeInlineCss, []);
// may be used in the future for handling rel=modulepreload, rel=icon, rel=manifest etc.
const linkIds: [] = [];
const scripts = pageInfo?.hoistedScript ?? null;
const scripts = pageData.hoistedScript ?? null;
if (!pageModulePromise) {
throw new Error(
`Unable to find the module for ${pageData.component}. This is unexpected and likely a bug in Astro, please report.`

View file

@ -3,13 +3,8 @@ import type { RouteData, SSRResult } from '../../@types/astro.js';
import type { PageOptions } from '../../vite-plugin-astro/types.js';
import { prependForwardSlash, removeFileExtension } from '../path.js';
import { viteID } from '../util.js';
import {
ASTRO_PAGE_RESOLVED_MODULE_ID,
getVirtualModulePageIdFromPath,
} from './plugins/plugin-pages.js';
import { RESOLVED_SPLIT_MODULE_ID } from './plugins/plugin-ssr.js';
import { ASTRO_PAGE_EXTENSION_POST_PATTERN } from './plugins/util.js';
import type { AllPagesData, PageBuildData, StylesheetAsset, ViteID } from './types.js';
import type { PageBuildData, StylesheetAsset, ViteID } from './types.js';
import { makePageDataKey } from './plugins/util.js';
export interface BuildInternals {
/**
@ -45,7 +40,7 @@ export interface BuildInternals {
/**
* A map for page-specific information.
*/
pagesByComponent: Map<string, PageBuildData>;
pagesByKeys: Map<string, PageBuildData>;
/**
* A map for page-specific output.
@ -134,7 +129,7 @@ export function createBuildInternals(): BuildInternals {
inlinedScripts: new Map(),
entrySpecifierToBundleMap: new Map<string, string>(),
pageToBundleMap: new Map<string, string>(),
pagesByComponent: new Map(),
pagesByKeys: new Map(),
pageOptionsByPage: new Map(),
pagesByViteID: new Map(),
pagesByClientOnly: new Map(),
@ -161,7 +156,7 @@ export function trackPageData(
componentURL: URL
): void {
pageData.moduleSpecifier = componentModuleId;
internals.pagesByComponent.set(component, pageData);
internals.pagesByKeys.set(pageData.key, pageData);
internals.pagesByViteID.set(viteID(componentURL), pageData);
}
@ -229,16 +224,77 @@ export function* getPageDatasByClientOnlyID(
}
}
export function getPageDataByComponent(
/**
* From its route and component, get the page data from the build internals.
* @param internals Build Internals with all the pages
* @param route The route of the page, used to identify the page
* @param component The component of the page, used to identify the page
*/
export function getPageData(
internals: BuildInternals,
route: string,
component: string
): PageBuildData | undefined {
if (internals.pagesByComponent.has(component)) {
return internals.pagesByComponent.get(component);
}
let pageData = internals.pagesByKeys.get(makePageDataKey(route, component));
if (pageData) { return pageData;}
return undefined;
}
/**
* Get all pages datas from the build internals, using a specific component.
* @param internals Build Internals with all the pages
* @param component path to the component, used to identify related pages
*/
export function getPagesDatasByComponent(
internals: BuildInternals,
component: string
): PageBuildData[] {
const pageDatas: PageBuildData[] = [];
internals.pagesByKeys.forEach((pageData) => {
if (component === pageData.component) pageDatas.push(pageData);
})
return pageDatas;
}
// TODO: Should be removed in the future. (Astro 5?)
/**
* Map internals.pagesByKeys to a new map with the public key instead of the internal key.
* This function is only used to avoid breaking changes in the Integrations API, after we changed the way
* we identify pages, from the entrypoint component to an internal key.
* If the page component is unique -> the public key is the component path. (old behavior)
* If the page component is shared -> the public key is the internal key. (new behavior)
* The new behavior on shared entrypoint it's not a breaking change, because it was not supported before.
* @param pagesByKeys A map of all page data by their internal key
*/
export function getPageDatasWithPublicKey(pagesByKeys: Map<string, PageBuildData>): Map<string, PageBuildData> {
// Create a map to store the pages with the public key, mimicking internal.pagesByKeys
const pagesWithPublicKey = new Map<string, PageBuildData>();
const pagesByComponentsArray = Array.from(pagesByKeys.values()).map((pageData) => {
return { component: pageData.component, pageData: pageData };
});
// Get pages with unique component, and set the public key to the component.
const pagesWithUniqueComponent = pagesByComponentsArray.filter((page) => {
return pagesByComponentsArray.filter((p) => p.component === page.component).length === 1;
});
pagesWithUniqueComponent.forEach((page) => {
pagesWithPublicKey.set(page.component, page.pageData);
});
// Get pages with shared component, and set the public key to the internal key.
const pagesWithSharedComponent = pagesByComponentsArray.filter((page) => {
return pagesByComponentsArray.filter((p) => p.component === page.component).length > 1;
});
pagesWithSharedComponent.forEach((page) => {
pagesWithPublicKey.set(page.pageData.key, page.pageData);
});
return pagesWithPublicKey;
}
export function getPageDataByViteID(
internals: BuildInternals,
viteid: ViteID
@ -253,44 +309,8 @@ export function hasPageDataByViteID(internals: BuildInternals, viteid: ViteID):
return internals.pagesByViteID.has(viteid);
}
export function* eachPageData(internals: BuildInternals) {
yield* internals.pagesByComponent.values();
}
export function* eachPageFromAllPages(allPages: AllPagesData): Generator<[string, PageBuildData]> {
for (const [path, pageData] of Object.entries(allPages)) {
yield [path, pageData];
}
}
export function* eachPageDataFromEntryPoint(
internals: BuildInternals
): Generator<[PageBuildData, string]> {
for (const [entrypoint, filePath] of internals.entrySpecifierToBundleMap) {
// virtual pages can be emitted with different prefixes:
// - the classic way are pages emitted with prefix ASTRO_PAGE_RESOLVED_MODULE_ID -> plugin-pages
// - pages emitted using `build.split`, in this case pages are emitted with prefix RESOLVED_SPLIT_MODULE_ID
if (
entrypoint.includes(ASTRO_PAGE_RESOLVED_MODULE_ID) ||
entrypoint.includes(RESOLVED_SPLIT_MODULE_ID)
) {
const [, pageName] = entrypoint.split(':');
const pageData = internals.pagesByComponent.get(
`${pageName.replace(ASTRO_PAGE_EXTENSION_POST_PATTERN, '.')}`
);
if (!pageData) {
throw new Error(
"Build failed. Astro couldn't find the emitted page from " + pageName + ' pattern'
);
}
yield [pageData, filePath];
}
}
}
export function hasPrerenderedPages(internals: BuildInternals) {
for (const pageData of eachPageData(internals)) {
for (const pageData of internals.pagesByKeys.values()) {
if (pageData.route.prerender) {
return true;
}
@ -350,27 +370,23 @@ export function mergeInlineCss(
return acc;
}
export function isHoistedScript(internals: BuildInternals, id: string): boolean {
return internals.hoistedScriptIdToPagesMap.has(id);
}
export function* getPageDatasByHoistedScriptId(
/**
* Get all pages data from the build internals, using a specific hoisted script id.
* @param internals Build Internals with all the pages
* @param id Hoisted script id, used to identify the pages using it
*/
export function getPageDatasByHoistedScriptId(
internals: BuildInternals,
id: string
): Generator<PageBuildData, void, unknown> {
): PageBuildData[]{
const set = internals.hoistedScriptIdToPagesMap.get(id);
const pageDatas: PageBuildData[] = [];
if (set) {
for (const pageId of set) {
const pageData = getPageDataByComponent(internals, pageId.slice(1));
if (pageData) {
yield pageData;
}
getPagesDatasByComponent(internals, pageId.slice(1)).forEach((pageData) => {
pageDatas.push(pageData);
});
}
}
}
// From a component path such as pages/index.astro find the entrypoint module
export function getEntryFilePathFromComponentPath(internals: BuildInternals, path: string) {
const id = getVirtualModulePageIdFromPath(path);
return internals.entrySpecifierToBundleMap.get(id);
return pageDatas;
}

View file

@ -4,6 +4,7 @@ import type { AllPagesData } from './types.js';
import * as colors from 'kleur/colors';
import { debug } from '../logger/core.js';
import { makePageDataKey } from './plugins/util.js';
export interface CollectPagesDataOptions {
settings: AstroSettings;
@ -35,6 +36,8 @@ export async function collectPagesData(
// and is then cached across all future SSR builds. In the past, we've had trouble
// with parallelized builds without guaranteeing that this is called first.
for (const route of manifest.routes) {
// Generate a unique key to identify each page in the build process.
const key = makePageDataKey(route.route, route.component);
// static route:
if (route.pathname) {
const routeCollectionLogTimeout = setInterval(() => {
@ -47,8 +50,8 @@ export async function collectPagesData(
clearInterval(routeCollectionLogTimeout);
}, 10000);
builtPaths.add(route.pathname);
allPages[route.component] = {
allPages[key] = {
key: key,
component: route.component,
route,
moduleSpecifier: '',
@ -70,8 +73,8 @@ export async function collectPagesData(
continue;
}
// dynamic route:
allPages[route.component] = {
allPages[key] = {
key: key,
component: route.component,
route,
moduleSpecifier: '',

View file

@ -20,20 +20,11 @@ import {
} from '../render/ssr-element.js';
import { isServerLikeOutput } from '../util.js';
import { getOutDirWithinCwd } from './common.js';
import {
type BuildInternals,
cssOrder,
getEntryFilePathFromComponentPath,
getPageDataByComponent,
mergeInlineCss,
} from './internal.js';
import { type BuildInternals, cssOrder, getPageData, mergeInlineCss } from './internal.js';
import { ASTRO_PAGE_MODULE_ID, ASTRO_PAGE_RESOLVED_MODULE_ID } from './plugins/plugin-pages.js';
import { RESOLVED_SPLIT_MODULE_ID } from './plugins/plugin-ssr.js';
import {
ASTRO_PAGE_EXTENSION_POST_PATTERN,
getVirtualModulePageNameFromPath,
} from './plugins/util.js';
import type { PageBuildData, SinglePageBuiltModule, StaticBuildOptions } from './types.js';
import { getPagesFromVirtualModulePageName, getVirtualModulePageName } from './plugins/util.js';
import { i18nHasFallback } from './util.js';
/**
@ -163,7 +154,7 @@ export class BuildPipeline extends Pipeline {
settings,
} = this;
const links = new Set<never>();
const pageBuildData = getPageDataByComponent(internals, routeData.component);
const pageBuildData = getPageData(internals, routeData.route, routeData.component);
const scripts = createModuleScriptsSet(
pageBuildData?.hoistedScript ? [pageBuildData.hoistedScript] : [],
base,
@ -203,37 +194,47 @@ export class BuildPipeline extends Pipeline {
/**
* It collects the routes to generate during the build.
*
* It returns a map of page information and their relative entry point as a string.
*/
retrieveRoutesToGenerate(): Map<PageBuildData, string> {
const pages = new Map<PageBuildData, string>();
for (const [entrypoint, filePath] of this.internals.entrySpecifierToBundleMap) {
for (const [virtualModulePageName, filePath] of this.internals.entrySpecifierToBundleMap) {
// virtual pages can be emitted with different prefixes:
// - the classic way are pages emitted with prefix ASTRO_PAGE_RESOLVED_MODULE_ID -> plugin-pages
// - pages emitted using `build.split`, in this case pages are emitted with prefix RESOLVED_SPLIT_MODULE_ID
// - pages emitted using `functionPerRoute`, in this case pages are emitted with prefix RESOLVED_SPLIT_MODULE_ID
if (
entrypoint.includes(ASTRO_PAGE_RESOLVED_MODULE_ID) ||
entrypoint.includes(RESOLVED_SPLIT_MODULE_ID)
virtualModulePageName.includes(ASTRO_PAGE_RESOLVED_MODULE_ID) ||
virtualModulePageName.includes(RESOLVED_SPLIT_MODULE_ID)
) {
const [, pageName] = entrypoint.split(':');
const pageData = this.internals.pagesByComponent.get(
`${pageName.replace(ASTRO_PAGE_EXTENSION_POST_PATTERN, '.')}`
);
if (!pageData) {
throw new Error(
"Build failed. Astro couldn't find the emitted page from " + pageName + ' pattern'
let pageDatas: PageBuildData[] = [];
if (virtualModulePageName.includes(ASTRO_PAGE_RESOLVED_MODULE_ID)) {
pageDatas.push(
...getPagesFromVirtualModulePageName(
this.internals,
ASTRO_PAGE_RESOLVED_MODULE_ID,
virtualModulePageName
)
);
}
pages.set(pageData, filePath);
if (virtualModulePageName.includes(RESOLVED_SPLIT_MODULE_ID)) {
pageDatas.push(
...getPagesFromVirtualModulePageName(
this.internals,
RESOLVED_SPLIT_MODULE_ID,
virtualModulePageName
)
);
}
for (const pageData of pageDatas) {
pages.set(pageData, filePath);
}
}
}
for (const [path, pageData] of this.internals.pagesByComponent.entries()) {
for (const pageData of this.internals.pagesByKeys.values()) {
if (routeIsRedirect(pageData.route)) {
pages.set(pageData, path);
pages.set(pageData, pageData.component);
} else if (
routeIsFallback(pageData.route) &&
(i18nHasFallback(this.config) ||
@ -245,7 +246,7 @@ export class BuildPipeline extends Pipeline {
// The values of the map are the actual `.mjs` files that are generated during the build
// Here, we take the component path and transform it in the virtual module name
const moduleSpecifier = getVirtualModulePageNameFromPath(ASTRO_PAGE_MODULE_ID, path);
const moduleSpecifier = getVirtualModulePageName(ASTRO_PAGE_MODULE_ID, pageData.component);
// We retrieve the original JS module
const filePath = this.internals.entrySpecifierToBundleMap.get(moduleSpecifier);
if (filePath) {
@ -330,7 +331,7 @@ export class BuildPipeline extends Pipeline {
throw new Error(`Expected a redirect route.`);
}
if (route.redirectRoute) {
const filePath = getEntryFilePathFromComponentPath(internals, route.redirectRoute.component);
const filePath = getEntryFilePath(this.internals, route.redirectRoute);
if (filePath) {
const url = createEntryURL(filePath, outFolder);
const ssrEntryPage: SinglePageBuiltModule = await import(url.toString());
@ -350,7 +351,7 @@ export class BuildPipeline extends Pipeline {
throw new Error(`Expected a redirect route.`);
}
if (route.redirectRoute) {
const filePath = getEntryFilePathFromComponentPath(internals, route.redirectRoute.component);
const filePath = getEntryFilePath(this.internals, route.redirectRoute);
if (filePath) {
const url = createEntryURL(filePath, outFolder);
const ssrEntryPage: SinglePageBuiltModule = await import(url.toString());
@ -365,3 +366,11 @@ export class BuildPipeline extends Pipeline {
function createEntryURL(filePath: string, outFolder: URL) {
return new URL('./' + filePath + `?time=${Date.now()}`, outFolder);
}
/**
* For a given pageData, returns the entry file pathaka a resolved virtual module in our internals' specifiers.
*/
function getEntryFilePath(internals: BuildInternals, pageData: RouteData) {
const id = '\x00' + getVirtualModulePageName(ASTRO_PAGE_MODULE_ID, pageData.component);
return internals.entrySpecifierToBundleMap.get(id);
}

View file

@ -14,11 +14,9 @@ import {
moduleIsTopLevelPage,
} from '../graph.js';
import {
eachPageData,
getPageDataByViteID,
getPageDatasByClientOnlyID,
getPageDatasByHoistedScriptId,
isHoistedScript,
} from '../internal.js';
import { extendManualChunks, shouldInlineAsset } from './util.js';
@ -147,7 +145,7 @@ function rollupPluginAstroBuildCSS(options: PluginOptions): VitePlugin[] {
if (pageData) {
appendCSSToPage(pageData, meta, pagesToCss, depth, order);
}
} else if (options.target === 'client' && isHoistedScript(internals, pageInfo.id)) {
} else if (options.target === 'client' && internals.hoistedScriptIdToPagesMap.has(pageInfo.id)) {
for (const pageData of getPageDatasByHoistedScriptId(internals, pageInfo.id)) {
appendCSSToPage(pageData, meta, pagesToCss, -1, order);
}
@ -199,7 +197,7 @@ function rollupPluginAstroBuildCSS(options: PluginOptions): VitePlugin[] {
(chunk) => chunk.type === 'asset' && chunk.name === 'style.css'
);
if (cssChunk === undefined) return;
for (const pageData of eachPageData(internals)) {
for (const pageData of internals.pagesByKeys.values()) {
const cssToInfoMap = (pagesToCss[pageData.moduleSpecifier] ??= {});
cssToInfoMap[cssChunk.fileName] = { depth: -1, order: -1 };
}
@ -238,14 +236,13 @@ function rollupPluginAstroBuildCSS(options: PluginOptions): VitePlugin[] {
let sheetAddedToPage = false;
// Apply `pagesToCss` information to the respective `pageData.styles`
for (const pageData of eachPageData(internals)) {
internals.pagesByKeys.forEach((pageData) => {
const orderingInfo = pagesToCss[pageData.moduleSpecifier]?.[stylesheet.fileName];
if (orderingInfo !== undefined) {
pageData.styles.push({ ...orderingInfo, sheet });
sheetAddedToPage = true;
}
}
})
// Apply `moduleIdToPropagatedCss` information to `internals.propagatedStylesMap`.
// NOTE: It's pretty much a copy over to `internals.propagatedStylesMap` as it should be

View file

@ -19,6 +19,7 @@ import { getOutFile, getOutFolder } from '../common.js';
import { type BuildInternals, cssOrder, mergeInlineCss } from '../internal.js';
import type { AstroBuildPlugin } from '../plugin.js';
import type { StaticBuildOptions } from '../types.js';
import { makePageDataKey } from './util.js';
const manifestReplace = '@@ASTRO_MANIFEST_REPLACE@@';
const replaceExp = new RegExp(`['"]${manifestReplace}['"]`, 'g');
@ -189,7 +190,7 @@ function buildManifest(
}
for (const route of opts.manifest.routes) {
const pageData = internals.pagesByComponent.get(route.component);
const pageData = internals.pagesByKeys.get(makePageDataKey(route.route, route.component));
if (route.prerender || !pageData) continue;
const scripts: SerializedRouteInfo['scripts'] = [];
if (pageData.hoistedScript) {

View file

@ -1,20 +1,15 @@
import type { Plugin as VitePlugin } from 'vite';
import { routeIsRedirect } from '../../redirects/index.js';
import { addRollupInput } from '../add-rollup-input.js';
import { type BuildInternals, eachPageFromAllPages } from '../internal.js';
import { type BuildInternals } from '../internal.js';
import type { AstroBuildPlugin } from '../plugin.js';
import type { StaticBuildOptions } from '../types.js';
import { RENDERERS_MODULE_ID } from './plugin-renderers.js';
import { getPathFromVirtualModulePageName, getVirtualModulePageNameFromPath } from './util.js';
import { getPagesFromVirtualModulePageName, getVirtualModulePageName } from './util.js';
export const ASTRO_PAGE_MODULE_ID = '@astro-page:';
export const ASTRO_PAGE_RESOLVED_MODULE_ID = '\0' + ASTRO_PAGE_MODULE_ID;
export function getVirtualModulePageIdFromPath(path: string) {
const name = getVirtualModulePageNameFromPath(ASTRO_PAGE_MODULE_ID, path);
return '\x00' + name;
}
function vitePluginPages(opts: StaticBuildOptions, internals: BuildInternals): VitePlugin {
return {
name: '@astro/plugin-build-pages',
@ -22,11 +17,13 @@ function vitePluginPages(opts: StaticBuildOptions, internals: BuildInternals): V
if (opts.settings.config.output === 'static') {
const inputs = new Set<string>();
for (const [path, pageData] of eachPageFromAllPages(opts.allPages)) {
for (const pageData of Object.values(opts.allPages)) {
if (routeIsRedirect(pageData.route)) {
continue;
}
inputs.add(getVirtualModulePageNameFromPath(ASTRO_PAGE_MODULE_ID, path));
inputs.add(
getVirtualModulePageName(ASTRO_PAGE_MODULE_ID, pageData.component)
);
}
return addRollupInput(options, Array.from(inputs));
@ -41,9 +38,8 @@ function vitePluginPages(opts: StaticBuildOptions, internals: BuildInternals): V
if (id.startsWith(ASTRO_PAGE_RESOLVED_MODULE_ID)) {
const imports: string[] = [];
const exports: string[] = [];
const pageName = getPathFromVirtualModulePageName(ASTRO_PAGE_RESOLVED_MODULE_ID, id);
const pageData = internals.pagesByComponent.get(pageName);
if (pageData) {
const pageDatas = getPagesFromVirtualModulePageName(internals, ASTRO_PAGE_RESOLVED_MODULE_ID, id);
for (const pageData of pageDatas) {
const resolvedPage = await this.resolve(pageData.moduleSpecifier);
if (resolvedPage) {
imports.push(`const page = () => import(${JSON.stringify(pageData.moduleSpecifier)});`);

View file

@ -7,14 +7,13 @@ import { routeIsRedirect } from '../../redirects/index.js';
import { isServerLikeOutput } from '../../util.js';
import { addRollupInput } from '../add-rollup-input.js';
import type { BuildInternals } from '../internal.js';
import { eachPageFromAllPages } from '../internal.js';
import type { AstroBuildPlugin } from '../plugin.js';
import type { StaticBuildOptions } from '../types.js';
import { SSR_MANIFEST_VIRTUAL_MODULE_ID } from './plugin-manifest.js';
import { MIDDLEWARE_MODULE_ID } from './plugin-middleware.js';
import { ASTRO_PAGE_MODULE_ID } from './plugin-pages.js';
import { RENDERERS_MODULE_ID } from './plugin-renderers.js';
import { getPathFromVirtualModulePageName, getVirtualModulePageNameFromPath } from './util.js';
import { getComponentFromVirtualModulePageName, getVirtualModulePageName } from './util.js';
export const SSR_VIRTUAL_MODULE_ID = '@astrojs-ssr-virtual-entry';
export const RESOLVED_SSR_VIRTUAL_MODULE_ID = '\0' + SSR_VIRTUAL_MODULE_ID;
@ -44,18 +43,21 @@ function vitePluginSSR(
let i = 0;
const pageMap: string[] = [];
for (const [path, pageData] of eachPageFromAllPages(allPages)) {
for (const pageData of Object.values(allPages)) {
if (routeIsRedirect(pageData.route)) {
continue;
}
const virtualModuleName = getVirtualModulePageNameFromPath(ASTRO_PAGE_MODULE_ID, path);
const virtualModuleName = getVirtualModulePageName(
ASTRO_PAGE_MODULE_ID,
pageData.component
);
let module = await this.resolve(virtualModuleName);
if (module) {
const variable = `_page${i}`;
// we need to use the non-resolved ID in order to resolve correctly the virtual module
imports.push(`const ${variable} = () => import("${virtualModuleName}");`);
const pageData2 = internals.pagesByComponent.get(path);
const pageData2 = internals.pagesByKeys.get(pageData.key);
if (pageData2) {
pageMap.push(`[${JSON.stringify(pageData2.component)}, ${variable}]`);
}
@ -147,11 +149,13 @@ function vitePluginSSRSplit(
if (functionPerRouteEnabled) {
const inputs = new Set<string>();
for (const [path, pageData] of eachPageFromAllPages(options.allPages)) {
for (const pageData of Object.values(options.allPages)) {
if (routeIsRedirect(pageData.route)) {
continue;
}
inputs.add(getVirtualModulePageNameFromPath(SPLIT_MODULE_ID, path));
inputs.add(
getVirtualModulePageName(SPLIT_MODULE_ID, pageData.component)
);
}
return addRollupInput(opts, Array.from(inputs));
@ -167,9 +171,8 @@ function vitePluginSSRSplit(
const imports: string[] = [];
const contents: string[] = [];
const exports: string[] = [];
const path = getPathFromVirtualModulePageName(RESOLVED_SPLIT_MODULE_ID, id);
const virtualModuleName = getVirtualModulePageNameFromPath(ASTRO_PAGE_MODULE_ID, path);
const componentPath = getComponentFromVirtualModulePageName(RESOLVED_SPLIT_MODULE_ID, id);
const virtualModuleName = getVirtualModulePageName(ASTRO_PAGE_MODULE_ID, componentPath);
let module = await this.resolve(virtualModuleName);
if (module) {
// we need to use the non-resolved ID in order to resolve correctly the virtual module
@ -284,7 +287,7 @@ if (_start in serverEntrypointModule) {
* we can't use `writeBundle` hook to get the final file name of the entry point written on disk.
* We use this hook instead.
*
* We retrieve the {@link RouteData} that belongs the current moduleKey
* We retrieve all the {@link RouteData} that have the same component as the one we are processing.
*/
function storeEntryPoint(
moduleKey: string,
@ -292,9 +295,9 @@ function storeEntryPoint(
internals: BuildInternals,
fileName: string
) {
const componentPath = getPathFromVirtualModulePageName(RESOLVED_SPLIT_MODULE_ID, moduleKey);
for (const [page, pageData] of eachPageFromAllPages(options.allPages)) {
if (componentPath == page) {
const componentPath = getComponentFromVirtualModulePageName(RESOLVED_SPLIT_MODULE_ID, moduleKey);
for (const pageData of Object.values(options.allPages)) {
if (componentPath == pageData.component) {
const publicPath = fileURLToPath(options.settings.config.build.server);
internals.entryPoints.set(pageData.route, pathToFileURL(join(publicPath, fileName)));
}

View file

@ -1,5 +1,7 @@
import { extname } from 'node:path';
import type { BuildOptions, Rollup, Plugin as VitePlugin } from 'vite';
import type { BuildInternals } from '../internal.js';
import type { PageBuildData } from '../types.js';
// eslint-disable-next-line @typescript-eslint/ban-types
type OutputOptionsHook = Extract<VitePlugin['outputOptions'], Function>;
@ -40,19 +42,28 @@ export function extendManualChunks(outputOptions: OutputOptions, hooks: ExtendMa
};
}
// This is an arbitrary string that we are going to replace the dot of the extension
// This is an arbitrary string that we use to replace the dot of the extension.
export const ASTRO_PAGE_EXTENSION_POST_PATTERN = '@_@';
// This is an arbitrary string that we use to make a pageData key
// Has to be a invalid character for a route, to avoid conflicts.
export const ASTRO_PAGE_KEY_SEPARATOR = '&';
/**
* Generate a unique key to identify each page in the build process.
* @param route Usually pageData.route.route
* @param componentPath Usually pageData.component
*/
export function makePageDataKey(route: string, componentPath: string): string {
return route + ASTRO_PAGE_KEY_SEPARATOR + componentPath;
}
/**
* Prevents Rollup from triggering other plugins in the process by masking the extension (hence the virtual file).
*
* 1. We add a fixed prefix, which is used as virtual module naming convention
* 2. If the path has an extension (at the end of the path), we replace the dot that belongs to the extension with an arbitrary string.
*
* @param virtualModulePrefix
* @param path
* Inverse function of getComponentFromVirtualModulePageName() below.
* @param virtualModulePrefix The prefix used to create the virtual module
* @param path Page component path
*/
export function getVirtualModulePageNameFromPath(virtualModulePrefix: string, path: string) {
export function getVirtualModulePageName(virtualModulePrefix: string, path: string): string {
const extension = extname(path);
return (
virtualModulePrefix +
@ -63,13 +74,34 @@ export function getVirtualModulePageNameFromPath(virtualModulePrefix: string, pa
}
/**
*
* @param virtualModulePrefix
* @param id
* From the VirtualModulePageName, and the internals, get all pageDatas that use this
* component as their entry point.
* @param virtualModulePrefix The prefix used to create the virtual module
* @param id Virtual module name
*/
export function getPathFromVirtualModulePageName(virtualModulePrefix: string, id: string) {
const pageName = id.slice(virtualModulePrefix.length);
return pageName.replace(ASTRO_PAGE_EXTENSION_POST_PATTERN, '.');
export function getPagesFromVirtualModulePageName(internals: BuildInternals, virtualModulePrefix: string, id: string): PageBuildData[]
{
const path = getComponentFromVirtualModulePageName(virtualModulePrefix, id);
const pages: PageBuildData[] = [];
internals.pagesByKeys.forEach(pageData => {
if (pageData.component === path) {
pages.push(pageData);
}
});
return pages;
}
/**
* From the VirtualModulePageName, get the component path.
* Remember that the component can be use by multiple routes.
* Inverse function of getVirtualModulePageName() above.
* @param virtualModulePrefix The prefix at the beginning of the virtual module
* @param id Virtual module name
*/
export function getComponentFromVirtualModulePageName(virtualModulePrefix: string, id: string): string {
return id.slice(virtualModulePrefix.length).replace(ASTRO_PAGE_EXTENSION_POST_PATTERN, '.');
}
export function shouldInlineAsset(

View file

@ -9,11 +9,7 @@ import * as vite from 'vite';
import type { RouteData } from '../../@types/astro.js';
import { PROPAGATED_ASSET_FLAG } from '../../content/consts.js';
import { hasAnyContentFlag } from '../../content/utils.js';
import {
type BuildInternals,
createBuildInternals,
eachPageData,
} from '../../core/build/internal.js';
import { type BuildInternals, createBuildInternals, getPageDatasWithPublicKey } from '../../core/build/internal.js';
import { emptyDir, removeEmptyDirs } from '../../core/fs/index.js';
import { appendForwardSlash, prependForwardSlash, removeFileExtension } from '../../core/path.js';
import { isModeServerWithNoAdapter, isServerLikeOutput } from '../../core/util.js';
@ -39,7 +35,6 @@ import { encodeName, getTimeStat, viteBuildReturnToRollupOutputs } from './util.
export async function viteBuild(opts: StaticBuildOptions) {
const { allPages, settings } = opts;
// Make sure we have an adapter before building
if (isModeServerWithNoAdapter(opts.settings)) {
throw new AstroError(AstroErrorData.NoAdapterInstalled);
@ -48,17 +43,18 @@ export async function viteBuild(opts: StaticBuildOptions) {
settings.timer.start('SSR build');
// The pages to be built for rendering purposes.
// (comment above may be outdated ?)
const pageInput = new Set<string>();
// Build internals needed by the CSS plugin
const internals = createBuildInternals();
for (const [component, pageData] of Object.entries(allPages)) {
const astroModuleURL = new URL('./' + component, settings.config.root);
const astroModuleId = prependForwardSlash(component);
for (const pageData of Object.values(allPages)) {
const astroModuleURL = new URL('./' + pageData.component, settings.config.root);
const astroModuleId = prependForwardSlash(pageData.component);
// Track the page data in internals
trackPageData(internals, component, pageData, astroModuleId, astroModuleURL);
trackPageData(internals, pageData.component, pageData, astroModuleId, astroModuleURL);
if (!routeIsRedirect(pageData.route)) {
pageInput.add(astroModuleId);
@ -75,7 +71,6 @@ export async function viteBuild(opts: StaticBuildOptions) {
// Register plugins
const container = createPluginContainer(opts, internals);
registerAllPlugins(container);
// Build your project (SSR application code, assets, client JS, etc.)
const ssrTime = performance.now();
opts.logger.info('build', `Building ${settings.config.output} entrypoints...`);
@ -275,7 +270,7 @@ async function ssrBuild(
const updatedViteBuildConfig = await runHookBuildSetup({
config: settings.config,
pages: internals.pagesByComponent,
pages: getPageDatasWithPublicKey(internals.pagesByKeys),
vite: viteBuildConfig,
target: 'server',
logger: opts.logger,
@ -336,7 +331,7 @@ async function clientBuild(
await runHookBuildSetup({
config: settings.config,
pages: internals.pagesByComponent,
pages: getPageDatasWithPublicKey(internals.pagesByKeys),
vite: viteBuildConfig,
target: 'client',
logger: opts.logger,
@ -370,19 +365,26 @@ 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.
* If a component is shared between a statically rendered route and a SSR route, it will still be included in the SSR build.
*/
async function cleanStaticOutput(
opts: StaticBuildOptions,
internals: BuildInternals,
ssrOutputChunkNames: string[]
) {
const allStaticFiles = new Set();
for (const pageData of eachPageData(internals)) {
if (pageData.route.prerender && !pageData.hasSharedModules) {
const { moduleSpecifier } = pageData;
const pageBundleId = internals.pageToBundleMap.get(moduleSpecifier);
const entryBundleId = internals.entrySpecifierToBundleMap.get(moduleSpecifier);
allStaticFiles.add(pageBundleId ?? entryBundleId);
const prerenderedFiles = new Set();
const onDemandsFiles = new Set();
for (const pageData of internals.pagesByKeys.values()) {
const { moduleSpecifier } = pageData;
const bundleId = internals.pageToBundleMap.get(moduleSpecifier) ?? internals.entrySpecifierToBundleMap.get(moduleSpecifier);
if (pageData.route.prerender && !pageData.hasSharedModules && !onDemandsFiles.has(bundleId)) {
prerenderedFiles.add(bundleId);
} else {
onDemandsFiles.add(bundleId);
// Check if the component was not previously added to the static build by a statically rendered route
if (prerenderedFiles.has(bundleId)) {
prerenderedFiles.delete(bundleId);
}
}
}
const ssr = isServerLikeOutput(opts.settings.config);
@ -400,7 +402,7 @@ async function cleanStaticOutput(
// These chunks should only contain prerendering logic, so they are safe to modify.
await Promise.all(
files.map(async (filename) => {
if (!allStaticFiles.has(filename)) {
if (!prerenderedFiles.has(filename)) {
return;
}
const url = new URL(filename, out);

View file

@ -23,6 +23,7 @@ export type StylesheetAsset =
export type HoistedScriptAsset = { type: 'inline' | 'external'; value: string };
export interface PageBuildData {
key: string;
component: ComponentPath;
route: RouteData;
moduleSpecifier: string;

View file

@ -0,0 +1,34 @@
import { defineConfig } from 'astro/config';
// https://astro.build/config
export default defineConfig({
integrations: [
{
name: 'astropi',
hooks: {
'astro:config:setup': async ({ injectRoute }) => {
injectRoute({
pattern: `/injected-a`,
entrypoint: './src/to-inject.astro',
prerender: true,
});
injectRoute({
pattern: `/injected-b`,
entrypoint: './src/to-inject.astro',
prerender: true,
});
injectRoute({
pattern: `/dynamic-a/[id]`,
entrypoint: './src/[id].astro',
prerender: true,
});
injectRoute({
pattern: `/dynamic-b/[id]`,
entrypoint: './src/[id].astro',
prerender: true,
});
},
},
},
],
});

View file

@ -0,0 +1,8 @@
{
"name": "@test/reuse-injected-entrypoint",
"version": "0.0.0",
"private": true,
"dependencies": {
"astro": "workspace:*"
}
}

View file

@ -0,0 +1,20 @@
---
export async function getStaticPaths() {
return [
{ params: { id: 'id-1' } },
{ params: { id: 'id-2' } }
];
}
const { id } = Astro.params;
---
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width" />
<title>Routing</title>
</head>
<body>
<h1>[id].astro</h1>
<p>{id}</p>
</body>
</html>

View file

@ -0,0 +1,12 @@
---
---
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width" />
<title>Routing</title>
</head>
<body>
<h1>index.astro</h1>
</body>
</html>

View file

@ -0,0 +1,12 @@
---
---
<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>

View file

@ -0,0 +1,135 @@
import assert from 'node:assert/strict';
import { after, before, describe, it } from 'node:test';
import { load as cheerioLoad } from 'cheerio';
import { loadFixture } from './test-utils.js';
const routes = [
{
description: 'matches / to index.astro',
url: '/',
h1: 'index.astro',
},
{
description: 'matches /injected-a to to-inject.astro',
url: '/injected-a',
h1: 'to-inject.astro',
},
{
description: 'matches /injected-b to to-inject.astro',
url: '/injected-b',
h1: 'to-inject.astro',
},
{
description: 'matches /dynamic-a/id-1 to [id].astro',
url: '/dynamic-a/id-1',
h1: '[id].astro',
p: 'id-1',
},
{
description: 'matches /dynamic-a/id-2 to [id].astro',
url: '/dynamic-a/id-2',
h1: '[id].astro',
p: 'id-2',
},
{
description: 'matches /dynamic-b/id-1 to [id].astro',
url: '/dynamic-b/id-1',
h1: '[id].astro',
p: 'id-1',
},
{
description: 'matches /dynamic-b/id-2 to [id].astro',
url: '/dynamic-b/id-2',
h1: '[id].astro',
p: 'id-2',
},
];
function appendForwardSlash(path) {
return path.endsWith('/') ? path : path + '/';
}
describe('Reuse injected entrypoint', () => {
describe('build', () => {
let fixture;
before(async () => {
fixture = await loadFixture({
root: './fixtures/reuse-injected-entrypoint/',
});
await fixture.build();
});
routes.forEach(({ description, url, fourOhFour, h1, p, htmlMatch }) => {
const isEndpoint = htmlMatch && !h1 && !p;
it(description, async () => {
const htmlFile = isEndpoint ? url : `${appendForwardSlash(url)}index.html`;
if (fourOhFour) {
assert.equal(fixture.pathExists(htmlFile), false);
return;
}
const html = await fixture.readFile(htmlFile);
const $ = cheerioLoad(html);
if (h1) {
assert.equal($('h1').text(), h1);
}
if (p) {
assert.equal($('p').text(), p);
}
if (htmlMatch) {
assert.equal(html, htmlMatch);
}
});
});
});
describe('dev', () => {
let fixture;
let devServer;
before(async () => {
fixture = await loadFixture({
root: './fixtures/reuse-injected-entrypoint/',
});
devServer = await fixture.startDevServer();
});
after(async () => {
await devServer.stop();
});
routes.forEach(({ description, url, fourOhFour, h1, p, htmlMatch }) => {
const isEndpoint = htmlMatch && !h1 && !p;
// checks URLs as written above
it(description, async () => {
const html = await fixture.fetch(url).then((res) => res.text());
const $ = cheerioLoad(html);
if (fourOhFour) {
assert.equal($('title').text(), '404: Not Found');
return;
}
if (h1) {
assert.equal($('h1').text(), h1);
}
if (p) {
assert.equal($('p').text(), p);
}
if (htmlMatch) {
assert.equal(html, htmlMatch);
}
});
});
});
});

View file

@ -8,7 +8,7 @@ import stripAnsi from 'strip-ansi';
import { check } from '../dist/cli/check/index.js';
import build from '../dist/core/build/index.js';
import { RESOLVED_SPLIT_MODULE_ID } from '../dist/core/build/plugins/plugin-ssr.js';
import { getVirtualModulePageNameFromPath } from '../dist/core/build/plugins/util.js';
import { getVirtualModulePageName } from '../dist/core/build/plugins/util.js';
import { makeSplitEntryPointFileName } from '../dist/core/build/static-build.js';
import { mergeConfig, resolveConfig } from '../dist/core/config/index.js';
import { dev, preview } from '../dist/core/index.js';
@ -221,7 +221,7 @@ export async function loadFixture(inlineConfig) {
return app;
},
loadEntryPoint: async (pagePath, routes, streaming) => {
const virtualModule = getVirtualModulePageNameFromPath(RESOLVED_SPLIT_MODULE_ID, pagePath);
const virtualModule = getVirtualModulePageName(RESOLVED_SPLIT_MODULE_ID, pagePath);
const filePath = makeSplitEntryPointFileName(virtualModule, routes);
const url = new URL(`./server/${filePath}?id=${fixtureId}`, config.outDir);
const { createApp, manifest } = await import(url);

128
pnpm-lock.yaml generated
View file

@ -3336,6 +3336,12 @@ importers:
specifier: workspace:*
version: link:../../..
packages/astro/test/fixtures/reuse-injected-entrypoint:
dependencies:
astro:
specifier: workspace:*
version: link:../../..
packages/astro/test/fixtures/root-srcdir-css:
dependencies:
astro:
@ -5623,8 +5629,8 @@ packages:
'@jridgewell/gen-mapping': 0.3.5
'@jridgewell/trace-mapping': 0.3.25
/@antfu/utils@0.7.7:
resolution: {integrity: sha512-gFPqTG7otEJ8uP6wrhDv6mqwGWYZKNvAcCq6u9hOj0c+IKCEsY4L1oC9trPq2SaWIzAfHvqfBDxF591JkMf+kg==}
/@antfu/utils@0.7.8:
resolution: {integrity: sha512-rWQkqXRESdjXtc+7NRfK9lASQjpXJu1ayp7qi1d23zZorY+wBHVLHHoVcMsEnkqEBWTFqbztO7/QdJFzyEcLTg==}
dev: false
/@asamuzakjp/dom-selector@2.0.2:
@ -5830,7 +5836,7 @@ packages:
'@babel/helper-optimise-call-expression': 7.22.5
'@babel/helper-replace-supers': 7.24.1(@babel/core@7.24.5)
'@babel/helper-skip-transparent-expression-wrappers': 7.22.5
'@babel/helper-split-export-declaration': 7.24.5
'@babel/helper-split-export-declaration': 7.22.6
semver: 6.3.1
dev: false
@ -5940,6 +5946,13 @@ packages:
'@babel/types': 7.24.5
dev: false
/@babel/helper-split-export-declaration@7.22.6:
resolution: {integrity: sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==}
engines: {node: '>=6.9.0'}
dependencies:
'@babel/types': 7.24.5
dev: false
/@babel/helper-split-export-declaration@7.24.5:
resolution: {integrity: sha512-5CHncttXohrHk8GWOFCcCl4oRD9fKosWlIRgWm4ql9VYioKm52Mk2xsmoohvm7f3JoiLSM5ZgJuRaf5QZZYd3Q==}
engines: {node: '>=6.9.0'}
@ -7445,8 +7458,8 @@ packages:
resolution: {integrity: sha512-n5JEf16Wr4mdkRMZ8wMP/wN9/sHmTjRPbouXjJH371mZ2LEGDl72t8tEsMRNFerQN/QJtivOxqK1frdGa4QK5Q==}
engines: {node: '>=10'}
/@jsonjoy.com/base64@1.1.1(tslib@2.6.2):
resolution: {integrity: sha512-LnFjVChaGY8cZVMwAIMjvA1XwQjZ/zIXHyh28IyJkyNkzof4Dkm1+KN9UIm3lHhREH4vs7XwZ0NpkZKnwOtEfg==}
/@jsonjoy.com/base64@1.1.2(tslib@2.6.2):
resolution: {integrity: sha512-q6XAnWQDIMA3+FTiOYajoYqySkO+JSat0ytXGSuRdq9uXE7o92gzuQwQM14xaCRlBLGq3v5miDGC4vkVTn54xA==}
engines: {node: '>=10.0'}
peerDependencies:
tslib: '2'
@ -7457,8 +7470,8 @@ packages:
tslib: 2.6.2
dev: true
/@jsonjoy.com/json-pack@1.0.2(tslib@2.6.2):
resolution: {integrity: sha512-4KMApTgb1Hvjz9Ue7unziJ1xNy3k6d2erp0hz1iXryXsf6LEM3KwN6YrfbqT0vqkUO8Tu+CSnvMia9cWX6YGVw==}
/@jsonjoy.com/json-pack@1.0.4(tslib@2.6.2):
resolution: {integrity: sha512-aOcSN4MeAtFROysrbqG137b7gaDDSmVrl5mpo6sT/w+kcXpWnzhMjmY/Fh/sDx26NBxyIE7MB1seqLeCAzy9Sg==}
engines: {node: '>=10.0'}
peerDependencies:
tslib: '2'
@ -7466,15 +7479,15 @@ packages:
tslib:
optional: true
dependencies:
'@jsonjoy.com/base64': 1.1.1(tslib@2.6.2)
'@jsonjoy.com/util': 1.1.0(tslib@2.6.2)
'@jsonjoy.com/base64': 1.1.2(tslib@2.6.2)
'@jsonjoy.com/util': 1.1.3(tslib@2.6.2)
hyperdyperid: 1.2.0
thingies: 1.21.0(tslib@2.6.2)
tslib: 2.6.2
dev: true
/@jsonjoy.com/util@1.1.0(tslib@2.6.2):
resolution: {integrity: sha512-Yz+xITJ3Y/w0DBISwPkBETP5/cITHXscjgQNZIkfrVz1V7/ahJY8vw+T+LZy/KtXgKuUWqu4GALAQ3bhGt9J8A==}
/@jsonjoy.com/util@1.1.3(tslib@2.6.2):
resolution: {integrity: sha512-g//kkF4kOwUjemValCtOc/xiYzmwMRmWq3Bn+YnzOzuZLHq2PpMOxxIayN3cKbo7Ko2Np65t6D9H81IvXbXhqg==}
engines: {node: '>=10.0'}
peerDependencies:
tslib: '2'
@ -7482,7 +7495,6 @@ packages:
tslib:
optional: true
dependencies:
hyperdyperid: 1.2.0
tslib: 2.6.2
dev: true
@ -9008,6 +9020,16 @@ packages:
estree-walker: 2.0.2
source-map-js: 1.2.0
/@vue/compiler-core@3.4.27:
resolution: {integrity: sha512-E+RyqY24KnyDXsCuQrI+mlcdW3ALND6U7Gqa/+bVwbcpcR3BRRIckFoz7Qyd4TTlnugtwuI7YgjbvsLmxb+yvg==}
dependencies:
'@babel/parser': 7.24.5
'@vue/shared': 3.4.27
entities: 4.5.0
estree-walker: 2.0.2
source-map-js: 1.2.0
dev: false
/@vue/compiler-dom@3.4.21:
resolution: {integrity: sha512-IZC6FKowtT1sl0CR5DpXSiEB5ayw75oT2bma1BEhV7RRR1+cfwLrxc2Z8Zq/RGFzJ8w5r9QtCOvTjQgdn0IKmA==}
dependencies:
@ -9028,6 +9050,13 @@ packages:
'@vue/compiler-core': 3.4.26
'@vue/shared': 3.4.26
/@vue/compiler-dom@3.4.27:
resolution: {integrity: sha512-kUTvochG/oVgE1w5ViSr3KUBh9X7CWirebA3bezTbB5ZKBQZwR2Mwj9uoSKRMFcz4gSMzzLXBPD6KpCLb9nvWw==}
dependencies:
'@vue/compiler-core': 3.4.27
'@vue/shared': 3.4.27
dev: false
/@vue/compiler-sfc@3.4.21:
resolution: {integrity: sha512-me7epoTxYlY+2CUM7hy9PCDdpMPfIwrOvAXud2Upk10g4YLv9UBW7kL798TvMeDhPthkZ0CONNrK2GoeI1ODiQ==}
dependencies:
@ -9042,20 +9071,6 @@ packages:
source-map-js: 1.2.0
dev: false
/@vue/compiler-sfc@3.4.24:
resolution: {integrity: sha512-nRAlJUK02FTWfA2nuvNBAqsDZuERGFgxZ8sGH62XgFSvMxO2URblzulExsmj4gFZ8e+VAyDooU9oAoXfEDNxTA==}
dependencies:
'@babel/parser': 7.24.5
'@vue/compiler-core': 3.4.24
'@vue/compiler-dom': 3.4.24
'@vue/compiler-ssr': 3.4.24
'@vue/shared': 3.4.24
estree-walker: 2.0.2
magic-string: 0.30.10
postcss: 8.4.38
source-map-js: 1.2.0
dev: false
/@vue/compiler-sfc@3.4.26:
resolution: {integrity: sha512-It1dp+FAOCgluYSVYlDn5DtZBxk1NCiJJfu2mlQqa/b+k8GL6NG/3/zRbJnHdhV2VhxFghaDq5L4K+1dakW6cw==}
dependencies:
@ -9069,6 +9084,20 @@ packages:
postcss: 8.4.38
source-map-js: 1.2.0
/@vue/compiler-sfc@3.4.27:
resolution: {integrity: sha512-nDwntUEADssW8e0rrmE0+OrONwmRlegDA1pD6QhVeXxjIytV03yDqTey9SBDiALsvAd5U4ZrEKbMyVXhX6mCGA==}
dependencies:
'@babel/parser': 7.24.5
'@vue/compiler-core': 3.4.27
'@vue/compiler-dom': 3.4.27
'@vue/compiler-ssr': 3.4.27
'@vue/shared': 3.4.27
estree-walker: 2.0.2
magic-string: 0.30.10
postcss: 8.4.38
source-map-js: 1.2.0
dev: false
/@vue/compiler-ssr@3.4.21:
resolution: {integrity: sha512-M5+9nI2lPpAsgXOGQobnIueVqc9sisBFexh5yMIMRAPYLa7+5wEJs8iqOZc1WAa9WQbx9GR2twgznU8LTIiZ4Q==}
dependencies:
@ -9076,19 +9105,19 @@ packages:
'@vue/shared': 3.4.21
dev: false
/@vue/compiler-ssr@3.4.24:
resolution: {integrity: sha512-ZsAtr4fhaUFnVcDqwW3bYCSDwq+9Gk69q2r/7dAHDrOMw41kylaMgOP4zRnn6GIEJkQznKgrMOGPMFnLB52RbQ==}
dependencies:
'@vue/compiler-dom': 3.4.24
'@vue/shared': 3.4.24
dev: false
/@vue/compiler-ssr@3.4.26:
resolution: {integrity: sha512-FNwLfk7LlEPRY/g+nw2VqiDKcnDTVdCfBREekF8X74cPLiWHUX6oldktf/Vx28yh4STNy7t+/yuLoMBBF7YDiQ==}
dependencies:
'@vue/compiler-dom': 3.4.26
'@vue/shared': 3.4.26
/@vue/compiler-ssr@3.4.27:
resolution: {integrity: sha512-CVRzSJIltzMG5FcidsW0jKNQnNRYC8bT21VegyMMtHmhW3UOI7knmUehzswXLrExDLE6lQCZdrhD4ogI7c+vuw==}
dependencies:
'@vue/compiler-dom': 3.4.27
'@vue/shared': 3.4.27
dev: false
/@vue/devtools-core@7.1.3(vite@5.2.10)(vue@3.4.26):
resolution: {integrity: sha512-pVbWi8pf2Z/fZPioYOIgu+cv9pQG55k4D8bL31ec+Wfe+pQR0ImFDu0OhHfch1Ra8uvLLrAZTF4IKeGAkmzD4A==}
dependencies:
@ -9201,6 +9230,10 @@ packages:
/@vue/shared@3.4.26:
resolution: {integrity: sha512-Fg4zwR0GNnjzodMt3KRy2AWGMKQXByl56+4HjN87soxLNU9P5xcJkstAlIeEF3cU6UYOzmJl1tV0dVPGIljCnQ==}
/@vue/shared@3.4.27:
resolution: {integrity: sha512-DL3NmY2OFlqmYYrzp39yi3LDkKxa5vZVwxWdQ3rG0ekuWscHraeIbnI8t+aZK7qhYqEqWKTUdijadunb9pnrgA==}
dev: false
/@webcomponents/template-shadowroot@0.2.1:
resolution: {integrity: sha512-fXL/vIUakyZL62hyvUh+EMwbVoTc0hksublmRz6ai6et8znHkJa6gtqMUZo1oc7dIz46exHSIImml9QTdknMHg==}
dev: false
@ -13014,9 +13047,9 @@ packages:
resolution: {integrity: sha512-36cVYFMaa9HNEYyvkyKCwker8DBmOdjWLrfekE/cHEKJ806fCfKNVhOJNvoyV/CrGSZDtfQPbhn0Zid0gbH0Hw==}
engines: {node: '>= 4.0.0'}
dependencies:
'@jsonjoy.com/json-pack': 1.0.2(tslib@2.6.2)
'@jsonjoy.com/util': 1.1.0(tslib@2.6.2)
sonic-forest: 1.0.0(tslib@2.6.2)
'@jsonjoy.com/json-pack': 1.0.4(tslib@2.6.2)
'@jsonjoy.com/util': 1.1.3(tslib@2.6.2)
sonic-forest: 1.0.3(tslib@2.6.2)
tslib: 2.6.2
dev: true
@ -15608,8 +15641,8 @@ packages:
solid-js: 1.8.17
dev: false
/sonic-forest@1.0.0(tslib@2.6.2):
resolution: {integrity: sha512-yFO2N4uTUFtgKLw03WWFpN1iEwZySweMsa18XN3Kt0yYrlmVHunC2ZgM+437zDoKISAJHcH3Cg18U7d6tuSgSQ==}
/sonic-forest@1.0.3(tslib@2.6.2):
resolution: {integrity: sha512-dtwajos6IWMEWXdEbW1IkEkyL2gztCAgDplRIX+OT5aRKnEd5e7r7YCxRgXZdhRP1FBdOBf8axeTPhzDv8T4wQ==}
engines: {node: '>=10.0'}
peerDependencies:
tslib: '2'
@ -15617,6 +15650,7 @@ packages:
tslib:
optional: true
dependencies:
tree-dump: 1.0.1(tslib@2.6.2)
tslib: 2.6.2
dev: true
@ -16164,6 +16198,18 @@ packages:
punycode: 2.3.1
dev: true
/tree-dump@1.0.1(tslib@2.6.2):
resolution: {integrity: sha512-WCkcRBVPSlHHq1dc/px9iOfqklvzCbdRwvlNfxGZsrHqf6aZttfPrd7DJTt6oR10dwUfpFFQeVTkPbBIZxX/YA==}
engines: {node: '>=10.0'}
peerDependencies:
tslib: '2'
peerDependenciesMeta:
tslib:
optional: true
dependencies:
tslib: 2.6.2
dev: true
/trim-lines@3.0.1:
resolution: {integrity: sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==}
@ -16733,7 +16779,7 @@ packages:
vite:
optional: true
dependencies:
'@antfu/utils': 0.7.7
'@antfu/utils': 0.7.8
'@rollup/pluginutils': 5.1.0
debug: 4.3.4(supports-color@8.1.1)
error-stack-parser-es: 0.1.1
@ -16809,7 +16855,7 @@ packages:
'@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.24.5)
'@babel/plugin-transform-typescript': 7.24.4(@babel/core@7.24.5)
'@vue/babel-plugin-jsx': 1.2.2(@babel/core@7.24.5)
'@vue/compiler-dom': 3.4.26
'@vue/compiler-dom': 3.4.24
kolorist: 1.8.0
magic-string: 0.30.10
vite: 5.2.10(@types/node@18.19.31)(sass@1.75.0)
@ -16825,7 +16871,7 @@ packages:
vue:
optional: true
dependencies:
'@vue/compiler-sfc': 3.4.24
'@vue/compiler-sfc': 3.4.27
svgo: 3.2.0
dev: false