[Content collections] Remove experimental flag (#5825)

* refactor: remove experimental.cc from core

* chore: remove experimental flag from tests

* fix: mock contentDir in remark tests

* fix: check vfile.path in rel-image-error plugin

* fix: move .astro/ excludes to all test/fixtures

* fix: include test/**/fixtures in ignore

* chore: changeset
This commit is contained in:
Ben Holmes 2023-01-11 12:51:31 -05:00 committed by GitHub
parent 665a2c2225
commit 52209ca2ad
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
27 changed files with 58 additions and 103 deletions

View file

@ -0,0 +1,14 @@
---
'astro': major
'@astrojs/mdx': major
'@astrojs/markdown-remark': major
---
Baseline the experimental `contentCollections` flag. You're free to remove this from your astro config!
```diff
import { defineConfig } from 'astro/config';
export default defineConfig({
- experimental: { contentCollections: true }
})

4
.gitignore vendored
View file

@ -24,3 +24,7 @@ packages/integrations/**/.netlify/
# exclude IntelliJ/WebStorm stuff # exclude IntelliJ/WebStorm stuff
.idea .idea
# ignore content collection generated files
packages/**/test/**/fixtures/**/.astro/
packages/**/test/**/fixtures/**/env.d.ts

View file

@ -7,7 +7,4 @@ import sitemap from '@astrojs/sitemap';
export default defineConfig({ export default defineConfig({
site: 'https://example.com', site: 'https://example.com',
integrations: [mdx(), sitemap()], integrations: [mdx(), sitemap()],
experimental: {
contentCollections: true,
},
}); });

View file

@ -83,7 +83,6 @@ export interface CLIFlags {
port?: number; port?: number;
config?: string; config?: string;
drafts?: boolean; drafts?: boolean;
experimentalContentCollections?: boolean;
} }
export interface BuildConfig { export interface BuildConfig {
@ -911,34 +910,13 @@ export interface AstroUserConfig {
legacy?: object; legacy?: object;
/** /**
* @docs
* @kind heading * @kind heading
* @name Experimental Flags * @name Experimental Flags
* @description * @description
* Astro offers experimental flags to give users early access to new features. * Astro offers experimental flags to give users early access to new features.
* These flags are not guaranteed to be stable. * These flags are not guaranteed to be stable.
*/ */
experimental?: { experimental?: object;
/**
* @docs
* @name experimental.contentCollections
* @type {boolean}
* @default `false`
* @version 1.7.0
* @description
* Enable experimental support for [Content Collections](https://docs.astro.build/en/guides/content-collections/). This makes the `src/content/` directory a reserved directory for Astro to manage, and introduces the `astro:content` module for querying this content.
*
* To enable this feature, set `experimental.contentCollections` to `true` in your Astro config:
*
* ```js
* {
* experimental: {
* contentCollections: true,
* },
* }
*/
contentCollections?: boolean;
};
// Legacy options to be removed // Legacy options to be removed

View file

@ -349,7 +349,6 @@ async function generatePath(
logging, logging,
markdown: { markdown: {
...settings.config.markdown, ...settings.config.markdown,
isExperimentalContentCollections: settings.config.experimental.contentCollections,
contentDir: getContentPaths(settings.config).contentDir, contentDir: getContentPaths(settings.config).contentDir,
}, },
mode: opts.mode, mode: opts.mode,

View file

@ -157,8 +157,7 @@ async function ssrBuild(opts: StaticBuildOptions, internals: BuildInternals, inp
}), }),
vitePluginPrerender(opts, internals), vitePluginPrerender(opts, internals),
...(viteConfig.plugins || []), ...(viteConfig.plugins || []),
settings.config.experimental.contentCollections && astroBundleDelayedAssetPlugin({ internals }),
astroBundleDelayedAssetPlugin({ internals }),
// SSR needs to be last // SSR needs to be last
ssr && vitePluginSSR(internals, settings.adapter!), ssr && vitePluginSSR(internals, settings.adapter!),
], ],

View file

