237 lines
8.6 KiB
Plaintext
237 lines
8.6 KiB
Plaintext
|
import { join } from "node:path";
|
||
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
||
|
import { isFunctionPerRouteEnabled } from "../../../integrations/index.js";
|
||
|
import { isServerLikeOutput } from "../../../prerender/utils.js";
|
||
|
import { routeIsRedirect } from "../../redirects/index.js";
|
||
|
import { addRollupInput } from "../add-rollup-input.js";
|
||
|
import { eachPageFromAllPages } from "../internal.js";
|
||
|
import { SSR_MANIFEST_VIRTUAL_MODULE_ID } from "./plugin-manifest.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 { MIDDLEWARE_MODULE_ID } from "./plugin-middleware.js";
|
||
|
const SSR_VIRTUAL_MODULE_ID = "@astrojs-ssr-virtual-entry";
|
||
|
const RESOLVED_SSR_VIRTUAL_MODULE_ID = "\0" + SSR_VIRTUAL_MODULE_ID;
|
||
|
function vitePluginSSR(internals, adapter, options) {
|
||
|
return {
|
||
|
name: "@astrojs/vite-plugin-astro-ssr-server",
|
||
|
enforce: "post",
|
||
|
options(opts) {
|
||
|
return addRollupInput(opts, [SSR_VIRTUAL_MODULE_ID]);
|
||
|
},
|
||
|
resolveId(id) {
|
||
|
if (id === SSR_VIRTUAL_MODULE_ID) {
|
||
|
return RESOLVED_SSR_VIRTUAL_MODULE_ID;
|
||
|
}
|
||
|
},
|
||
|
async load(id) {
|
||
|
if (id === RESOLVED_SSR_VIRTUAL_MODULE_ID) {
|
||
|
const { allPages } = options;
|
||
|
const imports = [];
|
||
|
const contents = [];
|
||
|
const exports = [];
|
||
|
let i = 0;
|
||
|
const pageMap = [];
|
||
|
for (const [path, pageData] of eachPageFromAllPages(allPages)) {
|
||
|
if (routeIsRedirect(pageData.route)) {
|
||
|
continue;
|
||
|
}
|
||
|
const virtualModuleName = getVirtualModulePageNameFromPath(ASTRO_PAGE_MODULE_ID, path);
|
||
|
let module = await this.resolve(virtualModuleName);
|
||
|
if (module) {
|
||
|
const variable = `_page${i}`;
|
||
|
imports.push(`const ${variable} = () => import("${virtualModuleName}");`);
|
||
|
const pageData2 = internals.pagesByComponent.get(path);
|
||
|
if (pageData2) {
|
||
|
pageMap.push(`[${JSON.stringify(pageData2.component)}, ${variable}]`);
|
||
|
}
|
||
|
i++;
|
||
|
}
|
||
|
}
|
||
|
contents.push(`const pageMap = new Map([
|
||
|
${pageMap.join(",\n ")}
|
||
|
]);`);
|
||
|
exports.push(`export { pageMap }`);
|
||
|
const middleware = await this.resolve(MIDDLEWARE_MODULE_ID);
|
||
|
const ssrCode = generateSSRCode(adapter, middleware.id);
|
||
|
imports.push(...ssrCode.imports);
|
||
|
contents.push(...ssrCode.contents);
|
||
|
return [...imports, ...contents, ...exports].join("\n");
|
||
|
}
|
||
|
return void 0;
|
||
|
},
|
||
|
async generateBundle(_opts, bundle) {
|
||
|
for (const [, chunk] of Object.entries(bundle)) {
|
||
|
if (chunk.type === "asset") {
|
||
|
internals.staticFiles.add(chunk.fileName);
|
||
|
}
|
||
|
}
|
||
|
for (const [, chunk] of Object.entries(bundle)) {
|
||
|
if (chunk.type === "asset") {
|
||
|
continue;
|
||
|
}
|
||
|
if (chunk.modules[RESOLVED_SSR_VIRTUAL_MODULE_ID]) {
|
||
|
internals.ssrEntryChunk = chunk;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
}
|
||
|
function pluginSSR(options, internals) {
|
||
|
const ssr = isServerLikeOutput(options.settings.config);
|
||
|
const functionPerRouteEnabled = isFunctionPerRouteEnabled(options.settings.adapter);
|
||
|
return {
|
||
|
targets: ["server"],
|
||
|
hooks: {
|
||
|
"build:before": () => {
|
||
|
let vitePlugin = ssr && functionPerRouteEnabled === false ? vitePluginSSR(internals, options.settings.adapter, options) : void 0;
|
||
|
return {
|
||
|
enforce: "after-user-plugins",
|
||
|
vitePlugin
|
||
|
};
|
||
|
},
|
||
|
"build:post": async () => {
|
||
|
if (!ssr) {
|
||
|
return;
|
||
|
}
|
||
|
if (functionPerRouteEnabled) {
|
||
|
return;
|
||
|
}
|
||
|
if (!internals.ssrEntryChunk) {
|
||
|
throw new Error(`Did not generate an entry chunk for SSR`);
|
||
|
}
|
||
|
internals.ssrEntryChunk.fileName = options.settings.config.build.serverEntry;
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
}
|
||
|
const SPLIT_MODULE_ID = "@astro-page-split:";
|
||
|
const RESOLVED_SPLIT_MODULE_ID = "\0@astro-page-split:";
|
||
|
function vitePluginSSRSplit(internals, adapter, options) {
|
||
|
const functionPerRouteEnabled = isFunctionPerRouteEnabled(options.settings.adapter);
|
||
|
return {
|
||
|
name: "@astrojs/vite-plugin-astro-ssr-split",
|
||
|
enforce: "post",
|
||
|
options(opts) {
|
||
|
if (functionPerRouteEnabled) {
|
||
|
const inputs = /* @__PURE__ */ new Set();
|
||
|
for (const [path, pageData] of eachPageFromAllPages(options.allPages)) {
|
||
|
if (routeIsRedirect(pageData.route)) {
|
||
|
continue;
|
||
|
}
|
||
|
inputs.add(getVirtualModulePageNameFromPath(SPLIT_MODULE_ID, path));
|
||
|
}
|
||
|
return addRollupInput(opts, Array.from(inputs));
|
||
|
}
|
||
|
},
|
||
|
resolveId(id) {
|
||
|
if (id.startsWith(SPLIT_MODULE_ID)) {
|
||
|
return "\0" + id;
|
||
|
}
|
||
|
},
|
||
|
async load(id) {
|
||
|
if (id.startsWith(RESOLVED_SPLIT_MODULE_ID)) {
|
||
|
const imports = [];
|
||
|
const contents = [];
|
||
|
const exports = [];
|
||
|
const path = getPathFromVirtualModulePageName(RESOLVED_SPLIT_MODULE_ID, id);
|
||
|
const virtualModuleName = getVirtualModulePageNameFromPath(ASTRO_PAGE_MODULE_ID, path);
|
||
|
let module = await this.resolve(virtualModuleName);
|
||
|
if (module) {
|
||
|
imports.push(`import * as pageModule from "${virtualModuleName}";`);
|
||
|
}
|
||
|
const middleware = await this.resolve(MIDDLEWARE_MODULE_ID);
|
||
|
const ssrCode = generateSSRCode(adapter, middleware.id);
|
||
|
imports.push(...ssrCode.imports);
|
||
|
contents.push(...ssrCode.contents);
|
||
|
exports.push("export { pageModule }");
|
||
|
return [...imports, ...contents, ...exports].join("\n");
|
||
|
}
|
||
|
return void 0;
|
||
|
},
|
||
|
async generateBundle(_opts, bundle) {
|
||
|
for (const [, chunk] of Object.entries(bundle)) {
|
||
|
if (chunk.type === "asset") {
|
||
|
internals.staticFiles.add(chunk.fileName);
|
||
|
}
|
||
|
}
|
||
|
for (const [, chunk] of Object.entries(bundle)) {
|
||
|
if (chunk.type === "asset") {
|
||
|
continue;
|
||
|
}
|
||
|
for (const moduleKey of Object.keys(chunk.modules)) {
|
||
|
if (moduleKey.startsWith(RESOLVED_SPLIT_MODULE_ID)) {
|
||
|
internals.ssrSplitEntryChunks.set(moduleKey, chunk);
|
||
|
storeEntryPoint(moduleKey, options, internals, chunk.fileName);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
}
|
||
|
function pluginSSRSplit(options, internals) {
|
||
|
const ssr = isServerLikeOutput(options.settings.config);
|
||
|
const functionPerRouteEnabled = isFunctionPerRouteEnabled(options.settings.adapter);
|
||
|
return {
|
||
|
targets: ["server"],
|
||
|
hooks: {
|
||
|
"build:before": () => {
|
||
|
let vitePlugin = ssr && functionPerRouteEnabled ? vitePluginSSRSplit(internals, options.settings.adapter, options) : void 0;
|
||
|
return {
|
||
|
enforce: "after-user-plugins",
|
||
|
vitePlugin
|
||
|
};
|
||
|
}
|
||
|
}
|
||
|
};
|
||
|
}
|
||
|
function generateSSRCode(adapter, middlewareId) {
|
||
|
const edgeMiddleware = adapter?.adapterFeatures?.edgeMiddleware ?? false;
|
||
|
const pageMap = isFunctionPerRouteEnabled(adapter) ? "pageModule" : "pageMap";
|
||
|
const imports = [
|
||
|
`import { renderers } from '${RENDERERS_MODULE_ID}';`,
|
||
|
`import { manifest as defaultManifest } from '${SSR_MANIFEST_VIRTUAL_MODULE_ID}';`,
|
||
|
`import * as serverEntrypointModule from '${adapter.serverEntrypoint}';`,
|
||
|
edgeMiddleware ? `` : `import { onRequest as middleware } from '${middlewareId}';`
|
||
|
];
|
||
|
const contents = [
|
||
|
edgeMiddleware ? `const middleware = (_, next) => next()` : "",
|
||
|
`const _manifest = Object.assign(defaultManifest, {`,
|
||
|
` ${pageMap},`,
|
||
|
` renderers,`,
|
||
|
` middleware`,
|
||
|
`});`,
|
||
|
`const _args = ${adapter.args ? JSON.stringify(adapter.args, null, 4) : "undefined"};`,
|
||
|
adapter.exports ? `const _exports = serverEntrypointModule.createExports(_manifest, _args);` : "",
|
||
|
...adapter.exports?.map((name) => {
|
||
|
if (name === "default") {
|
||
|
return `export default _exports.default;`;
|
||
|
} else {
|
||
|
return `export const ${name} = _exports['${name}'];`;
|
||
|
}
|
||
|
}) ?? [],
|
||
|
`serverEntrypointModule.start?.(_manifest, _args);`
|
||
|
];
|
||
|
return {
|
||
|
imports,
|
||
|
contents
|
||
|
};
|
||
|
}
|
||
|
function storeEntryPoint(moduleKey, options, internals, fileName) {
|
||
|
const componentPath = getPathFromVirtualModulePageName(RESOLVED_SPLIT_MODULE_ID, moduleKey);
|
||
|
for (const [page, pageData] of eachPageFromAllPages(options.allPages)) {
|
||
|
if (componentPath == page) {
|
||
|
const publicPath = fileURLToPath(options.settings.config.build.server);
|
||
|
internals.entryPoints.set(pageData.route, pathToFileURL(join(publicPath, fileName)));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
export {
|
||
|
RESOLVED_SPLIT_MODULE_ID,
|
||
|
RESOLVED_SSR_VIRTUAL_MODULE_ID,
|
||
|
SPLIT_MODULE_ID,
|
||
|
SSR_VIRTUAL_MODULE_ID,
|
||
|
pluginSSR,
|
||
|
pluginSSRSplit
|
||
|
};
|