feat: implement with cache
This commit is contained in:
parent
83af723ac5
commit
acbb8b7e6d
3 changed files with 97 additions and 80 deletions
|
@ -1053,7 +1053,9 @@ export interface ContentEntryType {
|
||||||
fileUrl: URL;
|
fileUrl: URL;
|
||||||
contents: string;
|
contents: string;
|
||||||
}): GetEntryInfoReturnType | Promise<GetEntryInfoReturnType>;
|
}): GetEntryInfoReturnType | Promise<GetEntryInfoReturnType>;
|
||||||
getModule?(params: { entry: ContentEntryModule }): rollup.LoadResult | Promise<rollup.LoadResult>;
|
getRenderModule?(params: {
|
||||||
|
entry: ContentEntryModule;
|
||||||
|
}): rollup.LoadResult | Promise<rollup.LoadResult>;
|
||||||
contentModuleTypes?: string;
|
contentModuleTypes?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -45,10 +45,98 @@ export function astroContentImportPlugin({
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getEntryDataById(
|
// Used by the `render-module` plugin to avoid double-parsing your schema
|
||||||
fileId: string,
|
const contentEntryModuleByIdCache = new Map<string, ContentEntryModule>();
|
||||||
pluginContext: PluginContext
|
|
||||||
): Promise<ContentEntryModule> {
|
const plugins: Plugin[] = [
|
||||||
|
{
|
||||||
|
name: 'astro:content-imports',
|
||||||
|
async load(viteId) {
|
||||||
|
if (isContentFlagImport(viteId, contentEntryExts)) {
|
||||||
|
const { fileId } = getFileInfo(viteId, settings.config);
|
||||||
|
const { id, slug, collection, body, data, _internal } = await getContentEntryModule({
|
||||||
|
fileId,
|
||||||
|
pluginContext: this,
|
||||||
|
});
|
||||||
|
|
||||||
|
const code = escapeViteEnvReferences(`
|
||||||
|
export const id = ${JSON.stringify(id)};
|
||||||
|
export const collection = ${JSON.stringify(collection)};
|
||||||
|
export const slug = ${JSON.stringify(slug)};
|
||||||
|
export const body = ${JSON.stringify(body)};
|
||||||
|
export const data = ${devalue.uneval(data) /* TODO: reuse astro props serializer */};
|
||||||
|
export const _internal = {
|
||||||
|
filePath: ${JSON.stringify(_internal.filePath)},
|
||||||
|
rawData: ${JSON.stringify(_internal.rawData)},
|
||||||
|
};
|
||||||
|
`);
|
||||||
|
return { code };
|
||||||
|
}
|
||||||
|
},
|
||||||
|
configureServer(viteServer) {
|
||||||
|
viteServer.watcher.on('all', async (event, entry) => {
|
||||||
|
if (
|
||||||
|
['add', 'unlink', 'change'].includes(event) &&
|
||||||
|
getEntryType(entry, contentPaths, contentEntryExts) === 'config'
|
||||||
|
) {
|
||||||
|
// Content modules depend on config, so we need to invalidate them.
|
||||||
|
for (const modUrl of viteServer.moduleGraph.urlToModuleMap.keys()) {
|
||||||
|
if (
|
||||||
|
isContentFlagImport(modUrl, contentEntryExts) ||
|
||||||
|
// TODO: refine to content types with getModule
|
||||||
|
contentEntryExts.some((ext) => modUrl.endsWith(ext))
|
||||||
|
) {
|
||||||
|
const mod = await viteServer.moduleGraph.getModuleByUrl(modUrl);
|
||||||
|
if (mod) {
|
||||||
|
viteServer.moduleGraph.invalidateModule(mod);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
async transform(code, id) {
|
||||||
|
if (isContentFlagImport(id, contentEntryExts)) {
|
||||||
|
// Escape before Rollup internal transform.
|
||||||
|
// Base on MUCH trial-and-error, inspired by MDX integration 2-step transform.
|
||||||
|
return { code: escapeViteEnvReferences(code) };
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
if (settings.contentEntryTypes.some((t) => t.getRenderModule)) {
|
||||||
|
plugins.push({
|
||||||
|
name: 'astro:content-render-imports',
|
||||||
|
async load(viteId) {
|
||||||
|
if (!contentEntryExts.some((ext) => viteId.endsWith(ext))) return;
|
||||||
|
|
||||||
|
const { fileId } = getFileInfo(viteId, settings.config);
|
||||||
|
for (const contentEntryType of settings.contentEntryTypes) {
|
||||||
|
if (contentEntryType.getRenderModule) {
|
||||||
|
const entry = await contentEntryModuleByIdCache.get(fileId);
|
||||||
|
if (!entry)
|
||||||
|
throw new AstroError({
|
||||||
|
...AstroErrorData.UnknownContentCollectionError,
|
||||||
|
message: `Unable to render ${JSON.stringify(
|
||||||
|
fileId
|
||||||
|
)}. Did you import this module directly without using a content collection query?`,
|
||||||
|
});
|
||||||
|
|
||||||
|
return contentEntryType.getRenderModule({ entry });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getContentEntryModule({
|
||||||
|
fileId,
|
||||||
|
pluginContext,
|
||||||
|
}: {
|
||||||
|
fileId: string;
|
||||||
|
pluginContext: PluginContext;
|
||||||
|
}): Promise<ContentEntryModule> {
|
||||||
const observable = globalContentConfigObserver.get();
|
const observable = globalContentConfigObserver.get();
|
||||||
|
|
||||||
// Content config should be loaded before this plugin is used
|
// Content config should be loaded before this plugin is used
|
||||||
|
@ -122,82 +210,9 @@ export function astroContentImportPlugin({
|
||||||
data,
|
data,
|
||||||
body: info.body,
|
body: info.body,
|
||||||
};
|
};
|
||||||
|
contentEntryModuleByIdCache.set(fileId, contentEntryModule);
|
||||||
return contentEntryModule;
|
return contentEntryModule;
|
||||||
}
|
}
|
||||||
|
|
||||||
const plugins: Plugin[] = [
|
|
||||||
{
|
|
||||||
name: 'astro:content-imports',
|
|
||||||
async load(viteId) {
|
|
||||||
const { fileId } = getFileInfo(viteId, settings.config);
|
|
||||||
if (isContentFlagImport(viteId, contentEntryExts)) {
|
|
||||||
const { id, slug, collection, body, data, _internal } = await getEntryDataById(
|
|
||||||
fileId,
|
|
||||||
this
|
|
||||||
);
|
|
||||||
|
|
||||||
const code = escapeViteEnvReferences(`
|
|
||||||
export const id = ${JSON.stringify(id)};
|
|
||||||
export const collection = ${JSON.stringify(collection)};
|
|
||||||
export const slug = ${JSON.stringify(slug)};
|
|
||||||
export const body = ${JSON.stringify(body)};
|
|
||||||
export const data = ${devalue.uneval(data) /* TODO: reuse astro props serializer */};
|
|
||||||
export const _internal = {
|
|
||||||
filePath: ${JSON.stringify(_internal.filePath)},
|
|
||||||
rawData: ${JSON.stringify(_internal.rawData)},
|
|
||||||
};
|
|
||||||
`);
|
|
||||||
return { code };
|
|
||||||
}
|
|
||||||
},
|
|
||||||
configureServer(viteServer) {
|
|
||||||
viteServer.watcher.on('all', async (event, entry) => {
|
|
||||||
if (
|
|
||||||
['add', 'unlink', 'change'].includes(event) &&
|
|
||||||
getEntryType(entry, contentPaths, contentEntryExts) === 'config'
|
|
||||||
) {
|
|
||||||
// Content modules depend on config, so we need to invalidate them.
|
|
||||||
for (const modUrl of viteServer.moduleGraph.urlToModuleMap.keys()) {
|
|
||||||
if (
|
|
||||||
isContentFlagImport(modUrl, contentEntryExts) ||
|
|
||||||
// TODO: refine to content types with getModule
|
|
||||||
contentEntryExts.some((ext) => modUrl.endsWith(ext))
|
|
||||||
) {
|
|
||||||
const mod = await viteServer.moduleGraph.getModuleByUrl(modUrl);
|
|
||||||
if (mod) {
|
|
||||||
viteServer.moduleGraph.invalidateModule(mod);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
async transform(code, id) {
|
|
||||||
if (isContentFlagImport(id, contentEntryExts)) {
|
|
||||||
// Escape before Rollup internal transform.
|
|
||||||
// Base on MUCH trial-and-error, inspired by MDX integration 2-step transform.
|
|
||||||
return { code: escapeViteEnvReferences(code) };
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
if (settings.contentEntryTypes.some((t) => t.getModule)) {
|
|
||||||
plugins.push({
|
|
||||||
name: 'astro:content-render-modules',
|
|
||||||
async load(viteId) {
|
|
||||||
if (!contentEntryExts.some((ext) => viteId.endsWith(ext))) return;
|
|
||||||
|
|
||||||
const { fileId } = getFileInfo(viteId, settings.config);
|
|
||||||
for (const contentEntryType of settings.contentEntryTypes) {
|
|
||||||
if (contentEntryType.getModule) {
|
|
||||||
const entry = await getEntryDataById(fileId, this);
|
|
||||||
return contentEntryType.getModule({ entry });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return plugins;
|
return plugins;
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,7 +36,7 @@ export default function markdoc(markdocConfig: Config = {}): IntegrationWithPriv
|
||||||
addContentEntryType({
|
addContentEntryType({
|
||||||
extensions: ['.mdoc'],
|
extensions: ['.mdoc'],
|
||||||
getEntryInfo,
|
getEntryInfo,
|
||||||
getModule({ entry }: any): Partial<rollup.LoadResult> {
|
getRenderModule({ entry }: any): Partial<rollup.LoadResult> {
|
||||||
validateRenderProperties(markdocConfig, config);
|
validateRenderProperties(markdocConfig, config);
|
||||||
const ast = Markdoc.parse(entry.body);
|
const ast = Markdoc.parse(entry.body);
|
||||||
const content = Markdoc.transform(ast, {
|
const content = Markdoc.transform(ast, {
|
||||||
|
|
Loading…
Reference in a new issue