@ -76,15 +76,13 @@ export function rollupPluginAstroBuildCSS(options: PluginOptions): VitePlugin[]
// For CSS, create a hash of all of the pages that use it. // For CSS, create a hash of all of the pages that use it.
// This causes CSS to be built into shared chunks when used by multiple pages. // This causes CSS to be built into shared chunks when used by multiple pages.
if (isCSSRequest(id)) { if (isCSSRequest(id)) {
if (settings.config.experimental.contentCollections) { for (const [pageInfo] of walkParentInfos(id, {
for (const [pageInfo] of walkParentInfos(id, { getModuleInfo: args[0].getModuleInfo,
getModuleInfo: args[0].getModuleInfo, })) {
})) { if (new URL(pageInfo.id, 'file://').searchParams.has(DELAYED_ASSET_FLAG)) {
if (new URL(pageInfo.id, 'file://').searchParams.has(DELAYED_ASSET_FLAG)) { // Split delayed assets to separate modules
// Split delayed assets to separate modules // so they can be injected where needed
// so they can be injected where needed return createNameHash(id, [id]);
return createNameHash(id, [id]);
}
} }
} }
return createNameForParentPages(id, args[0]); return createNameForParentPages(id, args[0]);
@ -174,17 +172,10 @@ export function rollupPluginAstroBuildCSS(options: PluginOptions): VitePlugin[]
id, id,
this, this,
function until(importer) { function until(importer) {
if (settings.config.experimental.contentCollections) { return new URL(importer, 'file://').searchParams.has(DELAYED_ASSET_FLAG);
// Short circuit when `contentCollections` is enabled.
return new URL(importer, 'file://').searchParams.has(DELAYED_ASSET_FLAG);
}
return false;
} }
)) { )) {
if ( if (new URL(pageInfo.id, 'file://').searchParams.has(DELAYED_ASSET_FLAG)) {
settings.config.experimental.contentCollections &&
new URL(pageInfo.id, 'file://').searchParams.has(DELAYED_ASSET_FLAG)
) {
for (const parent of walkParentInfos(id, this)) { for (const parent of walkParentInfos(id, this)) {
const parentInfo = parent[0]; const parentInfo = parent[0];
if (moduleIsTopLevelPage(parentInfo)) { if (moduleIsTopLevelPage(parentInfo)) {

View file

@ -210,7 +210,6 @@ function buildManifest(
base: settings.config.base, base: settings.config.base,
markdown: { markdown: {
...settings.config.markdown, ...settings.config.markdown,
isExperimentalContentCollections: settings.config.experimental.contentCollections,
contentDir: getContentPaths(settings.config).contentDir, contentDir: getContentPaths(settings.config).contentDir,
}, },
pageMap: null as any, pageMap: null as any,

View file

@ -100,10 +100,6 @@ export function resolveFlags(flags: Partial<Flags>): CLIFlags {
host: host:
typeof flags.host === 'string' || typeof flags.host === 'boolean' ? flags.host : undefined, typeof flags.host === 'string' || typeof flags.host === 'boolean' ? flags.host : undefined,
drafts: typeof flags.drafts === 'boolean' ? flags.drafts : undefined, drafts: typeof flags.drafts === 'boolean' ? flags.drafts : undefined,
experimentalContentCollections:
typeof flags.experimentalContentCollections === 'boolean'
? flags.experimentalContentCollections
: undefined,
}; };
} }
@ -132,7 +128,6 @@ function mergeCLIFlags(astroConfig: AstroUserConfig, flags: CLIFlags) {
// TODO: Come back here and refactor to remove this expected error. // TODO: Come back here and refactor to remove this expected error.
astroConfig.server.host = flags.host; astroConfig.server.host = flags.host;
} }
if (flags.experimentalContentCollections) astroConfig.experimental.contentCollections = true;
return astroConfig; return astroConfig;
} }

View file

@ -34,9 +34,6 @@ const ASTRO_CONFIG_DEFAULTS: AstroUserConfig & any = {
}, },
vite: {}, vite: {},
legacy: {}, legacy: {},
experimental: {
contentCollections: false,
},
}; };
export const AstroConfigSchema = z.object({ export const AstroConfigSchema = z.object({
@ -167,15 +164,7 @@ export const AstroConfigSchema = z.object({
vite: z vite: z
.custom<ViteUserConfig>((data) => data instanceof Object && !Array.isArray(data)) .custom<ViteUserConfig>((data) => data instanceof Object && !Array.isArray(data))
.default(ASTRO_CONFIG_DEFAULTS.vite), .default(ASTRO_CONFIG_DEFAULTS.vite),
experimental: z experimental: z.object({}).optional().default({}),
.object({
contentCollections: z
.boolean()
.optional()
.default(ASTRO_CONFIG_DEFAULTS.experimental.contentCollections),
})
.optional()
.default({}),
legacy: z.object({}).optional().default({}), legacy: z.object({}).optional().default({}),
}); });

View file

@ -104,13 +104,9 @@ export async function createVite(
astroHeadPropagationPlugin({ settings }), astroHeadPropagationPlugin({ settings }),
astroScannerPlugin({ settings, logging }), astroScannerPlugin({ settings, logging }),
astroInjectEnvTsPlugin({ settings, logging, fs }), astroInjectEnvTsPlugin({ settings, logging, fs }),
...(settings.config.experimental.contentCollections astroContentVirtualModPlugin({ settings }),
? [ astroContentServerPlugin({ fs, settings, logging, mode }),
astroContentVirtualModPlugin({ settings }), astroDelayedAssetPlugin({ mode }),
astroContentServerPlugin({ fs, settings, logging, mode }),
astroDelayedAssetPlugin({ mode }),
]
: []),
], ],
publicDir: fileURLToPath(settings.config.publicDir), publicDir: fileURLToPath(settings.config.publicDir),
root: fileURLToPath(settings.config.root), root: fileURLToPath(settings.config.root),

View file

@ -24,7 +24,6 @@ export function createDevelopmentEnvironment(
logging, logging,
markdown: { markdown: {
...settings.config.markdown, ...settings.config.markdown,
isExperimentalContentCollections: settings.config.experimental.contentCollections,
contentDir: getContentPaths(settings.config).contentDir, contentDir: getContentPaths(settings.config).contentDir,
}, },
mode, mode,

View file

@ -71,7 +71,6 @@ export default function markdown({ settings, logging }: AstroPluginOptions): Plu
const renderResult = await renderMarkdown(raw.content, { const renderResult = await renderMarkdown(raw.content, {
...settings.config.markdown, ...settings.config.markdown,
fileURL: new URL(`file://${fileId}`), fileURL: new URL(`file://${fileId}`),
isExperimentalContentCollections: settings.config.experimental.contentCollections,
contentDir: getContentPaths(settings.config).contentDir, contentDir: getContentPaths(settings.config).contentDir,
frontmatter: raw.data, frontmatter: raw.data,
}); });

View file

@ -1,2 +0,0 @@
.astro/
env.d.ts

View file

@ -4,7 +4,4 @@ import mdx from '@astrojs/mdx';
// https://astro.build/config // https://astro.build/config
export default defineConfig({ export default defineConfig({
integrations: [mdx()], integrations: [mdx()],
experimental: {
contentCollections: true,
},
}); });

View file

@ -4,7 +4,4 @@ import mdx from '@astrojs/mdx';
// https://astro.build/config // https://astro.build/config
export default defineConfig({ export default defineConfig({
integrations: [mdx()], integrations: [mdx()],
experimental: {
contentCollections: true,
},
}); });

View file

@ -4,7 +4,4 @@ import mdx from '@astrojs/mdx';
// https://astro.build/config // https://astro.build/config
export default defineConfig({ export default defineConfig({
integrations: [mdx()], integrations: [mdx()],
experimental: {
contentCollections: true,
},
}); });

View file

@ -3,5 +3,4 @@ import mdx from '@astrojs/mdx';
export default defineConfig({ export default defineConfig({
integrations: [mdx()], integrations: [mdx()],
experimental: { contentCollections: true },
}); });

View file

@ -47,7 +47,6 @@ describe('Content Collections - render()', () => {
userConfig: { userConfig: {
integrations: [mdx()], integrations: [mdx()],
vite: { server: { middlewareMode: true } }, vite: { server: { middlewareMode: true } },
experimental: { contentCollections: true },
}, },
}, },
async (container) => { async (container) => {
@ -121,7 +120,6 @@ describe('Content Collections - render()', () => {
userConfig: { userConfig: {
integrations: [mdx()], integrations: [mdx()],
vite: { server: { middlewareMode: true } }, vite: { server: { middlewareMode: true } },
experimental: { contentCollections: true },
}, },
}, },
async (container) => { async (container) => {
@ -193,7 +191,6 @@ describe('Content Collections - render()', () => {
userConfig: { userConfig: {
integrations: [mdx()], integrations: [mdx()],
vite: { server: { middlewareMode: true } }, vite: { server: { middlewareMode: true } },
experimental: { contentCollections: true },
}, },
}, },
async (container) => { async (container) => {
@ -259,7 +256,6 @@ describe('Content Collections - render()', () => {
userConfig: { userConfig: {
integrations: [mdx()], integrations: [mdx()],
vite: { server: { middlewareMode: true } }, vite: { server: { middlewareMode: true } },
experimental: { contentCollections: true },
}, },
}, },
async (container) => { async (container) => {

View file

@ -161,9 +161,8 @@ export async function getRemarkPlugins(
remarkPlugins = [...remarkPlugins, ...ignoreStringPlugins(mdxOptions.remarkPlugins)]; remarkPlugins = [...remarkPlugins, ...ignoreStringPlugins(mdxOptions.remarkPlugins)];
// Apply last in case user plugins resolve relative image paths // Apply last in case user plugins resolve relative image paths
if (config.experimental.contentCollections) { remarkPlugins.push(toRemarkContentRelImageError(config));
remarkPlugins.push(toRemarkContentRelImageError(config));
}
return remarkPlugins; return remarkPlugins;
} }

View file

@ -53,7 +53,6 @@ export async function renderMarkdown(
remarkRehype = markdownConfigDefaults.remarkRehype, remarkRehype = markdownConfigDefaults.remarkRehype,
gfm = markdownConfigDefaults.gfm, gfm = markdownConfigDefaults.gfm,
smartypants = markdownConfigDefaults.smartypants, smartypants = markdownConfigDefaults.smartypants,
isExperimentalContentCollections = false,
contentDir, contentDir,
frontmatter: userFrontmatter = {}, frontmatter: userFrontmatter = {},
} = opts; } = opts;
@ -91,9 +90,7 @@ export async function renderMarkdown(
} }
// Apply later in case user plugins resolve relative image paths // Apply later in case user plugins resolve relative image paths
if (isExperimentalContentCollections) { parser.use([toRemarkContentRelImageError({ contentDir })]);
parser.use([toRemarkContentRelImageError({ contentDir })]);
}
parser.use([ parser.use([
[ [

View file

@ -10,6 +10,8 @@ import type { VFile } from 'vfile';
export default function toRemarkContentRelImageError({ contentDir }: { contentDir: URL }) { export default function toRemarkContentRelImageError({ contentDir }: { contentDir: URL }) {
return function remarkContentRelImageError() { return function remarkContentRelImageError() {
return (tree: any, vfile: VFile) => { return (tree: any, vfile: VFile) => {
if (typeof vfile?.path !== 'string') return;
const isContentFile = pathToFileURL(vfile.path).href.startsWith(contentDir.href); const isContentFile = pathToFileURL(vfile.path).href.startsWith(contentDir.href);
if (!isContentFile) return; if (!isContentFile) return;

View file

@ -59,8 +59,6 @@ export interface MarkdownRenderingOptions extends AstroMarkdownOptions {
scopedClassName: string | null; scopedClassName: string | null;
}; };
/** Used to prevent relative image imports from `src/content/` */ /** Used to prevent relative image imports from `src/content/` */
isExperimentalContentCollections?: boolean;
/** Used to prevent relative image imports from `src/content/` */
contentDir: URL; contentDir: URL;
/** Used for frontmatter injection plugins */ /** Used for frontmatter injection plugins */
frontmatter?: Record<string, any>; frontmatter?: Record<string, any>;

View file

@ -1,10 +1,14 @@
import { renderMarkdown } from '../dist/index.js'; import { renderMarkdown } from '../dist/index.js';
import chai from 'chai'; import chai from 'chai';
import { mockRenderMarkdownParams } from './test-utils.js';
describe('autolinking', () => { describe('autolinking', () => {
describe('plain md', () => { describe('plain md', () => {
it('autolinks URLs starting with a protocol in plain text', async () => { it('autolinks URLs starting with a protocol in plain text', async () => {
const { code } = await renderMarkdown(`See https://example.com for more.`, {}); const { code } = await renderMarkdown(
`See https://example.com for more.`,
mockRenderMarkdownParams
);
chai chai
.expect(code.replace(/\n/g, '')) .expect(code.replace(/\n/g, ''))
@ -12,7 +16,10 @@ describe('autolinking', () => {
}); });
it('autolinks URLs starting with "www." in plain text', async () => { it('autolinks URLs starting with "www." in plain text', async () => {
const { code } = await renderMarkdown(`See www.example.com for more.`, {}); const { code } = await renderMarkdown(
`See www.example.com for more.`,
mockRenderMarkdownParams
);
chai chai
.expect(code.trim()) .expect(code.trim())
@ -22,7 +29,7 @@ describe('autolinking', () => {
it('does not autolink URLs in code blocks', async () => { it('does not autolink URLs in code blocks', async () => {
const { code } = await renderMarkdown( const { code } = await renderMarkdown(
'See `https://example.com` or `www.example.com` for more.', 'See `https://example.com` or `www.example.com` for more.',
{} mockRenderMarkdownParams
); );
chai chai

View file

@ -1,9 +1,13 @@
import { renderMarkdown } from '../dist/index.js'; import { renderMarkdown } from '../dist/index.js';
import { expect } from 'chai'; import { expect } from 'chai';
import { mockRenderMarkdownParams } from './test-utils.js';
describe('entities', () => { describe('entities', () => {
it('should not unescape entities in regular Markdown', async () => { it('should not unescape entities in regular Markdown', async () => {
const { code } = await renderMarkdown(`&lt;i&gt;This should NOT be italic&lt;/i&gt;`, {}); const { code } = await renderMarkdown(
`&lt;i&gt;This should NOT be italic&lt;/i&gt;`,
mockRenderMarkdownParams
);
expect(code).to.equal(`<p>&#x3C;i>This should NOT be italic&#x3C;/i></p>`); expect(code).to.equal(`<p>&#x3C;i>This should NOT be italic&#x3C;/i></p>`);
}); });

View file

@ -1,4 +1,5 @@
import { renderMarkdown } from '../dist/index.js'; import { renderMarkdown } from '../dist/index.js';
import { mockRenderMarkdownParams } from './test-utils.js';
import chai from 'chai'; import chai from 'chai';
import { fileURLToPath } from 'node:url'; import { fileURLToPath } from 'node:url';
@ -8,6 +9,7 @@ describe('plugins', () => {
it('should be able to get file path when passing fileURL', async () => { it('should be able to get file path when passing fileURL', async () => {
let context; let context;
await renderMarkdown(`test`, { await renderMarkdown(`test`, {
...mockRenderMarkdownParams,
fileURL: new URL('virtual.md', import.meta.url), fileURL: new URL('virtual.md', import.meta.url),
remarkPlugins: [ remarkPlugins: [
function () { function () {

View file

@ -0,0 +1,3 @@
export const mockRenderMarkdownParams = {
contentDir: new URL('file:///src/content/'),
};