diff --git a/examples/snowpack/astro/components/Nav.astro b/examples/snowpack/astro/components/Nav.astro index a5f14d656..d2c0e943c 100644 --- a/examples/snowpack/astro/components/Nav.astro +++ b/examples/snowpack/astro/components/Nav.astro @@ -345,8 +345,8 @@ export let version: string = '3.1.2'; }; diff --git a/examples/snowpack/astro/components/PluginSearchPage.jsx b/examples/snowpack/astro/components/PluginSearchPage.jsx index 621cbe02b..51c7e6b0f 100644 --- a/examples/snowpack/astro/components/PluginSearchPage.jsx +++ b/examples/snowpack/astro/components/PluginSearchPage.jsx @@ -43,7 +43,7 @@ function Card({ result }) { ); } -export default function PluginSearchPage() { +function PluginSearchPageLive() { const searchParams = new URLSearchParams(window.location.search); const [results, setResults] = useState(null); const [searchQuery, setSearchQuery] = useState(searchParams.get('q')); @@ -65,9 +65,6 @@ export default function PluginSearchPage() { setResults(await searchPlugins(formula)); return false; } - // if (document.getElementById('loading-message')) { - // document.getElementById('loading-message').style.display = 'none'; - // } return ( <> @@ -118,3 +115,7 @@ export default function PluginSearchPage() { ); } + +export default function PluginSearchPage(props) { + return import.meta.env.astro ?
Loading...
: +} diff --git a/examples/snowpack/astro/pages/plugins.astro b/examples/snowpack/astro/pages/plugins.astro index bffe9b4b9..ddd7632e8 100644 --- a/examples/snowpack/astro/pages/plugins.astro +++ b/examples/snowpack/astro/pages/plugins.astro @@ -66,7 +66,7 @@ let description = 'Snowpack plugins allow for configuration-minimal tooling inte Creating your own plugin is easy!

-
+
diff --git a/package-lock.json b/package-lock.json index 2e2f028b9..83d45dc04 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2956,15 +2956,15 @@ "integrity": "sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==" }, "preact": { - "version": "10.5.12", - "resolved": "https://registry.npmjs.org/preact/-/preact-10.5.12.tgz", - "integrity": "sha512-r6siDkuD36oszwlCkcqDJCAKBQxGoeEGytw2DGMD5A/GGdu5Tymw+N2OBXwvOLxg6d1FeY8MgMV3cc5aVQo4Cg==", + "version": "10.5.13", + "resolved": "https://registry.npmjs.org/preact/-/preact-10.5.13.tgz", + "integrity": "sha512-q/vlKIGNwzTLu+jCcvywgGrt+H/1P/oIRSD6mV4ln3hmlC+Aa34C7yfPI4+5bzW8pONyVXYS7SvXosy2dKKtWQ==", "dev": true }, "preact-render-to-string": { - "version": "5.1.16", - "resolved": "https://registry.npmjs.org/preact-render-to-string/-/preact-render-to-string-5.1.16.tgz", - "integrity": "sha512-HvO3W29Sziz9r5FZGwl2e34XJKzyRLvjhouv3cpkCGszNPdnvkO8p4B6CBpe0MT/tzR+QVbmsAKLrMK222UXew==", + "version": "5.1.18", + "resolved": "https://registry.npmjs.org/preact-render-to-string/-/preact-render-to-string-5.1.18.tgz", + "integrity": "sha512-jTL6iTZeheYOhb54r7KuyrNCf33lc+Z52Wos5P1z2wGZ/dREfhBVwrK1qGOrl4fboBN1KxC1lxhBchDHNZr8Uw==", "dev": true, "requires": { "pretty-format": "^3.8.0" diff --git a/package.json b/package.json index 5762c5d2e..0f4b70f6f 100644 --- a/package.json +++ b/package.json @@ -81,8 +81,8 @@ "eslint-plugin-prettier": "^3.3.1", "estree-walker": "^3.0.0", "nodemon": "^2.0.7", - "preact": "^10.5.12", - "preact-render-to-string": "^5.1.14", + "preact": "^10.5.13", + "preact-render-to-string": "^5.1.18", "prettier": "^2.2.1", "typescript": "^4.2.3", "uvu": "^0.5.1" diff --git a/src/build.ts b/src/build.ts index 25d5e5ec6..ffae6fac0 100644 --- a/src/build.ts +++ b/src/build.ts @@ -61,7 +61,7 @@ export async function build(astroConfig: AstroConfig): Promise<0 | 1> { const runtime = await createRuntime(astroConfig, { logging: runtimeLogging }); const { runtimeConfig } = runtime; - const { snowpack } = runtimeConfig; + const { backendSnowpack: snowpack } = runtimeConfig; const resolve = (pkgName: string) => snowpack.getUrlForPackage(pkgName); const imports = new Set(); diff --git a/src/frontend/render/renderer.ts b/src/frontend/render/renderer.ts index d7afc0558..9589cef85 100644 --- a/src/frontend/render/renderer.ts +++ b/src/frontend/render/renderer.ts @@ -5,7 +5,7 @@ interface DynamicRenderContext { } export interface Renderer { - renderStatic(Component: any): (props: Record, ...children: any[]) => string; + renderStatic(Component: any): (props: Record, ...children: any[]) => string; render(context: { root: string; Component: string; props: string; [key: string]: string }): string; imports?: Record; } diff --git a/src/runtime.ts b/src/runtime.ts index f36ef1225..e0ac09de7 100644 --- a/src/runtime.ts +++ b/src/runtime.ts @@ -10,9 +10,12 @@ import { loadConfiguration, logger as snowpackLogger, startServer as startSnowpa interface RuntimeConfig { astroConfig: AstroConfig; logging: LogOptions; - snowpack: SnowpackDevServer; - snowpackRuntime: SnowpackServerRuntime; - snowpackConfig: SnowpackConfig; + backendSnowpack: SnowpackDevServer; + backendSnowpackRuntime: SnowpackServerRuntime; + backendSnowpackConfig: SnowpackConfig; + frontendSnowpack: SnowpackDevServer; + frontendSnowpackRuntime: SnowpackServerRuntime; + frontendSnowpackConfig: SnowpackConfig; } type LoadResultSuccess = { @@ -29,7 +32,7 @@ export type LoadResult = LoadResultSuccess | LoadResultNotFound | LoadResultErro snowpackLogger.level = 'silent'; async function load(config: RuntimeConfig, rawPathname: string | undefined): Promise { - const { logging, snowpack, snowpackRuntime } = config; + const { logging, backendSnowpackRuntime, frontendSnowpack } = config; const { astroRoot } = config.astroConfig; const fullurl = new URL(rawPathname || '/', 'https://example.org/'); @@ -43,7 +46,8 @@ async function load(config: RuntimeConfig, rawPathname: string | undefined): Pro // Non-Astro pages (file resources) if (!existsSync(selectedPageLoc) && !existsSync(selectedPageMdLoc)) { try { - const result = await snowpack.loadUrl(reqPath); + console.log('loading', reqPath); + const result = await frontendSnowpack.loadUrl(reqPath); // success return { @@ -63,7 +67,7 @@ async function load(config: RuntimeConfig, rawPathname: string | undefined): Pro for (const url of [`/_astro/pages/${selectedPage}.astro.js`, `/_astro/pages/${selectedPage}.md.js`]) { try { - const mod = await snowpackRuntime.importModule(url); + const mod = await backendSnowpackRuntime.importModule(url); debug(logging, 'resolve', `${reqPath} -> ${url}`); let html = (await mod.exports.__renderPage({ request: { @@ -128,7 +132,7 @@ interface RuntimeOptions { logging: LogOptions; } -export async function createRuntime(astroConfig: AstroConfig, { logging }: RuntimeOptions): Promise { +async function createSnowpack(astroConfig: AstroConfig, env: Record) { const { projectRoot, astroRoot, extensions } = astroConfig; const internalPath = new URL('./frontend/', import.meta.url); @@ -170,23 +174,42 @@ export async function createRuntime(astroConfig: AstroConfig, { logging }: Runti external: ['@vue/server-renderer', 'node-fetch'], }, }); + + const envConfig = snowpackConfig.env || (snowpackConfig.env = {}); + Object.assign(envConfig, env); + snowpack = await startSnowpackServer({ config: snowpackConfig, lockfile: null, }); const snowpackRuntime = snowpack.getServerRuntime(); + return { snowpack, snowpackRuntime, snowpackConfig }; +} + +export async function createRuntime(astroConfig: AstroConfig, { logging }: RuntimeOptions): Promise { + const { snowpack: backendSnowpack, snowpackRuntime: backendSnowpackRuntime, snowpackConfig: backendSnowpackConfig } = await createSnowpack(astroConfig, { + astro: true, + }); + + const { snowpack: frontendSnowpack, snowpackRuntime: frontendSnowpackRuntime, snowpackConfig: frontendSnowpackConfig } = await createSnowpack(astroConfig, { + astro: false, + }); + const runtimeConfig: RuntimeConfig = { astroConfig, logging, - snowpack, - snowpackRuntime, - snowpackConfig, + backendSnowpack, + backendSnowpackRuntime, + backendSnowpackConfig, + frontendSnowpack, + frontendSnowpackRuntime, + frontendSnowpackConfig, }; return { runtimeConfig, load: load.bind(null, runtimeConfig), - shutdown: () => snowpack.shutdown(), + shutdown: () => Promise.all([backendSnowpack.shutdown(), frontendSnowpack.shutdown()]).then(() => void 0), }; } diff --git a/src/style-stuff.ts b/src/style-stuff.ts deleted file mode 100644 index e69de29bb..000000000 diff --git a/test/astro-fallback.test.js b/test/astro-fallback.test.js new file mode 100644 index 000000000..2acf29f8e --- /dev/null +++ b/test/astro-fallback.test.js @@ -0,0 +1,19 @@ +import { suite } from 'uvu'; +import * as assert from 'uvu/assert'; +import { doc } from './test-utils.js'; +import { setup } from './helpers.js'; + +const Fallback = suite('Dynamic component fallback'); + +setup(Fallback, './fixtures/astro-fallback'); + +Fallback('Shows static content', async (context) => { + const result = await context.runtime.load('/'); + + assert.equal(result.statusCode, 200); + + const $ = doc(result.contents); + assert.equal($('#fallback').text(), 'static'); +}); + +Fallback.run(); diff --git a/test/fixtures/astro-fallback/astro.config.mjs b/test/fixtures/astro-fallback/astro.config.mjs new file mode 100644 index 000000000..ac85e54d8 --- /dev/null +++ b/test/fixtures/astro-fallback/astro.config.mjs @@ -0,0 +1,8 @@ +export default { + projectRoot: '.', + astroRoot: './astro', + dist: './_site', + extensions: { + '.jsx': 'preact' + } +}; diff --git a/test/fixtures/astro-fallback/astro/components/Client.jsx b/test/fixtures/astro-fallback/astro/components/Client.jsx new file mode 100644 index 000000000..d79536e27 --- /dev/null +++ b/test/fixtures/astro-fallback/astro/components/Client.jsx @@ -0,0 +1,7 @@ +import { h } from 'preact'; + +export default function(props) { + return ( +
{import.meta.env.astro ? 'static' : 'dynamic'}
+ ); +}; \ No newline at end of file diff --git a/test/fixtures/astro-fallback/astro/pages/index.astro b/test/fixtures/astro-fallback/astro/pages/index.astro new file mode 100644 index 000000000..f4f20c322 --- /dev/null +++ b/test/fixtures/astro-fallback/astro/pages/index.astro @@ -0,0 +1,16 @@ +--- +import Client from '../components/Client.jsx'; + +let title = 'My Page' +--- + + + + {title} + + +

{title}

+ + + + \ No newline at end of file diff --git a/test/helpers.js b/test/helpers.js new file mode 100644 index 000000000..c913ef912 --- /dev/null +++ b/test/helpers.js @@ -0,0 +1,33 @@ +import { createRuntime } from '../lib/runtime.js'; +import { loadConfig } from '../lib/config.js'; +import * as assert from 'uvu/assert'; + +export function setup(Suite, fixturePath) { + let runtime, setupError; + + Suite.before(async (context) => { + const astroConfig = await loadConfig(new URL(fixturePath, import.meta.url).pathname); + + const logging = { + level: 'error', + dest: process.stderr, + }; + + try { + runtime = await createRuntime(astroConfig, { logging }); + } catch (err) { + console.error(err); + setupError = err; + } + + context.runtime = runtime; + }); + + Suite.after(async () => { + (await runtime) && runtime.shutdown(); + }); + + Suite('No errors creating a runtime', () => { + assert.equal(setupError, undefined); + }); +}