From 9aff6eee717abcea781410cb3dd22c47d26ecc37 Mon Sep 17 00:00:00 2001 From: Matthew Phillips Date: Tue, 21 Dec 2021 11:57:50 -0500 Subject: [PATCH] Flagged static (performance optimized) build (#2168) * Progress on build demo * Go back to ESM * Some more progress on the new build * More progress here * Add support for hot reload * Almost done * Remove debugging stuff * chore(lint): Prettier fix * Pass through the origin * Do not use ssr mode * Use the logger * chore(lint): Prettier fix * Update yarn lock * Fix types * Only build chunks that are astro pages * Debugging windows * Prevent compilation race condition * Read the file if not found in the cache * Give a better error message when we can't find a page * chore(lint): Prettier fix * Fix windows maybe * chore(lint): Prettier fix * Some more windows debugging * chore(lint): Prettier fix * Remove console logs * More debugging * chore(lint): Prettier fix * More debugging info * chore(lint): Prettier fix * Remove logging again * Try to prevent port conflicts Co-authored-by: github-actions[bot] --- examples/fast-build/astro.config.mjs | 11 + examples/fast-build/package.json | 16 + .../fast-build/src/components/Greeting.vue | 20 + examples/fast-build/src/images/penguin.jpg | Bin 0 -> 12013 bytes examples/fast-build/src/images/random.jpg | Bin 0 -> 14553 bytes examples/fast-build/src/pages/index.astro | 32 + examples/fast-build/src/styles/global.css | 3 + packages/astro/package.json | 2 +- packages/astro/src/@types/astro.ts | 2 + packages/astro/src/cli/index.ts | 4 + packages/astro/src/core/build/index.ts | 187 ++---- packages/astro/src/core/build/internal.ts | 45 ++ packages/astro/src/core/build/page-data.ts | 122 ++++ .../astro/src/core/build/scan-based-build.ts | 68 ++ packages/astro/src/core/build/static-build.ts | 195 ++++++ packages/astro/src/core/config.ts | 1 + packages/astro/src/core/ssr/index.ts | 117 ++++ packages/astro/src/runtime/server/index.ts | 26 +- .../astro/src/vite-plugin-astro/compile.ts | 110 ++++ packages/astro/src/vite-plugin-astro/index.ts | 141 ++-- packages/astro/src/vite-plugin-astro/query.ts | 35 + .../astro/src/vite-plugin-build-css/index.ts | 53 +- .../astro/src/vite-plugin-build-html/index.ts | 18 +- packages/astro/test/preact-component.test.js | 3 + packages/astro/test/react-component.test.js | 3 + packages/astro/test/solid-component.test.js | 3 + packages/astro/test/svelte-component.test.js | 3 + packages/astro/test/test-utils.js | 3 +- packages/astro/test/vue-component.test.js | 3 + yarn.lock | 606 +++++++++++++++++- 30 files changed, 1531 insertions(+), 301 deletions(-) create mode 100644 examples/fast-build/astro.config.mjs create mode 100644 examples/fast-build/package.json create mode 100644 examples/fast-build/src/components/Greeting.vue create mode 100644 examples/fast-build/src/images/penguin.jpg create mode 100644 examples/fast-build/src/images/random.jpg create mode 100644 examples/fast-build/src/pages/index.astro create mode 100644 examples/fast-build/src/styles/global.css create mode 100644 packages/astro/src/core/build/internal.ts create mode 100644 packages/astro/src/core/build/page-data.ts create mode 100644 packages/astro/src/core/build/scan-based-build.ts create mode 100644 packages/astro/src/core/build/static-build.ts create mode 100644 packages/astro/src/vite-plugin-astro/compile.ts create mode 100644 packages/astro/src/vite-plugin-astro/query.ts diff --git a/examples/fast-build/astro.config.mjs b/examples/fast-build/astro.config.mjs new file mode 100644 index 000000000..32eca8696 --- /dev/null +++ b/examples/fast-build/astro.config.mjs @@ -0,0 +1,11 @@ +import { imagetools } from 'vite-imagetools'; + +// @ts-check +export default /** @type {import('astro').AstroUserConfig} */ ({ + renderers: [ + "@astrojs/renderer-vue" + ], + vite: { + plugins: [imagetools()] + } +}); diff --git a/examples/fast-build/package.json b/examples/fast-build/package.json new file mode 100644 index 000000000..4abd5fc13 --- /dev/null +++ b/examples/fast-build/package.json @@ -0,0 +1,16 @@ +{ + "name": "@example/fast-build", + "version": "0.0.1", + "private": true, + "scripts": { + "dev": "astro dev --experimental-static-build", + "start": "astro dev", + "build": "astro build --experimental-static-build", + "preview": "astro preview" + }, + "devDependencies": { + "astro": "^0.21.6", + "unocss": "^0.15.5", + "vite-imagetools": "^4.0.1" + } +} diff --git a/examples/fast-build/src/components/Greeting.vue b/examples/fast-build/src/components/Greeting.vue new file mode 100644 index 000000000..69fa4fbca --- /dev/null +++ b/examples/fast-build/src/components/Greeting.vue @@ -0,0 +1,20 @@ + + + + + diff --git a/examples/fast-build/src/images/penguin.jpg b/examples/fast-build/src/images/penguin.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6c5dcd37a30a6c9da324b15932349f06a275539b GIT binary patch literal 12013 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 literal 0 HcmV?d00001 diff --git a/examples/fast-build/src/images/random.jpg b/examples/fast-build/src/images/random.jpg new file mode 100644 index 0000000000000000000000000000000000000000..29188383791f3b4f5e9a66b60b37f6cd705e5507 GIT binary patch literal 14553 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 literal 0 HcmV?d00001 diff --git a/examples/fast-build/src/pages/index.astro b/examples/fast-build/src/pages/index.astro new file mode 100644 index 000000000..b5b9785da --- /dev/null +++ b/examples/fast-build/src/pages/index.astro @@ -0,0 +1,32 @@ +--- +import imgUrl from '../images/penguin.jpg'; +import grayscaleUrl from '../images/random.jpg?grayscale=true'; +import Greeting from '../components/Greeting.vue'; +--- + + + + Demo app + + + +
+

Images

+ +

Imported in JS

+ +
+ +
+

Component CSS

+ +
+ +
+

ImageTools

+ +
+ + \ No newline at end of file diff --git a/examples/fast-build/src/styles/global.css b/examples/fast-build/src/styles/global.css new file mode 100644 index 000000000..9f52e094e --- /dev/null +++ b/examples/fast-build/src/styles/global.css @@ -0,0 +1,3 @@ +body { + background: lightcoral; +} diff --git a/packages/astro/package.json b/packages/astro/package.json index 8435c3c20..9a0db9f66 100644 --- a/packages/astro/package.json +++ b/packages/astro/package.json @@ -56,7 +56,7 @@ "test": "mocha --parallel --timeout 15000" }, "dependencies": { - "@astrojs/compiler": "^0.5.4", + "@astrojs/compiler": "^0.6.0", "@astrojs/language-server": "^0.8.2", "@astrojs/markdown-remark": "^0.5.0", "@astrojs/prism": "0.3.0", diff --git a/packages/astro/src/@types/astro.ts b/packages/astro/src/@types/astro.ts index bce09f050..cdb2771d5 100644 --- a/packages/astro/src/@types/astro.ts +++ b/packages/astro/src/@types/astro.ts @@ -363,11 +363,13 @@ export interface SSRElement { export interface SSRMetadata { renderers: Renderer[]; pathname: string; + experimentalStaticBuild: boolean; } export interface SSRResult { styles: Set; scripts: Set; + links: Set; createAstro(Astro: AstroGlobalPartial, props: Record, slots: Record | null): AstroGlobal; _metadata: SSRMetadata; } diff --git a/packages/astro/src/cli/index.ts b/packages/astro/src/cli/index.ts index 621678e50..03c84a711 100644 --- a/packages/astro/src/cli/index.ts +++ b/packages/astro/src/cli/index.ts @@ -25,6 +25,7 @@ interface CLIState { hostname?: string; port?: number; config?: string; + experimentalStaticBuild?: boolean; }; } @@ -37,6 +38,7 @@ function resolveArgs(flags: Arguments): CLIState { port: typeof flags.port === 'number' ? flags.port : undefined, config: typeof flags.config === 'string' ? flags.config : undefined, hostname: typeof flags.hostname === 'string' ? flags.hostname : undefined, + experimentalStaticBuild: typeof flags.experimentalStaticBuild === 'boolean' ? flags.experimentalStaticBuild : false, }; if (flags.version) { @@ -73,6 +75,7 @@ function printHelp() { --config Specify the path to the Astro config file. --project-root Specify the path to the project root folder. --no-sitemap Disable sitemap generation (build only). + --experimental-static-build A more performant build that expects assets to be define statically. --verbose Enable verbose logging --silent Disable logging --version Show the version number and exit. @@ -92,6 +95,7 @@ function mergeCLIFlags(astroConfig: AstroConfig, flags: CLIState['options']) { if (typeof flags.site === 'string') astroConfig.buildOptions.site = flags.site; if (typeof flags.port === 'number') astroConfig.devOptions.port = flags.port; if (typeof flags.hostname === 'string') astroConfig.devOptions.hostname = flags.hostname; + if (typeof flags.experimentalStaticBuild === 'boolean') astroConfig.buildOptions.experimentalStaticBuild = flags.experimentalStaticBuild; } /** The primary CLI action */ diff --git a/packages/astro/src/core/build/index.ts b/packages/astro/src/core/build/index.ts index be1496b61..3789f9789 100644 --- a/packages/astro/src/core/build/index.ts +++ b/packages/astro/src/core/build/index.ts @@ -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 { AllPagesData } 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 fs from 'fs'; import * as colors from 'kleur/colors'; import { polyfill } from '@astropub/webapi'; import { performance } from 'perf_hooks'; import vite, { ViteDevServer } from '../vite.js'; -import { fileURLToPath } from 'url'; import { createVite, ViteConfigWithSSR } from '../create-vite.js'; import { debug, defaultLogOptions, info, levels, timerMessage, warn } from '../logger.js'; -import { preload as ssrPreload } from '../ssr/index.js'; -import { generatePaginateFunction } from '../ssr/paginate.js'; -import { createRouteManifest, validateGetStaticPathsModule, validateGetStaticPathsResult } from '../ssr/routing.js'; -import { generateRssFunction } from '../ssr/rss.js'; +import { createRouteManifest } from '../ssr/routing.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 { mode?: string; @@ -82,137 +77,45 @@ class AstroBuilder { debug(logging, 'build', timerMessage('Vite started', timer.viteStart)); timer.loadStart = performance.now(); - const assets: Record = {}; - 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, - filePath: new URL(`./${route.component}`, this.config.projectRoot), - logging, - mode: 'production', - origin, - pathname: route.pathname, - route, - routeCache: this.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 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, - }), - }; - }) - ); + const { assets, allPages } = await collectPagesData({ + astroConfig: this.config, + logging: this.logging, + manifest: this.manifest, + origin, + routeCache: this.routeCache, + viteServer: this.viteServer, + }); debug(logging, 'build', timerMessage('All pages loaded', timer.loadStart)); - // 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(); - const chunkToReferenceIdMap = new Map(); - - // This is a mapping of pathname to the string source of all collected - // inline