summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/astro/content-module.template.mjs2
-rw-r--r--packages/astro/src/content/vite-plugin-content-assets.ts15
-rw-r--r--packages/astro/src/content/vite-plugin-content-virtual-mod.ts94
-rw-r--r--packages/astro/src/core/build/index.ts2
-rw-r--r--packages/astro/src/core/build/plugin.ts5
-rw-r--r--packages/astro/src/core/build/plugins/index.ts2
-rw-r--r--packages/astro/src/core/build/plugins/plugin-chunks.ts26
-rw-r--r--packages/astro/src/core/build/plugins/plugin-content.ts121
-rw-r--r--packages/astro/src/core/build/plugins/plugin-css.ts8
-rw-r--r--packages/astro/src/core/build/static-build.ts26
-rw-r--r--packages/astro/src/core/build/util.ts4
-rw-r--r--packages/astro/src/core/config/schema.ts5
-rw-r--r--packages/astro/src/runtime/server/render/component.ts13
-rw-r--r--packages/astro/test/experimental-content-collection-references.test.js5
-rw-r--r--packages/astro/test/experimental-content-collections-css-inline-stylesheets.test.js26
-rw-r--r--packages/astro/test/experimental-content-collections-render.test.js12
-rw-r--r--packages/astro/test/experimental-content-collections.test.js85
17 files changed, 259 insertions, 192 deletions
diff --git a/packages/astro/content-module.template.mjs b/packages/astro/content-module.template.mjs
index 137e44252..35c6a55c9 100644
--- a/packages/astro/content-module.template.mjs
+++ b/packages/astro/content-module.template.mjs
@@ -42,7 +42,7 @@ function createGlobLookup(glob) {
};
}
-const renderEntryGlob = '@@RENDER_ENTRY_GLOB_PATH@@'
+const renderEntryGlob = '@@RENDER_ENTRY_GLOB_PATH@@';
const collectionToRenderEntryMap = createCollectionToGlobResultMap({
globResult: renderEntryGlob,
contentDir,
diff --git a/packages/astro/src/content/vite-plugin-content-assets.ts b/packages/astro/src/content/vite-plugin-content-assets.ts
index 8dafc1be8..d1f2ca4ce 100644
--- a/packages/astro/src/content/vite-plugin-content-assets.ts
+++ b/packages/astro/src/content/vite-plugin-content-assets.ts
@@ -194,10 +194,7 @@ export function astroConfigBuildPlugin(
JSON.stringify(Array.from(entryStyles))
);
} else {
- newCode = newCode.replace(
- JSON.stringify(STYLES_PLACEHOLDER),
- "[]"
- );
+ newCode = newCode.replace(JSON.stringify(STYLES_PLACEHOLDER), '[]');
}
if (entryLinks.size) {
newCode = newCode.replace(
@@ -205,10 +202,7 @@ export function astroConfigBuildPlugin(
JSON.stringify(Array.from(entryLinks).map(prependBase))
);
} else {
- newCode = newCode.replace(
- JSON.stringify(LINKS_PLACEHOLDER),
- "[]"
- );
+ newCode = newCode.replace(JSON.stringify(LINKS_PLACEHOLDER), '[]');
}
if (entryScripts.size) {
const entryFileNames = new Set<string>();
@@ -235,10 +229,7 @@ export function astroConfigBuildPlugin(
)
);
} else {
- newCode = newCode.replace(
- JSON.stringify(SCRIPTS_PLACEHOLDER),
- "[]"
- );
+ newCode = newCode.replace(JSON.stringify(SCRIPTS_PLACEHOLDER), '[]');
}
mutate(chunk, ['server'], newCode);
}
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 1f4f7eead..941359c97 100644
--- a/packages/astro/src/content/vite-plugin-content-virtual-mod.ts
+++ b/packages/astro/src/content/vite-plugin-content-virtual-mod.ts
@@ -5,11 +5,19 @@ import { fileURLToPath, pathToFileURL } from 'node:url';
import pLimit from 'p-limit';
import { type Plugin } from 'vite';
import type { AstroSettings } from '../@types/astro.js';
+import { encodeName } from '../core/build/util.js';
import { AstroError, AstroErrorData } from '../core/errors/index.js';
import { appendForwardSlash, removeFileExtension } from '../core/path.js';
import { rootRelativePath } from '../core/util.js';
-import { encodeName } from '../core/build/util.js';
-import { CONTENT_FLAG, CONTENT_RENDER_FLAG, DATA_FLAG, VIRTUAL_MODULE_ID, RESOLVED_VIRTUAL_MODULE_ID } from './consts.js';
+import { isServerLikeOutput } from '../prerender/utils.js';
+import type { AstroPluginMetadata } from '../vite-plugin-astro/index.js';
+import {
+ CONTENT_FLAG,
+ CONTENT_RENDER_FLAG,
+ DATA_FLAG,
+ RESOLVED_VIRTUAL_MODULE_ID,
+ VIRTUAL_MODULE_ID,
+} from './consts.js';
import {
getContentEntryIdAndSlug,
getContentPaths,
@@ -22,12 +30,10 @@ import {
getExtGlob,
type ContentLookupMap,
} from './utils.js';
-import type { AstroPluginMetadata } from '../vite-plugin-astro/index.js';
-import { isServerLikeOutput } from '../prerender/utils.js';
interface AstroContentVirtualModPluginParams {
settings: AstroSettings;
- fs: typeof nodeFs
+ fs: typeof nodeFs;
}
export function astroContentVirtualModPlugin({
@@ -40,7 +46,7 @@ export function astroContentVirtualModPlugin({
name: 'astro-content-virtual-mod-plugin',
enforce: 'pre',
configResolved(config) {
- IS_DEV = config.mode === 'development'
+ IS_DEV = config.mode === 'development';
},
resolveId(id) {
if (id === VIRTUAL_MODULE_ID) {
@@ -51,7 +57,7 @@ export function astroContentVirtualModPlugin({
return RESOLVED_VIRTUAL_MODULE_ID;
} else {
// For SSG (production), we will build this file ourselves
- return { id: RESOLVED_VIRTUAL_MODULE_ID, external: true }
+ return { id: RESOLVED_VIRTUAL_MODULE_ID, external: true };
}
}
},
@@ -72,9 +78,9 @@ export function astroContentVirtualModPlugin({
scripts: [],
containsHead: true,
propagation: 'in-tree',
- pageOptions: {}
- }
- } satisfies AstroPluginMetadata
+ pageOptions: {},
+ },
+ } satisfies AstroPluginMetadata,
};
}
},
@@ -87,7 +93,7 @@ export function astroContentVirtualModPlugin({
const prefix = depth > 0 ? '../'.repeat(depth) : './';
return code.replaceAll(RESOLVED_VIRTUAL_MODULE_ID, `${prefix}content/entry.mjs`);
}
- }
+ },
};
}
@@ -95,11 +101,11 @@ export async function generateContentEntryFile({
settings,
lookupMap,
IS_DEV,
- IS_SERVER
+ IS_SERVER,
}: {
settings: AstroSettings;
fs: typeof nodeFs;
- lookupMap: ContentLookupMap
+ lookupMap: ContentLookupMap;
IS_DEV: boolean;
IS_SERVER: boolean;
}) {
@@ -113,12 +119,26 @@ export async function generateContentEntryFile({
const contentEntryConfigByExt = getEntryConfigByExtMap(settings.contentEntryTypes);
const contentEntryExts = [...contentEntryConfigByExt.keys()];
const dataEntryExts = getDataEntryExts(settings);
- const createGlob = (value: string[], flag: string) => `import.meta.glob(${JSON.stringify(value)}, { query: { ${flag}: true } })`
- contentEntryGlobResult = createGlob(globWithUnderscoresIgnored(relContentDir, contentEntryExts), CONTENT_FLAG);
- dataEntryGlobResult = createGlob(globWithUnderscoresIgnored(relContentDir, dataEntryExts), DATA_FLAG);
- renderEntryGlobResult = createGlob(globWithUnderscoresIgnored(relContentDir, contentEntryExts), CONTENT_RENDER_FLAG);
+ const createGlob = (value: string[], flag: string) =>
+ `import.meta.glob(${JSON.stringify(value)}, { query: { ${flag}: true } })`;
+ contentEntryGlobResult = createGlob(
+ globWithUnderscoresIgnored(relContentDir, contentEntryExts),
+ CONTENT_FLAG
+ );
+ dataEntryGlobResult = createGlob(
+ globWithUnderscoresIgnored(relContentDir, dataEntryExts),
+ DATA_FLAG
+ );
+ renderEntryGlobResult = createGlob(
+ globWithUnderscoresIgnored(relContentDir, contentEntryExts),
+ CONTENT_RENDER_FLAG
+ );
} else {
- contentEntryGlobResult = getStringifiedCollectionFromLookup('content', relContentDir, lookupMap);
+ contentEntryGlobResult = getStringifiedCollectionFromLookup(
+ 'content',
+ relContentDir,
+ lookupMap
+ );
dataEntryGlobResult = getStringifiedCollectionFromLookup('data', relContentDir, lookupMap);
renderEntryGlobResult = getStringifiedCollectionFromLookup('render', relContentDir, lookupMap);
}
@@ -126,48 +146,42 @@ export async function generateContentEntryFile({
const virtualModContents = nodeFs
.readFileSync(contentPaths.virtualModTemplate, 'utf-8')
.replace('@@CONTENT_DIR@@', relContentDir)
- .replace(
- "'@@CONTENT_ENTRY_GLOB_PATH@@'",
- contentEntryGlobResult
- )
- .replace(
- "'@@DATA_ENTRY_GLOB_PATH@@'",
- dataEntryGlobResult
- )
- .replace(
- "'@@RENDER_ENTRY_GLOB_PATH@@'",
- renderEntryGlobResult
- ).replace(
- '/* @@LOOKUP_MAP_ASSIGNMENT@@ */',
- `lookupMap = ${JSON.stringify(lookupMap)};`
- );
+ .replace("'@@CONTENT_ENTRY_GLOB_PATH@@'", contentEntryGlobResult)
+ .replace("'@@DATA_ENTRY_GLOB_PATH@@'", dataEntryGlobResult)
+ .replace("'@@RENDER_ENTRY_GLOB_PATH@@'", renderEntryGlobResult)
+ .replace('/* @@LOOKUP_MAP_ASSIGNMENT@@ */', `lookupMap = ${JSON.stringify(lookupMap)};`);
return virtualModContents;
}
-function getStringifiedCollectionFromLookup(wantedType: 'content' | 'data' | 'render', relContentDir: string, lookupMap: ContentLookupMap) {
+function getStringifiedCollectionFromLookup(
+ wantedType: 'content' | 'data' | 'render',
+ relContentDir: string,
+ lookupMap: ContentLookupMap
+) {
let str = '{';
// In dev, we don't need to normalize the import specifier at all. Vite handles it.
let normalize = (slug: string) => slug;
// For prod builds, we need to transform from `/src/content/**/*.{md,mdx,json,yaml}` to a relative `./**/*.mjs` import
if (process.env.NODE_ENV === 'production') {
const suffix = wantedType === 'render' ? '.entry.mjs' : '.mjs';
- normalize = (slug: string) => `${removeFileExtension(encodeName(slug)).replace(relContentDir, './')}${suffix}`
+ normalize = (slug: string) =>
+ `${removeFileExtension(encodeName(slug)).replace(relContentDir, './')}${suffix}`;
} else {
let suffix = '';
if (wantedType === 'content') suffix = CONTENT_FLAG;
else if (wantedType === 'data') suffix = DATA_FLAG;
else if (wantedType === 'render') suffix = CONTENT_RENDER_FLAG;
- normalize = (slug: string) => `${slug}?${suffix}`
+ normalize = (slug: string) => `${slug}?${suffix}`;
}
for (const { type, entries } of Object.values(lookupMap)) {
- if (type === wantedType || wantedType === 'render' && type === 'content') {
+ if (type === wantedType || (wantedType === 'render' && type === 'content')) {
for (const slug of Object.values(entries)) {
- str += `\n "${slug}": () => import("${normalize(slug)}"),`
+ str += `\n "${slug}": () => import("${normalize(slug)}"),`;
}
}
}
- str += '\n}'
+ str += '\n}';
return str;
}
@@ -202,7 +216,7 @@ export async function generateLookupMap({
cwd: fileURLToPath(root),
fs,
}
- )
+ );
// Run 10 at a time to prevent `await getEntrySlug` from accessing the filesystem all at once.
// Each await shouldn't take too long for the work to be noticably slow too.
diff --git a/packages/astro/src/core/build/index.ts b/packages/astro/src/core/build/index.ts
index 0960760a4..f096b8f76 100644
--- a/packages/astro/src/core/build/index.ts
+++ b/packages/astro/src/core/build/index.ts
@@ -70,7 +70,7 @@ export default async function build(
const contentCacheDir = new URL('./content/', astroConfig.cacheDir);
if (fs.existsSync(contentCacheDir)) {
logger.warn('content', 'clearing cache');
- await fs.promises.rm(contentCacheDir, { force: true, recursive: true })
+ await fs.promises.rm(contentCacheDir, { force: true, recursive: true });
}
}
diff --git a/packages/astro/src/core/build/plugin.ts b/packages/astro/src/core/build/plugin.ts
index ef1207e3f..c611c5186 100644
--- a/packages/astro/src/core/build/plugin.ts
+++ b/packages/astro/src/core/build/plugin.ts
@@ -17,7 +17,10 @@ export interface BuildBeforeHookResult {
export type AstroBuildPlugin = {
targets: BuildTarget[];
hooks?: {
- 'build:before'?: (opts: { target: BuildTarget; input: Set<string> }) => BuildBeforeHookResult | Promise<BuildBeforeHookResult>;
+ 'build:before'?: (opts: {
+ target: BuildTarget;
+ input: Set<string>;
+ }) => BuildBeforeHookResult | Promise<BuildBeforeHookResult>;
'build:post'?: (opts: {
ssrOutputs: RollupOutputArray;
clientOutputs: RollupOutputArray;
diff --git a/packages/astro/src/core/build/plugins/index.ts b/packages/astro/src/core/build/plugins/index.ts
index 3e6a5e6d6..879f72210 100644
--- a/packages/astro/src/core/build/plugins/index.ts
+++ b/packages/astro/src/core/build/plugins/index.ts
@@ -3,6 +3,7 @@ import { astroHeadBuildPlugin } from '../../../vite-plugin-head/index.js';
import type { AstroBuildPluginContainer } from '../plugin.js';
import { pluginAliasResolve } from './plugin-alias-resolve.js';
import { pluginAnalyzer } from './plugin-analyzer.js';
+import { pluginChunks } from './plugin-chunks.js';
import { pluginComponentEntry } from './plugin-component-entry.js';
import { pluginContent } from './plugin-content.js';
import { pluginCSS } from './plugin-css.js';
@@ -13,7 +14,6 @@ import { pluginMiddleware } from './plugin-middleware.js';
import { pluginPages } from './plugin-pages.js';
import { pluginPrerender } from './plugin-prerender.js';
import { pluginRenderers } from './plugin-renderers.js';
-import { pluginChunks } from './plugin-chunks.js';
import { pluginSSR, pluginSSRSplit } from './plugin-ssr.js';
export function registerAllPlugins({ internals, options, register }: AstroBuildPluginContainer) {
diff --git a/packages/astro/src/core/build/plugins/plugin-chunks.ts b/packages/astro/src/core/build/plugins/plugin-chunks.ts
index 3a2767ef1..30b3e4938 100644
--- a/packages/astro/src/core/build/plugins/plugin-chunks.ts
+++ b/packages/astro/src/core/build/plugins/plugin-chunks.ts
@@ -3,19 +3,19 @@ import type { AstroBuildPlugin } from '../plugin.js';
import { extendManualChunks } from './util.js';
export function vitePluginChunks(): VitePlugin {
- return {
- name: 'astro:chunks',
- outputOptions(outputOptions) {
- extendManualChunks(outputOptions, {
- after(id) {
- // Place Astro's server runtime in a single `astro/server.mjs` file
- if (id.includes('astro/dist/runtime/server/')) {
- return 'astro/server'
- }
- },
- });
- }
- }
+ return {
+ name: 'astro:chunks',
+ outputOptions(outputOptions) {
+ extendManualChunks(outputOptions, {
+ after(id) {
+ // Place Astro's server runtime in a single `astro/server.mjs` file
+ if (id.includes('astro/dist/runtime/server/')) {
+ return 'astro/server';
+ }
+ },
+ });
+ },
+ };
}
// Build plugin that configures specific chunking behavior
diff --git a/packages/astro/src/core/build/plugins/plugin-content.ts b/packages/astro/src/core/build/plugins/plugin-content.ts
index 537fbbc12..c28fa6904 100644
--- a/packages/astro/src/core/build/plugins/plugin-content.ts
+++ b/packages/astro/src/core/build/plugins/plugin-content.ts
@@ -1,20 +1,23 @@
-import { normalizePath, type Plugin as VitePlugin } from 'vite';
-import fsMod from 'node:fs';
import { createHash } from 'node:crypto';
+import fsMod from 'node:fs';
+import { fileURLToPath } from 'node:url';
+import pLimit from 'p-limit';
+import { normalizePath, type Plugin as VitePlugin } from 'vite';
+import { CONTENT_RENDER_FLAG, PROPAGATED_ASSET_FLAG } from '../../../content/consts.js';
+import { hasContentFlag, type ContentLookupMap } from '../../../content/utils.js';
+import {
+ generateContentEntryFile,
+ generateLookupMap,
+} from '../../../content/vite-plugin-content-virtual-mod.js';
+import { isServerLikeOutput } from '../../../prerender/utils.js';
+import { joinPaths, removeFileExtension, removeLeadingForwardSlash } from '../../path.js';
import { addRollupInput } from '../add-rollup-input.js';
import { type BuildInternals } from '../internal.js';
import type { AstroBuildPlugin } from '../plugin.js';
-import type { StaticBuildOptions } from '../types.js';
-import { generateContentEntryFile, generateLookupMap } from '../../../content/vite-plugin-content-virtual-mod.js';
-import { joinPaths, removeFileExtension, removeLeadingForwardSlash } from '../../path.js';
-import { fileURLToPath } from 'node:url';
-import { type ContentLookupMap, hasContentFlag } from '../../../content/utils.js';
-import { CONTENT_RENDER_FLAG, PROPAGATED_ASSET_FLAG } from '../../../content/consts.js';
import { copyFiles } from '../static-build.js';
-import pLimit from 'p-limit';
-import { extendManualChunks } from './util.js';
-import { isServerLikeOutput } from '../../../prerender/utils.js';
+import type { StaticBuildOptions } from '../types.js';
import { encodeName } from '../util.js';
+import { extendManualChunks } from './util.js';
const CONTENT_CACHE_DIR = './content/';
const CONTENT_MANIFEST_FILE = './manifest.json';
@@ -45,7 +48,11 @@ function createContentManifest(): ContentManifest {
return { version: -1, entries: [], serverEntries: [], clientEntries: [] };
}
-function vitePluginContent(opts: StaticBuildOptions, lookupMap: ContentLookupMap, internals: BuildInternals): VitePlugin {
+function vitePluginContent(
+ opts: StaticBuildOptions,
+ lookupMap: ContentLookupMap,
+ internals: BuildInternals
+): VitePlugin {
const { config } = opts.settings;
const { cacheDir } = config;
const distRoot = config.outDir;
@@ -66,7 +73,7 @@ function vitePluginContent(opts: StaticBuildOptions, lookupMap: ContentLookupMap
const data = fsMod.readFileSync(contentManifestFile, { encoding: 'utf8' });
oldManifest = JSON.parse(data);
internals.cachedClientEntries = oldManifest.clientEntries;
- } catch { }
+ } catch {}
}
return {
@@ -85,7 +92,7 @@ function vitePluginContent(opts: StaticBuildOptions, lookupMap: ContentLookupMap
const inputs = [`${input}?${collectionTypeToFlag(type)}`];
if (type === 'content') {
// Content entries also need to include the version with the RENDER flag
- inputs.push(`${input}?${CONTENT_RENDER_FLAG}`)
+ inputs.push(`${input}?${CONTENT_RENDER_FLAG}`);
}
newOptions = addRollupInput(newOptions, inputs);
}
@@ -95,7 +102,7 @@ function vitePluginContent(opts: StaticBuildOptions, lookupMap: ContentLookupMap
}
// If nothing needs to be rebuilt, we inject a fake entrypoint to appease Rollup
if (entries.buildFromSource.length === 0) {
- newOptions = addRollupInput(newOptions, [virtualEmptyModuleId])
+ newOptions = addRollupInput(newOptions, [virtualEmptyModuleId]);
injectedEmptyFile = true;
}
return newOptions;
@@ -108,9 +115,14 @@ function vitePluginContent(opts: StaticBuildOptions, lookupMap: ContentLookupMap
before(id, meta) {
if (id.startsWith(srcPath) && id.slice(srcPath.length).startsWith('content')) {
const info = meta.getModuleInfo(id);
- if (info?.dynamicImporters.length === 1 && hasContentFlag(info.dynamicImporters[0], PROPAGATED_ASSET_FLAG)) {
+ if (
+ info?.dynamicImporters.length === 1 &&
+ hasContentFlag(info.dynamicImporters[0], PROPAGATED_ASSET_FLAG)
+ ) {
const [srcRelativePath] = id.replace(rootPath, '/').split('?');
- const resultId = encodeName(`${removeLeadingForwardSlash(removeFileExtension(srcRelativePath))}.render.mjs`);
+ const resultId = encodeName(
+ `${removeLeadingForwardSlash(removeFileExtension(srcRelativePath))}.render.mjs`
+ );
return resultId;
}
const [srcRelativePath, flag] = id.replace(rootPath, '/').split('?');
@@ -120,11 +132,14 @@ function vitePluginContent(opts: StaticBuildOptions, lookupMap: ContentLookupMap
if (flag === PROPAGATED_ASSET_FLAG) {
suffix = '.entry.mjs';
}
- id = removeLeadingForwardSlash(removeFileExtension(encodeName(id.replace(srcPath, '/')))) + suffix;
+ id =
+ removeLeadingForwardSlash(
+ removeFileExtension(encodeName(id.replace(srcPath, '/')))
+ ) + suffix;
return id;
}
}
- }
+ },
});
},
@@ -137,20 +152,26 @@ function vitePluginContent(opts: StaticBuildOptions, lookupMap: ContentLookupMap
async load(id) {
if (id === resolvedVirtualEmptyModuleId) {
return {
- code: `// intentionally left empty!\nexport default {}`
- }
+ code: `// intentionally left empty!\nexport default {}`,
+ };
}
},
async generateBundle(_options, bundle) {
- const code = await generateContentEntryFile({ settings: opts.settings, fs: fsMod, lookupMap, IS_DEV: false, IS_SERVER: false });
+ const code = await generateContentEntryFile({
+ settings: opts.settings,
+ fs: fsMod,
+ lookupMap,
+ IS_DEV: false,
+ IS_SERVER: false,
+ });
this.emitFile({
type: 'prebuilt-chunk',
code,
- fileName: 'content/entry.mjs'
- })
+ fileName: 'content/entry.mjs',
+ });
if (!injectedEmptyFile) return;
- Object.keys(bundle).forEach(key => {
+ Object.keys(bundle).forEach((key) => {
const mod = bundle[key];
if (mod.type === 'asset') return;
if (mod.facadeModuleId === resolvedVirtualEmptyModuleId) {
@@ -168,7 +189,7 @@ function vitePluginContent(opts: StaticBuildOptions, lookupMap: ContentLookupMap
...internals.discoveredHydratedComponents.keys(),
...internals.discoveredClientOnlyComponents.keys(),
...internals.discoveredScripts,
- ])
+ ]);
// Likewise, these are server modules that might not be referenced
// once the cached items are excluded from the build process
const serverComponents = new Set([
@@ -178,10 +199,12 @@ function vitePluginContent(opts: StaticBuildOptions, lookupMap: ContentLookupMap
newManifest.serverEntries = Array.from(serverComponents);
newManifest.clientEntries = Array.from(clientComponents);
await fsMod.promises.mkdir(contentCacheDir, { recursive: true });
- await fsMod.promises.writeFile(contentManifestFile, JSON.stringify(newManifest), { encoding: 'utf8' });
+ await fsMod.promises.writeFile(contentManifestFile, JSON.stringify(newManifest), {
+ encoding: 'utf8',
+ });
const cacheExists = fsMod.existsSync(cache);
- fsMod.mkdirSync(cache, { recursive: true })
+ fsMod.mkdirSync(cache, { recursive: true });
await fsMod.promises.mkdir(cacheTmp, { recursive: true });
await copyFiles(distContentRoot, cacheTmp, true);
if (cacheExists) {
@@ -189,7 +212,7 @@ function vitePluginContent(opts: StaticBuildOptions, lookupMap: ContentLookupMap
}
await copyFiles(cacheTmp, contentCacheDir);
await fsMod.promises.rm(cacheTmp, { recursive: true, force: true });
- }
+ },
};
}
@@ -214,7 +237,10 @@ interface ContentEntries {
restoreFromCache: ContentManifestKey[];
buildFromSource: ContentManifestKey[];
}
-function getEntriesFromManifests(oldManifest: ContentManifest, newManifest: ContentManifest): ContentEntries {
+function getEntriesFromManifests(
+ oldManifest: ContentManifest,
+ newManifest: ContentManifest
+): ContentEntries {
const { version: oldVersion, entries: oldEntries } = oldManifest;
const { version: newVersion, entries: newEntries } = newManifest;
let entries: ContentEntries = { restoreFromCache: [], buildFromSource: [] };
@@ -224,7 +250,9 @@ function getEntriesFromManifests(oldManifest: ContentManifest, newManifest: Cont
entries.buildFromSource = Array.from(newEntryMap.keys());
return entries;
}
- const oldEntryHashMap = new Map<string, ContentManifestKey>(oldEntries.map(([key, hash]) => [hash, key]))
+ const oldEntryHashMap = new Map<string, ContentManifestKey>(
+ oldEntries.map(([key, hash]) => [hash, key])
+ );
for (const [entry, hash] of newEntryMap) {
if (oldEntryHashMap.has(hash)) {
@@ -236,8 +264,16 @@ function getEntriesFromManifests(oldManifest: ContentManifest, newManifest: Cont
return entries;
}
-async function generateContentManifest(opts: StaticBuildOptions, lookupMap: ContentLookupMap): Promise<ContentManifest> {
- let manifest: ContentManifest = { version: CONTENT_MANIFEST_VERSION, entries: [], serverEntries: [], clientEntries: [] };
+async function generateContentManifest(
+ opts: StaticBuildOptions,
+ lookupMap: ContentLookupMap
+): Promise<ContentManifest> {
+ let manifest: ContentManifest = {
+ version: CONTENT_MANIFEST_VERSION,
+ entries: [],
+ serverEntries: [],
+ clientEntries: [],
+ };
const limit = pLimit(10);
const promises: Promise<void>[] = [];
@@ -245,10 +281,12 @@ async function generateContentManifest(opts: StaticBuildOptions, lookupMap: Cont
for (const entry of Object.values(entries)) {
const key: ContentManifestKey = { collection, type, entry };
const fileURL = new URL(encodeURI(joinPaths(opts.settings.config.root.toString(), entry)));
- promises.push(limit(async () => {
- const data = await fsMod.promises.readFile(fileURL, { encoding: 'utf8' });
- manifest.entries.push([key, checksum(data)])
- }));
+ promises.push(
+ limit(async () => {
+ const data = await fsMod.promises.readFile(fileURL, { encoding: 'utf8' });
+ manifest.entries.push([key, checksum(data)]);
+ })
+ );
}
}
@@ -262,10 +300,13 @@ function checksum(data: string): string {
function collectionTypeToFlag(type: 'content' | 'data') {
const name = type[0].toUpperCase() + type.slice(1);
- return `astro${name}CollectionEntry`
+ return `astro${name}CollectionEntry`;
}
-export function pluginContent(opts: StaticBuildOptions, internals: BuildInternals): AstroBuildPlugin {
+export function pluginContent(
+ opts: StaticBuildOptions,
+ internals: BuildInternals
+): AstroBuildPlugin {
const cachedChunks = new URL('./chunks/', opts.settings.config.cacheDir);
const distChunks = new URL('./chunks/', opts.settings.config.outDir);
@@ -296,7 +337,7 @@ export function pluginContent(opts: StaticBuildOptions, internals: BuildInternal
if (fsMod.existsSync(distChunks)) {
await copyFiles(distChunks, cachedChunks, true);
}
- }
+ },
},
};
}
diff --git a/packages/astro/src/core/build/plugins/plugin-css.ts b/packages/astro/src/core/build/plugins/plugin-css.ts
index dd5d0af03..1073ed056 100644
--- a/packages/astro/src/core/build/plugins/plugin-css.ts
+++ b/packages/astro/src/core/build/plugins/plugin-css.ts
@@ -93,9 +93,13 @@ function rollupPluginAstroBuildCSS(options: PluginOptions): VitePlugin[] {
// so they can be injected where needed
const chunkId = assetName.createNameHash(id, [id]);
internals.cssModuleToChunkIdMap.set(id, chunkId);
- if (options.buildOptions.settings.config.output === 'static' && options.buildOptions.settings.config.experimental.contentCollectionCache) {
+ if (
+ options.buildOptions.settings.config.output === 'static' &&
+ options.buildOptions.settings.config.experimental.contentCollectionCache
+ ) {
// TODO: Handle inlining?
- const propagatedStyles = internals.propagatedStylesMap.get(pageInfo.id) ?? new Set();
+ const propagatedStyles =
+ internals.propagatedStylesMap.get(pageInfo.id) ?? new Set();
propagatedStyles.add({ type: 'external', src: chunkId });
internals.propagatedStylesMap.set(pageInfo.id, propagatedStyles);
}
diff --git a/packages/astro/src/core/build/static-build.ts b/packages/astro/src/core/build/static-build.ts
index e80c288c0..81dcdb4a0 100644
--- a/packages/astro/src/core/build/static-build.ts
+++ b/packages/astro/src/core/build/static-build.ts
@@ -7,6 +7,8 @@ import path, { extname } from 'node:path';
import { fileURLToPath, pathToFileURL } from 'node:url';
import * as vite from 'vite';
import type { RouteData } from '../../@types/astro.js';
+import { PROPAGATED_ASSET_FLAG } from '../../content/consts.js';
+import { hasAnyContentFlag } from '../../content/utils.js';
import {
createBuildInternals,
eachPageData,
@@ -32,8 +34,6 @@ import { RESOLVED_SPLIT_MODULE_ID, RESOLVED_SSR_VIRTUAL_MODULE_ID } from './plug
import { ASTRO_PAGE_EXTENSION_POST_PATTERN } from './plugins/util.js';
import type { StaticBuildOptions } from './types.js';
import { encodeName, getTimeStat } from './util.js';
-import { hasAnyContentFlag } from '../../content/utils.js';
-import { PROPAGATED_ASSET_FLAG } from '../../content/consts.js';
export async function viteBuild(opts: StaticBuildOptions) {
const { allPages, settings } = opts;
@@ -82,7 +82,7 @@ export async function viteBuild(opts: StaticBuildOptions) {
const ssrOutput = await ssrBuild(opts, internals, pageInput, container);
opts.logger.info('build', dim(`Completed in ${getTimeStat(ssrTime, performance.now())}.`));
settings.timer.end('SSR build');
-
+
settings.timer.start('Client build');
const rendererClientEntrypoints = settings.renderers
@@ -183,7 +183,7 @@ async function ssrBuild(
const { name } = chunkInfo;
let prefix = 'chunks/';
let suffix = '_[hash].mjs';
-
+
if (isContentCache) {
prefix += `${buildID}/`;
suffix = '.mjs';
@@ -207,7 +207,7 @@ async function ssrBuild(
return [prefix, sanitizedName, suffix].join('');
}
const encoded = encodeName(name);
- return [prefix, encoded, suffix].join('')
+ return [prefix, encoded, suffix].join('');
},
assetFileNames: `${settings.config.build.assets}/[name].[hash][extname]`,
...viteConfig.build?.rollupOptions?.output,
@@ -226,7 +226,11 @@ async function ssrBuild(
return 'renderers.mjs';
} else if (chunkInfo.facadeModuleId === RESOLVED_SSR_MANIFEST_VIRTUAL_MODULE_ID) {
return 'manifest_[hash].mjs';
- } else if (settings.config.experimental.contentCollectionCache && chunkInfo.facadeModuleId && hasAnyContentFlag(chunkInfo.facadeModuleId)) {
+ } else if (
+ settings.config.experimental.contentCollectionCache &&
+ chunkInfo.facadeModuleId &&
+ hasAnyContentFlag(chunkInfo.facadeModuleId)
+ ) {
const [srcRelative, flag] = chunkInfo.facadeModuleId.split('/src/')[1].split('?');
if (flag === PROPAGATED_ASSET_FLAG) {
return encodeName(`${removeFileExtension(srcRelative)}.entry.mjs`);
@@ -438,12 +442,10 @@ export async function copyFiles(fromFolder: URL, toFolder: URL, includeDotfiles
const from = new URL(filename, fromFolder);
const to = new URL(filename, toFolder);
const lastFolder = new URL('./', to);
- return fs.promises
- .mkdir(lastFolder, { recursive: true })
- .then(async function fsCopyFile() {
- const p = await fs.promises.copyFile(from, to, fs.constants.COPYFILE_FICLONE);
- return p;
- });
+ return fs.promises.mkdir(lastFolder, { recursive: true }).then(async function fsCopyFile() {
+ const p = await fs.promises.copyFile(from, to, fs.constants.COPYFILE_FICLONE);
+ return p;
+ });
})
);
}
diff --git a/packages/astro/src/core/build/util.ts b/packages/astro/src/core/build/util.ts
index e3551f73a..e46a0713a 100644
--- a/packages/astro/src/core/build/util.ts
+++ b/packages/astro/src/core/build/util.ts
@@ -41,8 +41,8 @@ export function encodeName(name: string): string {
// Detect if the chunk name has as % sign that is not encoded.
// This is borrowed from Node core: https://github.com/nodejs/node/blob/3838b579e44bf0c2db43171c3ce0da51eb6b05d5/lib/internal/url.js#L1382-L1391
// We do this because you cannot import a module with this character in it.
- for(let i = 0; i < name.length; i++) {
- if(name[i] === '%') {
+ for (let i = 0; i < name.length; i++) {
+ if (name[i] === '%') {
const third = name.codePointAt(i + 2)! | 0x20;
if (name[i + 1] !== '2' || third !== 102) {
return `${name.replace(/%/g, '_percent_')}`;
diff --git a/packages/astro/src/core/config/schema.ts b/packages/astro/src/core/config/schema.ts
index 13b31c7e0..eaa11786a 100644
--- a/packages/astro/src/core/config/schema.ts
+++ b/packages/astro/src/core/config/schema.ts
@@ -389,7 +389,10 @@ export const AstroConfigSchema = z.object({
}
})
),
- contentCollectionCache: z.boolean().optional().default(ASTRO_CONFIG_DEFAULTS.experimental.contentCollectionCache),
+ contentCollectionCache: z
+ .boolean()
+ .optional()
+ .default(ASTRO_CONFIG_DEFAULTS.experimental.contentCollectionCache),
})
.strict(
`Invalid or outdated experimental feature.\nCheck for incorrect spelling or outdated Astro version.\nSee https://docs.astro.build/en/reference/configuration-reference/#experimental-flags for a list of all current experiments.`
diff --git a/packages/astro/src/runtime/server/render/component.ts b/packages/astro/src/runtime/server/render/component.ts
index 68c61bcc6..dfc5d6c5b 100644
--- a/packages/astro/src/runtime/server/render/component.ts
+++ b/packages/astro/src/runtime/server/render/component.ts
@@ -13,16 +13,9 @@ import { extractDirectives, generateHydrateScript } from '../hydration.js';
import { serializeProps } from '../serialize.js';
import { shorthash } from '../shorthash.js';
import { isPromise } from '../util.js';
-import {
- isAstroComponentFactory,
- type AstroComponentFactory,
-} from './astro/factory.js';
-import {
- createAstroComponentInstance
-} from './astro/instance.js'
-import {
- renderTemplate,
-} from './astro/index.js';
+import { isAstroComponentFactory, type AstroComponentFactory } from './astro/factory.js';
+import { renderTemplate } from './astro/index.js';
+import { createAstroComponentInstance } from './astro/instance.js';
import {
Fragment,
diff --git a/packages/astro/test/experimental-content-collection-references.test.js b/packages/astro/test/experimental-content-collection-references.test.js
index ae55fc9de..b5de6a61e 100644
--- a/packages/astro/test/experimental-content-collection-references.test.js
+++ b/packages/astro/test/experimental-content-collection-references.test.js
@@ -6,7 +6,10 @@ describe('Experimental Content Collections cache - references', () => {
let fixture;
let devServer;
before(async () => {
- fixture = await loadFixture({ root: './fixtures/content-collection-references/', experimental: { contentCollectionCache: true } });
+ fixture = await loadFixture({
+ root: './fixtures/content-collection-references/',
+ experimental: { contentCollectionCache: true },
+ });
});
after(() => fixture.clean());
diff --git a/packages/astro/test/experimental-content-collections-css-inline-stylesheets.test.js b/packages/astro/test/experimental-content-collections-css-inline-stylesheets.test.js
index 10dee6d9f..6f762a24f 100644
--- a/packages/astro/test/experimental-content-collections-css-inline-stylesheets.test.js
+++ b/packages/astro/test/experimental-content-collections-css-inline-stylesheets.test.js
@@ -18,8 +18,8 @@ describe('Experimental Content Collections cache inlineStylesheets', () => {
inlineStylesheets: 'never',
},
experimental: {
- contentCollectionCache: true
- }
+ contentCollectionCache: true,
+ },
});
await fixture.build();
});
@@ -62,8 +62,8 @@ describe('Experimental Content Collections cache - inlineStylesheets to never in
inlineStylesheets: 'never',
},
experimental: {
- contentCollectionCache: true
- }
+ contentCollectionCache: true,
+ },
});
await fixture.build();
app = await fixture.loadTestAdapterApp();
@@ -111,14 +111,14 @@ describe.skip('Experimental Content Collections cache - inlineStylesheets to aut
},
},
experimental: {
- contentCollectionCache: true
- }
+ contentCollectionCache: true,
+ },
});
await fixture.build();
});
after(() => fixture.clean());
-
+
it.skip('Renders some <style> and some <link> tags', async () => {
const html = await fixture.readFile('/index.html');
const $ = cheerio.load(html);
@@ -162,8 +162,8 @@ describe('Setting inlineStylesheets to auto in server output', () => {
},
},
experimental: {
- contentCollectionCache: true
- }
+ contentCollectionCache: true,
+ },
});
await fixture.build();
app = await fixture.loadTestAdapterApp();
@@ -209,8 +209,8 @@ describe('Setting inlineStylesheets to always in static output', () => {
inlineStylesheets: 'always',
},
experimental: {
- contentCollectionCache: true
- }
+ contentCollectionCache: true,
+ },
});
await fixture.build();
});
@@ -252,8 +252,8 @@ describe('Setting inlineStylesheets to always in server output', () => {
inlineStylesheets: 'always',
},
experimental: {
- contentCollectionCache: true
- }
+ contentCollectionCache: true,
+ },
});
await fixture.build();
app = await fixture.loadTestAdapterApp();
diff --git a/packages/astro/test/experimental-content-collections-render.test.js b/packages/astro/test/experimental-content-collections-render.test.js
index 2ae03d6c4..d3ec1b1dc 100644
--- a/packages/astro/test/experimental-content-collections-render.test.js
+++ b/packages/astro/test/experimental-content-collections-render.test.js
@@ -16,8 +16,8 @@ describe('Experimental Content Collections cache - render()', () => {
// test suite was authored when inlineStylesheets defaulted to never
build: { inlineStylesheets: 'never' },
experimental: {
- contentCollectionCache: true
- }
+ contentCollectionCache: true,
+ },
});
await fixture.build();
});
@@ -116,8 +116,8 @@ describe('Experimental Content Collections cache - render()', () => {
// test suite was authored when inlineStylesheets defaulted to never
build: { inlineStylesheets: 'never' },
experimental: {
- contentCollectionCache: true
- }
+ contentCollectionCache: true,
+ },
});
await fixture.build();
});
@@ -209,8 +209,8 @@ describe('Experimental Content Collections cache - render()', () => {
fixture = await loadFixture({
root: './fixtures/content/',
experimental: {
- contentCollectionCache: true
- }
+ contentCollectionCache: true,
+ },
});
devServer = await fixture.startDevServer();
});
diff --git a/packages/astro/test/experimental-content-collections.test.js b/packages/astro/test/experimental-content-collections.test.js
index 30ef8b20a..25e19b250 100644
--- a/packages/astro/test/experimental-content-collections.test.js
+++ b/packages/astro/test/experimental-content-collections.test.js
@@ -9,7 +9,10 @@ describe('Experimental Content Collections cache', () => {
describe('Query', () => {
let fixture;
before(async () => {
- fixture = await loadFixture({ root: './fixtures/content-collections/', experimental: { contentCollectionCache: true } });
+ fixture = await loadFixture({
+ root: './fixtures/content-collections/',
+ experimental: { contentCollectionCache: true },
+ });
await fixture.build();
});
@@ -27,13 +30,15 @@ describe('Experimental Content Collections cache', () => {
expect(Array.isArray(json.withoutConfig)).to.equal(true);
const ids = json.withoutConfig.map((item) => item.id).sort();
- expect(ids).to.deep.equal([
- 'columbia.md',
- 'endeavour.md',
- 'enterprise.md',
- // Spaces allowed in IDs
- 'promo/launch week.mdx',
- ].sort());
+ expect(ids).to.deep.equal(
+ [
+ 'columbia.md',
+ 'endeavour.md',
+ 'enterprise.md',
+ // Spaces allowed in IDs
+ 'promo/launch week.mdx',
+ ].sort()
+ );
});
it('Handles spaces in `without config` slugs', async () => {
@@ -41,13 +46,15 @@ describe('Experimental Content Collections cache', () => {
expect(Array.isArray(json.withoutConfig)).to.equal(true);
const slugs = json.withoutConfig.map((item) => item.slug).sort();
- expect(slugs).to.deep.equal([
- 'columbia',
- 'endeavour',
- 'enterprise',
- // "launch week.mdx" is converted to "launch-week.mdx"
- 'promo/launch-week',
- ].sort());
+ expect(slugs).to.deep.equal(
+ [
+ 'columbia',
+ 'endeavour',
+ 'enterprise',
+ // "launch week.mdx" is converted to "launch-week.mdx"
+ 'promo/launch-week',
+ ].sort()
+ );
});
it('Returns `with schema` collection', async () => {
@@ -163,9 +170,12 @@ describe('Experimental Content Collections cache', () => {
let fixture;
before(async () => {
- fixture = await loadFixture({ root: './fixtures/content-static-paths-integration/', experimental: {
- contentCollectionCache: true
- } });
+ fixture = await loadFixture({
+ root: './fixtures/content-static-paths-integration/',
+ experimental: {
+ contentCollectionCache: true,
+ },
+ });
await fixture.build();
});
@@ -198,16 +208,19 @@ describe('Experimental Content Collections cache', () => {
describe('With spaces in path', () => {
it('Does not throw', async () => {
- const fixture = await loadFixture({ root: './fixtures/content with spaces in folder name/', experimental: {
- contentCollectionCache: true
- } });
+ const fixture = await loadFixture({
+ root: './fixtures/content with spaces in folder name/',
+ experimental: {
+ contentCollectionCache: true,
+ },
+ });
let error = null;
try {
await fixture.build();
} catch (e) {
error = e.message;
} finally {
- await fixture.clean()
+ await fixture.clean();
}
expect(error).to.be.null;
});
@@ -217,8 +230,8 @@ describe('Experimental Content Collections cache', () => {
const fixture = await loadFixture({
root: './fixtures/content-collections-with-config-mjs/',
experimental: {
- contentCollectionCache: true
- }
+ contentCollectionCache: true,
+ },
});
let error;
try {
@@ -226,7 +239,7 @@ describe('Experimental Content Collections cache', () => {
} catch (e) {
error = e.message;
} finally {
- await fixture.clean()
+ await fixture.clean();
}
expect(error).to.include('**title**: Expected type `"string"`, received "number"');
});
@@ -236,8 +249,8 @@ describe('Experimental Content Collections cache', () => {
const fixture = await loadFixture({
root: './fixtures/content-collections-with-config-mts/',
experimental: {
- contentCollectionCache: true
- }
+ contentCollectionCache: true,
+ },
});
let error;
try {
@@ -245,7 +258,7 @@ describe('Experimental Content Collections cache', () => {
} catch (e) {
error = e.message;
} finally {
- await fixture.clean()
+ await fixture.clean();
}
expect(error).to.include('**title**: Expected type `"string"`, received "number"');
});
@@ -256,8 +269,8 @@ describe('Experimental Content Collections cache', () => {
const fixture = await loadFixture({
root: './fixtures/content-collections-empty-md-file/',
experimental: {
- contentCollectionCache: true
- }
+ contentCollectionCache: true,
+ },
});
let error;
try {
@@ -265,7 +278,7 @@ describe('Experimental Content Collections cache', () => {
} catch (e) {
error = e.message;
} finally {
- await fixture.clean()
+ await fixture.clean();
}
expect(error).to.include('**title**: Required');
});
@@ -276,8 +289,8 @@ describe('Experimental Content Collections cache', () => {
const fixture = await loadFixture({
root: './fixtures/content-collections-empty-dir/',
experimental: {
- contentCollectionCache: true
- }
+ contentCollectionCache: true,
+ },
});
let error;
try {
@@ -285,7 +298,7 @@ describe('Experimental Content Collections cache', () => {
} catch (e) {
error = e.message;
} finally {
- await fixture.clean()
+ await fixture.clean();
}
expect(error).to.be.undefined;
// TODO: try to render a page
@@ -305,8 +318,8 @@ describe('Experimental Content Collections cache', () => {
plugins: [preventNodeBuiltinDependencyPlugin()],
},
experimental: {
- contentCollectionCache: true
- }
+ contentCollectionCache: true,
+ },
});
await fixture.build();
app = await fixture.loadTestAdapterApp();