Compare commits
1 commit
main
...
spike/incr
Author | SHA1 | Date | |
---|---|---|---|
|
6782a8611a |
23 changed files with 359 additions and 130 deletions
|
@ -13,17 +13,13 @@ export { z } from 'astro/zod';
|
||||||
|
|
||||||
const contentDir = '@@CONTENT_DIR@@';
|
const contentDir = '@@CONTENT_DIR@@';
|
||||||
|
|
||||||
const contentEntryGlob = import.meta.glob('@@CONTENT_ENTRY_GLOB_PATH@@', {
|
const contentEntryGlob = '@@CONTENT_ENTRY_GLOB_PATH@@';
|
||||||
query: { astroContentCollectionEntry: true },
|
|
||||||
});
|
|
||||||
const contentCollectionToEntryMap = createCollectionToGlobResultMap({
|
const contentCollectionToEntryMap = createCollectionToGlobResultMap({
|
||||||
globResult: contentEntryGlob,
|
globResult: contentEntryGlob,
|
||||||
contentDir,
|
contentDir,
|
||||||
});
|
});
|
||||||
|
|
||||||
const dataEntryGlob = import.meta.glob('@@DATA_ENTRY_GLOB_PATH@@', {
|
const dataEntryGlob = '@@DATA_ENTRY_GLOB_PATH@@';
|
||||||
query: { astroDataCollectionEntry: true },
|
|
||||||
});
|
|
||||||
const dataCollectionToEntryMap = createCollectionToGlobResultMap({
|
const dataCollectionToEntryMap = createCollectionToGlobResultMap({
|
||||||
globResult: dataEntryGlob,
|
globResult: dataEntryGlob,
|
||||||
contentDir,
|
contentDir,
|
||||||
|
@ -45,9 +41,7 @@ function createGlobLookup(glob) {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const renderEntryGlob = import.meta.glob('@@RENDER_ENTRY_GLOB_PATH@@', {
|
const renderEntryGlob = '@@RENDER_ENTRY_GLOB_PATH@@'
|
||||||
query: { astroRenderContent: true },
|
|
||||||
});
|
|
||||||
const collectionToRenderEntryMap = createCollectionToGlobResultMap({
|
const collectionToRenderEntryMap = createCollectionToGlobResultMap({
|
||||||
globResult: renderEntryGlob,
|
globResult: renderEntryGlob,
|
||||||
contentDir,
|
contentDir,
|
||||||
|
|
|
@ -69,7 +69,7 @@ export function createGetCollection({
|
||||||
let entries: any[] = [];
|
let entries: any[] = [];
|
||||||
// Cache `getCollection()` calls in production only
|
// Cache `getCollection()` calls in production only
|
||||||
// prevents stale cache in development
|
// prevents stale cache in development
|
||||||
if (import.meta.env.PROD && cacheEntriesByCollection.has(collection)) {
|
if (!import.meta.env?.DEV && cacheEntriesByCollection.has(collection)) {
|
||||||
// Always return a new instance so consumers can safely mutate it
|
// Always return a new instance so consumers can safely mutate it
|
||||||
entries = [...cacheEntriesByCollection.get(collection)!];
|
entries = [...cacheEntriesByCollection.get(collection)!];
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -112,14 +112,14 @@ export function astroConfigBuildPlugin(
|
||||||
): AstroBuildPlugin {
|
): AstroBuildPlugin {
|
||||||
let ssrPluginContext: any = undefined;
|
let ssrPluginContext: any = undefined;
|
||||||
return {
|
return {
|
||||||
build: 'ssr',
|
targets: ['server', 'content'],
|
||||||
hooks: {
|
hooks: {
|
||||||
'build:before': ({ build }) => {
|
'build:before': ({ target }) => {
|
||||||
return {
|
return {
|
||||||
vitePlugin: {
|
vitePlugin: {
|
||||||
name: 'astro:content-build-plugin',
|
name: 'astro:content-build-plugin',
|
||||||
generateBundle() {
|
generateBundle() {
|
||||||
if (build === 'ssr') {
|
if (target === 'server') {
|
||||||
ssrPluginContext = this;
|
ssrPluginContext = this;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -206,7 +206,7 @@ export function astroConfigBuildPlugin(
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
mutate(chunk, 'server', newCode);
|
mutate(chunk, ['server'], newCode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -4,9 +4,9 @@ import { extname } from 'node:path';
|
||||||
import { fileURLToPath, pathToFileURL } from 'node:url';
|
import { fileURLToPath, pathToFileURL } from 'node:url';
|
||||||
import pLimit from 'p-limit';
|
import pLimit from 'p-limit';
|
||||||
import type { Plugin } from 'vite';
|
import type { Plugin } from 'vite';
|
||||||
import type { AstroSettings, ContentEntryType } from '../@types/astro.js';
|
import type { AstroSettings } from '../@types/astro.js';
|
||||||
import { AstroError, AstroErrorData } from '../core/errors/index.js';
|
import { AstroError, AstroErrorData } from '../core/errors/index.js';
|
||||||
import { appendForwardSlash } from '../core/path.js';
|
import { appendForwardSlash, joinPaths, removeFileExtension, removeLeadingForwardSlash, slash } from '../core/path.js';
|
||||||
import { rootRelativePath } from '../core/util.js';
|
import { rootRelativePath } from '../core/util.js';
|
||||||
import { VIRTUAL_MODULE_ID } from './consts.js';
|
import { VIRTUAL_MODULE_ID } from './consts.js';
|
||||||
import {
|
import {
|
||||||
|
@ -20,7 +20,6 @@ import {
|
||||||
getEntryType,
|
getEntryType,
|
||||||
getExtGlob,
|
getExtGlob,
|
||||||
type ContentLookupMap,
|
type ContentLookupMap,
|
||||||
type ContentPaths,
|
|
||||||
} from './utils.js';
|
} from './utils.js';
|
||||||
|
|
||||||
interface AstroContentVirtualModPluginParams {
|
interface AstroContentVirtualModPluginParams {
|
||||||
|
@ -30,38 +29,6 @@ interface AstroContentVirtualModPluginParams {
|
||||||
export function astroContentVirtualModPlugin({
|
export function astroContentVirtualModPlugin({
|
||||||
settings,
|
settings,
|
||||||
}: AstroContentVirtualModPluginParams): Plugin {
|
}: AstroContentVirtualModPluginParams): Plugin {
|
||||||
const contentPaths = getContentPaths(settings.config);
|
|
||||||
const relContentDir = rootRelativePath(settings.config.root, contentPaths.contentDir);
|
|
||||||
|
|
||||||
const contentEntryConfigByExt = getEntryConfigByExtMap(settings.contentEntryTypes);
|
|
||||||
const contentEntryExts = [...contentEntryConfigByExt.keys()];
|
|
||||||
const dataEntryExts = getDataEntryExts(settings);
|
|
||||||
|
|
||||||
const virtualModContents = fsMod
|
|
||||||
.readFileSync(contentPaths.virtualModTemplate, 'utf-8')
|
|
||||||
.replace(
|
|
||||||
'@@COLLECTION_NAME_BY_REFERENCE_KEY@@',
|
|
||||||
new URL('reference-map.json', contentPaths.cacheDir).pathname
|
|
||||||
)
|
|
||||||
.replace('@@CONTENT_DIR@@', relContentDir)
|
|
||||||
.replace(
|
|
||||||
"'@@CONTENT_ENTRY_GLOB_PATH@@'",
|
|
||||||
JSON.stringify(globWithUnderscoresIgnored(relContentDir, contentEntryExts))
|
|
||||||
)
|
|
||||||
.replace(
|
|
||||||
"'@@DATA_ENTRY_GLOB_PATH@@'",
|
|
||||||
JSON.stringify(globWithUnderscoresIgnored(relContentDir, dataEntryExts))
|
|
||||||
)
|
|
||||||
.replace(
|
|
||||||
"'@@RENDER_ENTRY_GLOB_PATH@@'",
|
|
||||||
JSON.stringify(
|
|
||||||
globWithUnderscoresIgnored(
|
|
||||||
relContentDir,
|
|
||||||
/** Note: data collections excluded */ contentEntryExts
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
const astroContentVirtualModuleId = '\0' + VIRTUAL_MODULE_ID;
|
const astroContentVirtualModuleId = '\0' + VIRTUAL_MODULE_ID;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -73,45 +40,80 @@ export function astroContentVirtualModPlugin({
|
||||||
},
|
},
|
||||||
async load(id) {
|
async load(id) {
|
||||||
if (id === astroContentVirtualModuleId) {
|
if (id === astroContentVirtualModuleId) {
|
||||||
const stringifiedLookupMap = await getStringifiedLookupMap({
|
const lookupMap = await generateLookupMap({
|
||||||
|
settings,
|
||||||
fs: fsMod,
|
fs: fsMod,
|
||||||
contentPaths,
|
|
||||||
contentEntryConfigByExt,
|
|
||||||
dataEntryExts,
|
|
||||||
root: settings.config.root,
|
|
||||||
});
|
});
|
||||||
|
const code = await generateContentEntryFile({ settings, fs: fsMod, lookupMap });
|
||||||
|
|
||||||
return {
|
return {
|
||||||
code: virtualModContents.replace(
|
code
|
||||||
'/* @@LOOKUP_MAP_ASSIGNMENT@@ */',
|
|
||||||
`lookupMap = ${stringifiedLookupMap};`
|
|
||||||
),
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function generateContentEntryFile({
|
||||||
|
settings,
|
||||||
|
fs,
|
||||||
|
lookupMap,
|
||||||
|
}: {
|
||||||
|
settings: AstroSettings;
|
||||||
|
fs: typeof fsMod;
|
||||||
|
lookupMap: ContentLookupMap
|
||||||
|
}) {
|
||||||
|
const contentPaths = getContentPaths(settings.config);
|
||||||
|
const relContentDir = rootRelativePath(settings.config.root, contentPaths.contentDir);
|
||||||
|
|
||||||
|
const contentEntryConfigByExt = getEntryConfigByExtMap(settings.contentEntryTypes);
|
||||||
|
const contentEntryExts = [...contentEntryConfigByExt.keys()];
|
||||||
|
const dataEntryExts = getDataEntryExts(settings);
|
||||||
|
|
||||||
|
const [contentEntryGlobResult, dataEntryGlobResult, renderEntryGlobResult] = await Promise.all([contentEntryExts, dataEntryExts, contentEntryExts].map((exts, i) => getStringifiedGlobResult(settings, exts, i === 2 ? '.render.mjs' : undefined)));
|
||||||
|
|
||||||
|
const virtualModContents = fs
|
||||||
|
.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)};`
|
||||||
|
);
|
||||||
|
|
||||||
|
return virtualModContents;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate a map from a collection + slug to the local file path.
|
* Generate a map from a collection + slug to the local file path.
|
||||||
* This is used internally to resolve entry imports when using `getEntry()`.
|
* This is used internally to resolve entry imports when using `getEntry()`.
|
||||||
* @see `content-module.template.mjs`
|
* @see `content-module.template.mjs`
|
||||||
*/
|
*/
|
||||||
export async function getStringifiedLookupMap({
|
export async function generateLookupMap({
|
||||||
contentPaths,
|
settings,
|
||||||
contentEntryConfigByExt,
|
|
||||||
dataEntryExts,
|
|
||||||
root,
|
|
||||||
fs,
|
fs,
|
||||||
}: {
|
}: {
|
||||||
contentEntryConfigByExt: Map<string, ContentEntryType>;
|
settings: AstroSettings;
|
||||||
dataEntryExts: string[];
|
|
||||||
contentPaths: Pick<ContentPaths, 'contentDir' | 'config'>;
|
|
||||||
root: URL;
|
|
||||||
fs: typeof fsMod;
|
fs: typeof fsMod;
|
||||||
}) {
|
}) {
|
||||||
|
const { root } = settings.config;
|
||||||
|
const contentPaths = getContentPaths(settings.config);
|
||||||
|
const relContentDir = rootRelativePath(root, contentPaths.contentDir, false);
|
||||||
|
|
||||||
|
const contentEntryConfigByExt = getEntryConfigByExtMap(settings.contentEntryTypes);
|
||||||
|
const dataEntryExts = getDataEntryExts(settings);
|
||||||
|
|
||||||
const { contentDir } = contentPaths;
|
const { contentDir } = contentPaths;
|
||||||
const relContentDir = rootRelativePath(root, contentDir, false);
|
|
||||||
const contentEntryExts = [...contentEntryConfigByExt.keys()];
|
const contentEntryExts = [...contentEntryConfigByExt.keys()];
|
||||||
|
|
||||||
let lookupMap: ContentLookupMap = {};
|
let lookupMap: ContentLookupMap = {};
|
||||||
|
@ -200,7 +202,7 @@ export async function getStringifiedLookupMap({
|
||||||
|
|
||||||
await Promise.all(promises);
|
await Promise.all(promises);
|
||||||
|
|
||||||
return JSON.stringify(lookupMap);
|
return lookupMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
const UnexpectedLookupMapError = new AstroError({
|
const UnexpectedLookupMapError = new AstroError({
|
||||||
|
@ -208,6 +210,31 @@ const UnexpectedLookupMapError = new AstroError({
|
||||||
message: `Unexpected error while parsing content entry IDs and slugs.`,
|
message: `Unexpected error while parsing content entry IDs and slugs.`,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
async function getStringifiedGlobResult(settings: AstroSettings, exts: string[], importExtension = '.mjs'): Promise<string> {
|
||||||
|
const pattern = globWithUnderscoresIgnored('./', exts);
|
||||||
|
const contentPaths = getContentPaths(settings.config);
|
||||||
|
|
||||||
|
const files = await glob(pattern, {
|
||||||
|
cwd: fileURLToPath(contentPaths.contentDir),
|
||||||
|
fs: {
|
||||||
|
readdir: fsMod.readdir.bind(fsMod),
|
||||||
|
readdirSync: fsMod.readdirSync.bind(fsMod),
|
||||||
|
},
|
||||||
|
onlyFiles: true,
|
||||||
|
objectMode: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
let str = '{';
|
||||||
|
for (const file of files) {
|
||||||
|
const importSpecifier = `./${removeFileExtension(removeLeadingForwardSlash(slash(file.path)))}${importExtension}`;
|
||||||
|
const srcRelativePath = new URL(`./${slash(file.path)}`, contentPaths.contentDir).toString().replace(settings.config.root.toString(), '/')
|
||||||
|
str += `\n "${srcRelativePath}": () => import("${importSpecifier}"),`
|
||||||
|
}
|
||||||
|
str += '\n}'
|
||||||
|
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
function globWithUnderscoresIgnored(relContentDir: string, exts: string[]): string[] {
|
function globWithUnderscoresIgnored(relContentDir: string, exts: string[]): string[] {
|
||||||
const extGlob = getExtGlob(exts);
|
const extGlob = getExtGlob(exts);
|
||||||
const contentDir = appendForwardSlash(relContentDir);
|
const contentDir = appendForwardSlash(relContentDir);
|
||||||
|
|
|
@ -5,16 +5,19 @@ import type { StaticBuildOptions, ViteBuildReturn } from './types.js';
|
||||||
type RollupOutputArray = Extract<ViteBuildReturn, Array<any>>;
|
type RollupOutputArray = Extract<ViteBuildReturn, Array<any>>;
|
||||||
type OutputChunkorAsset = RollupOutputArray[number]['output'][number];
|
type OutputChunkorAsset = RollupOutputArray[number]['output'][number];
|
||||||
type OutputChunk = Extract<OutputChunkorAsset, { type: 'chunk' }>;
|
type OutputChunk = Extract<OutputChunkorAsset, { type: 'chunk' }>;
|
||||||
|
export type BuildTarget = 'server' | 'client' | 'content';
|
||||||
|
|
||||||
type MutateChunk = (chunk: OutputChunk, build: 'server' | 'client', newCode: string) => void;
|
type MutateChunk = (chunk: OutputChunk, targets: BuildTarget[], newCode: string) => void;
|
||||||
|
|
||||||
|
export interface BuildBeforeHookResult {
|
||||||
|
enforce?: 'after-user-plugins';
|
||||||
|
vitePlugin: VitePlugin | VitePlugin[] | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
export type AstroBuildPlugin = {
|
export type AstroBuildPlugin = {
|
||||||
build: 'ssr' | 'client' | 'both';
|
targets: BuildTarget[];
|
||||||
hooks?: {
|
hooks?: {
|
||||||
'build:before'?: (opts: { build: 'ssr' | 'client'; input: Set<string> }) => {
|
'build:before'?: (opts: { target: BuildTarget; input: Set<string> }) => BuildBeforeHookResult | Promise<BuildBeforeHookResult>;
|
||||||
enforce?: 'after-user-plugins';
|
|
||||||
vitePlugin: VitePlugin | VitePlugin[] | undefined;
|
|
||||||
};
|
|
||||||
'build:post'?: (opts: {
|
'build:post'?: (opts: {
|
||||||
ssrOutputs: RollupOutputArray;
|
ssrOutputs: RollupOutputArray;
|
||||||
clientOutputs: RollupOutputArray;
|
clientOutputs: RollupOutputArray;
|
||||||
|
@ -24,40 +27,32 @@ export type AstroBuildPlugin = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export function createPluginContainer(options: StaticBuildOptions, internals: BuildInternals) {
|
export function createPluginContainer(options: StaticBuildOptions, internals: BuildInternals) {
|
||||||
const clientPlugins: AstroBuildPlugin[] = [];
|
const plugins = new Map<BuildTarget, AstroBuildPlugin[]>();
|
||||||
const ssrPlugins: AstroBuildPlugin[] = [];
|
|
||||||
const allPlugins = new Set<AstroBuildPlugin>();
|
const allPlugins = new Set<AstroBuildPlugin>();
|
||||||
|
for (const target of ['client', 'server', 'content'] satisfies BuildTarget[]) {
|
||||||
|
plugins.set(target, []);
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
options,
|
options,
|
||||||
internals,
|
internals,
|
||||||
register(plugin: AstroBuildPlugin) {
|
register(plugin: AstroBuildPlugin) {
|
||||||
allPlugins.add(plugin);
|
allPlugins.add(plugin);
|
||||||
switch (plugin.build) {
|
for (const target of plugin.targets) {
|
||||||
case 'client': {
|
const targetPlugins = plugins.get(target) ?? [];
|
||||||
clientPlugins.push(plugin);
|
targetPlugins.push(plugin);
|
||||||
break;
|
plugins.set(target, targetPlugins);
|
||||||
}
|
|
||||||
case 'ssr': {
|
|
||||||
ssrPlugins.push(plugin);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 'both': {
|
|
||||||
clientPlugins.push(plugin);
|
|
||||||
ssrPlugins.push(plugin);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// Hooks
|
// Hooks
|
||||||
runBeforeHook(build: 'ssr' | 'client', input: Set<string>) {
|
async runBeforeHook(target: BuildTarget, input: Set<string>) {
|
||||||
let plugins = build === 'ssr' ? ssrPlugins : clientPlugins;
|
let targetPlugins = plugins.get(target) ?? [];
|
||||||
let vitePlugins: Array<VitePlugin | VitePlugin[]> = [];
|
let vitePlugins: Array<VitePlugin | VitePlugin[]> = [];
|
||||||
let lastVitePlugins: Array<VitePlugin | VitePlugin[]> = [];
|
let lastVitePlugins: Array<VitePlugin | VitePlugin[]> = [];
|
||||||
for (const plugin of plugins) {
|
for (const plugin of targetPlugins) {
|
||||||
if (plugin.hooks?.['build:before']) {
|
if (plugin.hooks?.['build:before']) {
|
||||||
let result = plugin.hooks['build:before']({ build, input });
|
let result = await plugin.hooks['build:before']({ target, input });
|
||||||
if (result.vitePlugin) {
|
if (result.vitePlugin) {
|
||||||
vitePlugins.push(result.vitePlugin);
|
vitePlugins.push(result.vitePlugin);
|
||||||
}
|
}
|
||||||
|
@ -74,7 +69,7 @@ export function createPluginContainer(options: StaticBuildOptions, internals: Bu
|
||||||
const mutations = new Map<
|
const mutations = new Map<
|
||||||
string,
|
string,
|
||||||
{
|
{
|
||||||
build: 'server' | 'client';
|
targets: BuildTarget[];
|
||||||
code: string;
|
code: string;
|
||||||
}
|
}
|
||||||
>();
|
>();
|
||||||
|
@ -93,10 +88,10 @@ export function createPluginContainer(options: StaticBuildOptions, internals: Bu
|
||||||
clientOutputs.push(clientReturn);
|
clientOutputs.push(clientReturn);
|
||||||
}
|
}
|
||||||
|
|
||||||
const mutate: MutateChunk = (chunk, build, newCode) => {
|
const mutate: MutateChunk = (chunk, targets, newCode) => {
|
||||||
chunk.code = newCode;
|
chunk.code = newCode;
|
||||||
mutations.set(chunk.fileName, {
|
mutations.set(chunk.fileName, {
|
||||||
build,
|
targets,
|
||||||
code: newCode,
|
code: newCode,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
|
@ -4,7 +4,9 @@ import type { AstroBuildPluginContainer } from '../plugin.js';
|
||||||
import { pluginAliasResolve } from './plugin-alias-resolve.js';
|
import { pluginAliasResolve } from './plugin-alias-resolve.js';
|
||||||
import { pluginAnalyzer } from './plugin-analyzer.js';
|
import { pluginAnalyzer } from './plugin-analyzer.js';
|
||||||
import { pluginComponentEntry } from './plugin-component-entry.js';
|
import { pluginComponentEntry } from './plugin-component-entry.js';
|
||||||
|
import { pluginContent } from './plugin-content.js';
|
||||||
import { pluginCSS } from './plugin-css.js';
|
import { pluginCSS } from './plugin-css.js';
|
||||||
|
import { pluginExternalize } from './plugin-external.js';
|
||||||
import { pluginHoistedScripts } from './plugin-hoisted-scripts.js';
|
import { pluginHoistedScripts } from './plugin-hoisted-scripts.js';
|
||||||
import { pluginInternals } from './plugin-internals.js';
|
import { pluginInternals } from './plugin-internals.js';
|
||||||
import { pluginManifest } from './plugin-manifest.js';
|
import { pluginManifest } from './plugin-manifest.js';
|
||||||
|
@ -23,6 +25,7 @@ export function registerAllPlugins({ internals, options, register }: AstroBuildP
|
||||||
register(pluginRenderers(options));
|
register(pluginRenderers(options));
|
||||||
register(pluginMiddleware(options, internals));
|
register(pluginMiddleware(options, internals));
|
||||||
register(pluginPages(options, internals));
|
register(pluginPages(options, internals));
|
||||||
|
register(pluginContent(options, internals));
|
||||||
register(pluginCSS(options, internals));
|
register(pluginCSS(options, internals));
|
||||||
register(astroHeadBuildPlugin(internals));
|
register(astroHeadBuildPlugin(internals));
|
||||||
register(pluginPrerender(options, internals));
|
register(pluginPrerender(options, internals));
|
||||||
|
@ -30,4 +33,5 @@ export function registerAllPlugins({ internals, options, register }: AstroBuildP
|
||||||
register(pluginHoistedScripts(options, internals));
|
register(pluginHoistedScripts(options, internals));
|
||||||
register(pluginSSR(options, internals));
|
register(pluginSSR(options, internals));
|
||||||
register(pluginSSRSplit(options, internals));
|
register(pluginSSRSplit(options, internals));
|
||||||
|
register(pluginExternalize());
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,7 +52,7 @@ function matches(pattern: string | RegExp, importee: string) {
|
||||||
|
|
||||||
export function pluginAliasResolve(internals: BuildInternals): AstroBuildPlugin {
|
export function pluginAliasResolve(internals: BuildInternals): AstroBuildPlugin {
|
||||||
return {
|
return {
|
||||||
build: 'client',
|
targets: ['client'],
|
||||||
hooks: {
|
hooks: {
|
||||||
'build:before': () => {
|
'build:before': () => {
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -330,7 +330,7 @@ export function pluginAnalyzer(
|
||||||
internals: BuildInternals
|
internals: BuildInternals
|
||||||
): AstroBuildPlugin {
|
): AstroBuildPlugin {
|
||||||
return {
|
return {
|
||||||
build: 'ssr',
|
targets: ['server'],
|
||||||
hooks: {
|
hooks: {
|
||||||
'build:before': () => {
|
'build:before': () => {
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -77,7 +77,7 @@ export function normalizeEntryId(id: string): string {
|
||||||
|
|
||||||
export function pluginComponentEntry(internals: BuildInternals): AstroBuildPlugin {
|
export function pluginComponentEntry(internals: BuildInternals): AstroBuildPlugin {
|
||||||
return {
|
return {
|
||||||
build: 'client',
|
targets: ['client'],
|
||||||
hooks: {
|
hooks: {
|
||||||
'build:before': () => {
|
'build:before': () => {
|
||||||
return {
|
return {
|
||||||
|
|
70
packages/astro/src/core/build/plugins/plugin-content.ts
Normal file
70
packages/astro/src/core/build/plugins/plugin-content.ts
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
import type { Plugin as VitePlugin } from 'vite';
|
||||||
|
import fsMod from 'node:fs';
|
||||||
|
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 } from '../../path.js';
|
||||||
|
import { fileURLToPath } from 'node:url';
|
||||||
|
import type { ContentLookupMap } from '../../../content/utils.js';
|
||||||
|
import { CONTENT_RENDER_FLAG } from '../../../content/consts.js';
|
||||||
|
|
||||||
|
function vitePluginContent(opts: StaticBuildOptions, lookupMap: ContentLookupMap): VitePlugin {
|
||||||
|
return {
|
||||||
|
name: '@astro/plugin-build-content',
|
||||||
|
|
||||||
|
options(options) {
|
||||||
|
let newOptions = Object.assign({}, options);
|
||||||
|
if (opts.settings.config.output === 'static') {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
|
for (const [_collectionName, { type, entries }] of Object.entries(lookupMap)) {
|
||||||
|
let newInputs = Object.values(entries).flatMap(entry => {
|
||||||
|
const input = fileURLToPath(joinPaths(opts.settings.config.root.toString(), entry));
|
||||||
|
const inputs = [`${input}?${collectionTypeToFlag(type)}`];
|
||||||
|
if (type === 'content') {
|
||||||
|
inputs.push(`${input}?${CONTENT_RENDER_FLAG}`)
|
||||||
|
}
|
||||||
|
return inputs;
|
||||||
|
})
|
||||||
|
newOptions = addRollupInput(newOptions, newInputs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return newOptions;
|
||||||
|
},
|
||||||
|
|
||||||
|
resolveId(id) {
|
||||||
|
console.log(id);
|
||||||
|
},
|
||||||
|
|
||||||
|
async generateBundle() {
|
||||||
|
const content = await generateContentEntryFile({ settings: opts.settings, fs: fsMod, lookupMap });
|
||||||
|
this.emitFile({
|
||||||
|
type: 'prebuilt-chunk',
|
||||||
|
code: content,
|
||||||
|
fileName: 'content/index.mjs'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function collectionTypeToFlag(type: 'content' | 'data') {
|
||||||
|
const name = type[0].toUpperCase() + type.slice(1);
|
||||||
|
return `astro${name}CollectionEntry`
|
||||||
|
}
|
||||||
|
|
||||||
|
export function pluginContent(opts: StaticBuildOptions, _internals: BuildInternals): AstroBuildPlugin {
|
||||||
|
return {
|
||||||
|
targets: ['content'],
|
||||||
|
hooks: {
|
||||||
|
async 'build:before'() {
|
||||||
|
// TODO: filter lookupMap based on file hashes
|
||||||
|
const lookupMap = await generateLookupMap({ settings: opts.settings, fs: fsMod });
|
||||||
|
|
||||||
|
return {
|
||||||
|
vitePlugin: vitePluginContent(opts, lookupMap),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
|
@ -4,7 +4,7 @@ import type { GetModuleInfo } from 'rollup';
|
||||||
import { type ResolvedConfig, type Plugin as VitePlugin } from 'vite';
|
import { type ResolvedConfig, type Plugin as VitePlugin } from 'vite';
|
||||||
import { isBuildableCSSRequest } from '../../../vite-plugin-astro-server/util.js';
|
import { isBuildableCSSRequest } from '../../../vite-plugin-astro-server/util.js';
|
||||||
import type { BuildInternals } from '../internal.js';
|
import type { BuildInternals } from '../internal.js';
|
||||||
import type { AstroBuildPlugin } from '../plugin.js';
|
import type { AstroBuildPlugin, BuildTarget } from '../plugin.js';
|
||||||
import type { PageBuildData, StaticBuildOptions, StylesheetAsset } from '../types.js';
|
import type { PageBuildData, StaticBuildOptions, StylesheetAsset } from '../types.js';
|
||||||
|
|
||||||
import { PROPAGATED_ASSET_FLAG } from '../../../content/consts.js';
|
import { PROPAGATED_ASSET_FLAG } from '../../../content/consts.js';
|
||||||
|
@ -22,7 +22,7 @@ import { extendManualChunks } from './util.js';
|
||||||
interface PluginOptions {
|
interface PluginOptions {
|
||||||
internals: BuildInternals;
|
internals: BuildInternals;
|
||||||
buildOptions: StaticBuildOptions;
|
buildOptions: StaticBuildOptions;
|
||||||
target: 'client' | 'server';
|
target: BuildTarget;
|
||||||
}
|
}
|
||||||
|
|
||||||
/***** ASTRO PLUGIN *****/
|
/***** ASTRO PLUGIN *****/
|
||||||
|
@ -32,13 +32,13 @@ export function pluginCSS(
|
||||||
internals: BuildInternals
|
internals: BuildInternals
|
||||||
): AstroBuildPlugin {
|
): AstroBuildPlugin {
|
||||||
return {
|
return {
|
||||||
build: 'both',
|
targets: ['client', 'server'],
|
||||||
hooks: {
|
hooks: {
|
||||||
'build:before': ({ build }) => {
|
'build:before': ({ target }) => {
|
||||||
let plugins = rollupPluginAstroBuildCSS({
|
let plugins = rollupPluginAstroBuildCSS({
|
||||||
buildOptions: options,
|
buildOptions: options,
|
||||||
internals,
|
internals,
|
||||||
target: build === 'ssr' ? 'server' : 'client',
|
target,
|
||||||
});
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
42
packages/astro/src/core/build/plugins/plugin-external.ts
Normal file
42
packages/astro/src/core/build/plugins/plugin-external.ts
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
import type { Plugin as VitePlugin } from 'vite';
|
||||||
|
import type { AstroBuildPlugin } from '../plugin.js';
|
||||||
|
import { slash, removeLeadingForwardSlash } from '../../path.js';
|
||||||
|
|
||||||
|
export function vitePluginExternalize(): VitePlugin {
|
||||||
|
const MODULE_ID = `astro:content`;
|
||||||
|
const VIRTUAL_MODULE_ID = `\0${MODULE_ID}`;
|
||||||
|
|
||||||
|
return {
|
||||||
|
name: '@astro/plugin-externalize',
|
||||||
|
enforce: 'pre',
|
||||||
|
resolveId(id) {
|
||||||
|
// Ensure that `astro:content` is treated as external and rewritten to the final entrypoint
|
||||||
|
if (id === MODULE_ID) {
|
||||||
|
return { id: VIRTUAL_MODULE_ID, external: true }
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
renderChunk(code, chunk) {
|
||||||
|
if (chunk.imports.find(name => name === VIRTUAL_MODULE_ID)) {
|
||||||
|
// We want to generate a relative path and avoid a hardcoded absolute path in the output!
|
||||||
|
const steps = removeLeadingForwardSlash(slash(chunk.fileName)).split('/').length - 1;
|
||||||
|
const prefix = '../'.repeat(steps) || './';
|
||||||
|
// dist/content/index.mjs is generated by the "content" build
|
||||||
|
return code.replace(VIRTUAL_MODULE_ID, `${prefix}content/index.mjs`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function pluginExternalize(): AstroBuildPlugin {
|
||||||
|
return {
|
||||||
|
targets: ['server'],
|
||||||
|
hooks: {
|
||||||
|
'build:before': () => {
|
||||||
|
return {
|
||||||
|
vitePlugin: vitePluginExternalize(),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
|
@ -108,7 +108,7 @@ export function pluginHoistedScripts(
|
||||||
internals: BuildInternals
|
internals: BuildInternals
|
||||||
): AstroBuildPlugin {
|
): AstroBuildPlugin {
|
||||||
return {
|
return {
|
||||||
build: 'client',
|
targets: ['client'],
|
||||||
hooks: {
|
hooks: {
|
||||||
'build:before': () => {
|
'build:before': () => {
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -62,7 +62,7 @@ export function vitePluginInternals(input: Set<string>, internals: BuildInternal
|
||||||
|
|
||||||
export function pluginInternals(internals: BuildInternals): AstroBuildPlugin {
|
export function pluginInternals(internals: BuildInternals): AstroBuildPlugin {
|
||||||
return {
|
return {
|
||||||
build: 'both',
|
targets: ['client', 'server'],
|
||||||
hooks: {
|
hooks: {
|
||||||
'build:before': ({ input }) => {
|
'build:before': ({ input }) => {
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -79,7 +79,7 @@ export function pluginManifest(
|
||||||
internals: BuildInternals
|
internals: BuildInternals
|
||||||
): AstroBuildPlugin {
|
): AstroBuildPlugin {
|
||||||
return {
|
return {
|
||||||
build: 'ssr',
|
targets: ['server'],
|
||||||
hooks: {
|
hooks: {
|
||||||
'build:before': () => {
|
'build:before': () => {
|
||||||
return {
|
return {
|
||||||
|
@ -107,7 +107,7 @@ export function pluginManifest(
|
||||||
: undefined,
|
: undefined,
|
||||||
});
|
});
|
||||||
const code = injectManifest(manifest, internals.manifestEntryChunk);
|
const code = injectManifest(manifest, internals.manifestEntryChunk);
|
||||||
mutate(internals.manifestEntryChunk, 'server', code);
|
mutate(internals.manifestEntryChunk, ['server'], code);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -71,7 +71,7 @@ export function pluginMiddleware(
|
||||||
internals: BuildInternals
|
internals: BuildInternals
|
||||||
): AstroBuildPlugin {
|
): AstroBuildPlugin {
|
||||||
return {
|
return {
|
||||||
build: 'ssr',
|
targets: ['server'],
|
||||||
hooks: {
|
hooks: {
|
||||||
'build:before': () => {
|
'build:before': () => {
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -104,7 +104,7 @@ export function shouldBundleMiddleware(settings: AstroSettings) {
|
||||||
|
|
||||||
export function pluginPages(opts: StaticBuildOptions, internals: BuildInternals): AstroBuildPlugin {
|
export function pluginPages(opts: StaticBuildOptions, internals: BuildInternals): AstroBuildPlugin {
|
||||||
return {
|
return {
|
||||||
build: 'ssr',
|
targets: ['server'],
|
||||||
hooks: {
|
hooks: {
|
||||||
'build:before': () => {
|
'build:before': () => {
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -40,7 +40,7 @@ export function pluginPrerender(
|
||||||
internals: BuildInternals
|
internals: BuildInternals
|
||||||
): AstroBuildPlugin {
|
): AstroBuildPlugin {
|
||||||
return {
|
return {
|
||||||
build: 'ssr',
|
targets: ['server'],
|
||||||
hooks: {
|
hooks: {
|
||||||
'build:before': () => {
|
'build:before': () => {
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -48,7 +48,8 @@ export function vitePluginRenderers(opts: StaticBuildOptions): VitePlugin {
|
||||||
|
|
||||||
export function pluginRenderers(opts: StaticBuildOptions): AstroBuildPlugin {
|
export function pluginRenderers(opts: StaticBuildOptions): AstroBuildPlugin {
|
||||||
return {
|
return {
|
||||||
build: 'ssr',
|
// TODO: handle for content?
|
||||||
|
targets: ['server'],
|
||||||
hooks: {
|
hooks: {
|
||||||
'build:before': () => {
|
'build:before': () => {
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -97,7 +97,7 @@ export function pluginSSR(
|
||||||
const ssr = isServerLikeOutput(options.settings.config);
|
const ssr = isServerLikeOutput(options.settings.config);
|
||||||
const functionPerRouteEnabled = isFunctionPerRouteEnabled(options.settings.adapter);
|
const functionPerRouteEnabled = isFunctionPerRouteEnabled(options.settings.adapter);
|
||||||
return {
|
return {
|
||||||
build: 'ssr',
|
targets: ['server'],
|
||||||
hooks: {
|
hooks: {
|
||||||
'build:before': () => {
|
'build:before': () => {
|
||||||
let vitePlugin =
|
let vitePlugin =
|
||||||
|
@ -218,7 +218,7 @@ export function pluginSSRSplit(
|
||||||
const functionPerRouteEnabled = isFunctionPerRouteEnabled(options.settings.adapter);
|
const functionPerRouteEnabled = isFunctionPerRouteEnabled(options.settings.adapter);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
build: 'ssr',
|
targets: ['server'],
|
||||||
hooks: {
|
hooks: {
|
||||||
'build:before': () => {
|
'build:before': () => {
|
||||||
let vitePlugin =
|
let vitePlugin =
|
||||||
|
|
|
@ -4,7 +4,7 @@ import glob from 'fast-glob';
|
||||||
import { bgGreen, bgMagenta, black, dim } from 'kleur/colors';
|
import { bgGreen, bgMagenta, black, dim } from 'kleur/colors';
|
||||||
import fs from 'node:fs';
|
import fs from 'node:fs';
|
||||||
import path, { extname } from 'node:path';
|
import path, { extname } from 'node:path';
|
||||||
import { fileURLToPath } from 'node:url';
|
import { fileURLToPath, pathToFileURL } from 'node:url';
|
||||||
import * as vite from 'vite';
|
import * as vite from 'vite';
|
||||||
import type { RouteData } from '../../@types/astro.js';
|
import type { RouteData } from '../../@types/astro.js';
|
||||||
import {
|
import {
|
||||||
|
@ -13,7 +13,7 @@ import {
|
||||||
type BuildInternals,
|
type BuildInternals,
|
||||||
} from '../../core/build/internal.js';
|
} from '../../core/build/internal.js';
|
||||||
import { emptyDir, removeEmptyDirs } from '../../core/fs/index.js';
|
import { emptyDir, removeEmptyDirs } from '../../core/fs/index.js';
|
||||||
import { appendForwardSlash, prependForwardSlash } from '../../core/path.js';
|
import { appendForwardSlash, prependForwardSlash, removeFileExtension } from '../../core/path.js';
|
||||||
import { isModeServerWithNoAdapter } from '../../core/util.js';
|
import { isModeServerWithNoAdapter } from '../../core/util.js';
|
||||||
import { runHookBuildSetup } from '../../integrations/index.js';
|
import { runHookBuildSetup } from '../../integrations/index.js';
|
||||||
import { getOutputDirectory, isServerLikeOutput } from '../../prerender/utils.js';
|
import { getOutputDirectory, isServerLikeOutput } from '../../prerender/utils.js';
|
||||||
|
@ -32,6 +32,8 @@ import { RESOLVED_SPLIT_MODULE_ID, RESOLVED_SSR_VIRTUAL_MODULE_ID } from './plug
|
||||||
import { ASTRO_PAGE_EXTENSION_POST_PATTERN } from './plugins/util.js';
|
import { ASTRO_PAGE_EXTENSION_POST_PATTERN } from './plugins/util.js';
|
||||||
import type { PageBuildData, StaticBuildOptions } from './types.js';
|
import type { PageBuildData, StaticBuildOptions } from './types.js';
|
||||||
import { getTimeStat } from './util.js';
|
import { getTimeStat } from './util.js';
|
||||||
|
import { hasContentFlag } from '../../content/utils.js';
|
||||||
|
import { CONTENT_FLAGS, CONTENT_RENDER_FLAG, PROPAGATED_ASSET_FLAG } from '../../content/consts.js';
|
||||||
|
|
||||||
export async function viteBuild(opts: StaticBuildOptions) {
|
export async function viteBuild(opts: StaticBuildOptions) {
|
||||||
const { allPages, settings } = opts;
|
const { allPages, settings } = opts;
|
||||||
|
@ -77,13 +79,26 @@ export async function viteBuild(opts: StaticBuildOptions) {
|
||||||
const container = createPluginContainer(opts, internals);
|
const container = createPluginContainer(opts, internals);
|
||||||
registerAllPlugins(container);
|
registerAllPlugins(container);
|
||||||
|
|
||||||
// Build your project (SSR application code, assets, client JS, etc.)
|
let buildContent = async () => {
|
||||||
const ssrTime = performance.now();
|
const contentTime = performance.now();
|
||||||
opts.logger.info('build', `Building ${settings.config.output} entrypoints...`);
|
opts.logger.info('content', `Building collections...`);
|
||||||
const ssrOutput = await ssrBuild(opts, internals, pageInput, container);
|
await contentBuild(opts, internals, new Set(), container);
|
||||||
opts.logger.info('build', dim(`Completed in ${getTimeStat(ssrTime, performance.now())}.`));
|
opts.logger.info('content', dim(`Completed in ${getTimeStat(contentTime, performance.now())}.`));
|
||||||
|
}
|
||||||
|
|
||||||
|
let ssrOutput: any;
|
||||||
|
let buildServer = async () => {
|
||||||
|
// Build your project (SSR application code, assets, client JS, etc.)
|
||||||
|
const ssrTime = performance.now();
|
||||||
|
opts.logger.info('build', `Building ${settings.config.output} entrypoints...`);
|
||||||
|
ssrOutput = await ssrBuild(opts, internals, pageInput, container);
|
||||||
|
opts.logger.info('build', dim(`Completed in ${getTimeStat(ssrTime, performance.now())}.`));
|
||||||
|
|
||||||
|
settings.timer.end('SSR build');
|
||||||
|
}
|
||||||
|
|
||||||
|
await Promise.all([buildContent(), buildServer()]);
|
||||||
|
|
||||||
settings.timer.end('SSR build');
|
|
||||||
settings.timer.start('Client build');
|
settings.timer.start('Client build');
|
||||||
|
|
||||||
const rendererClientEntrypoints = settings.renderers
|
const rendererClientEntrypoints = settings.renderers
|
||||||
|
@ -149,7 +164,7 @@ async function ssrBuild(
|
||||||
const ssr = isServerLikeOutput(settings.config);
|
const ssr = isServerLikeOutput(settings.config);
|
||||||
const out = getOutputDirectory(settings.config);
|
const out = getOutputDirectory(settings.config);
|
||||||
const routes = Object.values(allPages).map((pd) => pd.route);
|
const routes = Object.values(allPages).map((pd) => pd.route);
|
||||||
const { lastVitePlugins, vitePlugins } = container.runBeforeHook('ssr', input);
|
const { lastVitePlugins, vitePlugins } = await container.runBeforeHook('server', input);
|
||||||
|
|
||||||
const viteBuildConfig: vite.InlineConfig = {
|
const viteBuildConfig: vite.InlineConfig = {
|
||||||
...viteConfig,
|
...viteConfig,
|
||||||
|
@ -234,6 +249,87 @@ async function ssrBuild(
|
||||||
return await vite.build(updatedViteBuildConfig);
|
return await vite.build(updatedViteBuildConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function contentBuild(
|
||||||
|
opts: StaticBuildOptions,
|
||||||
|
internals: BuildInternals,
|
||||||
|
input: Set<string>,
|
||||||
|
container: AstroBuildPluginContainer
|
||||||
|
) {
|
||||||
|
const { settings, viteConfig } = opts;
|
||||||
|
const ssr = isServerLikeOutput(settings.config);
|
||||||
|
const out = getOutputDirectory(settings.config);
|
||||||
|
const { lastVitePlugins, vitePlugins } = await container.runBeforeHook('content', input);
|
||||||
|
|
||||||
|
const viteBuildConfig: vite.InlineConfig = {
|
||||||
|
...viteConfig,
|
||||||
|
mode: viteConfig.mode || 'production',
|
||||||
|
// Check using `settings...` as `viteConfig` always defaults to `warn` by Astro
|
||||||
|
logLevel: settings.config.vite.logLevel ?? 'error',
|
||||||
|
build: {
|
||||||
|
target: 'esnext',
|
||||||
|
// Vite defaults cssMinify to false in SSR by default, but we want to minify it
|
||||||
|
// as the CSS generated are used and served to the client.
|
||||||
|
cssMinify: viteConfig.build?.minify == null ? true : !!viteConfig.build?.minify,
|
||||||
|
...viteConfig.build,
|
||||||
|
emptyOutDir: false,
|
||||||
|
manifest: false,
|
||||||
|
outDir: fileURLToPath(out),
|
||||||
|
copyPublicDir: !ssr,
|
||||||
|
rollupOptions: {
|
||||||
|
...viteConfig.build?.rollupOptions,
|
||||||
|
input: [],
|
||||||
|
output: {
|
||||||
|
format: 'esm',
|
||||||
|
chunkFileNames(info) {
|
||||||
|
if (info.moduleIds.length === 1) {
|
||||||
|
const url = pathToFileURL(info.moduleIds[0]);
|
||||||
|
const distRelative = url.toString().replace(settings.config.srcDir.toString(), '')
|
||||||
|
let entryFileName = removeFileExtension(distRelative);
|
||||||
|
return `${entryFileName}.render.mjs`;
|
||||||
|
}
|
||||||
|
return '[name]_[hash].mjs';
|
||||||
|
},
|
||||||
|
...viteConfig.build?.rollupOptions?.output,
|
||||||
|
entryFileNames(info) {
|
||||||
|
const params = new URLSearchParams(info.moduleIds[0].split('?').pop() ?? '');
|
||||||
|
const flags = Array.from(params.keys());
|
||||||
|
const url = pathToFileURL(info.moduleIds[0]);
|
||||||
|
const distRelative = url.toString().replace(settings.config.srcDir.toString(), '')
|
||||||
|
|
||||||
|
let entryFileName = removeFileExtension(distRelative);
|
||||||
|
if (flags[0] === PROPAGATED_ASSET_FLAG) {
|
||||||
|
entryFileName += `.assets`
|
||||||
|
} else if (flags[0] === CONTENT_RENDER_FLAG) {
|
||||||
|
entryFileName += '.render'
|
||||||
|
}
|
||||||
|
return `${entryFileName}.mjs`;
|
||||||
|
},
|
||||||
|
assetFileNames: `${settings.config.build.assets}/[name].[extname]`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
ssr: true,
|
||||||
|
ssrEmitAssets: true,
|
||||||
|
// improve build performance
|
||||||
|
minify: false,
|
||||||
|
modulePreload: { polyfill: false },
|
||||||
|
reportCompressedSize: false,
|
||||||
|
},
|
||||||
|
plugins: [...vitePlugins, ...(viteConfig.plugins || []), ...lastVitePlugins],
|
||||||
|
envPrefix: viteConfig.envPrefix ?? 'PUBLIC_',
|
||||||
|
base: settings.config.base,
|
||||||
|
};
|
||||||
|
|
||||||
|
const updatedViteBuildConfig = await runHookBuildSetup({
|
||||||
|
config: settings.config,
|
||||||
|
pages: internals.pagesByComponent,
|
||||||
|
vite: viteBuildConfig,
|
||||||
|
target: 'server',
|
||||||
|
logger: opts.logger,
|
||||||
|
});
|
||||||
|
|
||||||
|
return await vite.build(updatedViteBuildConfig);
|
||||||
|
}
|
||||||
|
|
||||||
async function clientBuild(
|
async function clientBuild(
|
||||||
opts: StaticBuildOptions,
|
opts: StaticBuildOptions,
|
||||||
internals: BuildInternals,
|
internals: BuildInternals,
|
||||||
|
@ -255,7 +351,7 @@ async function clientBuild(
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { lastVitePlugins, vitePlugins } = container.runBeforeHook('client', input);
|
const { lastVitePlugins, vitePlugins } = await container.runBeforeHook('client', input);
|
||||||
opts.logger.info(null, `\n${bgGreen(black(' building client '))}`);
|
opts.logger.info(null, `\n${bgGreen(black(' building client '))}`);
|
||||||
|
|
||||||
const viteBuildConfig: vite.InlineConfig = {
|
const viteBuildConfig: vite.InlineConfig = {
|
||||||
|
@ -309,7 +405,7 @@ async function runPostBuildHooks(
|
||||||
const build = container.options.settings.config.build;
|
const build = container.options.settings.config.build;
|
||||||
for (const [fileName, mutation] of mutations) {
|
for (const [fileName, mutation] of mutations) {
|
||||||
const root = isServerLikeOutput(config)
|
const root = isServerLikeOutput(config)
|
||||||
? mutation.build === 'server'
|
? mutation.targets.includes('server')
|
||||||
? build.server
|
? build.server
|
||||||
: build.client
|
: build.client
|
||||||
: config.outDir;
|
: config.outDir;
|
||||||
|
@ -412,7 +508,7 @@ async function copyFiles(fromFolder: URL, toFolder: URL, includeDotfiles = false
|
||||||
const lastFolder = new URL('./', to);
|
const lastFolder = new URL('./', to);
|
||||||
return fs.promises
|
return fs.promises
|
||||||
.mkdir(lastFolder, { recursive: true })
|
.mkdir(lastFolder, { recursive: true })
|
||||||
.then(() => fs.promises.copyFile(from, to));
|
.then(() => fs.promises.copyFile(from, to, fs.constants.COPYFILE_FICLONE));
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -103,7 +103,7 @@ export default function configHeadVitePlugin(): vite.Plugin {
|
||||||
|
|
||||||
export function astroHeadBuildPlugin(internals: BuildInternals): AstroBuildPlugin {
|
export function astroHeadBuildPlugin(internals: BuildInternals): AstroBuildPlugin {
|
||||||
return {
|
return {
|
||||||
build: 'ssr',
|
targets: ['server'],
|
||||||
hooks: {
|
hooks: {
|
||||||
'build:before'() {
|
'build:before'() {
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -65,7 +65,7 @@ export default async function copy() {
|
||||||
const dest = resolve(file.replace(/^[^/]+/, 'dist'));
|
const dest = resolve(file.replace(/^[^/]+/, 'dist'));
|
||||||
return fs
|
return fs
|
||||||
.mkdir(dirname(dest), { recursive: true })
|
.mkdir(dirname(dest), { recursive: true })
|
||||||
.then(() => fs.copyFile(resolve(file), dest));
|
.then(() => fs.copyFile(resolve(file), dest, fs.constants.COPYFILE_FICLONE));
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue