summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Matthew Phillips <matthew@matthewphillips.info> 2022-01-13 09:23:03 -0500
committerGravatar GitHub <noreply@github.com> 2022-01-13 09:23:03 -0500
commit2aa5ba5c52d0fa6eb2d17ca0b38a761ab40f8ca4 (patch)
treee0dfea31da415d14a1a9bfc46b4a3391db397ab1
parentff9dbc69279178b5f0f843b40f86f9c68dedbc1d (diff)
downloadastro-2aa5ba5c52d0fa6eb2d17ca0b38a761ab40f8ca4.tar.gz
astro-2aa5ba5c52d0fa6eb2d17ca0b38a761ab40f8ca4.tar.zst
astro-2aa5ba5c52d0fa6eb2d17ca0b38a761ab40f8ca4.zip
Fix use of frameworks in the static build (#2367)
* Fix use of frameworks in the static build * Adding a changeset * fix typescript * Empty out the directory before running the builds * Use a util to empty the directory * Only empty the outdir if needed * Move prepareOutDir to its own module * Prepare outDir is actually sync
-rw-r--r--.changeset/long-eagles-care.md5
-rw-r--r--packages/astro/src/@types/astro.ts2
-rw-r--r--packages/astro/src/core/build/fs.ts28
-rw-r--r--packages/astro/src/core/build/static-build.ts45
-rw-r--r--packages/astro/src/core/ssr/index.ts3
-rw-r--r--packages/astro/test/fixtures/static-build-frameworks/src/components/PCounter.jsx19
-rw-r--r--packages/astro/test/fixtures/static-build-frameworks/src/pages/index.astro12
-rw-r--r--packages/astro/test/static-build-frameworks.test.js29
8 files changed, 136 insertions, 7 deletions
diff --git a/.changeset/long-eagles-care.md b/.changeset/long-eagles-care.md
new file mode 100644
index 000000000..716b9b3ab
--- /dev/null
+++ b/.changeset/long-eagles-care.md
@@ -0,0 +1,5 @@
+---
+'astro': patch
+---
+
+Fixes use of framework renderers in the static build
diff --git a/packages/astro/src/@types/astro.ts b/packages/astro/src/@types/astro.ts
index 2e60da3b7..3c1548698 100644
--- a/packages/astro/src/@types/astro.ts
+++ b/packages/astro/src/@types/astro.ts
@@ -279,6 +279,8 @@ export interface Renderer {
name: string;
/** Import statement for renderer */
source?: string;
+ /** Import statement for the server renderer */
+ serverEntry: string;
/** Scripts to be injected before component */
polyfills?: string[];
/** Polyfills that need to run before hydration ever occurs */
diff --git a/packages/astro/src/core/build/fs.ts b/packages/astro/src/core/build/fs.ts
new file mode 100644
index 000000000..f557b3cbf
--- /dev/null
+++ b/packages/astro/src/core/build/fs.ts
@@ -0,0 +1,28 @@
+import type { AstroConfig } from '../../@types/astro';
+
+import fs from 'fs';
+import npath from 'path';
+import { fileURLToPath } from 'url';
+
+export function emptyDir(dir: string, skip?: Set<string>): void {
+ for (const file of fs.readdirSync(dir)) {
+ if (skip?.has(file)) {
+ continue
+ }
+ const abs = npath.resolve(dir, file)
+ // baseline is Node 12 so can't use rmSync :(
+ if (fs.lstatSync(abs).isDirectory()) {
+ emptyDir(abs)
+ fs.rmdirSync(abs)
+ } else {
+ fs.unlinkSync(abs)
+ }
+ }
+}
+
+export function prepareOutDir(astroConfig: AstroConfig) {
+ const outDir = fileURLToPath(astroConfig.dist);
+ if (fs.existsSync(outDir)) {
+ return emptyDir(outDir, new Set(['.git']));
+ }
+}
diff --git a/packages/astro/src/core/build/static-build.ts b/packages/astro/src/core/build/static-build.ts
index 40afe728e..b21c81b00 100644
--- a/packages/astro/src/core/build/static-build.ts
+++ b/packages/astro/src/core/build/static-build.ts
@@ -1,6 +1,6 @@
import type { OutputChunk, OutputAsset, PreRenderedChunk, RollupOutput } from 'rollup';
import type { Plugin as VitePlugin, UserConfig } from '../vite';
-import type { AstroConfig, RouteCache, SSRElement } from '../../@types/astro';
+import type { AstroConfig, Renderer, RouteCache, SSRElement } from '../../@types/astro';
import type { AllPagesData } from './types';
import type { LogOptions } from '../logger';
import type { ViteConfigWithSSR } from '../create-vite';
@@ -19,6 +19,7 @@ import { rollupPluginAstroBuildCSS } from '../../vite-plugin-build-css/index.js'
import { getParamsAndProps } from '../ssr/index.js';
import { createResult } from '../ssr/result.js';
import { renderPage } from '../../runtime/server/index.js';
+import { prepareOutDir } from './fs.js';
export interface StaticBuildOptions {
allPages: AllPagesData;
@@ -35,6 +36,8 @@ function addPageName(pathname: string, opts: StaticBuildOptions): void {
opts.pageNames.push(pathname.replace(/\/?$/, pathrepl).replace(/^\//, ''));
}
+
+
// Determines of a Rollup chunk is an entrypoint page.
function chunkIsPage(output: OutputAsset | OutputChunk, internals: BuildInternals) {
if (output.type !== 'chunk') {
@@ -82,6 +85,11 @@ export async function staticBuild(opts: StaticBuildOptions) {
// Build internals needed by the CSS plugin
const internals = createBuildInternals();
+ // Empty out the dist folder, if needed. Vite has a config for doing this
+ // but because we are running 2 vite builds in parallel, that would cause a race
+ // condition, so we are doing it ourselves
+ prepareOutDir(astroConfig);
+
// Run the SSR build and client build in parallel
const [ssrResult] = (await Promise.all([ssrBuild(opts, internals, pageInput), clientBuild(opts, internals, jsInput)])) as RollupOutput[];
@@ -97,7 +105,7 @@ async function ssrBuild(opts: StaticBuildOptions, internals: BuildInternals, inp
logLevel: 'error',
mode: 'production',
build: {
- emptyOutDir: true,
+ emptyOutDir: false,
minify: false,
outDir: fileURLToPath(astroConfig.dist),
ssr: true,
@@ -163,18 +171,41 @@ async function clientBuild(opts: StaticBuildOptions, internals: BuildInternals,
});
}
+async function collectRenderers(opts: StaticBuildOptions): Promise<Renderer[]> {
+ // All of the PageDatas have the same renderers, so just grab one.
+ const pageData = Object.values(opts.allPages)[0];
+ // These renderers have been loaded through Vite. To generate pages
+ // we need the ESM loaded version. This creates that.
+ const viteLoadedRenderers = pageData.preload[0];
+
+ const renderers = await Promise.all(viteLoadedRenderers.map(async r => {
+ const mod = await import(r.serverEntry);
+ return Object.create(r, {
+ ssr: {
+ value: mod.default
+ }
+ }) as Renderer;
+ }));
+
+ return renderers;
+}
+
async function generatePages(result: RollupOutput, opts: StaticBuildOptions, internals: BuildInternals, facadeIdToPageDataMap: Map<string, PageBuildData>) {
debug(opts.logging, 'generate', 'End build step, now generating');
+
+ // Get renderers to be shared for each page generation.
+ const renderers = await collectRenderers(opts);
+
const generationPromises = [];
for (let output of result.output) {
if (chunkIsPage(output, internals)) {
- generationPromises.push(generatePage(output as OutputChunk, opts, internals, facadeIdToPageDataMap));
+ generationPromises.push(generatePage(output as OutputChunk, opts, internals, facadeIdToPageDataMap, renderers));
}
}
await Promise.all(generationPromises);
}
-async function generatePage(output: OutputChunk, opts: StaticBuildOptions, internals: BuildInternals, facadeIdToPageDataMap: Map<string, PageBuildData>) {
+async function generatePage(output: OutputChunk, opts: StaticBuildOptions, internals: BuildInternals, facadeIdToPageDataMap: Map<string, PageBuildData>, renderers: Renderer[]) {
const { astroConfig } = opts;
let url = new URL('./' + output.fileName, astroConfig.dist);
@@ -198,6 +229,7 @@ async function generatePage(output: OutputChunk, opts: StaticBuildOptions, inter
internals,
linkIds,
Component,
+ renderers,
};
const renderPromises = pageData.paths.map((path) => {
@@ -211,16 +243,17 @@ interface GeneratePathOptions {
internals: BuildInternals;
linkIds: string[];
Component: AstroComponentFactory;
+ renderers: Renderer[];
}
async function generatePath(pathname: string, opts: StaticBuildOptions, gopts: GeneratePathOptions) {
const { astroConfig, logging, origin, pageNames, routeCache } = opts;
- const { Component, internals, linkIds, pageData } = gopts;
+ const { Component, internals, linkIds, pageData, renderers } = gopts;
// This adds the page name to the array so it can be shown as part of stats.
addPageName(pathname, opts);
- const [renderers, mod] = pageData.preload;
+ const [,mod] = pageData.preload;
try {
const [params, pageProps] = await getParamsAndProps({
diff --git a/packages/astro/src/core/ssr/index.ts b/packages/astro/src/core/ssr/index.ts
index eb6e3c4e8..fd1b1694c 100644
--- a/packages/astro/src/core/ssr/index.ts
+++ b/packages/astro/src/core/ssr/index.ts
@@ -52,9 +52,10 @@ async function resolveRenderer(viteServer: vite.ViteDevServer, renderer: string,
resolvedRenderer.name = name;
if (client) resolvedRenderer.source = path.posix.join(renderer, client);
+ resolvedRenderer.serverEntry = path.posix.join(renderer, server);
if (Array.isArray(hydrationPolyfills)) resolvedRenderer.hydrationPolyfills = hydrationPolyfills.map((src: string) => path.posix.join(renderer, src));
if (Array.isArray(polyfills)) resolvedRenderer.polyfills = polyfills.map((src: string) => path.posix.join(renderer, src));
- const { url } = await viteServer.moduleGraph.ensureEntryFromUrl(path.posix.join(renderer, server));
+ const { url } = await viteServer.moduleGraph.ensureEntryFromUrl(resolvedRenderer.serverEntry);
const { default: rendererSSR } = await viteServer.ssrLoadModule(url);
resolvedRenderer.ssr = rendererSSR;
diff --git a/packages/astro/test/fixtures/static-build-frameworks/src/components/PCounter.jsx b/packages/astro/test/fixtures/static-build-frameworks/src/components/PCounter.jsx
new file mode 100644
index 000000000..6a67d6203
--- /dev/null
+++ b/packages/astro/test/fixtures/static-build-frameworks/src/components/PCounter.jsx
@@ -0,0 +1,19 @@
+import { h } from 'preact';
+import { useState } from 'preact/hooks';
+
+export default function Counter({ children }) {
+ const [count, setCount] = useState(0);
+ const add = () => setCount((i) => i + 1);
+ const subtract = () => setCount((i) => i - 1);
+
+ return (
+ <>
+ <div class="counter">
+ <button onClick={subtract}>-</button>
+ <pre>{count}</pre>
+ <button onClick={add}>+</button>
+ </div>
+ <div class="counter-message">{children}</div>
+ </>
+ );
+}
diff --git a/packages/astro/test/fixtures/static-build-frameworks/src/pages/index.astro b/packages/astro/test/fixtures/static-build-frameworks/src/pages/index.astro
new file mode 100644
index 000000000..53e5ce551
--- /dev/null
+++ b/packages/astro/test/fixtures/static-build-frameworks/src/pages/index.astro
@@ -0,0 +1,12 @@
+---
+import PCounter from '../components/PCounter.jsx';
+---
+<html>
+<head>
+<title>Testing</title>
+</head>
+<body>
+<h1>Testing</h1>
+<PCounter client:load />
+</body>
+</html>
diff --git a/packages/astro/test/static-build-frameworks.test.js b/packages/astro/test/static-build-frameworks.test.js
new file mode 100644
index 000000000..22ba13b3c
--- /dev/null
+++ b/packages/astro/test/static-build-frameworks.test.js
@@ -0,0 +1,29 @@
+import { expect } from 'chai';
+import cheerio from 'cheerio';
+import { loadFixture } from './test-utils.js';
+
+function addLeadingSlash(path) {
+ return path.startsWith('/') ? path : '/' + path;
+}
+
+describe('Static build - frameworks', () => {
+ let fixture;
+
+ before(async () => {
+ fixture = await loadFixture({
+ projectRoot: './fixtures/static-build-frameworks/',
+ renderers: [
+ '@astrojs/renderer-preact'
+ ],
+ buildOptions: {
+ experimentalStaticBuild: true,
+ },
+ });
+ await fixture.build();
+ });
+
+ it('can build preact', async () => {
+ const html = await fixture.readFile('/index.html');
+ expect(html).to.be.a('string');
+ });
+});