Almost done
This commit is contained in:
parent
03447124a3
commit
f6e24d1a97
19 changed files with 501 additions and 264 deletions
|
@ -1,11 +1,11 @@
|
||||||
{
|
{
|
||||||
"name": "@example/cool-app",
|
"name": "@example/fast-build",
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "astro dev",
|
"dev": "astro dev --experimental-static-build",
|
||||||
"start": "astro dev",
|
"start": "astro dev",
|
||||||
"build": "astro build",
|
"build": "astro build --experimental-static-build",
|
||||||
"preview": "astro preview"
|
"preview": "astro preview"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
|
@ -56,7 +56,7 @@
|
||||||
"test": "mocha --parallel --timeout 15000"
|
"test": "mocha --parallel --timeout 15000"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@astrojs/compiler": "^0.5.4",
|
"@astrojs/compiler": "^0.6.0",
|
||||||
"@astrojs/language-server": "^0.8.2",
|
"@astrojs/language-server": "^0.8.2",
|
||||||
"@astrojs/markdown-remark": "^0.5.0",
|
"@astrojs/markdown-remark": "^0.5.0",
|
||||||
"@astrojs/prism": "0.3.0",
|
"@astrojs/prism": "0.3.0",
|
||||||
|
|
|
@ -363,6 +363,7 @@ export interface SSRElement {
|
||||||
export interface SSRMetadata {
|
export interface SSRMetadata {
|
||||||
renderers: Renderer[];
|
renderers: Renderer[];
|
||||||
pathname: string;
|
pathname: string;
|
||||||
|
experimentalStaticBuild: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SSRResult {
|
export interface SSRResult {
|
||||||
|
|
|
@ -1,23 +1,18 @@
|
||||||
import type { AstroConfig, ComponentInstance, GetStaticPathsResult, ManifestData, RouteCache, RouteData, RSSResult } from '../../@types/astro';
|
import type { AstroConfig, ManifestData, RouteCache } from '../../@types/astro';
|
||||||
import type { LogOptions } from '../logger';
|
import type { LogOptions } from '../logger';
|
||||||
import type { AllPagesData, PageBuildData } from './types';
|
import type { PageBuildData } from './types';
|
||||||
import type { RenderedChunk } from 'rollup';
|
|
||||||
|
|
||||||
import { rollupPluginAstroBuildHTML } from '../../vite-plugin-build-html/index.js';
|
|
||||||
import { rollupPluginAstroBuildCSS } from '../../vite-plugin-build-css/index.js';
|
|
||||||
import { vitePluginNewBuild } from '../../vite-plugin-new-build/index.js';
|
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import * as colors from 'kleur/colors';
|
import * as colors from 'kleur/colors';
|
||||||
import { performance } from 'perf_hooks';
|
import { performance } from 'perf_hooks';
|
||||||
import vite, { ViteDevServer } from '../vite.js';
|
import vite, { ViteDevServer } from '../vite.js';
|
||||||
import { fileURLToPath } from 'url';
|
|
||||||
import { createVite, ViteConfigWithSSR } from '../create-vite.js';
|
import { createVite, ViteConfigWithSSR } from '../create-vite.js';
|
||||||
import { debug, defaultLogOptions, info, levels, timerMessage, warn } from '../logger.js';
|
import { debug, defaultLogOptions, info, levels, timerMessage, warn } from '../logger.js';
|
||||||
import { preload as ssrPreload, renderComponent, getParamsAndProps } from '../ssr/index.js';
|
import { createRouteManifest } from '../ssr/routing.js';
|
||||||
import { generatePaginateFunction } from '../ssr/paginate.js';
|
|
||||||
import { createRouteManifest, validateGetStaticPathsModule, validateGetStaticPathsResult } from '../ssr/routing.js';
|
|
||||||
import { generateRssFunction } from '../ssr/rss.js';
|
|
||||||
import { generateSitemap } from '../ssr/sitemap.js';
|
import { generateSitemap } from '../ssr/sitemap.js';
|
||||||
|
import { collectPagesData } from './page-data.js';
|
||||||
|
import { build as scanBasedBuild } from './scan-based-build.js';
|
||||||
|
import { staticBuild } from './static-build.js';
|
||||||
|
|
||||||
export interface BuildOptions {
|
export interface BuildOptions {
|
||||||
mode?: string;
|
mode?: string;
|
||||||
|
@ -77,155 +72,45 @@ class AstroBuilder {
|
||||||
debug(logging, 'build', timerMessage('Vite started', timer.viteStart));
|
debug(logging, 'build', timerMessage('Vite started', timer.viteStart));
|
||||||
|
|
||||||
timer.loadStart = performance.now();
|
timer.loadStart = performance.now();
|
||||||
const assets: Record<string, string> = {};
|
const { assets, allPages } = await collectPagesData({
|
||||||
const allPages: AllPagesData = {};
|
|
||||||
// Collect all routes ahead-of-time, before we start the build.
|
|
||||||
// NOTE: This enforces that `getStaticPaths()` is only called once per route,
|
|
||||||
// and is then cached across all future SSR builds. In the past, we've had trouble
|
|
||||||
// with parallelized builds without guaranteeing that this is called first.
|
|
||||||
await Promise.all(
|
|
||||||
this.manifest.routes.map(async (route) => {
|
|
||||||
// static route:
|
|
||||||
if (route.pathname) {
|
|
||||||
allPages[route.component] = {
|
|
||||||
route,
|
|
||||||
paths: [route.pathname],
|
|
||||||
preload: await ssrPreload({
|
|
||||||
astroConfig: this.config,
|
astroConfig: this.config,
|
||||||
filePath: new URL(`./${route.component}`, this.config.projectRoot),
|
logging: this.logging,
|
||||||
logging,
|
manifest: this.manifest,
|
||||||
mode: 'production',
|
|
||||||
origin,
|
origin,
|
||||||
pathname: route.pathname,
|
|
||||||
route,
|
|
||||||
routeCache: this.routeCache,
|
routeCache: this.routeCache,
|
||||||
viteServer,
|
viteServer: this.viteServer
|
||||||
})
|
|
||||||
.then((routes) => {
|
|
||||||
const html = `${route.pathname}`.replace(/\/?$/, '/index.html');
|
|
||||||
debug(logging, 'build', `├── ${colors.bold(colors.green('✔'))} ${route.component} → ${colors.yellow(html)}`);
|
|
||||||
return routes;
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
debug(logging, 'build', `├── ${colors.bold(colors.red('✘'))} ${route.component}`);
|
|
||||||
throw err;
|
|
||||||
}),
|
|
||||||
};
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// dynamic route:
|
|
||||||
const result = await this.getStaticPathsForRoute(route)
|
|
||||||
.then((routes) => {
|
|
||||||
const label = routes.paths.length === 1 ? 'page' : 'pages';
|
|
||||||
debug(logging, 'build', `├── ${colors.bold(colors.green('✔'))} ${route.component} → ${colors.magenta(`[${routes.paths.length} ${label}]`)}`);
|
|
||||||
return routes;
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
|
||||||
debug(logging, 'build', `├── ${colors.bold(colors.red('✗'))} ${route.component}`);
|
|
||||||
throw err;
|
|
||||||
});
|
});
|
||||||
if (result.rss?.xml) {
|
|
||||||
const rssFile = new URL(result.rss.url.replace(/^\/?/, './'), this.config.dist);
|
|
||||||
if (assets[fileURLToPath(rssFile)]) {
|
|
||||||
throw new Error(`[getStaticPaths] RSS feed ${result.rss.url} already exists.\nUse \`rss(data, {url: '...'})\` to choose a unique, custom URL. (${route.component})`);
|
|
||||||
}
|
|
||||||
assets[fileURLToPath(rssFile)] = result.rss.xml;
|
|
||||||
}
|
|
||||||
allPages[route.component] = {
|
|
||||||
route,
|
|
||||||
paths: result.paths,
|
|
||||||
preload: await ssrPreload({
|
|
||||||
astroConfig: this.config,
|
|
||||||
filePath: new URL(`./${route.component}`, this.config.projectRoot),
|
|
||||||
logging,
|
|
||||||
mode: 'production',
|
|
||||||
origin,
|
|
||||||
pathname: result.paths[0],
|
|
||||||
route,
|
|
||||||
routeCache: this.routeCache,
|
|
||||||
viteServer,
|
|
||||||
}),
|
|
||||||
};
|
|
||||||
})
|
|
||||||
);
|
|
||||||
debug(logging, 'build', timerMessage('All pages loaded', timer.loadStart));
|
debug(logging, 'build', timerMessage('All pages loaded', timer.loadStart));
|
||||||
|
|
||||||
// Pure CSS chunks are chunks that only contain CSS.
|
// The names of each pages
|
||||||
// This is all of them, and chunkToReferenceIdMap maps them to a hash id used to find the final file.
|
|
||||||
const pureCSSChunks = new Set<RenderedChunk>();
|
|
||||||
const chunkToReferenceIdMap = new Map<string, string>();
|
|
||||||
|
|
||||||
// This is a mapping of pathname to the string source of all collected
|
|
||||||
// inline <style> for a page.
|
|
||||||
const astroStyleMap = new Map<string, string>();
|
|
||||||
// This is a virtual JS module that imports all dependent styles for a page.
|
|
||||||
const astroPageStyleMap = new Map<string, string>();
|
|
||||||
|
|
||||||
const pageNames: string[] = [];
|
const pageNames: string[] = [];
|
||||||
|
|
||||||
// Blah
|
|
||||||
const facadeIdToPageDataMap = new Map<string, PageBuildData>();
|
|
||||||
const facadeIdToAssetsMap = new Map<string, string[]>();
|
|
||||||
|
|
||||||
// Bundle the assets in your final build: This currently takes the HTML output
|
// Bundle the assets in your final build: This currently takes the HTML output
|
||||||
// of every page (stored in memory) and bundles the assets pointed to on those pages.
|
// of every page (stored in memory) and bundles the assets pointed to on those pages.
|
||||||
timer.buildStart = performance.now();
|
timer.buildStart = performance.now();
|
||||||
let result = await vite.build({
|
|
||||||
logLevel: 'error',
|
// Use the new faster static based build.
|
||||||
mode: 'production',
|
if(this.config.buildOptions.experimentalStaticBuild) {
|
||||||
build: {
|
await staticBuild({
|
||||||
emptyOutDir: true,
|
|
||||||
minify: false,// 'esbuild', // significantly faster than "terser" but may produce slightly-bigger bundles
|
|
||||||
outDir: fileURLToPath(this.config.dist),
|
|
||||||
ssr: true,
|
|
||||||
rollupOptions: {
|
|
||||||
// The `input` will be populated in the build rollup plugin.
|
|
||||||
input: [],
|
|
||||||
output: {
|
|
||||||
format: 'esm'
|
|
||||||
},
|
|
||||||
},
|
|
||||||
target: 'es2020', // must match an esbuild target
|
|
||||||
},
|
|
||||||
plugins: [
|
|
||||||
vitePluginNewBuild(),
|
|
||||||
rollupPluginAstroBuildHTML({
|
|
||||||
astroConfig: this.config,
|
|
||||||
astroPageStyleMap,
|
|
||||||
astroStyleMap,
|
|
||||||
chunkToReferenceIdMap,
|
|
||||||
pureCSSChunks,
|
|
||||||
logging,
|
|
||||||
origin,
|
|
||||||
allPages,
|
allPages,
|
||||||
|
astroConfig: this.config,
|
||||||
|
logging: this.logging,
|
||||||
|
origin: this.origin,
|
||||||
|
routeCache: this.routeCache,
|
||||||
|
viteConfig: this.viteConfig
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
await scanBasedBuild({
|
||||||
|
allPages,
|
||||||
|
astroConfig: this.config,
|
||||||
|
logging: this.logging,
|
||||||
pageNames,
|
pageNames,
|
||||||
routeCache: this.routeCache,
|
routeCache: this.routeCache,
|
||||||
viteServer,
|
viteConfig: this.viteConfig,
|
||||||
facadeIdToPageDataMap,
|
viteServer: this.viteServer,
|
||||||
}),
|
|
||||||
rollupPluginAstroBuildCSS({
|
|
||||||
astroPageStyleMap,
|
|
||||||
astroStyleMap,
|
|
||||||
chunkToReferenceIdMap,
|
|
||||||
pureCSSChunks,
|
|
||||||
facadeIdToAssetsMap,
|
|
||||||
}),
|
|
||||||
...(viteConfig.plugins || []),
|
|
||||||
],
|
|
||||||
publicDir: viteConfig.publicDir,
|
|
||||||
root: viteConfig.root,
|
|
||||||
envPrefix: 'PUBLIC_',
|
|
||||||
server: viteConfig.server,
|
|
||||||
base: this.config.buildOptions.site ? new URL(this.config.buildOptions.site).pathname : '/',
|
|
||||||
});
|
});
|
||||||
debug(logging, 'build', timerMessage('Vite build finished', timer.buildStart));
|
|
||||||
|
|
||||||
/* TODO REMOVE THIS NEW HACKY CODE */
|
|
||||||
console.log('End build step, now generating');
|
|
||||||
for(let out of (result as any).output) {
|
|
||||||
if(out.facadeModuleId)
|
|
||||||
await this.renderPages(out, facadeIdToPageDataMap, facadeIdToAssetsMap);
|
|
||||||
}
|
}
|
||||||
|
debug(logging, 'build', timerMessage('Vite build finished', timer.buildStart));
|
||||||
|
|
||||||
// Write any additionally generated assets to disk.
|
// Write any additionally generated assets to disk.
|
||||||
timer.assetsStart = performance.now();
|
timer.assetsStart = performance.now();
|
||||||
|
@ -255,53 +140,6 @@ class AstroBuilder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async renderPages(out: any, facadeIdToPageDataMap: Map<string, PageBuildData>, facadeIdToAssetsMap: Map<string, string[]>) {
|
|
||||||
let url = new URL('./' + out.fileName, this.config.dist);
|
|
||||||
const facadeId: string = out.facadeModuleId;
|
|
||||||
let pageData = facadeIdToPageDataMap.get(facadeId)!;
|
|
||||||
let linkIds = facadeIdToAssetsMap.get(facadeId) || [];
|
|
||||||
let compiledModule = await import(url.toString());
|
|
||||||
let Component = compiledModule.default;
|
|
||||||
|
|
||||||
const [renderers, mod] = pageData.preload;
|
|
||||||
|
|
||||||
for(let path of pageData.paths) {
|
|
||||||
try {
|
|
||||||
const [params, pageProps] = await getParamsAndProps({
|
|
||||||
route: pageData.route,
|
|
||||||
routeCache: this.routeCache,
|
|
||||||
logging: this.logging,
|
|
||||||
pathname: path,
|
|
||||||
mod
|
|
||||||
})
|
|
||||||
console.log(`Generating: ${path}`);
|
|
||||||
let html = await renderComponent(renderers, Component, this.config, path, this.origin, params, pageProps, linkIds);
|
|
||||||
let outFolder = new URL('.' + path + '/', this.config.dist);
|
|
||||||
let outFile = new URL('./index.html', outFolder);
|
|
||||||
await fs.promises.mkdir(outFolder, { recursive: true });
|
|
||||||
await fs.promises.writeFile(outFile, html, 'utf-8');
|
|
||||||
} catch(err) {
|
|
||||||
console.error("did not work", err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Extract all static paths from a dynamic route */
|
|
||||||
private async getStaticPathsForRoute(route: RouteData): Promise<{ paths: string[]; rss?: RSSResult }> {
|
|
||||||
if (!this.viteServer) throw new Error(`vite.createServer() not called!`);
|
|
||||||
const filePath = new URL(`./${route.component}`, this.config.projectRoot);
|
|
||||||
const mod = (await this.viteServer.ssrLoadModule(fileURLToPath(filePath))) as ComponentInstance;
|
|
||||||
validateGetStaticPathsModule(mod);
|
|
||||||
const rss = generateRssFunction(this.config.buildOptions.site, route);
|
|
||||||
const staticPaths: GetStaticPathsResult = (await mod.getStaticPaths!({ paginate: generatePaginateFunction(route), rss: rss.generator })).flat();
|
|
||||||
this.routeCache[route.component] = staticPaths;
|
|
||||||
validateGetStaticPathsResult(staticPaths, this.logging);
|
|
||||||
return {
|
|
||||||
paths: staticPaths.map((staticPath) => staticPath.params && route.generate(staticPath.params)).filter(Boolean),
|
|
||||||
rss: rss.rss,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Stats */
|
/** Stats */
|
||||||
private async printStats({ logging, timeStart, pageCount }: { logging: LogOptions; timeStart: number; pageCount: number }) {
|
private async printStats({ logging, timeStart, pageCount }: { logging: LogOptions; timeStart: number; pageCount: number }) {
|
||||||
/* eslint-disable no-console */
|
/* eslint-disable no-console */
|
||||||
|
|
45
packages/astro/src/core/build/internal.ts
Normal file
45
packages/astro/src/core/build/internal.ts
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
import type { RenderedChunk } from 'rollup';
|
||||||
|
|
||||||
|
export interface BuildInternals {
|
||||||
|
// Pure CSS chunks are chunks that only contain CSS.
|
||||||
|
pureCSSChunks: Set<RenderedChunk>;
|
||||||
|
// chunkToReferenceIdMap maps them to a hash id used to find the final file.
|
||||||
|
chunkToReferenceIdMap: Map<string, string>;
|
||||||
|
|
||||||
|
// This is a mapping of pathname to the string source of all collected
|
||||||
|
// inline <style> for a page.
|
||||||
|
astroStyleMap: Map<string, string>;
|
||||||
|
// This is a virtual JS module that imports all dependent styles for a page.
|
||||||
|
astroPageStyleMap: Map<string, string>;
|
||||||
|
|
||||||
|
// A mapping to entrypoints (facadeId) to assets (styles) that are added.
|
||||||
|
facadeIdToAssetsMap: Map<string, string[]>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates internal maps used to coordinate the CSS and HTML plugins.
|
||||||
|
* @returns {BuildInternals}
|
||||||
|
*/
|
||||||
|
export function createBuildInternals(): BuildInternals {
|
||||||
|
// Pure CSS chunks are chunks that only contain CSS.
|
||||||
|
// This is all of them, and chunkToReferenceIdMap maps them to a hash id used to find the final file.
|
||||||
|
const pureCSSChunks = new Set<RenderedChunk>();
|
||||||
|
const chunkToReferenceIdMap = new Map<string, string>();
|
||||||
|
|
||||||
|
// This is a mapping of pathname to the string source of all collected
|
||||||
|
// inline <style> for a page.
|
||||||
|
const astroStyleMap = new Map<string, string>();
|
||||||
|
// This is a virtual JS module that imports all dependent styles for a page.
|
||||||
|
const astroPageStyleMap = new Map<string, string>();
|
||||||
|
|
||||||
|
// A mapping to entrypoints (facadeId) to assets (styles) that are added.
|
||||||
|
const facadeIdToAssetsMap = new Map<string, string[]>();
|
||||||
|
|
||||||
|
return {
|
||||||
|
pureCSSChunks,
|
||||||
|
chunkToReferenceIdMap,
|
||||||
|
astroStyleMap,
|
||||||
|
astroPageStyleMap,
|
||||||
|
facadeIdToAssetsMap,
|
||||||
|
};
|
||||||
|
}
|
122
packages/astro/src/core/build/page-data.ts
Normal file
122
packages/astro/src/core/build/page-data.ts
Normal file
|
@ -0,0 +1,122 @@
|
||||||
|
import type { AstroConfig, ComponentInstance, GetStaticPathsResult, ManifestData, RouteCache, RouteData, RSSResult } from '../../@types/astro';
|
||||||
|
import type { AllPagesData } from './types';
|
||||||
|
import type { LogOptions } from '../logger';
|
||||||
|
import type { ViteDevServer } from 'vite';
|
||||||
|
|
||||||
|
import { fileURLToPath } from 'url';
|
||||||
|
import * as colors from 'kleur/colors';
|
||||||
|
import { debug } from '../logger.js';
|
||||||
|
import { preload as ssrPreload } from '../ssr/index.js';
|
||||||
|
import { validateGetStaticPathsModule, validateGetStaticPathsResult } from '../ssr/routing.js';
|
||||||
|
import { generatePaginateFunction } from '../ssr/paginate.js';
|
||||||
|
import { generateRssFunction } from '../ssr/rss.js';
|
||||||
|
|
||||||
|
export interface CollectPagesDataOptions {
|
||||||
|
astroConfig: AstroConfig;
|
||||||
|
logging: LogOptions;
|
||||||
|
manifest: ManifestData;
|
||||||
|
origin: string;
|
||||||
|
routeCache: RouteCache;
|
||||||
|
viteServer: ViteDevServer;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CollectPagesDataResult {
|
||||||
|
assets: Record<string, string>;
|
||||||
|
allPages: AllPagesData;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Examines the routes and returns a collection of information about each page.
|
||||||
|
export async function collectPagesData(opts: CollectPagesDataOptions): Promise<CollectPagesDataResult> {
|
||||||
|
const { astroConfig, logging, manifest, origin, routeCache, viteServer } = opts;
|
||||||
|
|
||||||
|
const assets: Record<string, string> = {};
|
||||||
|
const allPages: AllPagesData = {};
|
||||||
|
|
||||||
|
// Collect all routes ahead-of-time, before we start the build.
|
||||||
|
// NOTE: This enforces that `getStaticPaths()` is only called once per route,
|
||||||
|
// and is then cached across all future SSR builds. In the past, we've had trouble
|
||||||
|
// with parallelized builds without guaranteeing that this is called first.
|
||||||
|
await Promise.all(
|
||||||
|
manifest.routes.map(async (route) => {
|
||||||
|
// static route:
|
||||||
|
if (route.pathname) {
|
||||||
|
allPages[route.component] = {
|
||||||
|
route,
|
||||||
|
paths: [route.pathname],
|
||||||
|
preload: await ssrPreload({
|
||||||
|
astroConfig,
|
||||||
|
filePath: new URL(`./${route.component}`, astroConfig.projectRoot),
|
||||||
|
logging,
|
||||||
|
mode: 'production',
|
||||||
|
origin,
|
||||||
|
pathname: route.pathname,
|
||||||
|
route,
|
||||||
|
routeCache,
|
||||||
|
viteServer,
|
||||||
|
})
|
||||||
|
.then((routes) => {
|
||||||
|
const html = `${route.pathname}`.replace(/\/?$/, '/index.html');
|
||||||
|
debug(logging, 'build', `├── ${colors.bold(colors.green('✔'))} ${route.component} → ${colors.yellow(html)}`);
|
||||||
|
return routes;
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
debug(logging, 'build', `├── ${colors.bold(colors.red('✘'))} ${route.component}`);
|
||||||
|
throw err;
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// dynamic route:
|
||||||
|
const result = await getStaticPathsForRoute(opts, route)
|
||||||
|
.then((routes) => {
|
||||||
|
const label = routes.paths.length === 1 ? 'page' : 'pages';
|
||||||
|
debug(logging, 'build', `├── ${colors.bold(colors.green('✔'))} ${route.component} → ${colors.magenta(`[${routes.paths.length} ${label}]`)}`);
|
||||||
|
return routes;
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
debug(logging, 'build', `├── ${colors.bold(colors.red('✗'))} ${route.component}`);
|
||||||
|
throw err;
|
||||||
|
});
|
||||||
|
if (result.rss?.xml) {
|
||||||
|
const rssFile = new URL(result.rss.url.replace(/^\/?/, './'), astroConfig.dist);
|
||||||
|
if (assets[fileURLToPath(rssFile)]) {
|
||||||
|
throw new Error(`[getStaticPaths] RSS feed ${result.rss.url} already exists.\nUse \`rss(data, {url: '...'})\` to choose a unique, custom URL. (${route.component})`);
|
||||||
|
}
|
||||||
|
assets[fileURLToPath(rssFile)] = result.rss.xml;
|
||||||
|
}
|
||||||
|
allPages[route.component] = {
|
||||||
|
route,
|
||||||
|
paths: result.paths,
|
||||||
|
preload: await ssrPreload({
|
||||||
|
astroConfig,
|
||||||
|
filePath: new URL(`./${route.component}`, astroConfig.projectRoot),
|
||||||
|
logging,
|
||||||
|
mode: 'production',
|
||||||
|
origin,
|
||||||
|
pathname: result.paths[0],
|
||||||
|
route,
|
||||||
|
routeCache,
|
||||||
|
viteServer,
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
return { assets, allPages };
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getStaticPathsForRoute(opts: CollectPagesDataOptions, route: RouteData): Promise<{ paths: string[]; rss?: RSSResult }> {
|
||||||
|
const { astroConfig, logging, routeCache, viteServer } = opts;
|
||||||
|
if (!viteServer) throw new Error(`vite.createServer() not called!`);
|
||||||
|
const filePath = new URL(`./${route.component}`, astroConfig.projectRoot);
|
||||||
|
const mod = (await viteServer.ssrLoadModule(fileURLToPath(filePath))) as ComponentInstance;
|
||||||
|
validateGetStaticPathsModule(mod);
|
||||||
|
const rss = generateRssFunction(astroConfig.buildOptions.site, route);
|
||||||
|
const staticPaths: GetStaticPathsResult = (await mod.getStaticPaths!({ paginate: generatePaginateFunction(route), rss: rss.generator })).flat();
|
||||||
|
routeCache[route.component] = staticPaths;
|
||||||
|
validateGetStaticPathsResult(staticPaths, logging);
|
||||||
|
return {
|
||||||
|
paths: staticPaths.map((staticPath) => staticPath.params && route.generate(staticPath.params)).filter(Boolean),
|
||||||
|
rss: rss.rss,
|
||||||
|
};
|
||||||
|
}
|
69
packages/astro/src/core/build/scan-based-build.ts
Normal file
69
packages/astro/src/core/build/scan-based-build.ts
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
import type { RenderedChunk } from 'rollup';
|
||||||
|
import type { ViteDevServer } from 'vite';
|
||||||
|
import type { AstroConfig, RouteCache } from '../../@types/astro';
|
||||||
|
import type { AllPagesData } from './types';
|
||||||
|
import type { LogOptions } from '../logger';
|
||||||
|
import type { ViteConfigWithSSR } from '../create-vite.js';
|
||||||
|
|
||||||
|
import { fileURLToPath } from 'url';
|
||||||
|
import vite from '../vite.js';
|
||||||
|
import { createBuildInternals } from '../../core/build/internal.js';
|
||||||
|
import { rollupPluginAstroBuildHTML } from '../../vite-plugin-build-html/index.js';
|
||||||
|
import { rollupPluginAstroBuildCSS } from '../../vite-plugin-build-css/index.js';
|
||||||
|
|
||||||
|
export interface ScanBasedBuildOptions {
|
||||||
|
allPages: AllPagesData;
|
||||||
|
astroConfig: AstroConfig;
|
||||||
|
logging: LogOptions;
|
||||||
|
pageNames: string[];
|
||||||
|
routeCache: RouteCache;
|
||||||
|
viteConfig: ViteConfigWithSSR;
|
||||||
|
viteServer: ViteDevServer;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function build(opts: ScanBasedBuildOptions) {
|
||||||
|
const { allPages, astroConfig, logging, pageNames, routeCache, viteConfig, viteServer } = opts;
|
||||||
|
|
||||||
|
// Internal maps used to coordinate the HTML and CSS plugins.
|
||||||
|
const internals = createBuildInternals();
|
||||||
|
|
||||||
|
return await vite.build({
|
||||||
|
logLevel: 'error',
|
||||||
|
mode: 'production',
|
||||||
|
build: {
|
||||||
|
emptyOutDir: true,
|
||||||
|
minify: false,// 'esbuild', // significantly faster than "terser" but may produce slightly-bigger bundles
|
||||||
|
outDir: fileURLToPath(astroConfig.dist),
|
||||||
|
ssr: true,
|
||||||
|
rollupOptions: {
|
||||||
|
// The `input` will be populated in the build rollup plugin.
|
||||||
|
input: [],
|
||||||
|
output: {
|
||||||
|
format: 'esm'
|
||||||
|
},
|
||||||
|
},
|
||||||
|
target: 'es2020', // must match an esbuild target
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
rollupPluginAstroBuildHTML({
|
||||||
|
astroConfig,
|
||||||
|
internals,
|
||||||
|
logging,
|
||||||
|
origin,
|
||||||
|
allPages,
|
||||||
|
pageNames,
|
||||||
|
routeCache,
|
||||||
|
viteServer,
|
||||||
|
}),
|
||||||
|
rollupPluginAstroBuildCSS({
|
||||||
|
internals
|
||||||
|
}),
|
||||||
|
...(viteConfig.plugins || []),
|
||||||
|
],
|
||||||
|
publicDir: viteConfig.publicDir,
|
||||||
|
root: viteConfig.root,
|
||||||
|
envPrefix: 'PUBLIC_',
|
||||||
|
server: viteConfig.server,
|
||||||
|
base: astroConfig.buildOptions.site ? new URL(astroConfig.buildOptions.site).pathname : '/',
|
||||||
|
});
|
||||||
|
}
|
193
packages/astro/src/core/build/static-build.ts
Normal file
193
packages/astro/src/core/build/static-build.ts
Normal file
|
@ -0,0 +1,193 @@
|
||||||
|
import type { OutputChunk, PreRenderedChunk, RollupOutput } from 'rollup';
|
||||||
|
import type { Plugin as VitePlugin, ViteDevServer } from '../vite';
|
||||||
|
import type { AstroConfig, RouteCache } from '../../@types/astro';
|
||||||
|
import type { AllPagesData } from './types';
|
||||||
|
import type { LogOptions } from '../logger';
|
||||||
|
import type { ViteConfigWithSSR } from '../create-vite';
|
||||||
|
import type { PageBuildData } from './types';
|
||||||
|
import type { BuildInternals } from '../../core/build/internal.js';
|
||||||
|
import type { AstroComponentFactory } from '../../runtime/server';
|
||||||
|
|
||||||
|
import fs from 'fs';
|
||||||
|
import { fileURLToPath } from 'url';
|
||||||
|
import vite from '../vite.js';
|
||||||
|
import { info } from '../../core/logger.js';
|
||||||
|
import { createBuildInternals } from '../../core/build/internal.js';
|
||||||
|
import { rollupPluginAstroBuildCSS } from '../../vite-plugin-build-css/index.js';
|
||||||
|
import { renderComponent, getParamsAndProps } from '../ssr/index.js';
|
||||||
|
|
||||||
|
export interface StaticBuildOptions {
|
||||||
|
allPages: AllPagesData;
|
||||||
|
astroConfig: AstroConfig;
|
||||||
|
logging: LogOptions;
|
||||||
|
origin: string;
|
||||||
|
routeCache: RouteCache;
|
||||||
|
viteConfig: ViteConfigWithSSR;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function staticBuild(opts: StaticBuildOptions) {
|
||||||
|
const { allPages, astroConfig } = opts;
|
||||||
|
|
||||||
|
// The JavaScript entrypoints.
|
||||||
|
const jsInput: Set<string> = new Set();
|
||||||
|
|
||||||
|
// A map of each page .astro file, to the PageBuildData which contains information
|
||||||
|
// about that page, such as its paths.
|
||||||
|
const facadeIdToPageDataMap = new Map<string, PageBuildData>();
|
||||||
|
|
||||||
|
for (const [component, pageData] of Object.entries(allPages)) {
|
||||||
|
const [renderers, mod] = pageData.preload;
|
||||||
|
|
||||||
|
// Hydrated components are statically identified.
|
||||||
|
for (const path of mod.$$metadata.getAllHydratedComponentPaths()) {
|
||||||
|
// Note that this part is not yet implemented in the static build.
|
||||||
|
//jsInput.add(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
let astroModuleId = new URL('./' + component, astroConfig.projectRoot).pathname;
|
||||||
|
jsInput.add(astroModuleId);
|
||||||
|
facadeIdToPageDataMap.set(astroModuleId, pageData);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build internals needed by the CSS plugin
|
||||||
|
const internals = createBuildInternals();
|
||||||
|
|
||||||
|
// Perform the SSR build
|
||||||
|
const result = (await ssrBuild(opts, internals, jsInput) as RollupOutput);
|
||||||
|
|
||||||
|
// Generate each of the pages.
|
||||||
|
await generatePages(result, opts, internals, facadeIdToPageDataMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function ssrBuild(opts: StaticBuildOptions, internals: BuildInternals, input: Set<string>) {
|
||||||
|
const { astroConfig, viteConfig } = opts;
|
||||||
|
|
||||||
|
return await vite.build({
|
||||||
|
logLevel: 'error',
|
||||||
|
mode: 'production',
|
||||||
|
build: {
|
||||||
|
emptyOutDir: true,
|
||||||
|
minify: false,// 'esbuild', // significantly faster than "terser" but may produce slightly-bigger bundles
|
||||||
|
outDir: fileURLToPath(astroConfig.dist),
|
||||||
|
ssr: true,
|
||||||
|
rollupOptions: {
|
||||||
|
input: Array.from(input),
|
||||||
|
output: {
|
||||||
|
format: 'esm'
|
||||||
|
},
|
||||||
|
},
|
||||||
|
target: 'es2020', // must match an esbuild target
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
vitePluginNewBuild(),
|
||||||
|
rollupPluginAstroBuildCSS({
|
||||||
|
internals
|
||||||
|
}),
|
||||||
|
...(viteConfig.plugins || []),
|
||||||
|
],
|
||||||
|
publicDir: viteConfig.publicDir,
|
||||||
|
root: viteConfig.root,
|
||||||
|
envPrefix: 'PUBLIC_',
|
||||||
|
server: viteConfig.server,
|
||||||
|
base: astroConfig.buildOptions.site ? new URL(astroConfig.buildOptions.site).pathname : '/',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function generatePages(result: RollupOutput, opts: StaticBuildOptions, internals: BuildInternals, facadeIdToPageDataMap: Map<string, PageBuildData>) {
|
||||||
|
console.log('End build step, now generating');
|
||||||
|
const generationPromises = [];
|
||||||
|
for(let output of result.output) {
|
||||||
|
if(output.type === 'chunk' && output.facadeModuleId) {
|
||||||
|
generationPromises.push(
|
||||||
|
generatePage(output, opts, internals, facadeIdToPageDataMap)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await Promise.all(generationPromises);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async function generatePage(output: OutputChunk, opts: StaticBuildOptions, internals: BuildInternals, facadeIdToPageDataMap: Map<string, PageBuildData>) {
|
||||||
|
const { astroConfig } = opts;
|
||||||
|
|
||||||
|
let url = new URL('./' + output.fileName, astroConfig.dist);
|
||||||
|
const facadeId: string = output.facadeModuleId as string;
|
||||||
|
let pageData = facadeIdToPageDataMap.get(facadeId)!;
|
||||||
|
let linkIds = internals.facadeIdToAssetsMap.get(facadeId) || [];
|
||||||
|
let compiledModule = await import(url.toString());
|
||||||
|
let Component = compiledModule.default;
|
||||||
|
|
||||||
|
const generationOptions: Readonly<GeneratePathOptions> = {
|
||||||
|
pageData,
|
||||||
|
linkIds,
|
||||||
|
Component
|
||||||
|
};
|
||||||
|
|
||||||
|
const renderPromises = pageData.paths.map(path => {
|
||||||
|
return generatePath(path, opts, generationOptions)
|
||||||
|
});
|
||||||
|
return await Promise.all(renderPromises);
|
||||||
|
}
|
||||||
|
|
||||||
|
interface GeneratePathOptions {
|
||||||
|
pageData: PageBuildData;
|
||||||
|
linkIds: string[];
|
||||||
|
Component: AstroComponentFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function generatePath(path: string, opts: StaticBuildOptions, gopts: GeneratePathOptions) {
|
||||||
|
const { astroConfig, logging, origin, routeCache } = opts;
|
||||||
|
const { Component, linkIds, pageData } = gopts;
|
||||||
|
|
||||||
|
const [renderers, mod] = pageData.preload;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const [params, pageProps] = await getParamsAndProps({
|
||||||
|
route: pageData.route,
|
||||||
|
routeCache,
|
||||||
|
logging,
|
||||||
|
pathname: path,
|
||||||
|
mod
|
||||||
|
});
|
||||||
|
|
||||||
|
info(logging, 'generate', `Generating: ${path}`);
|
||||||
|
|
||||||
|
const html = await renderComponent(renderers, Component, astroConfig, path, origin, params, pageProps, linkIds);
|
||||||
|
const outFolder = new URL('.' + path + '/', astroConfig.dist);
|
||||||
|
const outFile = new URL('./index.html', outFolder);
|
||||||
|
await fs.promises.mkdir(outFolder, { recursive: true });
|
||||||
|
await fs.promises.writeFile(outFile, html, 'utf-8');
|
||||||
|
|
||||||
|
} catch(err) {
|
||||||
|
console.error(`Error rendering:`, err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
export function vitePluginNewBuild(): VitePlugin {
|
||||||
|
return {
|
||||||
|
name: '@astro/rollup-plugin-new-build',
|
||||||
|
|
||||||
|
configResolved(resolvedConfig) {
|
||||||
|
// Delete this hook because it causes assets not to be built
|
||||||
|
const plugins = resolvedConfig.plugins as VitePlugin[];
|
||||||
|
const viteAsset = plugins.find((p) => p.name === 'vite:asset');
|
||||||
|
if(viteAsset) {
|
||||||
|
delete viteAsset.generateBundle;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
outputOptions(outputOptions) {
|
||||||
|
Object.assign(outputOptions, {
|
||||||
|
entryFileNames(_chunk: PreRenderedChunk) {
|
||||||
|
return 'assets/[name].[hash].mjs';
|
||||||
|
},
|
||||||
|
chunkFileNames(_chunk: PreRenderedChunk) {
|
||||||
|
return 'assets/[name].[hash].mjs';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return outputOptions;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
|
@ -372,7 +372,8 @@ const uniqueElements = (item: any, index: number, all: any[]) => {
|
||||||
// styles and scripts into the head.
|
// styles and scripts into the head.
|
||||||
export async function renderPage(result: SSRResult, Component: AstroComponentFactory, props: any, children: any) {
|
export async function renderPage(result: SSRResult, Component: AstroComponentFactory, props: any, children: any) {
|
||||||
const template = await renderToString(result, Component, props, children);
|
const template = await renderToString(result, Component, props, children);
|
||||||
const styles = Array.from(result.styles)
|
const styles = result._metadata.experimentalStaticBuild ? [] :
|
||||||
|
Array.from(result.styles)
|
||||||
.filter(uniqueElements)
|
.filter(uniqueElements)
|
||||||
.map((style) =>
|
.map((style) =>
|
||||||
renderElement('style', {
|
renderElement('style', {
|
||||||
|
|
|
@ -45,6 +45,8 @@ async function compile(config: AstroConfig, filename: string, source: string, vi
|
||||||
sourcefile: filename,
|
sourcefile: filename,
|
||||||
sourcemap: 'both',
|
sourcemap: 'both',
|
||||||
internalURL: 'astro/internal',
|
internalURL: 'astro/internal',
|
||||||
|
experimentalStaticExtraction: config.buildOptions.experimentalStaticBuild,
|
||||||
|
// TODO add experimental flag here
|
||||||
preprocessStyle: async (value: string, attrs: Record<string, string>) => {
|
preprocessStyle: async (value: string, attrs: Record<string, string>) => {
|
||||||
const lang = `.${attrs?.lang || 'css'}`.toLowerCase();
|
const lang = `.${attrs?.lang || 'css'}`.toLowerCase();
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
import type { RenderedChunk } from 'rollup';
|
import type { RenderedChunk } from 'rollup';
|
||||||
import { Plugin as VitePlugin } from '../core/vite';
|
import type { BuildInternals } from '../core/build/internal';
|
||||||
|
|
||||||
import { STYLE_EXTENSIONS } from '../core/ssr/css.js';
|
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import esbuild from 'esbuild';
|
import esbuild from 'esbuild';
|
||||||
|
import { Plugin as VitePlugin } from '../core/vite';
|
||||||
|
import { STYLE_EXTENSIONS } from '../core/ssr/css.js';
|
||||||
|
|
||||||
const PLUGIN_NAME = '@astrojs/rollup-plugin-build-css';
|
const PLUGIN_NAME = '@astrojs/rollup-plugin-build-css';
|
||||||
|
|
||||||
|
@ -45,15 +46,11 @@ function isPageStyleVirtualModule(id: string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
interface PluginOptions {
|
interface PluginOptions {
|
||||||
astroStyleMap: Map<string, string>;
|
internals: BuildInternals;
|
||||||
astroPageStyleMap: Map<string, string>;
|
|
||||||
chunkToReferenceIdMap: Map<string, string>;
|
|
||||||
pureCSSChunks: Set<RenderedChunk>;
|
|
||||||
facadeIdToAssetsMap: Map<string, string[]>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function rollupPluginAstroBuildCSS(options: PluginOptions): VitePlugin {
|
export function rollupPluginAstroBuildCSS(options: PluginOptions): VitePlugin {
|
||||||
const { astroPageStyleMap, astroStyleMap, chunkToReferenceIdMap, pureCSSChunks, facadeIdToAssetsMap } = options;
|
const { internals } = options;
|
||||||
const styleSourceMap = new Map<string, string>();
|
const styleSourceMap = new Map<string, string>();
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -95,10 +92,10 @@ export function rollupPluginAstroBuildCSS(options: PluginOptions): VitePlugin {
|
||||||
|
|
||||||
async load(id) {
|
async load(id) {
|
||||||
if (isPageStyleVirtualModule(id)) {
|
if (isPageStyleVirtualModule(id)) {
|
||||||
return astroPageStyleMap.get(id) || null;
|
return internals.astroPageStyleMap.get(id) || null;
|
||||||
}
|
}
|
||||||
if (isStyleVirtualModule(id)) {
|
if (isStyleVirtualModule(id)) {
|
||||||
return astroStyleMap.get(id) || null;
|
return internals.astroStyleMap.get(id) || null;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
|
@ -128,7 +125,7 @@ export function rollupPluginAstroBuildCSS(options: PluginOptions): VitePlugin {
|
||||||
// if (!chunkCSS) return null; // don’t output empty .css files
|
// if (!chunkCSS) return null; // don’t output empty .css files
|
||||||
|
|
||||||
if (isPureCSS) {
|
if (isPureCSS) {
|
||||||
pureCSSChunks.add(chunk);
|
internals.pureCSSChunks.add(chunk);
|
||||||
}
|
}
|
||||||
|
|
||||||
const { code: minifiedCSS } = await esbuild.transform(chunkCSS, {
|
const { code: minifiedCSS } = await esbuild.transform(chunkCSS, {
|
||||||
|
@ -141,13 +138,13 @@ export function rollupPluginAstroBuildCSS(options: PluginOptions): VitePlugin {
|
||||||
source: minifiedCSS,
|
source: minifiedCSS,
|
||||||
});
|
});
|
||||||
|
|
||||||
chunkToReferenceIdMap.set(chunk.fileName, referenceId);
|
internals.chunkToReferenceIdMap.set(chunk.fileName, referenceId);
|
||||||
if(chunk.type === 'chunk') {
|
if(chunk.type === 'chunk') {
|
||||||
const facadeId = chunk.facadeModuleId!;
|
const facadeId = chunk.facadeModuleId!;
|
||||||
if(!facadeIdToAssetsMap.has(facadeId)) {
|
if(!internals.facadeIdToAssetsMap.has(facadeId)) {
|
||||||
facadeIdToAssetsMap.set(facadeId, []);
|
internals.facadeIdToAssetsMap.set(facadeId, []);
|
||||||
}
|
}
|
||||||
facadeIdToAssetsMap.get(facadeId)!.push(this.getFileName(referenceId));
|
internals.facadeIdToAssetsMap.get(facadeId)!.push(this.getFileName(referenceId));
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
@ -155,8 +152,8 @@ export function rollupPluginAstroBuildCSS(options: PluginOptions): VitePlugin {
|
||||||
|
|
||||||
// Delete CSS chunks so JS is not produced for them.
|
// Delete CSS chunks so JS is not produced for them.
|
||||||
generateBundle(opts, bundle) {
|
generateBundle(opts, bundle) {
|
||||||
if (pureCSSChunks.size) {
|
if (internals.pureCSSChunks.size) {
|
||||||
const pureChunkFilenames = new Set([...pureCSSChunks].map((chunk) => chunk.fileName));
|
const pureChunkFilenames = new Set([...internals.pureCSSChunks].map((chunk) => chunk.fileName));
|
||||||
const emptyChunkFiles = [...pureChunkFilenames]
|
const emptyChunkFiles = [...pureChunkFilenames]
|
||||||
.map((file) => path.basename(file))
|
.map((file) => path.basename(file))
|
||||||
.join('|')
|
.join('|')
|
||||||
|
@ -165,7 +162,7 @@ export function rollupPluginAstroBuildCSS(options: PluginOptions): VitePlugin {
|
||||||
|
|
||||||
for (const [chunkId, chunk] of Object.entries(bundle)) {
|
for (const [chunkId, chunk] of Object.entries(bundle)) {
|
||||||
if (chunk.type === 'chunk') {
|
if (chunk.type === 'chunk') {
|
||||||
if (pureCSSChunks.has(chunk)) {
|
if (internals.pureCSSChunks.has(chunk)) {
|
||||||
// Delete pure CSS chunks, these are JavaScript chunks that only import
|
// Delete pure CSS chunks, these are JavaScript chunks that only import
|
||||||
// other CSS files, so are empty at the end of bundling.
|
// other CSS files, so are empty at the end of bundling.
|
||||||
delete bundle[chunkId];
|
delete bundle[chunkId];
|
||||||
|
|
|
@ -1,8 +1,9 @@
|
||||||
import type { AstroConfig, RouteCache } from '../@types/astro';
|
import type { AstroConfig, RouteCache } from '../@types/astro';
|
||||||
import type { LogOptions } from '../core/logger';
|
import type { LogOptions } from '../core/logger';
|
||||||
import type { ViteDevServer, Plugin as VitePlugin } from '../core/vite';
|
import type { ViteDevServer, Plugin as VitePlugin } from '../core/vite';
|
||||||
import type { OutputChunk, PreRenderedChunk, RenderedChunk } from 'rollup';
|
import type { OutputChunk, PreRenderedChunk } from 'rollup';
|
||||||
import type { AllPagesData, PageBuildData } from '../core/build/types';
|
import type { AllPagesData } from '../core/build/types';
|
||||||
|
import type { BuildInternals } from '../core/build/internal';
|
||||||
import parse5 from 'parse5';
|
import parse5 from 'parse5';
|
||||||
import srcsetParse from 'srcset-parse';
|
import srcsetParse from 'srcset-parse';
|
||||||
import * as npath from 'path';
|
import * as npath from 'path';
|
||||||
|
@ -26,22 +27,17 @@ const STATUS_CODE_RE = /^404$/;
|
||||||
|
|
||||||
interface PluginOptions {
|
interface PluginOptions {
|
||||||
astroConfig: AstroConfig;
|
astroConfig: AstroConfig;
|
||||||
astroStyleMap: Map<string, string>;
|
internals: BuildInternals;
|
||||||
astroPageStyleMap: Map<string, string>;
|
|
||||||
chunkToReferenceIdMap: Map<string, string>;
|
|
||||||
logging: LogOptions;
|
logging: LogOptions;
|
||||||
allPages: AllPagesData;
|
allPages: AllPagesData;
|
||||||
pageNames: string[];
|
pageNames: string[];
|
||||||
pureCSSChunks: Set<RenderedChunk>;
|
|
||||||
origin: string;
|
origin: string;
|
||||||
routeCache: RouteCache;
|
routeCache: RouteCache;
|
||||||
viteServer: ViteDevServer;
|
viteServer: ViteDevServer;
|
||||||
|
|
||||||
facadeIdToPageDataMap: Map<string, PageBuildData>;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function rollupPluginAstroBuildHTML(options: PluginOptions): VitePlugin {
|
export function rollupPluginAstroBuildHTML(options: PluginOptions): VitePlugin {
|
||||||
const { astroConfig, astroStyleMap, astroPageStyleMap, chunkToReferenceIdMap, pureCSSChunks, logging, origin, allPages, routeCache, viteServer, pageNames } = options;
|
const { astroConfig, internals, logging, origin, allPages, routeCache, viteServer, pageNames } = options;
|
||||||
|
|
||||||
// The filepath root of the src folder
|
// The filepath root of the src folder
|
||||||
const srcRoot = astroConfig.src.pathname;
|
const srcRoot = astroConfig.src.pathname;
|
||||||
|
@ -74,16 +70,10 @@ export function rollupPluginAstroBuildHTML(options: PluginOptions): VitePlugin {
|
||||||
|
|
||||||
// Hydrated components are statically identified.
|
// Hydrated components are statically identified.
|
||||||
for (const path of mod.$$metadata.getAllHydratedComponentPaths()) {
|
for (const path of mod.$$metadata.getAllHydratedComponentPaths()) {
|
||||||
//jsInput.add(path);
|
jsInput.add(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
let astroModuleId = new URL('./' + component, astroConfig.projectRoot).pathname;
|
|
||||||
jsInput.add(astroModuleId);
|
|
||||||
options.facadeIdToPageDataMap.set(astroModuleId, pageData);
|
|
||||||
|
|
||||||
for (const pathname of pageData.paths) {
|
for (const pathname of pageData.paths) {
|
||||||
|
|
||||||
/*
|
|
||||||
pageNames.push(pathname.replace(/\/?$/, '/index.html').replace(/^\//, ''));
|
pageNames.push(pathname.replace(/\/?$/, '/index.html').replace(/^\//, ''));
|
||||||
const id = ASTRO_PAGE_PREFIX + pathname;
|
const id = ASTRO_PAGE_PREFIX + pathname;
|
||||||
const html = await ssrRender(renderers, mod, {
|
const html = await ssrRender(renderers, mod, {
|
||||||
|
@ -169,7 +159,7 @@ export function rollupPluginAstroBuildHTML(options: PluginOptions): VitePlugin {
|
||||||
|
|
||||||
if (styles) {
|
if (styles) {
|
||||||
const styleId = getAstroStyleId(pathname);
|
const styleId = getAstroStyleId(pathname);
|
||||||
astroStyleMap.set(styleId, styles);
|
internals.astroStyleMap.set(styleId, styles);
|
||||||
// Put this at the front of imports
|
// Put this at the front of imports
|
||||||
assetImports.unshift(styleId);
|
assetImports.unshift(styleId);
|
||||||
}
|
}
|
||||||
|
@ -183,7 +173,7 @@ export function rollupPluginAstroBuildHTML(options: PluginOptions): VitePlugin {
|
||||||
if (assetImports.length) {
|
if (assetImports.length) {
|
||||||
const pageStyleId = getAstroPageStyleId(pathname);
|
const pageStyleId = getAstroPageStyleId(pathname);
|
||||||
const jsSource = assetImports.map((sid) => `import '${sid}';`).join('\n');
|
const jsSource = assetImports.map((sid) => `import '${sid}';`).join('\n');
|
||||||
astroPageStyleMap.set(pageStyleId, jsSource);
|
internals.astroPageStyleMap.set(pageStyleId, jsSource);
|
||||||
assetInput.add(pageStyleId);
|
assetInput.add(pageStyleId);
|
||||||
|
|
||||||
// preserve asset order in the order we encounter them
|
// preserve asset order in the order we encounter them
|
||||||
|
@ -191,8 +181,6 @@ export function rollupPluginAstroBuildHTML(options: PluginOptions): VitePlugin {
|
||||||
if (!pageStyleImportOrder.includes(assetHref)) pageStyleImportOrder.push(assetHref);
|
if (!pageStyleImportOrder.includes(assetHref)) pageStyleImportOrder.push(assetHref);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -243,12 +231,9 @@ export function rollupPluginAstroBuildHTML(options: PluginOptions): VitePlugin {
|
||||||
if (!pageName) {
|
if (!pageName) {
|
||||||
pageName = 'index';
|
pageName = 'index';
|
||||||
}
|
}
|
||||||
return `assets/${pageName}.[hash].mjs`;
|
return `assets/${pageName}.[hash].js`;
|
||||||
}
|
}
|
||||||
return 'assets/[name].[hash].mjs';
|
return 'assets/[name].[hash].js';
|
||||||
},
|
|
||||||
chunkFileNames(chunk: PreRenderedChunk) {
|
|
||||||
return 'assets/[name].[hash].mjs';
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return outputOptions;
|
return outputOptions;
|
||||||
|
@ -281,7 +266,7 @@ export function rollupPluginAstroBuildHTML(options: PluginOptions): VitePlugin {
|
||||||
|
|
||||||
// Sort CSS in order of appearance in HTML (pageStyleImportOrder)
|
// Sort CSS in order of appearance in HTML (pageStyleImportOrder)
|
||||||
// This is the “global ordering” used below
|
// This is the “global ordering” used below
|
||||||
const sortedCSSChunks = [...pureCSSChunks];
|
const sortedCSSChunks = [...internals.pureCSSChunks];
|
||||||
sortedCSSChunks.sort((a, b) => {
|
sortedCSSChunks.sort((a, b) => {
|
||||||
let aIndex = Math.min(
|
let aIndex = Math.min(
|
||||||
...Object.keys(a.modules).map((id) => {
|
...Object.keys(a.modules).map((id) => {
|
||||||
|
@ -311,7 +296,7 @@ export function rollupPluginAstroBuildHTML(options: PluginOptions): VitePlugin {
|
||||||
|
|
||||||
const referenceIDs: string[] = [];
|
const referenceIDs: string[] = [];
|
||||||
for (const chunkID of chunkModules) {
|
for (const chunkID of chunkModules) {
|
||||||
const referenceID = chunkToReferenceIdMap.get(chunkID);
|
const referenceID = internals.chunkToReferenceIdMap.get(chunkID);
|
||||||
if (referenceID) referenceIDs.push(referenceID);
|
if (referenceID) referenceIDs.push(referenceID);
|
||||||
}
|
}
|
||||||
for (const id of Object.keys(chunk.modules)) {
|
for (const id of Object.keys(chunk.modules)) {
|
||||||
|
|
|
@ -1,16 +0,0 @@
|
||||||
import type { Plugin as VitePlugin } from '../core/vite';
|
|
||||||
|
|
||||||
export function vitePluginNewBuild(): VitePlugin {
|
|
||||||
return {
|
|
||||||
name: '@astro/rollup-plugin-new-build',
|
|
||||||
|
|
||||||
configResolved(resolvedConfig) {
|
|
||||||
// Delete this hook because it causes assets not to be built
|
|
||||||
const plugins = resolvedConfig.plugins as VitePlugin[];
|
|
||||||
const viteAsset = plugins.find((p) => p.name === 'vite:asset');
|
|
||||||
if(viteAsset) {
|
|
||||||
delete viteAsset.generateBundle;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in a new issue