diff --git a/.changeset/clever-garlics-doubt.md b/.changeset/clever-garlics-doubt.md
deleted file mode 100644
index a09ca541e..000000000
--- a/.changeset/clever-garlics-doubt.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-'@astrojs/sitemap': patch
----
-
-exported enum type to support typescript > 5.0
diff --git a/.changeset/curvy-hotels-study.md b/.changeset/curvy-hotels-study.md
deleted file mode 100644
index 7ac2e8033..000000000
--- a/.changeset/curvy-hotels-study.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-'@astrojs/partytown': patch
----
-
-fix typescript type for partytown options
diff --git a/.changeset/dirty-singers-enjoy.md b/.changeset/dirty-singers-enjoy.md
deleted file mode 100644
index b02f166fe..000000000
--- a/.changeset/dirty-singers-enjoy.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-'@astrojs/mdx': patch
----
-
-Add `optimize` option for faster builds and rendering
diff --git a/.changeset/dry-taxis-suffer.md b/.changeset/dry-taxis-suffer.md
deleted file mode 100644
index b0cb68b24..000000000
--- a/.changeset/dry-taxis-suffer.md
+++ /dev/null
@@ -1,6 +0,0 @@
----
-'astro': patch
----
-
-Refactor how pages are emitted during the internal bundling. Now each
-page is emitted as a separate entry point.
diff --git a/.changeset/eighty-gifts-cheer.md b/.changeset/eighty-gifts-cheer.md
deleted file mode 100644
index 41ca0d7f6..000000000
--- a/.changeset/eighty-gifts-cheer.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-'astro': patch
----
-
-Fix CSS deduping and missing chunks
diff --git a/.changeset/eleven-tables-speak.md b/.changeset/eleven-tables-speak.md
deleted file mode 100644
index 3eac90a36..000000000
--- a/.changeset/eleven-tables-speak.md
+++ /dev/null
@@ -1,19 +0,0 @@
----
-'@astrojs/markdoc': patch
----
-
-Add support for syntax highlighting with Shiki. Apply to your Markdoc config using the `extends` property:
-
-```js
-// markdoc.config.mjs
-import { defineMarkdocConfig } from '@astrojs/markdoc/config';
-import shiki from '@astrojs/markdoc/shiki';
-
-export default defineMarkdocConfig({
- extends: [
- shiki({ /** Shiki config options */ }),
- ],
-})
-```
-
-Learn more in the [`@astrojs/markdoc` README.](https://docs.astro.build/en/guides/integrations-guide/markdoc/#syntax-highlighting)
diff --git a/.changeset/eleven-walls-explain.md b/.changeset/eleven-walls-explain.md
deleted file mode 100644
index fd2772185..000000000
--- a/.changeset/eleven-walls-explain.md
+++ /dev/null
@@ -1,7 +0,0 @@
----
-'@astrojs/preact': patch
-'@astrojs/react': patch
-'@astrojs/vue': patch
----
-
-Fix `astro-static-slot` hydration mismatch error
diff --git a/.changeset/fifty-months-mix.md b/.changeset/fifty-months-mix.md
deleted file mode 100644
index 78a009950..000000000
--- a/.changeset/fifty-months-mix.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-'@astrojs/webapi': minor
----
-
-Add polyfill for `crypto`
diff --git a/.changeset/hungry-peaches-speak.md b/.changeset/hungry-peaches-speak.md
deleted file mode 100644
index 4467b521d..000000000
--- a/.changeset/hungry-peaches-speak.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-'astro': patch
----
-
-Prioritize dynamic prerendered routes over dynamic server routes
diff --git a/.changeset/lazy-zebras-invent.md b/.changeset/lazy-zebras-invent.md
deleted file mode 100644
index 1c2abb981..000000000
--- a/.changeset/lazy-zebras-invent.md
+++ /dev/null
@@ -1,6 +0,0 @@
----
-'@astrojs/mdx': patch
-'astro': patch
----
-
-Detect `mdx` files using their full extension
diff --git a/.changeset/moody-coats-develop.md b/.changeset/moody-coats-develop.md
deleted file mode 100644
index 20c12708c..000000000
--- a/.changeset/moody-coats-develop.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-'astro': patch
----
-
-Add error message if `Astro.glob` is called outside of an Astro file
diff --git a/.changeset/plenty-geese-fold.md b/.changeset/plenty-geese-fold.md
deleted file mode 100644
index aa7783e92..000000000
--- a/.changeset/plenty-geese-fold.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-'@astrojs/vercel': patch
----
-
-Fix `imagesConfig` being wrongly spelt as `imageConfig` in the README
diff --git a/.changeset/popular-berries-travel.md b/.changeset/popular-berries-travel.md
deleted file mode 100644
index a3755d267..000000000
--- a/.changeset/popular-berries-travel.md
+++ /dev/null
@@ -1,17 +0,0 @@
----
-'@astrojs/markdoc': patch
----
-
-Add a built-in extension for syntax highlighting with Prism. Apply to your Markdoc config using the `extends` property:
-
-```js
-// markdoc.config.mjs
-import { defineMarkdocConfig } from '@astrojs/markdoc/config';
-import prism from '@astrojs/markdoc/prism';
-
-export default defineMarkdocConfig({
- extends: [prism()],
-})
-```
-
-Learn more in the [`@astrojs/markdoc` README.](https://docs.astro.build/en/guides/integrations-guide/markdoc/#syntax-highlighting)
diff --git a/.changeset/small-wombats-know.md b/.changeset/small-wombats-know.md
deleted file mode 100644
index ca826a1aa..000000000
--- a/.changeset/small-wombats-know.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-'astro': patch
----
-
-fix miss a head when the templaterender has a promise
diff --git a/.changeset/spotty-glasses-return.md b/.changeset/spotty-glasses-return.md
deleted file mode 100644
index 6786f77eb..000000000
--- a/.changeset/spotty-glasses-return.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-'@astrojs/mdx': patch
----
-
-Remove `@mdx-js/rollup` dependency
diff --git a/.changeset/static-slot-css.md b/.changeset/static-slot-css.md
deleted file mode 100644
index a3f1c2475..000000000
--- a/.changeset/static-slot-css.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-'astro': patch
----
-
-fix: add astro-static-slot to the list of inert tags in astro css
diff --git a/.changeset/strange-socks-give.md b/.changeset/strange-socks-give.md
deleted file mode 100644
index f1e9492bd..000000000
--- a/.changeset/strange-socks-give.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-'astro': patch
----
-
-Use `AstroError` for `Astro.glob` errors
diff --git a/.changeset/wise-cars-hear.md b/.changeset/wise-cars-hear.md
deleted file mode 100644
index 21019c26f..000000000
--- a/.changeset/wise-cars-hear.md
+++ /dev/null
@@ -1,5 +0,0 @@
----
-'astro': patch
----
-
-The `src` property returned by ESM importing images with `astro:assets` is now an absolute path, unlocking support for importing images outside the project.
diff --git a/packages/astro/CHANGELOG.md b/packages/astro/CHANGELOG.md
index 9710862db..5eefd0415 100644
--- a/packages/astro/CHANGELOG.md
+++ b/packages/astro/CHANGELOG.md
@@ -1,5 +1,46 @@
# astro
+## 2.5.6
+
+### Patch Changes
+
+- [#7193](https://github.com/withastro/astro/pull/7193) [`8b041bf57`](https://github.com/withastro/astro/commit/8b041bf57c76830c4070330270521e05d8e58474) Thanks [@ematipico](https://github.com/ematipico)! - Refactor how pages are emitted during the internal bundling. Now each
+ page is emitted as a separate entry point.
+
+- [#7218](https://github.com/withastro/astro/pull/7218) [`6c7df28ab`](https://github.com/withastro/astro/commit/6c7df28ab34b756b8426443bf6976e24d4611a62) Thanks [@bluwy](https://github.com/bluwy)! - Fix CSS deduping and missing chunks
+
+- [#7235](https://github.com/withastro/astro/pull/7235) [`ee2aca80a`](https://github.com/withastro/astro/commit/ee2aca80a71afe843af943b11966fcf77f556cfb) Thanks [@MoustaphaDev](https://github.com/MoustaphaDev)! - Prioritize dynamic prerendered routes over dynamic server routes
+
+- [#7192](https://github.com/withastro/astro/pull/7192) [`7851f9258`](https://github.com/withastro/astro/commit/7851f9258fae2f54795470253df9ce4bcd5f9cb0) Thanks [@ematipico](https://github.com/ematipico)! - Detect `mdx` files using their full extension
+
+- [#7244](https://github.com/withastro/astro/pull/7244) [`bef3a75db`](https://github.com/withastro/astro/commit/bef3a75dbc48d584daff9f7f3d5a8937b0356170) Thanks [@bholmesdev](https://github.com/bholmesdev)! - Remove the auto-generated `$entry` variable for Markdoc entries. To access frontmatter as a variable, you can pass `entry.data` as a prop where you render your content:
+
+ ```astro
+ ---
+ import { getEntry } from 'astro:content';
+
+ const entry = await getEntry('docs', 'why-markdoc');
+ const { Content } = await entry.render();
+ ---
+
+
+ ```
+
+- [#7204](https://github.com/withastro/astro/pull/7204) [`52af9ad18`](https://github.com/withastro/astro/commit/52af9ad18840ffa4e2996386c82cbe34d9fd076a) Thanks [@bluwy](https://github.com/bluwy)! - Add error message if `Astro.glob` is called outside of an Astro file
+
+- [#7246](https://github.com/withastro/astro/pull/7246) [`f5063d0a0`](https://github.com/withastro/astro/commit/f5063d0a01e3179da902fdc0a2b22f88cb3c95c7) Thanks [@bholmesdev](https://github.com/bholmesdev)! - Fix content collection build errors for empty collections or underscore files of type `.json`.
+
+- [#7062](https://github.com/withastro/astro/pull/7062) [`cf621340b`](https://github.com/withastro/astro/commit/cf621340b00fda441f4ef43196c0363d09eae70c) Thanks [@wulinsheng123](https://github.com/wulinsheng123)! - fix miss a head when the templaterender has a promise
+
+- [#7189](https://github.com/withastro/astro/pull/7189) [`2bda7fb0b`](https://github.com/withastro/astro/commit/2bda7fb0bce346f7725086980e1648e2636bbefb) Thanks [@elevatebart](https://github.com/elevatebart)! - fix: add astro-static-slot to the list of inert tags in astro css
+
+- [#7219](https://github.com/withastro/astro/pull/7219) [`af3c5a2e2`](https://github.com/withastro/astro/commit/af3c5a2e25bd3e7b2a3f7f08e41ee457093c8cb1) Thanks [@bluwy](https://github.com/bluwy)! - Use `AstroError` for `Astro.glob` errors
+
+- [#7139](https://github.com/withastro/astro/pull/7139) [`f2f18b440`](https://github.com/withastro/astro/commit/f2f18b44055c6334a39d6379de88fe41e518aa1e) Thanks [@Princesseuh](https://github.com/Princesseuh)! - The `src` property returned by ESM importing images with `astro:assets` is now an absolute path, unlocking support for importing images outside the project.
+
+- Updated dependencies [[`bf63f615f`](https://github.com/withastro/astro/commit/bf63f615fc1b97d6fb84db55f7639084e3ada5af)]:
+ - @astrojs/webapi@2.2.0
+
## 2.5.5
### Patch Changes
diff --git a/packages/astro/package.json b/packages/astro/package.json
index 8fa7bb7f1..abd3f8fa8 100644
--- a/packages/astro/package.json
+++ b/packages/astro/package.json
@@ -1,6 +1,6 @@
{
"name": "astro",
- "version": "2.5.5",
+ "version": "2.5.6",
"description": "Astro is a modern site builder with web best practices, performance, and DX front-of-mind.",
"type": "module",
"author": "withastro",
@@ -117,7 +117,7 @@
"@astrojs/language-server": "^1.0.0",
"@astrojs/markdown-remark": "^2.2.1",
"@astrojs/telemetry": "^2.1.1",
- "@astrojs/webapi": "^2.1.1",
+ "@astrojs/webapi": "^2.2.0",
"@babel/core": "^7.21.8",
"@babel/generator": "^7.18.2",
"@babel/parser": "^7.18.4",
diff --git a/packages/astro/src/@types/astro.ts b/packages/astro/src/@types/astro.ts
index c37d9a3f7..bb37c4989 100644
--- a/packages/astro/src/@types/astro.ts
+++ b/packages/astro/src/@types/astro.ts
@@ -1275,8 +1275,9 @@ export interface ContentEntryType {
getRenderModule?(
this: rollup.PluginContext,
params: {
+ contents: string;
+ fileUrl: URL;
viteId: string;
- entry: ContentEntryModule;
}
): rollup.LoadResult | Promise;
contentModuleTypes?: string;
diff --git a/packages/astro/src/content/types-generator.ts b/packages/astro/src/content/types-generator.ts
index ee4c99077..7958c330f 100644
--- a/packages/astro/src/content/types-generator.ts
+++ b/packages/astro/src/content/types-generator.ts
@@ -11,12 +11,12 @@ import { info, warn, type LogOptions } from '../core/logger/core.js';
import { isRelativePath } from '../core/path.js';
import { CONTENT_TYPES_FILE, VIRTUAL_MODULE_ID } from './consts.js';
import {
- getContentEntryConfigByExtMap,
getContentEntryIdAndSlug,
getContentPaths,
getDataEntryExts,
getDataEntryId,
getEntryCollectionName,
+ getEntryConfigByExtMap,
getEntrySlug,
getEntryType,
reloadContentConfigObserver,
@@ -74,7 +74,7 @@ export async function createContentTypesGenerator({
}: CreateContentGeneratorParams) {
const collectionEntryMap: CollectionEntryMap = {};
const contentPaths = getContentPaths(settings.config, fs);
- const contentEntryConfigByExt = getContentEntryConfigByExtMap(settings);
+ const contentEntryConfigByExt = getEntryConfigByExtMap(settings.contentEntryTypes);
const contentEntryExts = [...contentEntryConfigByExt.keys()];
const dataEntryExts = getDataEntryExts(settings);
@@ -414,7 +414,11 @@ async function writeContentFiles({
for (const collectionKey of Object.keys(collectionEntryMap).sort()) {
const collectionConfig = contentConfig?.collections[JSON.parse(collectionKey)];
const collection = collectionEntryMap[collectionKey];
- if (collectionConfig?.type && collection.type !== collectionConfig.type) {
+ if (
+ collectionConfig?.type &&
+ collection.type !== 'unknown' &&
+ collection.type !== collectionConfig.type
+ ) {
viteServer.ws.send({
type: 'error',
err: new AstroError({
@@ -433,7 +437,14 @@ async function writeContentFiles({
});
return;
}
- switch (collection.type) {
+ const resolvedType: 'content' | 'data' =
+ collection.type === 'unknown'
+ ? // Add empty / unknown collections to the data type map by default
+ // This ensures `getCollection('empty-collection')` doesn't raise a type error
+ collectionConfig?.type ?? 'data'
+ : collection.type;
+
+ switch (resolvedType) {
case 'content':
contentTypesStr += `${collectionKey}: {\n`;
for (const entryKey of Object.keys(collection.entries).sort()) {
@@ -449,9 +460,6 @@ async function writeContentFiles({
contentTypesStr += `};\n`;
break;
case 'data':
- // Add empty / unknown collections to the data type map by default
- // This ensures `getCollection('empty-collection')` doesn't raise a type error
- case 'unknown':
dataTypesStr += `${collectionKey}: {\n`;
for (const entryKey of Object.keys(collection.entries).sort()) {
const dataType = collectionConfig?.schema ? `InferEntrySchema<${collectionKey}>` : 'any';
diff --git a/packages/astro/src/content/utils.ts b/packages/astro/src/content/utils.ts
index 686176096..40b2ab9e7 100644
--- a/packages/astro/src/content/utils.ts
+++ b/packages/astro/src/content/utils.ts
@@ -10,6 +10,7 @@ import type {
AstroConfig,
AstroSettings,
ContentEntryType,
+ DataEntryType,
ImageInputFormat,
} from '../@types/astro.js';
import { VALID_INPUT_FORMATS } from '../assets/consts.js';
@@ -172,9 +173,11 @@ export function getDataEntryExts(settings: Pick
return settings.dataEntryTypes.map((t) => t.extensions).flat();
}
-export function getContentEntryConfigByExtMap(settings: Pick) {
- const map: Map = new Map();
- for (const entryType of settings.contentEntryTypes) {
+export function getEntryConfigByExtMap(
+ entryTypes: TEntryType[]
+): Map {
+ const map: Map = new Map();
+ for (const entryType of entryTypes) {
for (const ext of entryType.extensions) {
map.set(ext, entryType);
}
diff --git a/packages/astro/src/content/vite-plugin-content-imports.ts b/packages/astro/src/content/vite-plugin-content-imports.ts
index c0d0571e3..8e8ee0ba0 100644
--- a/packages/astro/src/content/vite-plugin-content-imports.ts
+++ b/packages/astro/src/content/vite-plugin-content-imports.ts
@@ -5,6 +5,7 @@ import type { PluginContext } from 'rollup';
import { pathToFileURL } from 'url';
import type { Plugin } from 'vite';
import type {
+ AstroConfig,
AstroSettings,
ContentEntryModule,
ContentEntryType,
@@ -13,16 +14,16 @@ import type {
} from '../@types/astro.js';
import { AstroErrorData } from '../core/errors/errors-data.js';
import { AstroError } from '../core/errors/errors.js';
-import { escapeViteEnvReferences, getFileInfo } from '../vite-plugin-utils/index.js';
+import { escapeViteEnvReferences } from '../vite-plugin-utils/index.js';
import { CONTENT_FLAG, DATA_FLAG } from './consts.js';
import {
- getContentEntryConfigByExtMap,
getContentEntryExts,
getContentEntryIdAndSlug,
getContentPaths,
getDataEntryExts,
getDataEntryId,
getEntryCollectionName,
+ getEntryConfigByExtMap,
getEntryData,
getEntryType,
globalContentConfigObserver,
@@ -30,7 +31,6 @@ import {
parseEntrySlug,
reloadContentConfigObserver,
type ContentConfig,
- type ContentPaths,
} from './utils.js';
function getContentRendererByViteId(
@@ -70,14 +70,9 @@ export function astroContentImportPlugin({
const contentEntryExts = getContentEntryExts(settings);
const dataEntryExts = getDataEntryExts(settings);
- const contentEntryConfigByExt = getContentEntryConfigByExtMap(settings);
-
- const dataEntryExtToParser: Map = new Map();
- for (const entryType of settings.dataEntryTypes) {
- for (const ext of entryType.extensions) {
- dataEntryExtToParser.set(ext, entryType.getEntryInfo);
- }
- }
+ const contentEntryConfigByExt = getEntryConfigByExtMap(settings.contentEntryTypes);
+ const dataEntryConfigByExt = getEntryConfigByExtMap(settings.dataEntryTypes);
+ const { contentDir } = contentPaths;
const plugins: Plugin[] = [
{
@@ -89,9 +84,9 @@ export function astroContentImportPlugin({
// This cache only exists for the `render()` function specific to content.
const { id, data, collection, _internal } = await getDataEntryModule({
fileId,
- dataEntryExtToParser,
- contentPaths,
- settings,
+ entryConfigByExt: dataEntryConfigByExt,
+ contentDir,
+ config: settings.config,
fs,
pluginContext: this,
});
@@ -109,8 +104,12 @@ export const _internal = {
return code;
} else if (hasContentFlag(viteId, CONTENT_FLAG)) {
const fileId = viteId.split('?')[0];
- const { id, slug, collection, body, data, _internal } = await setContentEntryModuleCache({
+ const { id, slug, collection, body, data, _internal } = await getContentEntryModule({
fileId,
+ entryConfigByExt: contentEntryConfigByExt,
+ contentDir,
+ config: settings.config,
+ fs,
pluginContext: this,
});
@@ -170,152 +169,153 @@ export const _internal = {
if (settings.contentEntryTypes.some((t) => t.getRenderModule)) {
plugins.push({
name: 'astro:content-render-imports',
- async transform(_, viteId) {
+ async transform(contents, viteId) {
const contentRenderer = getContentRendererByViteId(viteId, settings);
if (!contentRenderer) return;
- const { fileId } = getFileInfo(viteId, settings.config);
- const entry = await getContentEntryModuleFromCache(fileId);
- if (!entry) {
- // Cached entry must exist (or be in-flight) when importing the module via content collections.
- // This is ensured by the `astro:content-imports` plugin.
- 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 contentRenderer.bind(this)({ entry, viteId });
+ const fileId = viteId.split('?')[0];
+ return contentRenderer.bind(this)({ viteId, contents, fileUrl: pathToFileURL(fileId) });
},
});
}
- /**
- * There are two content collection plugins that depend on the same entry data:
- * - `astro:content-imports` - creates module containing the `getCollection()` result.
- * - `astro:content-render-imports` - creates module containing the `collectionEntry.render()` result.
- *
- * We could run the same transforms to generate the slug and parsed data in each plugin,
- * though this would run the user's collection schema _twice_ for each entry.
- *
- * Instead, we've implemented a cache for all content entry data. To avoid race conditions,
- * this may store either the module itself or a queue of promises awaiting this module.
- * See the implementations of `getContentEntryModuleFromCache` and `setContentEntryModuleCache`.
- */
- const contentEntryModuleByIdCache = new Map<
- string,
- ContentEntryModule | AwaitingCacheResultQueue
- >();
- type AwaitingCacheResultQueue = {
- awaitingQueue: ((val: ContentEntryModule) => void)[];
- };
- function isAwaitingQueue(
- cacheEntry: ReturnType
- ): cacheEntry is AwaitingCacheResultQueue {
- return typeof cacheEntry === 'object' && cacheEntry != null && 'awaitingQueue' in cacheEntry;
- }
-
- function getContentEntryModuleFromCache(id: string): Promise {
- const cacheEntry = contentEntryModuleByIdCache.get(id);
- // It's possible to request an entry while `setContentEntryModuleCache` is still
- // setting that entry. In this case, queue a promise for `setContentEntryModuleCache`
- // to resolve once it is complete.
- if (isAwaitingQueue(cacheEntry)) {
- return new Promise((resolve, reject) => {
- cacheEntry.awaitingQueue.push(resolve);
- });
- } else if (cacheEntry) {
- return Promise.resolve(cacheEntry);
- }
- return Promise.resolve(undefined);
- }
-
- async function setContentEntryModuleCache({
- fileId,
- pluginContext,
- }: {
- fileId: string;
- pluginContext: PluginContext;
- }): Promise {
- // Create a queue so, if `getContentEntryModuleFromCache` is called
- // while this function is running, we can resolve all requests
- // in the `awaitingQueue` with the result.
- contentEntryModuleByIdCache.set(fileId, { awaitingQueue: [] });
-
- const contentConfig = await getContentConfigFromGlobal();
- const rawContents = await fs.promises.readFile(fileId, 'utf-8');
- const fileExt = extname(fileId);
- if (!contentEntryConfigByExt.has(fileExt)) {
- throw new AstroError({
- ...AstroErrorData.UnknownContentCollectionError,
- message: `No parser found for content entry ${JSON.stringify(
- fileId
- )}. Did you apply an integration for this file type?`,
- });
- }
- const contentEntryConfig = contentEntryConfigByExt.get(fileExt)!;
- const {
- rawData,
- body,
- slug: frontmatterSlug,
- data: unvalidatedData,
- } = await contentEntryConfig.getEntryInfo({
- fileUrl: pathToFileURL(fileId),
- contents: rawContents,
- });
- const entry = pathToFileURL(fileId);
- const { contentDir } = contentPaths;
- const collection = getEntryCollectionName({ entry, contentDir });
- if (collection === undefined)
- throw new AstroError(AstroErrorData.UnknownContentCollectionError);
-
- const { id, slug: generatedSlug } = getContentEntryIdAndSlug({ entry, contentDir, collection });
-
- const _internal = { filePath: fileId, rawData: rawData };
- // TODO: move slug calculation to the start of the build
- // to generate a performant lookup map for `getEntryBySlug`
- const slug = parseEntrySlug({
- id,
- collection,
- generatedSlug,
- frontmatterSlug,
- });
-
- const collectionConfig = contentConfig?.collections[collection];
- let data = collectionConfig
- ? await getEntryData(
- { id, collection, _internal, unvalidatedData },
- collectionConfig,
- pluginContext,
- settings.config
- )
- : unvalidatedData;
-
- const contentEntryModule: ContentEntryModule = {
- id,
- slug,
- collection,
- data,
- body,
- _internal,
- };
-
- const cacheEntry = contentEntryModuleByIdCache.get(fileId);
- // Pass the entry to all promises awaiting this result
- if (isAwaitingQueue(cacheEntry)) {
- for (const resolve of cacheEntry.awaitingQueue) {
- resolve(contentEntryModule);
- }
- }
- contentEntryModuleByIdCache.set(fileId, contentEntryModule);
- return contentEntryModule;
- }
-
return plugins;
}
+type GetEntryModuleParams = {
+ fs: typeof fsMod;
+ fileId: string;
+ contentDir: URL;
+ pluginContext: PluginContext;
+ entryConfigByExt: Map;
+ config: AstroConfig;
+};
+
+async function getContentEntryModule(
+ params: GetEntryModuleParams
+): Promise {
+ const { fileId, contentDir, pluginContext, config } = params;
+ const { collectionConfig, entryConfig, entry, rawContents, collection } =
+ await getEntryModuleBaseInfo(params);
+
+ const {
+ rawData,
+ data: unvalidatedData,
+ body,
+ slug: frontmatterSlug,
+ } = await entryConfig.getEntryInfo({
+ fileUrl: pathToFileURL(fileId),
+ contents: rawContents,
+ });
+ const _internal = { filePath: fileId, rawData };
+ const { id, slug: generatedSlug } = getContentEntryIdAndSlug({ entry, contentDir, collection });
+
+ const slug = parseEntrySlug({
+ id,
+ collection,
+ generatedSlug,
+ frontmatterSlug,
+ });
+
+ const data = collectionConfig
+ ? await getEntryData(
+ { id, collection, _internal, unvalidatedData },
+ collectionConfig,
+ pluginContext,
+ config
+ )
+ : unvalidatedData;
+
+ const contentEntryModule: ContentEntryModule = {
+ id,
+ slug,
+ collection,
+ data,
+ body,
+ _internal,
+ };
+
+ return contentEntryModule;
+}
+
+async function getDataEntryModule(
+ params: GetEntryModuleParams
+): Promise {
+ const { fileId, contentDir, pluginContext, config } = params;
+ const { collectionConfig, entryConfig, entry, rawContents, collection } =
+ await getEntryModuleBaseInfo(params);
+
+ const { rawData = '', data: unvalidatedData } = await entryConfig.getEntryInfo({
+ fileUrl: pathToFileURL(fileId),
+ contents: rawContents,
+ });
+ const _internal = { filePath: fileId, rawData };
+ const id = getDataEntryId({ entry, contentDir, collection });
+
+ const data = collectionConfig
+ ? await getEntryData(
+ { id, collection, _internal, unvalidatedData },
+ collectionConfig,
+ pluginContext,
+ config
+ )
+ : unvalidatedData;
+
+ const dataEntryModule: DataEntryModule = {
+ id,
+ collection,
+ data,
+ _internal,
+ };
+
+ return dataEntryModule;
+}
+
+// Shared logic for `getContentEntryModule` and `getDataEntryModule`
+// Extracting to a helper was easier that conditionals and generics :)
+async function getEntryModuleBaseInfo({
+ fileId,
+ entryConfigByExt,
+ contentDir,
+ fs,
+}: GetEntryModuleParams) {
+ const contentConfig = await getContentConfigFromGlobal();
+ let rawContents;
+ try {
+ rawContents = await fs.promises.readFile(fileId, 'utf-8');
+ } catch (e) {
+ throw new AstroError({
+ ...AstroErrorData.UnknownContentCollectionError,
+ message: `Unexpected error reading entry ${JSON.stringify(fileId)}.`,
+ stack: e instanceof Error ? e.stack : undefined,
+ });
+ }
+ const fileExt = extname(fileId);
+ const entryConfig = entryConfigByExt.get(fileExt);
+
+ if (!entryConfig) {
+ throw new AstroError({
+ ...AstroErrorData.UnknownContentCollectionError,
+ message: `No parser found for data entry ${JSON.stringify(
+ fileId
+ )}. Did you apply an integration for this file type?`,
+ });
+ }
+ const entry = pathToFileURL(fileId);
+ const collection = getEntryCollectionName({ entry, contentDir });
+ if (collection === undefined) throw new AstroError(AstroErrorData.UnknownContentCollectionError);
+
+ const collectionConfig = contentConfig?.collections[collection];
+
+ return {
+ collectionConfig,
+ entry,
+ entryConfig,
+ collection,
+ rawContents,
+ };
+}
+
async function getContentConfigFromGlobal() {
const observable = globalContentConfigObserver.get();
@@ -352,68 +352,3 @@ async function getContentConfigFromGlobal() {
return contentConfig;
}
-
-type GetDataEntryModuleParams = {
- fs: typeof fsMod;
- fileId: string;
- contentPaths: Pick;
- pluginContext: PluginContext;
- dataEntryExtToParser: Map;
- settings: Pick;
-};
-
-async function getDataEntryModule({
- fileId,
- dataEntryExtToParser,
- contentPaths,
- fs,
- pluginContext,
- settings,
-}: GetDataEntryModuleParams): Promise {
- const contentConfig = await getContentConfigFromGlobal();
- let rawContents;
- try {
- rawContents = await fs.promises.readFile(fileId, 'utf-8');
- } catch (e) {
- throw new AstroError({
- ...AstroErrorData.UnknownContentCollectionError,
- message: `Unexpected error reading entry ${JSON.stringify(fileId)}.`,
- stack: e instanceof Error ? e.stack : undefined,
- });
- }
- const fileExt = extname(fileId);
- const dataEntryParser = dataEntryExtToParser.get(fileExt);
-
- if (!dataEntryParser) {
- throw new AstroError({
- ...AstroErrorData.UnknownContentCollectionError,
- message: `No parser found for data entry ${JSON.stringify(
- fileId
- )}. Did you apply an integration for this file type?`,
- });
- }
- const { data: unvalidatedData, rawData = '' } = await dataEntryParser({
- fileUrl: pathToFileURL(fileId),
- contents: rawContents,
- });
- const entry = pathToFileURL(fileId);
- const { contentDir } = contentPaths;
- const collection = getEntryCollectionName({ entry, contentDir });
- if (collection === undefined) throw new AstroError(AstroErrorData.UnknownContentCollectionError);
-
- const id = getDataEntryId({ entry, contentDir, collection });
-
- const _internal = { filePath: fileId, rawData };
-
- const collectionConfig = contentConfig?.collections[collection];
- const data = collectionConfig
- ? await getEntryData(
- { id, collection, _internal, unvalidatedData },
- collectionConfig,
- pluginContext,
- settings.config
- )
- : unvalidatedData;
-
- return { id, collection, data, _internal };
-}
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 71d41751e..838d6b425 100644
--- a/packages/astro/src/content/vite-plugin-content-virtual-mod.ts
+++ b/packages/astro/src/content/vite-plugin-content-virtual-mod.ts
@@ -4,17 +4,17 @@ import { extname } from 'node:path';
import { fileURLToPath, pathToFileURL } from 'node:url';
import pLimit from 'p-limit';
import type { Plugin } from 'vite';
-import type { AstroSettings } from '../@types/astro.js';
+import type { AstroSettings, ContentEntryType } from '../@types/astro.js';
import { AstroError, AstroErrorData } from '../core/errors/index.js';
import { rootRelativePath } from '../core/util.js';
import { VIRTUAL_MODULE_ID } from './consts.js';
import {
- getContentEntryConfigByExtMap,
getContentEntryIdAndSlug,
getContentPaths,
getDataEntryExts,
getDataEntryId,
getEntryCollectionName,
+ getEntryConfigByExtMap,
getEntrySlug,
getEntryType,
getExtGlob,
@@ -32,7 +32,7 @@ export function astroContentVirtualModPlugin({
const contentPaths = getContentPaths(settings.config);
const relContentDir = rootRelativePath(settings.config.root, contentPaths.contentDir);
- const contentEntryConfigByExt = getContentEntryConfigByExtMap(settings);
+ const contentEntryConfigByExt = getEntryConfigByExtMap(settings.contentEntryTypes);
const contentEntryExts = [...contentEntryConfigByExt.keys()];
const dataEntryExts = getDataEntryExts(settings);
@@ -43,8 +43,12 @@ export function astroContentVirtualModPlugin({
new URL('reference-map.json', contentPaths.cacheDir).pathname
)
.replace('@@CONTENT_DIR@@', relContentDir)
- .replace('@@CONTENT_ENTRY_GLOB_PATH@@', `${relContentDir}**/*${getExtGlob(contentEntryExts)}`)
- .replace('@@DATA_ENTRY_GLOB_PATH@@', `${relContentDir}**/*${getExtGlob(dataEntryExts)}`)
+ .replace(
+ '@@CONTENT_ENTRY_GLOB_PATH@@',
+ // [!_] = ignore files starting with "_"
+ `${relContentDir}**/[!_]*${getExtGlob(contentEntryExts)}`
+ )
+ .replace('@@DATA_ENTRY_GLOB_PATH@@', `${relContentDir}**/[!_]*${getExtGlob(dataEntryExts)}`)
.replace(
'@@RENDER_ENTRY_GLOB_PATH@@',
`${relContentDir}**/*${getExtGlob(/** Note: data collections excluded */ contentEntryExts)}`
@@ -92,7 +96,7 @@ export async function getStringifiedLookupMap({
root,
fs,
}: {
- contentEntryConfigByExt: ReturnType;
+ contentEntryConfigByExt: Map;
dataEntryExts: string[];
contentPaths: Pick;
root: URL;
diff --git a/packages/astro/test/units/dev/collections-mixed-content-errors.test.js b/packages/astro/test/units/dev/collections-mixed-content-errors.test.js
index 355f54a0f..d323946f8 100644
--- a/packages/astro/test/units/dev/collections-mixed-content-errors.test.js
+++ b/packages/astro/test/units/dev/collections-mixed-content-errors.test.js
@@ -119,4 +119,32 @@ title: Post
expect(e.hint).to.include("Try adding `type: 'data'`");
}
});
+
+ it('does not raise error for empty collection with config', async () => {
+ const fs = createFsWithFallback(
+ {
+ // Add placeholder to ensure directory exists
+ '/src/content/i18n/_placeholder.txt': 'Need content here',
+ '/src/content/config.ts': `
+ import { z, defineCollection } from 'astro:content';
+
+ const i18n = defineCollection({
+ type: 'data',
+ schema: z.object({
+ greeting: z.string(),
+ }),
+ });
+
+ export const collections = { i18n };`,
+ },
+ root
+ );
+
+ try {
+ const res = await sync({ fs });
+ expect(res).to.equal(0);
+ } catch (e) {
+ expect.fail(0, 1, `Did not expect sync to throw: ${e.message}`);
+ }
+ });
});
diff --git a/packages/integrations/cloudflare/package.json b/packages/integrations/cloudflare/package.json
index cd8bd1dec..99059421b 100644
--- a/packages/integrations/cloudflare/package.json
+++ b/packages/integrations/cloudflare/package.json
@@ -43,7 +43,7 @@
"tiny-glob": "^0.2.9"
},
"peerDependencies": {
- "astro": "workspace:^2.5.5"
+ "astro": "workspace:^2.5.6"
},
"devDependencies": {
"astro": "workspace:*",
diff --git a/packages/integrations/deno/package.json b/packages/integrations/deno/package.json
index fc0402570..60a8bd0a1 100644
--- a/packages/integrations/deno/package.json
+++ b/packages/integrations/deno/package.json
@@ -36,7 +36,7 @@
"esbuild": "^0.15.18"
},
"peerDependencies": {
- "astro": "workspace:^2.5.5"
+ "astro": "workspace:^2.5.6"
},
"devDependencies": {
"astro": "workspace:*",
diff --git a/packages/integrations/image/package.json b/packages/integrations/image/package.json
index 76fd1b633..ed7b1caba 100644
--- a/packages/integrations/image/package.json
+++ b/packages/integrations/image/package.json
@@ -62,7 +62,7 @@
"vite": "^4.3.1"
},
"peerDependencies": {
- "astro": "workspace:^2.5.5",
+ "astro": "workspace:^2.5.6",
"sharp": ">=0.31.0"
},
"peerDependenciesMeta": {
diff --git a/packages/integrations/markdoc/CHANGELOG.md b/packages/integrations/markdoc/CHANGELOG.md
index d2233ff60..a737acc4c 100644
--- a/packages/integrations/markdoc/CHANGELOG.md
+++ b/packages/integrations/markdoc/CHANGELOG.md
@@ -1,5 +1,59 @@
# @astrojs/markdoc
+## 0.3.0
+
+### Minor Changes
+
+- [#7244](https://github.com/withastro/astro/pull/7244) [`bef3a75db`](https://github.com/withastro/astro/commit/bef3a75dbc48d584daff9f7f3d5a8937b0356170) Thanks [@bholmesdev](https://github.com/bholmesdev)! - Remove the auto-generated `$entry` variable for Markdoc entries. To access frontmatter as a variable, you can pass `entry.data` as a prop where you render your content:
+
+ ```astro
+ ---
+ import { getEntry } from 'astro:content';
+
+ const entry = await getEntry('docs', 'why-markdoc');
+ const { Content } = await entry.render();
+ ---
+
+
+ ```
+
+### Patch Changes
+
+- [#7187](https://github.com/withastro/astro/pull/7187) [`1efaef6be`](https://github.com/withastro/astro/commit/1efaef6be0265c68eac706623778e8ad23b33247) Thanks [@bholmesdev](https://github.com/bholmesdev)! - Add support for syntax highlighting with Shiki. Apply to your Markdoc config using the `extends` property:
+
+ ```js
+ // markdoc.config.mjs
+ import { defineMarkdocConfig } from '@astrojs/markdoc/config';
+ import shiki from '@astrojs/markdoc/shiki';
+
+ export default defineMarkdocConfig({
+ extends: [
+ shiki({
+ /** Shiki config options */
+ }),
+ ],
+ });
+ ```
+
+ Learn more in the [`@astrojs/markdoc` README.](https://docs.astro.build/en/guides/integrations-guide/markdoc/#syntax-highlighting)
+
+- [#7209](https://github.com/withastro/astro/pull/7209) [`16b836411`](https://github.com/withastro/astro/commit/16b836411980f18c58ca15712d92cec1b3c95670) Thanks [@bholmesdev](https://github.com/bholmesdev)! - Add a built-in extension for syntax highlighting with Prism. Apply to your Markdoc config using the `extends` property:
+
+ ```js
+ // markdoc.config.mjs
+ import { defineMarkdocConfig } from '@astrojs/markdoc/config';
+ import prism from '@astrojs/markdoc/prism';
+
+ export default defineMarkdocConfig({
+ extends: [prism()],
+ });
+ ```
+
+ Learn more in the [`@astrojs/markdoc` README.](https://docs.astro.build/en/guides/integrations-guide/markdoc/#syntax-highlighting)
+
+- Updated dependencies [[`8b041bf57`](https://github.com/withastro/astro/commit/8b041bf57c76830c4070330270521e05d8e58474), [`6c7df28ab`](https://github.com/withastro/astro/commit/6c7df28ab34b756b8426443bf6976e24d4611a62), [`ee2aca80a`](https://github.com/withastro/astro/commit/ee2aca80a71afe843af943b11966fcf77f556cfb), [`7851f9258`](https://github.com/withastro/astro/commit/7851f9258fae2f54795470253df9ce4bcd5f9cb0), [`bef3a75db`](https://github.com/withastro/astro/commit/bef3a75dbc48d584daff9f7f3d5a8937b0356170), [`52af9ad18`](https://github.com/withastro/astro/commit/52af9ad18840ffa4e2996386c82cbe34d9fd076a), [`f5063d0a0`](https://github.com/withastro/astro/commit/f5063d0a01e3179da902fdc0a2b22f88cb3c95c7), [`cf621340b`](https://github.com/withastro/astro/commit/cf621340b00fda441f4ef43196c0363d09eae70c), [`2bda7fb0b`](https://github.com/withastro/astro/commit/2bda7fb0bce346f7725086980e1648e2636bbefb), [`af3c5a2e2`](https://github.com/withastro/astro/commit/af3c5a2e25bd3e7b2a3f7f08e41ee457093c8cb1), [`f2f18b440`](https://github.com/withastro/astro/commit/f2f18b44055c6334a39d6379de88fe41e518aa1e)]:
+ - astro@2.5.6
+
## 0.2.3
### Patch Changes
diff --git a/packages/integrations/markdoc/README.md b/packages/integrations/markdoc/README.md
index dd2f2d4de..da5aeb46a 100644
--- a/packages/integrations/markdoc/README.md
+++ b/packages/integrations/markdoc/README.md
@@ -97,13 +97,9 @@ const { Content } = await entry.render();
`@astrojs/markdoc` offers configuration options to use all of Markdoc's features and connect UI components to your content.
-### Using components
+### Use Astro components as Markdoc tags
-You can add Astro components to your Markdoc using both [Markdoc tags][markdoc-tags] and HTML element [nodes][markdoc-nodes].
-
-#### Render Markdoc tags as Astro components
-
-You may configure [Markdoc tags][markdoc-tags] that map to components. You can configure a new tag by creating a `markdoc.config.mjs|ts` file at the root of your project and configuring the `tag` attribute.
+You can configure [Markdoc tags][markdoc-tags] that map to `.astro` components. You can add a new tag by creating a `markdoc.config.mjs|ts` file at the root of your project and configuring the `tag` attribute.
This example renders an `Aside` component, and allows a `type` prop to be passed as a string:
@@ -141,9 +137,11 @@ Use tags like this fancy "aside" to add some *flair* to your docs.
{% /aside %}
```
-#### Render Markdoc nodes / HTML elements as Astro components
+### Custom headings
-You may also want to map standard HTML elements like headings and paragraphs to components. For this, you can configure a custom [Markdoc node][markdoc-nodes]. This example overrides Markdoc's `heading` node to render a `Heading` component, and passes through Astro's default heading properties to define attributes and generate heading ids / slugs:
+`@astrojs/markdoc` automatically adds anchor links to your headings, and [generates a list of `headings` via the content collections API](https://docs.astro.build/en/guides/content-collections/#rendering-content-to-html). To further customize how headings are rendered, you can apply an Astro component [as a Markdoc node][markdoc-nodes].
+
+This example renders a `Heading.astro` component using the `render` property:
```js
// markdoc.config.mjs
@@ -154,55 +152,20 @@ export default defineMarkdocConfig({
nodes: {
heading: {
render: Heading,
+ // Preserve default anchor link generation
...nodes.heading,
},
},
})
```
-All Markdown headings will render the `Heading.astro` component and pass `attributes` as component props. For headings, Astro provides the following attributes by default:
+All Markdown headings will render the `Heading.astro` component and pass the following `attributes` as component props:
- `level: number` The heading level 1 - 6
- `id: string` An `id` generated from the heading's text contents. This corresponds to the `slug` generated by the [content `render()` function](https://docs.astro.build/en/guides/content-collections/#rendering-content-to-html).
For example, the heading `### Level 3 heading!` will pass `level: 3` and `id: 'level-3-heading'` as component props.
-📚 [Find all of Markdoc's built-in nodes and node attributes on their documentation.](https://markdoc.dev/docs/nodes#built-in-nodes)
-
-#### Use client-side UI components
-
-Today, the `components` prop does not support the `client:` directive for hydrating components. To embed client-side components, create a wrapper `.astro` file to import your component and apply a `client:` directive manually.
-
-This example wraps a `Aside.tsx` component with a `ClientAside.astro` wrapper:
-
-```astro
----
-// src/components/ClientAside.astro
-import Aside from './Aside';
----
-
-
-```
-
-This component can be passed to the `render` prop for any [tag][markdoc-tags] or [node][markdoc-nodes] in your config:
-
-```js
-// markdoc.config.mjs
-import { defineMarkdocConfig } from '@astrojs/markdoc/config';
-import Aside from './src/components/Aside.astro';
-
-export default defineMarkdocConfig({
- tags: {
- aside: {
- render: Aside,
- attributes: {
- type: { type: String },
- }
- },
- },
-})
-```
-
### Syntax highlighting
`@astrojs/markdoc` provides [Shiki](https://github.com/shikijs/shiki) and [Prism](https://github.com/PrismJS) extensions to highlight your code blocks.
@@ -249,21 +212,83 @@ export default defineMarkdocConfig({
})
```
-📚 To learn about configuring Prism stylesheets, [see our syntax highlighting guide.](https://docs.astro.build/en/guides/markdown-content/#prism-configuration)
+📚 To learn about configuring Prism stylesheets, [see our syntax highlighting guide](https://docs.astro.build/en/guides/markdown-content/#prism-configuration).
-### Access frontmatter and content collection information from your templates
+### Set the root HTML element
-You can access content collection information from your Markdoc templates using the `$entry` variable. This includes the entry `slug`, `collection` name, and frontmatter `data` parsed by your content collection schema (if any). This example renders the `title` frontmatter property as a heading:
+Markdoc wraps documents with an `` tag by default. This can be changed from the `document` Markdoc node. This accepts an HTML element name or `null` if you prefer to remove the wrapper element:
-```md
----
-title: Welcome to Markdoc 👋
----
+```js
+// markdoc.config.mjs
+import { defineMarkdocConfig, nodes } from '@astrojs/markdoc/config';
-# {% $entry.data.title %}
+export default defineMarkdocConfig({
+ nodes: {
+ document: {
+ render: null, // default 'article'
+ ...nodes.document, // Apply defaults for other options
+ },
+ },
+})
```
-The `$entry` object matches [the `CollectionEntry` type](https://docs.astro.build/en/reference/api-reference/#collection-entry-type), excluding the `.render()` property.
+### Custom Markdoc nodes / elements
+
+You may want to render standard Markdown elements, such as paragraphs and bolded text, as Astro components. For this, you can configure a [Markdoc node][markdoc-nodes]. If a given node receives attributes, they will be available as component props.
+
+This example renders blockquotes with a custom `Quote.astro` component:
+
+```js
+// markdoc.config.mjs
+import { defineMarkdocConfig, nodes } from '@astrojs/markdoc/config';
+import Quote from './src/components/Quote.astro';
+
+export default defineMarkdocConfig({
+ nodes: {
+ blockquote: {
+ render: Quote,
+ // Apply Markdoc's defaults for other options
+ ...nodes.blockquote,
+ },
+ },
+})
+```
+
+📚 [Find all of Markdoc's built-in nodes and node attributes on their documentation.](https://markdoc.dev/docs/nodes#built-in-nodes)
+
+### Use client-side UI components
+
+Tags and nodes are restricted to `.astro` files. To embed client-side UI components in Markdoc, [use a wrapper `.astro` component that renders a framework component](/en/core-concepts/framework-components/#nesting-framework-components) with your desired `client:` directive.
+
+This example wraps a React `Aside.tsx` component with a `ClientAside.astro` component:
+
+```astro
+---
+// src/components/ClientAside.astro
+import Aside from './Aside';
+---
+
+
+```
+
+This Astro component can now be passed to the `render` prop for any [tag][markdoc-tags] or [node][markdoc-nodes] in your config:
+
+```js
+// markdoc.config.mjs
+import { defineMarkdocConfig } from '@astrojs/markdoc/config';
+import ClientAside from './src/components/ClientAside.astro';
+
+export default defineMarkdocConfig({
+ tags: {
+ aside: {
+ render: ClientAside,
+ attributes: {
+ type: { type: String },
+ }
+ },
+ },
+})
+```
### Markdoc config
@@ -340,6 +365,23 @@ export default defineMarkdocConfig({
})
```
+### Access frontmatter from your Markdoc content
+
+To access frontmatter, you can pass the entry `data` property [as a variable](#pass-markdoc-variables) where you render your content:
+
+```astro
+---
+import { getEntry } from 'astro:content';
+
+const entry = await getEntry('docs', 'why-markdoc');
+const { Content } = await entry.render();
+---
+
+
+```
+
+This can now be accessed as `$frontmatter` in your Markdoc.
+
## Examples
* The [Astro Markdoc starter template](https://github.com/withastro/astro/tree/latest/examples/with-markdoc) shows how to use Markdoc files in your Astro project.
diff --git a/packages/integrations/markdoc/package.json b/packages/integrations/markdoc/package.json
index 62ed853d7..369b7163a 100644
--- a/packages/integrations/markdoc/package.json
+++ b/packages/integrations/markdoc/package.json
@@ -1,7 +1,7 @@
{
"name": "@astrojs/markdoc",
"description": "Add support for Markdoc in your Astro site",
- "version": "0.2.3",
+ "version": "0.3.0",
"type": "module",
"types": "./dist/index.d.ts",
"author": "withastro",
@@ -51,7 +51,7 @@
"zod": "^3.17.3"
},
"peerDependencies": {
- "astro": "workspace:^2.5.5"
+ "astro": "workspace:^2.5.6"
},
"devDependencies": {
"@astrojs/markdown-remark": "^2.2.1",
diff --git a/packages/integrations/markdoc/src/index.ts b/packages/integrations/markdoc/src/index.ts
index 0486a44b5..17f012360 100644
--- a/packages/integrations/markdoc/src/index.ts
+++ b/packages/integrations/markdoc/src/index.ts
@@ -8,6 +8,7 @@ import { isValidUrl, MarkdocError, parseFrontmatter, prependForwardSlash } from
// @ts-expect-error Cannot find module 'astro/assets' or its corresponding type declarations.
import { emitESMImage } from 'astro/assets';
import { bold, red, yellow } from 'kleur/colors';
+import path from 'node:path';
import type * as rollup from 'rollup';
import { loadMarkdocConfig, type MarkdocConfigResult } from './load-config.js';
import { setupConfig } from './runtime.js';
@@ -61,10 +62,13 @@ export default function markdocIntegration(legacyConfig?: any): AstroIntegration
addContentEntryType({
extensions: ['.mdoc'],
getEntryInfo,
- async getRenderModule({ entry, viteId }) {
+ async getRenderModule({ contents, fileUrl, viteId }) {
+ const entry = getEntryInfo({ contents, fileUrl });
const ast = Markdoc.parse(entry.body);
const pluginContext = this;
- const markdocConfig = await setupConfig(userMarkdocConfig, entry);
+ const markdocConfig = await setupConfig(userMarkdocConfig);
+
+ const filePath = fileURLToPath(fileUrl);
const validationErrors = Markdoc.validate(ast, markdocConfig).filter((e) => {
return (
@@ -77,10 +81,11 @@ export default function markdocIntegration(legacyConfig?: any): AstroIntegration
});
if (validationErrors.length) {
// Heuristic: take number of newlines for `rawData` and add 2 for the `---` fences
- const frontmatterBlockOffset = entry._internal.rawData.split('\n').length + 2;
+ const frontmatterBlockOffset = entry.rawData.split('\n').length + 2;
+ const rootRelativePath = path.relative(fileURLToPath(astroConfig.root), filePath);
throw new MarkdocError({
message: [
- `**${String(entry.collection)} → ${String(entry.id)}** contains invalid content:`,
+ `**${String(rootRelativePath)}** contains invalid content:`,
...validationErrors.map((e) => `- ${e.error.message}`),
].join('\n'),
location: {
@@ -96,7 +101,7 @@ export default function markdocIntegration(legacyConfig?: any): AstroIntegration
await emitOptimizedImages(ast.children, {
astroConfig,
pluginContext,
- filePath: entry._internal.filePath,
+ filePath,
});
}
diff --git a/packages/integrations/markdoc/src/runtime.ts b/packages/integrations/markdoc/src/runtime.ts
index 5bf7e4412..a1861c68c 100644
--- a/packages/integrations/markdoc/src/runtime.ts
+++ b/packages/integrations/markdoc/src/runtime.ts
@@ -13,13 +13,9 @@ export { default as Markdoc } from '@markdoc/markdoc';
* TODO: virtual module to merge configs per-build instead of per-file?
*/
export async function setupConfig(
- userConfig: AstroMarkdocConfig,
- entry: ContentEntryModule
+ userConfig: AstroMarkdocConfig
): Promise> {
- let defaultConfig: AstroMarkdocConfig = {
- ...setupHeadingConfig(),
- variables: { entry },
- };
+ let defaultConfig: AstroMarkdocConfig = setupHeadingConfig();
if (userConfig.extends) {
for (let extension of userConfig.extends) {
diff --git a/packages/integrations/markdoc/test/fixtures/entry-prop/astro.config.mjs b/packages/integrations/markdoc/test/fixtures/variables/astro.config.mjs
similarity index 100%
rename from packages/integrations/markdoc/test/fixtures/entry-prop/astro.config.mjs
rename to packages/integrations/markdoc/test/fixtures/variables/astro.config.mjs
diff --git a/packages/integrations/markdoc/test/fixtures/entry-prop/package.json b/packages/integrations/markdoc/test/fixtures/variables/package.json
similarity index 78%
rename from packages/integrations/markdoc/test/fixtures/entry-prop/package.json
rename to packages/integrations/markdoc/test/fixtures/variables/package.json
index 149f6c35a..0ac7a3c82 100644
--- a/packages/integrations/markdoc/test/fixtures/entry-prop/package.json
+++ b/packages/integrations/markdoc/test/fixtures/variables/package.json
@@ -1,5 +1,5 @@
{
- "name": "@test/markdoc-entry-prop",
+ "name": "@test/markdoc-variables",
"version": "0.0.0",
"private": true,
"dependencies": {
diff --git a/packages/integrations/markdoc/test/fixtures/entry-prop/src/content/blog/entry.mdoc b/packages/integrations/markdoc/test/fixtures/variables/src/content/blog/entry.mdoc
similarity index 100%
rename from packages/integrations/markdoc/test/fixtures/entry-prop/src/content/blog/entry.mdoc
rename to packages/integrations/markdoc/test/fixtures/variables/src/content/blog/entry.mdoc
diff --git a/packages/integrations/markdoc/test/fixtures/entry-prop/src/content/config.ts b/packages/integrations/markdoc/test/fixtures/variables/src/content/config.ts
similarity index 100%
rename from packages/integrations/markdoc/test/fixtures/entry-prop/src/content/config.ts
rename to packages/integrations/markdoc/test/fixtures/variables/src/content/config.ts
diff --git a/packages/integrations/markdoc/test/fixtures/entry-prop/src/pages/index.astro b/packages/integrations/markdoc/test/fixtures/variables/src/pages/index.astro
similarity index 95%
rename from packages/integrations/markdoc/test/fixtures/entry-prop/src/pages/index.astro
rename to packages/integrations/markdoc/test/fixtures/variables/src/pages/index.astro
index d14187651..a2766faf0 100644
--- a/packages/integrations/markdoc/test/fixtures/entry-prop/src/pages/index.astro
+++ b/packages/integrations/markdoc/test/fixtures/variables/src/pages/index.astro
@@ -14,6 +14,6 @@ const { Content } = await entry.render();
Astro
-
+