astro-ghostcms/.pnpm-store/v3/files/31/81c535a2abce3a2944516b58080...

274 lines
9.9 KiB
Plaintext

import { createHash } from "node:crypto";
import fsMod from "node:fs";
import { fileURLToPath } from "node:url";
import pLimit from "p-limit";
import { normalizePath } from "vite";
import { CONTENT_RENDER_FLAG, PROPAGATED_ASSET_FLAG } from "../../../content/consts.js";
import { hasContentFlag } from "../../../content/utils.js";
import {
generateContentEntryFile,
generateLookupMap
} from "../../../content/vite-plugin-content-virtual-mod.js";
import { isServerLikeOutput } from "../../../prerender/utils.js";
import { joinPaths, removeFileExtension, removeLeadingForwardSlash } from "../../path.js";
import { addRollupInput } from "../add-rollup-input.js";
import {} from "../internal.js";
import { copyFiles } from "../static-build.js";
import { encodeName } from "../util.js";
import { extendManualChunks } from "./util.js";
const CONTENT_CACHE_DIR = "./content/";
const CONTENT_MANIFEST_FILE = "./manifest.json";
const CONTENT_MANIFEST_VERSION = 0;
const virtualEmptyModuleId = `virtual:empty-content`;
const resolvedVirtualEmptyModuleId = `\0${virtualEmptyModuleId}`;
function createContentManifest() {
return { version: -1, entries: [], serverEntries: [], clientEntries: [] };
}
function vitePluginContent(opts, lookupMap, internals) {
const { config } = opts.settings;
const { cacheDir } = config;
const distRoot = config.outDir;
const distContentRoot = new URL("./content/", distRoot);
const cachedChunks = new URL("./chunks/", opts.settings.config.cacheDir);
const distChunks = new URL("./chunks/", opts.settings.config.outDir);
const contentCacheDir = new URL(CONTENT_CACHE_DIR, cacheDir);
const contentManifestFile = new URL(CONTENT_MANIFEST_FILE, contentCacheDir);
const cache = contentCacheDir;
const cacheTmp = new URL("./.tmp/", cache);
let oldManifest = createContentManifest();
let newManifest = createContentManifest();
let entries;
let injectedEmptyFile = false;
if (fsMod.existsSync(contentManifestFile)) {
try {
const data = fsMod.readFileSync(contentManifestFile, { encoding: "utf8" });
oldManifest = JSON.parse(data);
internals.cachedClientEntries = oldManifest.clientEntries;
} catch {
}
}
return {
name: "@astro/plugin-build-content",
async options(options) {
let newOptions = Object.assign({}, options);
newManifest = await generateContentManifest(opts, lookupMap);
entries = getEntriesFromManifests(oldManifest, newManifest);
for (const { type, entry } of entries.buildFromSource) {
const fileURL = encodeURI(joinPaths(opts.settings.config.root.toString(), entry));
const input = fileURLToPath(fileURL);
const inputs = [`${input}?${collectionTypeToFlag(type)}`];
if (type === "content") {
inputs.push(`${input}?${CONTENT_RENDER_FLAG}`);
}
newOptions = addRollupInput(newOptions, inputs);
}
if (fsMod.existsSync(cachedChunks)) {
await copyFiles(cachedChunks, distChunks, true);
}
if (entries.buildFromSource.length === 0) {
newOptions = addRollupInput(newOptions, [virtualEmptyModuleId]);
injectedEmptyFile = true;
}
return newOptions;
},
outputOptions(outputOptions) {
const rootPath = normalizePath(fileURLToPath(opts.settings.config.root));
const srcPath = normalizePath(fileURLToPath(opts.settings.config.srcDir));
extendManualChunks(outputOptions, {
before(id, meta) {
if (id.startsWith(srcPath) && id.slice(srcPath.length).startsWith("content")) {
const info = meta.getModuleInfo(id);
if (info?.dynamicImporters.length === 1 && hasContentFlag(info.dynamicImporters[0], PROPAGATED_ASSET_FLAG)) {
const [srcRelativePath2] = id.replace(rootPath, "/").split("?");
const resultId = encodeName(
`${removeLeadingForwardSlash(removeFileExtension(srcRelativePath2))}.render.mjs`
);
return resultId;
}
const [srcRelativePath, flag] = id.replace(rootPath, "/").split("?");
const collectionEntry = findEntryFromSrcRelativePath(lookupMap, srcRelativePath);
if (collectionEntry) {
let suffix = ".mjs";
if (flag === PROPAGATED_ASSET_FLAG) {
suffix = ".entry.mjs";
}
id = removeLeadingForwardSlash(
removeFileExtension(encodeName(id.replace(srcPath, "/")))
) + suffix;
return id;
}
}
}
});
},
resolveId(id) {
if (id === virtualEmptyModuleId) {
return resolvedVirtualEmptyModuleId;
}
},
async load(id) {
if (id === resolvedVirtualEmptyModuleId) {
return {
code: `// intentionally left empty!
export default {}`
};
}
},
async generateBundle(_options, bundle) {
const code = await generateContentEntryFile({
settings: opts.settings,
fs: fsMod,
lookupMap,
IS_DEV: false,
IS_SERVER: false
});
this.emitFile({
type: "prebuilt-chunk",
code,
fileName: "content/entry.mjs"
});
if (!injectedEmptyFile)
return;
Object.keys(bundle).forEach((key) => {
const mod = bundle[key];
if (mod.type === "asset")
return;
if (mod.facadeModuleId === resolvedVirtualEmptyModuleId) {
delete bundle[key];
}
});
},
async writeBundle() {
const clientComponents = /* @__PURE__ */ new Set([
...oldManifest.clientEntries,
...internals.discoveredHydratedComponents.keys(),
...internals.discoveredClientOnlyComponents.keys(),
...internals.discoveredScripts
]);
const serverComponents = /* @__PURE__ */ new Set([
...oldManifest.serverEntries,
...internals.discoveredHydratedComponents.keys()
]);
newManifest.serverEntries = Array.from(serverComponents);
newManifest.clientEntries = Array.from(clientComponents);
await fsMod.promises.mkdir(contentCacheDir, { recursive: true });
await fsMod.promises.writeFile(contentManifestFile, JSON.stringify(newManifest), {
encoding: "utf8"
});
const cacheExists = fsMod.existsSync(cache);
fsMod.mkdirSync(cache, { recursive: true });
await fsMod.promises.mkdir(cacheTmp, { recursive: true });
await copyFiles(distContentRoot, cacheTmp, true);
if (cacheExists) {
await copyFiles(contentCacheDir, distContentRoot, false);
}
await copyFiles(cacheTmp, contentCacheDir);
await fsMod.promises.rm(cacheTmp, { recursive: true, force: true });
}
};
}
const entryCache = /* @__PURE__ */ new Map();
function findEntryFromSrcRelativePath(lookupMap, srcRelativePath) {
let value = entryCache.get(srcRelativePath);
if (value)
return value;
for (const collection of Object.values(lookupMap)) {
for (const entry of Object.values(collection)) {
for (const entryFile of Object.values(entry)) {
if (entryFile === srcRelativePath) {
value = entryFile;
entryCache.set(srcRelativePath, entryFile);
return value;
}
}
}
}
}
function getEntriesFromManifests(oldManifest, newManifest) {
const { version: oldVersion, entries: oldEntries } = oldManifest;
const { version: newVersion, entries: newEntries } = newManifest;
let entries = { restoreFromCache: [], buildFromSource: [] };
const newEntryMap = new Map(newEntries);
if (oldVersion !== newVersion || oldEntries.length === 0) {
entries.buildFromSource = Array.from(newEntryMap.keys());
return entries;
}
const oldEntryHashMap = new Map(
oldEntries.map(([key, hash]) => [hash, key])
);
for (const [entry, hash] of newEntryMap) {
if (oldEntryHashMap.has(hash)) {
entries.restoreFromCache.push(entry);
} else {
entries.buildFromSource.push(entry);
}
}
return entries;
}
async function generateContentManifest(opts, lookupMap) {
let manifest = {
version: CONTENT_MANIFEST_VERSION,
entries: [],
serverEntries: [],
clientEntries: []
};
const limit = pLimit(10);
const promises = [];
for (const [collection, { type, entries }] of Object.entries(lookupMap)) {
for (const entry of Object.values(entries)) {
const key = { collection, type, entry };
const fileURL = new URL(encodeURI(joinPaths(opts.settings.config.root.toString(), entry)));
promises.push(
limit(async () => {
const data = await fsMod.promises.readFile(fileURL, { encoding: "utf8" });
manifest.entries.push([key, checksum(data)]);
})
);
}
}
await Promise.all(promises);
return manifest;
}
function checksum(data) {
return createHash("sha1").update(data).digest("base64");
}
function collectionTypeToFlag(type) {
const name = type[0].toUpperCase() + type.slice(1);
return `astro${name}CollectionEntry`;
}
function pluginContent(opts, internals) {
const cachedChunks = new URL("./chunks/", opts.settings.config.cacheDir);
const distChunks = new URL("./chunks/", opts.settings.config.outDir);
return {
targets: ["server"],
hooks: {
async "build:before"() {
if (!opts.settings.config.experimental.contentCollectionCache) {
return { vitePlugin: void 0 };
}
if (isServerLikeOutput(opts.settings.config)) {
return { vitePlugin: void 0 };
}
const lookupMap = await generateLookupMap({ settings: opts.settings, fs: fsMod });
return {
vitePlugin: vitePluginContent(opts, lookupMap, internals)
};
},
async "build:post"() {
if (!opts.settings.config.experimental.contentCollectionCache) {
return;
}
if (isServerLikeOutput(opts.settings.config)) {
return;
}
if (fsMod.existsSync(distChunks)) {
await copyFiles(distChunks, cachedChunks, true);
}
}
}
};
}
export {
pluginContent
};