Skip to content

Commit 3f02d5f

Browse files
authored
feat: support new location for content config (#12475)
* feat: support new location for content config * Test fixes * Handle missing dir * Handle missing content dir * chore: changes from review * Revert legacy fixtures * Clarify changeset
1 parent 18a04c0 commit 3f02d5f

39 files changed

Lines changed: 79 additions & 37 deletions

File tree

.changeset/thirty-clocks-jump.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
'astro': minor
3+
---
4+
5+
Changes the default content config location from `src/content/config.*` to `src/content.config.*`.
6+
7+
The previous location is still supported, and is required if the `legacy.collections` flag is enabled.
File renamed without changes.

packages/astro/src/content/runtime.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,22 @@ type GlobResult = Record<string, LazyImport>;
2626
type CollectionToEntryMap = Record<string, GlobResult>;
2727
type GetEntryImport = (collection: string, lookupId: string) => Promise<LazyImport>;
2828

29+
export function getImporterFilename() {
30+
// The 4th line in the stack trace should be the importer filename
31+
const stackLine = new Error().stack?.split('\n')?.[3];
32+
if (!stackLine) {
33+
return null;
34+
}
35+
// Extract the relative path from the stack line
36+
const match = /\/(src\/.*?):\d+:\d+/.exec(stackLine);
37+
return match?.[1] ?? null;
38+
}
39+
2940
export function defineCollection(config: any) {
3041
if ('loader' in config) {
3142
if (config.type && config.type !== CONTENT_LAYER_TYPE) {
3243
throw new AstroUserError(
33-
'Collections that use the Content Layer API must have a `loader` defined and no `type` set.',
34-
"Check your collection definitions in `src/content/config.*`.'",
44+
`Collections that use the Content Layer API must have a \`loader\` defined and no \`type\` set. Check your collection definitions in ${getImporterFilename() ?? 'your content config file'}.`,
3545
);
3646
}
3747
config.type = CONTENT_LAYER_TYPE;

packages/astro/src/content/server-listeners.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,16 @@ export async function attachContentServerListeners({
2424
settings,
2525
}: ContentServerListenerParams) {
2626
const contentPaths = getContentPaths(settings.config, fs);
27-
28-
if (fs.existsSync(contentPaths.contentDir)) {
27+
if (!settings.config.legacy?.collections) {
28+
const contentGenerator = await createContentTypesGenerator({
29+
fs,
30+
settings,
31+
logger,
32+
viteServer,
33+
contentConfigObserver: globalContentConfigObserver,
34+
});
35+
await contentGenerator.init();
36+
} else if (fs.existsSync(contentPaths.contentDir)) {
2937
logger.debug(
3038
'content',
3139
`Watching ${cyan(

packages/astro/src/content/types-generator.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -86,13 +86,12 @@ export async function createContentTypesGenerator({
8686
async function init(): Promise<
8787
{ typesGenerated: true } | { typesGenerated: false; reason: 'no-content-dir' }
8888
> {
89-
if (!fs.existsSync(contentPaths.contentDir)) {
90-
return { typesGenerated: false, reason: 'no-content-dir' };
91-
}
92-
9389
events.push({ name: 'add', entry: contentPaths.config.url });
9490

9591
if (settings.config.legacy.collections) {
92+
if (!fs.existsSync(contentPaths.contentDir)) {
93+
return { typesGenerated: false, reason: 'no-content-dir' };
94+
}
9695
const globResult = await glob('**', {
9796
cwd: fileURLToPath(contentPaths.contentDir),
9897
fs: {

packages/astro/src/content/utils.ts

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -597,7 +597,7 @@ export async function autogenerateCollections({
597597
}) as any,
598598
};
599599
}
600-
if (!usesContentLayer) {
600+
if (!usesContentLayer && fs.existsSync(contentDir)) {
601601
// If the user hasn't defined any collections using the content layer, we'll try and help out by checking for
602602
// any orphaned folders in the content directory and creating collections for them.
603603
const orphanedCollections = [];
@@ -623,7 +623,7 @@ export async function autogenerateCollections({
623623
console.warn(
624624
`
625625
Auto-generating collections for folders in "src/content/" that are not defined as collections.
626-
This is deprecated, so you should define these collections yourself in "src/content/config.ts".
626+
This is deprecated, so you should define these collections yourself in "src/content.config.ts".
627627
The following collections have been auto-generated: ${orphanedCollections
628628
.map((name) => green(name))
629629
.join(', ')}\n`,
@@ -715,10 +715,10 @@ export type ContentPaths = {
715715
};
716716

717717
export function getContentPaths(
718-
{ srcDir }: Pick<AstroConfig, 'root' | 'srcDir'>,
718+
{ srcDir, legacy }: Pick<AstroConfig, 'root' | 'srcDir' | 'legacy'>,
719719
fs: typeof fsMod = fsMod,
720720
): ContentPaths {
721-
const configStats = search(fs, srcDir);
721+
const configStats = search(fs, srcDir, legacy?.collections);
722722
const pkgBase = new URL('../../', import.meta.url);
723723
return {
724724
contentDir: new URL('./content/', srcDir),
@@ -728,10 +728,16 @@ export function getContentPaths(
728728
config: configStats,
729729
};
730730
}
731-
function search(fs: typeof fsMod, srcDir: URL) {
732-
const paths = ['config.mjs', 'config.js', 'config.mts', 'config.ts'].map(
733-
(p) => new URL(`./content/${p}`, srcDir),
734-
);
731+
function search(fs: typeof fsMod, srcDir: URL, legacy?: boolean) {
732+
const paths = [
733+
...(legacy
734+
? []
735+
: ['content.config.mjs', 'content.config.js', 'content.config.mts', 'content.config.ts']),
736+
'content/config.mjs',
737+
'content/config.js',
738+
'content/config.mts',
739+
'content/config.ts',
740+
].map((p) => new URL(`./${p}`, srcDir));
735741
for (const file of paths) {
736742
if (fs.existsSync(file)) {
737743
return { exists: true, url: file };

packages/astro/src/core/errors/errors-data.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1446,7 +1446,8 @@ export const GenerateContentTypesError = {
14461446
title: 'Failed to generate content types.',
14471447
message: (errorMessage: string) =>
14481448
`\`astro sync\` command failed to generate content collection types: ${errorMessage}`,
1449-
hint: 'This error is often caused by a syntax error inside your content, or your content configuration file. Check your `src/content/config.*` file for typos.',
1449+
hint: (fileName?: string) =>
1450+
`This error is often caused by a syntax error inside your content, or your content configuration file. Check your ${fileName ?? 'content config'} file for typos.`,
14501451
} satisfies ErrorData;
14511452
/**
14521453
* @docs
@@ -1458,7 +1459,7 @@ export const GenerateContentTypesError = {
14581459
* @docs
14591460
* @description
14601461
* Astro encountered an unknown error loading your content collections.
1461-
* This can be caused by certain errors inside your `src/content/config.ts` file or some internal errors.
1462+
* This can be caused by certain errors inside your `src/content.config.ts` file or some internal errors.
14621463
*
14631464
* If you can reliably cause this error to happen, we'd appreciate if you could [open an issue](https://astro.build/issues/)
14641465
*/
@@ -1501,7 +1502,7 @@ export const GetEntryDeprecationError = {
15011502
* @description
15021503
* A Markdown or MDX entry does not match its collection schema.
15031504
* Make sure that all required fields are present, and that all fields are of the correct type.
1504-
* You can check against the collection schema in your `src/content/config.*` file.
1505+
* You can check against the collection schema in your `src/content.config.*` file.
15051506
* See the [Content collections documentation](https://docs.astro.build/en/guides/content-collections/) for more information.
15061507
*/
15071508
export const InvalidContentEntryFrontmatterError = {
@@ -1528,7 +1529,7 @@ export const InvalidContentEntryFrontmatterError = {
15281529
* @description
15291530
* A content entry does not match its collection schema.
15301531
* Make sure that all required fields are present, and that all fields are of the correct type.
1531-
* You can check against the collection schema in your `src/content/config.*` file.
1532+
* You can check against the collection schema in your `src/content.config.*` file.
15321533
* See the [Content collections documentation](https://docs.astro.build/en/guides/content-collections/) for more information.
15331534
*/
15341535
export const InvalidContentEntryDataError = {
@@ -1553,7 +1554,7 @@ export const InvalidContentEntryDataError = {
15531554
* @description
15541555
* A content entry does not match its collection schema.
15551556
* Make sure that all required fields are present, and that all fields are of the correct type.
1556-
* You can check against the collection schema in your `src/content/config.*` file.
1557+
* You can check against the collection schema in your `src/content.config.*` file.
15571558
* See the [Content collections documentation](https://docs.astro.build/en/guides/content-collections/) for more information.
15581559
*/
15591560
export const ContentEntryDataError = {

0 commit comments

Comments
 (0)