fix: wait for in-flight entry resolution
This commit is contained in:
parent
acbb8b7e6d
commit
61e4425494
1 changed files with 33 additions and 6 deletions
|
@ -45,16 +45,13 @@ export function astroContentImportPlugin({
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Used by the `render-module` plugin to avoid double-parsing your schema
|
|
||||||
const contentEntryModuleByIdCache = new Map<string, ContentEntryModule>();
|
|
||||||
|
|
||||||
const plugins: Plugin[] = [
|
const plugins: Plugin[] = [
|
||||||
{
|
{
|
||||||
name: 'astro:content-imports',
|
name: 'astro:content-imports',
|
||||||
async load(viteId) {
|
async load(viteId) {
|
||||||
if (isContentFlagImport(viteId, contentEntryExts)) {
|
if (isContentFlagImport(viteId, contentEntryExts)) {
|
||||||
const { fileId } = getFileInfo(viteId, settings.config);
|
const { fileId } = getFileInfo(viteId, settings.config);
|
||||||
const { id, slug, collection, body, data, _internal } = await getContentEntryModule({
|
const { id, slug, collection, body, data, _internal } = await setContentEntryModuleCache({
|
||||||
fileId,
|
fileId,
|
||||||
pluginContext: this,
|
pluginContext: this,
|
||||||
});
|
});
|
||||||
|
@ -114,7 +111,9 @@ export const _internal = {
|
||||||
const { fileId } = getFileInfo(viteId, settings.config);
|
const { fileId } = getFileInfo(viteId, settings.config);
|
||||||
for (const contentEntryType of settings.contentEntryTypes) {
|
for (const contentEntryType of settings.contentEntryTypes) {
|
||||||
if (contentEntryType.getRenderModule) {
|
if (contentEntryType.getRenderModule) {
|
||||||
const entry = await contentEntryModuleByIdCache.get(fileId);
|
const entry = await getContentEntryModuleFromCache(fileId);
|
||||||
|
// Cached entry must exist (or be in-flight) when importing the module via content collections.
|
||||||
|
// This is ensured by the `astro:content-imports` plugin.
|
||||||
if (!entry)
|
if (!entry)
|
||||||
throw new AstroError({
|
throw new AstroError({
|
||||||
...AstroErrorData.UnknownContentCollectionError,
|
...AstroErrorData.UnknownContentCollectionError,
|
||||||
|
@ -130,13 +129,34 @@ export const _internal = {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getContentEntryModule({
|
// Used by the `render-module` plugin to avoid double-parsing your schema
|
||||||
|
const contentEntryModuleByIdCache = new Map<string, ContentEntryModule | 'loading'>();
|
||||||
|
const awaitingCacheById = new Map<string, ((val: ContentEntryModule) => void)[]>();
|
||||||
|
function getContentEntryModuleFromCache(id: string) {
|
||||||
|
const value = contentEntryModuleByIdCache.get(id);
|
||||||
|
// It's possible for Vite to load modules that depend on this cache
|
||||||
|
// before the cache is populated. In that case, we queue a promise
|
||||||
|
// to be resolved by `setContentEntryModuleCache`.
|
||||||
|
if (value === 'loading') {
|
||||||
|
return new Promise<ContentEntryModule>((resolve, reject) => {
|
||||||
|
const awaiting = awaitingCacheById.get(id) ?? [];
|
||||||
|
awaiting.push(resolve);
|
||||||
|
awaitingCacheById.set(id, awaiting);
|
||||||
|
});
|
||||||
|
} else if (value) {
|
||||||
|
return Promise.resolve(value);
|
||||||
|
}
|
||||||
|
return Promise.resolve(undefined);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function setContentEntryModuleCache({
|
||||||
fileId,
|
fileId,
|
||||||
pluginContext,
|
pluginContext,
|
||||||
}: {
|
}: {
|
||||||
fileId: string;
|
fileId: string;
|
||||||
pluginContext: PluginContext;
|
pluginContext: PluginContext;
|
||||||
}): Promise<ContentEntryModule> {
|
}): Promise<ContentEntryModule> {
|
||||||
|
contentEntryModuleByIdCache.set(fileId, 'loading');
|
||||||
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
|
||||||
|
@ -211,6 +231,13 @@ export const _internal = {
|
||||||
body: info.body,
|
body: info.body,
|
||||||
};
|
};
|
||||||
contentEntryModuleByIdCache.set(fileId, contentEntryModule);
|
contentEntryModuleByIdCache.set(fileId, contentEntryModule);
|
||||||
|
const awaiting = awaitingCacheById.get(fileId);
|
||||||
|
if (awaiting) {
|
||||||
|
for (const resolve of awaiting) {
|
||||||
|
resolve(contentEntryModule);
|
||||||
|
}
|
||||||
|
awaitingCacheById.delete(fileId);
|
||||||
|
}
|
||||||
return contentEntryModule;
|
return contentEntryModule;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue