206 lines
8.7 KiB
JavaScript
206 lines
8.7 KiB
JavaScript
import { fileURLToPath } from "node:url";
|
|
import { normalizePath } from "vite";
|
|
import { ACTIONS_ENTRYPOINT_VIRTUAL_MODULE_ID } from "../actions/consts.js";
|
|
import { toFallbackType } from "../core/app/common.js";
|
|
import { toRoutingStrategy } from "../core/app/entrypoints/index.js";
|
|
import { MANIFEST_REPLACE } from "../core/build/plugins/plugin-manifest.js";
|
|
import {
|
|
getAlgorithm,
|
|
getDirectives,
|
|
getScriptHashes,
|
|
getScriptResources,
|
|
getStrictDynamic,
|
|
getStyleHashes,
|
|
getStyleResources,
|
|
shouldTrackCspHashes
|
|
} from "../core/csp/common.js";
|
|
import { createKey, encodeKey, getEnvironmentKey, hasEnvironmentKey } from "../core/encryption.js";
|
|
import { MIDDLEWARE_MODULE_ID } from "../core/middleware/vite-plugin.js";
|
|
import { SERVER_ISLAND_MANIFEST } from "../core/server-islands/vite-plugin-server-islands.js";
|
|
import { VIRTUAL_CACHE_PROVIDER_ID } from "../core/cache/vite-plugin.js";
|
|
import { VIRTUAL_SESSION_DRIVER_ID } from "../core/session/vite-plugin.js";
|
|
import { VIRTUAL_PAGES_MODULE_ID } from "../vite-plugin-pages/index.js";
|
|
import { ASTRO_RENDERERS_MODULE_ID } from "../vite-plugin-renderers/index.js";
|
|
import { ASTRO_ROUTES_MODULE_ID } from "../vite-plugin-routes/index.js";
|
|
import { cacheConfigToManifest } from "../core/cache/utils.js";
|
|
import { sessionConfigToManifest } from "../core/session/utils.js";
|
|
import { ASTRO_VITE_ENVIRONMENT_NAMES } from "../core/constants.js";
|
|
import { resolveMiddlewareMode } from "../integrations/adapter-utils.js";
|
|
const SERIALIZED_MANIFEST_ID = "virtual:astro:manifest";
|
|
const SERIALIZED_MANIFEST_RESOLVED_ID = "\0" + SERIALIZED_MANIFEST_ID;
|
|
function serializedManifestPlugin({
|
|
settings,
|
|
command,
|
|
sync
|
|
}) {
|
|
const normalizedSrcDir = normalizePath(fileURLToPath(settings.config.srcDir));
|
|
let encodedKeyPromise;
|
|
function getEncodedKey() {
|
|
encodedKeyPromise ??= (async () => {
|
|
const key = hasEnvironmentKey() ? await getEnvironmentKey() : await createKey();
|
|
return encodeKey(key);
|
|
})();
|
|
return encodedKeyPromise;
|
|
}
|
|
function reloadManifest(path, server) {
|
|
if (path != null && normalizePath(path).startsWith(normalizedSrcDir)) {
|
|
const environment = server.environments[ASTRO_VITE_ENVIRONMENT_NAMES.ssr];
|
|
const virtualMod = environment.moduleGraph.getModuleById(SERIALIZED_MANIFEST_RESOLVED_ID);
|
|
if (!virtualMod) return;
|
|
environment.moduleGraph.invalidateModule(virtualMod);
|
|
}
|
|
}
|
|
return {
|
|
name: SERIALIZED_MANIFEST_ID,
|
|
enforce: "pre",
|
|
configureServer(server) {
|
|
server.watcher.on("add", (path) => reloadManifest(path, server));
|
|
server.watcher.on("unlink", (path) => reloadManifest(path, server));
|
|
server.watcher.on("change", (path) => reloadManifest(path, server));
|
|
},
|
|
// Restrict to server environments only since the generated code imports
|
|
// server-only virtual modules (virtual:astro:routes, virtual:astro:pages)
|
|
applyToEnvironment(environment) {
|
|
return environment.name === ASTRO_VITE_ENVIRONMENT_NAMES.astro || environment.name === ASTRO_VITE_ENVIRONMENT_NAMES.ssr || environment.name === ASTRO_VITE_ENVIRONMENT_NAMES.prerender;
|
|
},
|
|
resolveId: {
|
|
filter: {
|
|
id: new RegExp(`^${SERIALIZED_MANIFEST_ID}$`)
|
|
},
|
|
handler() {
|
|
return SERIALIZED_MANIFEST_RESOLVED_ID;
|
|
}
|
|
},
|
|
load: {
|
|
filter: {
|
|
id: new RegExp(`^${SERIALIZED_MANIFEST_RESOLVED_ID}$`)
|
|
},
|
|
async handler() {
|
|
let manifestData;
|
|
if (command === "build" && !sync) {
|
|
manifestData = `'${MANIFEST_REPLACE}'`;
|
|
} else {
|
|
const serialized = await createSerializedManifest(settings, await getEncodedKey());
|
|
manifestData = JSON.stringify(serialized);
|
|
}
|
|
const hasCacheConfig = !!settings.config.experimental?.cache?.provider;
|
|
const cacheProviderLine = hasCacheConfig ? `cacheProvider: () => import('${VIRTUAL_CACHE_PROVIDER_ID}'),` : "";
|
|
const code = `
|
|
import { deserializeManifest as _deserializeManifest } from 'astro/app';
|
|
import { renderers } from '${ASTRO_RENDERERS_MODULE_ID}';
|
|
import { routes } from '${ASTRO_ROUTES_MODULE_ID}';
|
|
import { pageMap } from '${VIRTUAL_PAGES_MODULE_ID}';
|
|
|
|
const _manifest = _deserializeManifest((${manifestData}));
|
|
|
|
// _manifest.routes contains enriched route info with scripts and styles,
|
|
// TODO port this info over to virtual:astro:routes to prevent the need to
|
|
// have this duplication
|
|
const isDev = ${JSON.stringify(command === "dev")};
|
|
const manifestRoutes = isDev ? routes : _manifest.routes;
|
|
|
|
const manifest = Object.assign(_manifest, {
|
|
renderers,
|
|
actions: () => import('${ACTIONS_ENTRYPOINT_VIRTUAL_MODULE_ID}'),
|
|
middleware: () => import('${MIDDLEWARE_MODULE_ID}'),
|
|
sessionDriver: () => import('${VIRTUAL_SESSION_DRIVER_ID}'),
|
|
${cacheProviderLine}
|
|
serverIslandMappings: () => import('${SERVER_ISLAND_MANIFEST}'),
|
|
routes: manifestRoutes,
|
|
pageMap,
|
|
});
|
|
export { manifest };
|
|
`;
|
|
return { code };
|
|
}
|
|
}
|
|
};
|
|
}
|
|
async function createSerializedManifest(settings, encodedKey) {
|
|
let i18nManifest;
|
|
let csp;
|
|
if (settings.config.i18n) {
|
|
i18nManifest = {
|
|
fallback: settings.config.i18n.fallback,
|
|
strategy: toRoutingStrategy(settings.config.i18n.routing, settings.config.i18n.domains),
|
|
defaultLocale: settings.config.i18n.defaultLocale,
|
|
locales: settings.config.i18n.locales,
|
|
domainLookupTable: {},
|
|
fallbackType: toFallbackType(settings.config.i18n.routing),
|
|
domains: settings.config.i18n.domains
|
|
};
|
|
}
|
|
if (shouldTrackCspHashes(settings.config.security.csp)) {
|
|
csp = {
|
|
cspDestination: settings.adapter?.adapterFeatures?.staticHeaders ? "adapter" : void 0,
|
|
scriptHashes: getScriptHashes(settings.config.security.csp),
|
|
scriptResources: getScriptResources(settings.config.security.csp),
|
|
styleHashes: getStyleHashes(settings.config.security.csp),
|
|
styleResources: getStyleResources(settings.config.security.csp),
|
|
algorithm: getAlgorithm(settings.config.security.csp),
|
|
directives: getDirectives(settings),
|
|
isStrictDynamic: getStrictDynamic(settings.config.security.csp)
|
|
};
|
|
}
|
|
return {
|
|
rootDir: settings.config.root.toString(),
|
|
srcDir: settings.config.srcDir.toString(),
|
|
cacheDir: settings.config.cacheDir.toString(),
|
|
outDir: settings.config.outDir.toString(),
|
|
buildServerDir: settings.config.build.server.toString(),
|
|
buildClientDir: settings.config.build.client.toString(),
|
|
publicDir: settings.config.publicDir.toString(),
|
|
assetsDir: settings.config.build.assets,
|
|
trailingSlash: settings.config.trailingSlash,
|
|
buildFormat: settings.config.build.format,
|
|
compressHTML: settings.config.compressHTML,
|
|
serverLike: settings.buildOutput === "server",
|
|
middlewareMode: resolveMiddlewareMode(settings.adapter?.adapterFeatures),
|
|
assets: [],
|
|
entryModules: {},
|
|
routes: [],
|
|
adapterName: settings?.adapter?.name ?? "",
|
|
clientDirectives: Array.from(settings.clientDirectives.entries()),
|
|
renderers: [],
|
|
base: settings.config.base,
|
|
userAssetsBase: settings.config?.vite?.base,
|
|
assetsPrefix: settings.config.build.assetsPrefix,
|
|
site: settings.config.site,
|
|
componentMetadata: [],
|
|
inlinedScripts: [],
|
|
i18n: i18nManifest,
|
|
checkOrigin: (settings.config.security?.checkOrigin && settings.buildOutput === "server") ?? false,
|
|
allowedDomains: settings.config.security?.allowedDomains,
|
|
actionBodySizeLimit: settings.config.security?.actionBodySizeLimit ? settings.config.security.actionBodySizeLimit : 1024 * 1024,
|
|
// 1mb default
|
|
serverIslandBodySizeLimit: settings.config.security?.serverIslandBodySizeLimit ? settings.config.security.serverIslandBodySizeLimit : 1024 * 1024,
|
|
// 1mb default
|
|
key: encodedKey ?? await encodeKey(hasEnvironmentKey() ? await getEnvironmentKey() : await createKey()),
|
|
sessionConfig: sessionConfigToManifest(settings.config.session),
|
|
cacheConfig: cacheConfigToManifest(
|
|
settings.config.experimental?.cache,
|
|
settings.config.experimental?.routeRules
|
|
),
|
|
csp,
|
|
image: {
|
|
objectFit: settings.config.image.objectFit,
|
|
objectPosition: settings.config.image.objectPosition,
|
|
layout: settings.config.image.layout
|
|
},
|
|
devToolbar: {
|
|
enabled: settings.config.devToolbar.enabled && await settings.preferences.get("devToolbar.enabled"),
|
|
latestAstroVersion: settings.latestAstroVersion,
|
|
debugInfoOutput: "",
|
|
placement: settings.config.devToolbar.placement
|
|
},
|
|
logLevel: settings.logLevel,
|
|
shouldInjectCspMetaTags: false,
|
|
experimentalQueuedRendering: settings.config.experimental?.queuedRendering
|
|
};
|
|
}
|
|
export {
|
|
SERIALIZED_MANIFEST_ID,
|
|
SERIALIZED_MANIFEST_RESOLVED_ID,
|
|
serializedManifestPlugin
|
|
};
|