From 617adc92ab7b89e9686fdefc85abaa6c834fcd4c Mon Sep 17 00:00:00 2001 From: Emanuele Stoppa Date: Wed, 7 Aug 2024 15:07:46 +0100 Subject: [PATCH] address feedback --- packages/astro/src/content/consts.ts | 11 +++- packages/astro/src/content/data-store.ts | 26 ++++---- packages/astro/src/content/loaders/glob.ts | 6 +- packages/astro/src/content/runtime.ts | 61 +++++++------------ packages/astro/src/content/utils.ts | 9 ++- .../vite-plugin-content-virtual-mod.ts | 25 ++++---- packages/astro/src/core/errors/errors-data.ts | 3 +- .../src/content/config.ts | 2 +- .../src/pages/reptiles/[slug].astro | 2 +- 9 files changed, 69 insertions(+), 76 deletions(-) diff --git a/packages/astro/src/content/consts.ts b/packages/astro/src/content/consts.ts index 6c7b17d752b12..c1ac5ee70cabf 100644 --- a/packages/astro/src/content/consts.ts +++ b/packages/astro/src/content/consts.ts @@ -9,8 +9,15 @@ export const VIRTUAL_MODULE_ID = 'astro:content'; export const RESOLVED_VIRTUAL_MODULE_ID = '\0' + VIRTUAL_MODULE_ID; export const DATA_STORE_VIRTUAL_ID = 'astro:data-layer-content'; export const RESOLVED_DATA_STORE_VIRTUAL_ID = '\0' + DATA_STORE_VIRTUAL_ID; -export const MODULES_IMPORTS_ID = 'astro:content-module-imports'; -export const MODULES_IMPORTS_VIRTUAL_ID = '\0' + MODULES_IMPORTS_ID; + +// Used by the content layer to create a virtual module that loads the `modules.mjs`, a file created by the content layer +// to map modules that are renderer at runtime +export const MODULES_MJS_ID = 'astro:content-module-imports'; +export const MODULES_MJS_VIRTUAL_ID = '\0' + MODULES_MJS_ID; + +export const DEFERRED_MODULE = 'astro:content-layer-deferred-module'; + +// Used by the content layer to create a virtual module that loads the `assets.mjs` export const ASSET_IMPORTS_VIRTUAL_ID = 'astro:asset-imports'; export const ASSET_IMPORTS_RESOLVED_STUB_ID = '\0' + ASSET_IMPORTS_VIRTUAL_ID; export const LINKS_PLACEHOLDER = '@@ASTRO-LINKS@@'; diff --git a/packages/astro/src/content/data-store.ts b/packages/astro/src/content/data-store.ts index dd801fd548baa..36f19065ef07a 100644 --- a/packages/astro/src/content/data-store.ts +++ b/packages/astro/src/content/data-store.ts @@ -3,7 +3,7 @@ import type { MarkdownHeading } from '@astrojs/markdown-remark'; import * as devalue from 'devalue'; import { imageSrcToImportId, importIdToSymbolName } from '../assets/utils/resolveImports.js'; import { AstroError, AstroErrorData } from '../core/errors/index.js'; -import { CONTENT_MODULE_FLAG } from './consts.js'; +import {DEFERRED_MODULE} from './consts.js'; const SAVE_DEBOUNCE_MS = 500; @@ -36,9 +36,9 @@ export interface DataEntry = Record this.entries(collectionName), values: () => this.values(collectionName), keys: () => this.keys(collectionName), - set: ({ id: key, data, body, filePath, isModule, digest, rendered }) => { + set: ({ id: key, data, body, filePath, isDeferred, digest, rendered }) => { if (!key) { throw new Error(`ID must be a non-empty string`); } @@ -311,8 +310,8 @@ export default new Map([\n${lines.join(',\n')}]); if (rendered) { entry.rendered = rendered; } - if (isModule) { - entry.isModule = isModule; + if (isDeferred) { + entry.isDeferred = isDeferred; } this.set(collectionName, id, entry); return true; @@ -417,7 +416,10 @@ export interface ScopedDataStore { digest?: number | string; /** The rendered content, if applicable. */ rendered?: RenderedContent; - isModule?: boolean; + /** + * If an entry is a deferred, its rendering phase is delegated to a virtual module during the runtime phase. + */ + isDeferred?: boolean; }) => boolean; values: () => Array; keys: () => Array; @@ -469,10 +471,10 @@ function dataStoreSingleton() { } // TODO: find a better place to put this image -export function contentModuleToId(specifier: string, filePath: string) { +export function contentModuleToId(fileName: string, specifier: string) { const params = new URLSearchParams(specifier); - params.set('importer', filePath); - params.set(CONTENT_MODULE_FLAG, 'true'); + params.set('importer', fileName); + params.set(DEFERRED_MODULE, 'true'); return `${specifier}?${params.toString()}`; } diff --git a/packages/astro/src/content/loaders/glob.ts b/packages/astro/src/content/loaders/glob.ts index 792c6bab50b62..d0b04a6761bba 100644 --- a/packages/astro/src/content/loaders/glob.ts +++ b/packages/astro/src/content/loaders/glob.ts @@ -104,7 +104,7 @@ export function glob(globOptions: GlobOptions): Loader { if (existingEntry && existingEntry.digest === digest && existingEntry.filePath) { if (entryType.extensions.includes('.mdx')) { - store.addModuleImport(existingEntry.filePath, 'astro:content-module-imports'); + store.addModuleImport(existingEntry.filePath, 'astro:content-layer-deferred-module'); } if (existingEntry.rendered?.metadata?.imagePaths?.length) { @@ -130,8 +130,8 @@ export function glob(globOptions: GlobOptions): Loader { }); if (entryType.extensions.includes('.mdx')) { - store.addModuleImport(relativePath, 'astro:content-module-imports'); - store.set({ id, data: parsedData, body, filePath: relativePath, digest, isModule: true }); + store.addModuleImport(relativePath, 'astro:content-layer-deferred-module'); + store.set({ id, data: parsedData, body, filePath: relativePath, digest, isDeferred: true }); } else if (entryType.getRenderFunction) { let render = renderFunctionByContentType.get(entryType); if (!render) { diff --git a/packages/astro/src/content/runtime.ts b/packages/astro/src/content/runtime.ts index 6be792740616b..bbbe71611257d 100644 --- a/packages/astro/src/content/runtime.ts +++ b/packages/astro/src/content/runtime.ts @@ -88,44 +88,12 @@ export function createGetCollection({ const data = rawEntry.filePath ? updateImageReferencesInData(rawEntry.data, rawEntry.filePath, imageAssetMap) : rawEntry.data; - let entry; - if (rawEntry.isModule === true) { - try { - // @ts-expect-error virtual module - const { default: contentModules } = await import('astro:content-module-imports'); - const module = contentModules.get(rawEntry.filePath); - const resolvedComponent = await module(); - - entry = { - ...rawEntry, - collection, - id: rawEntry.id, - slug: rawEntry.id, - body: rawEntry.body, - data: rawEntry.data, - async render() { - return { - Content: resolvedComponent.Content, - rendered: { - metadata: { - headings: resolvedComponent.getHeadings?.() ?? [], - remarkPluginFrontmatter: resolvedComponent.frontmatter ?? {}, - } - } - }; - }, - }; - } catch (e) { - console.log(e) - } - - } else { - entry = { - ...rawEntry, - data, - collection, - }; - } + + const entry = { + ...rawEntry, + data, + collection, + }; if (hasFilter && !filter(entry)) { continue; } @@ -477,6 +445,23 @@ export async function renderEntry( return entry.render(); } + if (entry.isDeferred) { + // @ts-expect-error virtual module + const { default: contentModules } = await import('astro:content-module-imports'); + const module = contentModules.get(entry.filePath); + const resolvedComponent = await module(); + + return { + Content: resolvedComponent.Content, + rendered: { + metadata: { + headings: resolvedComponent.getHeadings?.() ?? [], + remarkPluginFrontmatter: resolvedComponent.frontmatter ?? {}, + }, + }, + }; + } + const html = entry?.rendered?.metadata?.imagePaths?.length && entry.filePath ? await updateImageReferencesInBody(entry.rendered.html, entry.filePath) diff --git a/packages/astro/src/content/utils.ts b/packages/astro/src/content/utils.ts index f7bfa8a531caa..dab8fb4b07411 100644 --- a/packages/astro/src/content/utils.ts +++ b/packages/astro/src/content/utils.ts @@ -18,7 +18,8 @@ import { isYAMLException } from '../core/errors/utils.js'; import type { Logger } from '../core/logger/core.js'; import { CONTENT_FLAGS, - CONTENT_LAYER_TYPE, CONTENT_MODULE_FLAG, + CONTENT_LAYER_TYPE, + DEFERRED_MODULE, IMAGE_IMPORT_PREFIX, PROPAGATED_ASSET_FLAG, } from './consts.js'; @@ -474,11 +475,9 @@ export function hasContentFlag(viteId: string, flag: (typeof CONTENT_FLAGS)[numb return flags.has(flag); } -export function hasContentModuleFlag( - viteId: string, -): boolean { +export function isDeferredModule(viteId: string): boolean { const flags = new URLSearchParams(viteId.split('?')[1] ?? ''); - return flags.has(CONTENT_MODULE_FLAG); + return flags.has(DEFERRED_MODULE); } async function loadContentConfig({ diff --git a/packages/astro/src/content/vite-plugin-content-virtual-mod.ts b/packages/astro/src/content/vite-plugin-content-virtual-mod.ts index fd57c5c16e567..36dc36c4bab89 100644 --- a/packages/astro/src/content/vite-plugin-content-virtual-mod.ts +++ b/packages/astro/src/content/vite-plugin-content-virtual-mod.ts @@ -23,8 +23,8 @@ import { DATA_STORE_FILE, DATA_STORE_VIRTUAL_ID, MODULES_IMPORTS_FILE, - MODULES_IMPORTS_ID, - MODULES_IMPORTS_VIRTUAL_ID, + MODULES_MJS_ID, + MODULES_MJS_VIRTUAL_ID, RESOLVED_DATA_STORE_VIRTUAL_ID, RESOLVED_VIRTUAL_MODULE_ID, VIRTUAL_MODULE_ID, @@ -40,7 +40,7 @@ import { getEntrySlug, getEntryType, getExtGlob, - hasContentModuleFlag, + isDeferredModule, } from './utils.js'; interface AstroContentVirtualModPluginParams { @@ -61,7 +61,7 @@ export function astroContentVirtualModPlugin({ configResolved(config) { IS_DEV = config.mode === 'development'; }, - async resolveId(id, importer) { + async resolveId(id) { if (id === VIRTUAL_MODULE_ID) { if (!settings.config.experimental.contentCollectionCache) { return RESOLVED_VIRTUAL_MODULE_ID; @@ -77,28 +77,27 @@ export function astroContentVirtualModPlugin({ return RESOLVED_DATA_STORE_VIRTUAL_ID; } - if (hasContentModuleFlag(id)) { + if (isDeferredModule(id)) { const [, query] = id.split('?'); const params = new URLSearchParams(query); const importerParam = params.get('importer'); - const importerPath = importerParam - ? fileURLToPath(new URL(importerParam, settings.config.root)) - : importer; + let importerPath = undefined; + if (importerParam && URL.canParse(importerParam, settings.config.root.toString())) { + importerPath = fileURLToPath(new URL(importerParam, settings.config.root)); + } if (importerPath) { return await this.resolve(importerPath); } } - if (id === MODULES_IMPORTS_ID) { + if (id === MODULES_MJS_ID) { const modules = new URL(MODULES_IMPORTS_FILE, settings.dotAstroDir); if (fs.existsSync(modules)) { return fileURLToPath(modules); } - return MODULES_IMPORTS_VIRTUAL_ID; + return MODULES_MJS_VIRTUAL_ID; } - - if (id === ASSET_IMPORTS_VIRTUAL_ID) { const assetImportsFile = new URL(ASSET_IMPORTS_FILE, settings.dotAstroDir); if (fs.existsSync(assetImportsFile)) { @@ -156,7 +155,7 @@ export function astroContentVirtualModPlugin({ return 'export default new Map()'; } - if (id === MODULES_IMPORTS_VIRTUAL_ID) { + if (id === MODULES_MJS_VIRTUAL_ID) { return 'export default new Map()'; } }, diff --git a/packages/astro/src/core/errors/errors-data.ts b/packages/astro/src/core/errors/errors-data.ts index 263a8a16aabcf..abc06592c466d 100644 --- a/packages/astro/src/core/errors/errors-data.ts +++ b/packages/astro/src/core/errors/errors-data.ts @@ -1490,7 +1490,8 @@ export const ContentLayerWriteError = { export const GetEntryDeprecationError = { name: 'GetEntryDeprecationError', title: 'Invalid use of `getDataEntryById` or `getEntryBySlug` function.', - message: (collection: string, method: string) => `The \`${method}\` function is deprecated and cannot be used to query the "${collection}" collection. Use \`getEntry\` instead.`, + message: (collection: string, method: string) => + `The \`${method}\` function is deprecated and cannot be used to query the "${collection}" collection. Use \`getEntry\` instead.`, hint: 'Use the `getEntry` or `getCollection` functions to query content layer collections.', } satisfies ErrorData; diff --git a/packages/astro/test/fixtures/content-layer-rendering/src/content/config.ts b/packages/astro/test/fixtures/content-layer-rendering/src/content/config.ts index 9a16cf32d540c..54c0fb5085bdf 100644 --- a/packages/astro/test/fixtures/content-layer-rendering/src/content/config.ts +++ b/packages/astro/test/fixtures/content-layer-rendering/src/content/config.ts @@ -1,5 +1,5 @@ import { defineCollection, z, reference } from 'astro:content'; -import { file, glob } from 'astro/loaders'; +import { glob } from 'astro/loaders'; const reptiles = defineCollection({ type: 'experimental_content', diff --git a/packages/astro/test/fixtures/content-layer-rendering/src/pages/reptiles/[slug].astro b/packages/astro/test/fixtures/content-layer-rendering/src/pages/reptiles/[slug].astro index 75ba77ba0bb92..526805e099474 100644 --- a/packages/astro/test/fixtures/content-layer-rendering/src/pages/reptiles/[slug].astro +++ b/packages/astro/test/fixtures/content-layer-rendering/src/pages/reptiles/[slug].astro @@ -8,7 +8,7 @@ export const getStaticPaths = (async () => { if(!collection) return [] return collection.map((reptile) => ({ params: { - slug: `/${reptile.id}` + slug: `${reptile.id}` }, props: { reptile