diff options
author | 2022-04-21 12:10:06 -0400 | |
---|---|---|
committer | 2022-04-21 12:10:06 -0400 | |
commit | ae9ac5cbdceba0687d83d56d9d5f80479ab88710 (patch) | |
tree | 26fc15585e7ed77fd47607f5e7211050813fa642 /packages/integrations | |
parent | 3cdc5f1bfb7801be93c1df582b2ec1484566759b (diff) | |
download | astro-ae9ac5cbdceba0687d83d56d9d5f80479ab88710.tar.gz astro-ae9ac5cbdceba0687d83d56d9d5f80479ab88710.tar.zst astro-ae9ac5cbdceba0687d83d56d9d5f80479ab88710.zip |
Fixes using React.lazy and Suspense (#3160)
* Revert "Revert "Fixes using React.lazy and Suspense""
This reverts commit e621c2f7d3844e950168f4198e4dd1c6f43031d0.
* Adds a changeset
* Fix ts errors
* Remove netlify metadata folder
Diffstat (limited to 'packages/integrations')
14 files changed, 118 insertions, 8 deletions
diff --git a/packages/integrations/deno/src/index.ts b/packages/integrations/deno/src/index.ts index d1b3b14ba..f0658f2c8 100644 --- a/packages/integrations/deno/src/index.ts +++ b/packages/integrations/deno/src/index.ts @@ -23,6 +23,10 @@ export default function createIntegration(args?: Options): AstroIntegration { }, 'astro:build:setup': ({ vite, target }) => { if (target === 'server') { + vite.resolve = vite.resolve || {}; + vite.resolve.alias = vite.resolve.alias || {}; + const alias = vite.resolve.alias as Record<string, string>; + alias['react-dom/server'] = 'react-dom/server.browser' vite.ssr = { noExternal: true, }; diff --git a/packages/integrations/deno/test/basics.test.js b/packages/integrations/deno/test/basics.test.js index 115883466..42efc87d9 100644 --- a/packages/integrations/deno/test/basics.test.js +++ b/packages/integrations/deno/test/basics.test.js @@ -13,6 +13,9 @@ Deno.test({ assertEquals(resp.status, 200); const html = await resp.text(); assert(html); + const doc = new DOMParser().parseFromString(html, `text/html`); + const div = doc.querySelector("#react"); + assert(div, 'div exists'); }); }, }); diff --git a/packages/integrations/deno/test/fixtures/basics/astro.config.mjs b/packages/integrations/deno/test/fixtures/basics/astro.config.mjs index e56fe2e98..af5f1aa6b 100644 --- a/packages/integrations/deno/test/fixtures/basics/astro.config.mjs +++ b/packages/integrations/deno/test/fixtures/basics/astro.config.mjs @@ -1,8 +1,10 @@ import { defineConfig } from 'astro/config'; import deno from '@astrojs/deno'; +import react from '@astrojs/react'; export default defineConfig({ adapter: deno(), + integrations: [react()], experimental: { ssr: true } diff --git a/packages/integrations/deno/test/fixtures/basics/package.json b/packages/integrations/deno/test/fixtures/basics/package.json index a623de766..7800873f7 100644 --- a/packages/integrations/deno/test/fixtures/basics/package.json +++ b/packages/integrations/deno/test/fixtures/basics/package.json @@ -4,6 +4,7 @@ "private": true, "dependencies": { "astro": "workspace:*", - "@astrojs/deno": "workspace:*" + "@astrojs/deno": "workspace:*", + "@astrojs/react": "workspace:*" } } diff --git a/packages/integrations/deno/test/fixtures/basics/src/components/React.jsx b/packages/integrations/deno/test/fixtures/basics/src/components/React.jsx new file mode 100644 index 000000000..42c74a7aa --- /dev/null +++ b/packages/integrations/deno/test/fixtures/basics/src/components/React.jsx @@ -0,0 +1,7 @@ +import React from 'react'; + +export default function() { + return ( + <div id="react">testing</div> + ); +} diff --git a/packages/integrations/deno/test/fixtures/basics/src/pages/index.astro b/packages/integrations/deno/test/fixtures/basics/src/pages/index.astro index 9a37d684b..4eb15f2f0 100644 --- a/packages/integrations/deno/test/fixtures/basics/src/pages/index.astro +++ b/packages/integrations/deno/test/fixtures/basics/src/pages/index.astro @@ -1,5 +1,5 @@ --- - +import ReactComponent from '../components/React.jsx'; --- <html> <head> @@ -8,5 +8,6 @@ </head> <body> <h1>Basic App on Deno</h1> + <ReactComponent /> </body> </html> diff --git a/packages/integrations/netlify/src/integration-edge-functions.ts b/packages/integrations/netlify/src/integration-edge-functions.ts index 0165c7831..b76617f1e 100644 --- a/packages/integrations/netlify/src/integration-edge-functions.ts +++ b/packages/integrations/netlify/src/integration-edge-functions.ts @@ -86,6 +86,10 @@ export function netlifyEdgeFunctions({ dist }: NetlifyEdgeFunctionsOptions = {}) }, 'astro:build:setup': ({ vite, target }) => { if (target === 'server') { + vite.resolve = vite.resolve || {}; + vite.resolve.alias = vite.resolve.alias || {}; + const alias = vite.resolve.alias as Record<string, string>; + alias['react-dom/server'] = 'react-dom/server.browser' vite.ssr = { noExternal: true, }; diff --git a/packages/integrations/netlify/test/edge-functions/deps.ts b/packages/integrations/netlify/test/edge-functions/deps.ts index f3e46181a..1b23a94f7 100644 --- a/packages/integrations/netlify/test/edge-functions/deps.ts +++ b/packages/integrations/netlify/test/edge-functions/deps.ts @@ -1,3 +1,4 @@ // @ts-nocheck export { fromFileUrl } from 'https://deno.land/std@0.110.0/path/mod.ts'; export { assertEquals, assert } from 'https://deno.land/std@0.132.0/testing/asserts.ts'; +export * from 'https://deno.land/x/deno_dom/deno-dom-wasm.ts'; diff --git a/packages/integrations/netlify/test/edge-functions/edge-basic.test.ts b/packages/integrations/netlify/test/edge-functions/edge-basic.test.ts index 7fc8877bd..0b29fc1a9 100644 --- a/packages/integrations/netlify/test/edge-functions/edge-basic.test.ts +++ b/packages/integrations/netlify/test/edge-functions/edge-basic.test.ts @@ -1,7 +1,7 @@ // @ts-ignore import { runBuild } from './test-utils.ts'; // @ts-ignore -import { assertEquals, assert } from './deps.ts'; +import { assertEquals, assert, DOMParser } from './deps.ts'; // @ts-ignore Deno.test({ @@ -9,12 +9,17 @@ Deno.test({ async fn() { let close = await runBuild('./fixtures/edge-basic/'); const { default: handler } = await import( - './fixtures/edge-basic/dist/edge-functions/entry.mjs' + './fixtures/edge-basic/dist/edge-functions/entry.js' ); const response = await handler(new Request('http://example.com/')); assertEquals(response.status, 200); const html = await response.text(); assert(html, 'got some html'); + + const doc = new DOMParser().parseFromString(html, `text/html`)!; + const div = doc.querySelector('#react'); + assert(div, 'div exists'); + await close(); }, }); diff --git a/packages/integrations/netlify/test/edge-functions/fixtures/edge-basic/astro.config.mjs b/packages/integrations/netlify/test/edge-functions/fixtures/edge-basic/astro.config.mjs index c55135e43..d7c899264 100644 --- a/packages/integrations/netlify/test/edge-functions/fixtures/edge-basic/astro.config.mjs +++ b/packages/integrations/netlify/test/edge-functions/fixtures/edge-basic/astro.config.mjs @@ -1,10 +1,12 @@ import { defineConfig } from 'astro/config'; import { netlifyEdgeFunctions } from '@astrojs/netlify'; +import react from "@astrojs/react"; export default defineConfig({ adapter: netlifyEdgeFunctions({ dist: new URL('./dist/', import.meta.url), }), + integrations: [react()], experimental: { ssr: true } diff --git a/packages/integrations/netlify/test/edge-functions/fixtures/edge-basic/package.json b/packages/integrations/netlify/test/edge-functions/fixtures/edge-basic/package.json index bbda2476b..16ff30088 100644 --- a/packages/integrations/netlify/test/edge-functions/fixtures/edge-basic/package.json +++ b/packages/integrations/netlify/test/edge-functions/fixtures/edge-basic/package.json @@ -4,6 +4,7 @@ "private": true, "dependencies": { "astro": "workspace:*", + "@astrojs/react": "workspace:*", "@astrojs/netlify": "workspace:*" } } diff --git a/packages/integrations/netlify/test/edge-functions/fixtures/edge-basic/src/components/React.jsx b/packages/integrations/netlify/test/edge-functions/fixtures/edge-basic/src/components/React.jsx new file mode 100644 index 000000000..c6cf39aa5 --- /dev/null +++ b/packages/integrations/netlify/test/edge-functions/fixtures/edge-basic/src/components/React.jsx @@ -0,0 +1,7 @@ +import React from 'react'; + +export default function() { + return ( + <div id="react">testing</div> + ) +} diff --git a/packages/integrations/netlify/test/edge-functions/fixtures/edge-basic/src/pages/index.astro b/packages/integrations/netlify/test/edge-functions/fixtures/edge-basic/src/pages/index.astro index a87de65db..80d2eed75 100644 --- a/packages/integrations/netlify/test/edge-functions/fixtures/edge-basic/src/pages/index.astro +++ b/packages/integrations/netlify/test/edge-functions/fixtures/edge-basic/src/pages/index.astro @@ -1,3 +1,6 @@ +--- +import ReactComponent from '../components/React.jsx'; +--- <html> <head><title>Testing</title></head> <body> @@ -6,5 +9,6 @@ <ul> <li><a href="/two/">Two</a></li> </ul> + <ReactComponent /> </body> </html> diff --git a/packages/integrations/react/server.js b/packages/integrations/react/server.js index 6ae49e7bc..b41492a7a 100644 --- a/packages/integrations/react/server.js +++ b/packages/integrations/react/server.js @@ -12,7 +12,7 @@ function errorIsComingFromPreactComponent(err) { ); } -function check(Component, props, children) { +async function check(Component, props, children) { // Note: there are packages that do some unholy things to create "components". // Checking the $$typeof property catches most of these patterns. if (typeof Component === 'object') { @@ -42,7 +42,7 @@ function check(Component, props, children) { return React.createElement('div'); } - renderToStaticMarkup(Tester, props, children, {}); + await renderToStaticMarkup(Tester, props, children, {}); if (error) { throw error; @@ -50,7 +50,13 @@ function check(Component, props, children) { return isReactComponent; } -function renderToStaticMarkup(Component, props, children, metadata) { +async function getNodeWritable() { + let nodeStreamBuiltinModuleName = 'stream'; + let { Writable } = await import(nodeStreamBuiltinModuleName); + return Writable; +} + +async function renderToStaticMarkup(Component, props, children, metadata) { delete props['class']; const vnode = React.createElement(Component, { ...props, @@ -59,12 +65,74 @@ function renderToStaticMarkup(Component, props, children, metadata) { let html; if (metadata && metadata.hydrate) { html = ReactDOM.renderToString(vnode); + if('renderToReadableStream' in ReactDOM) { + html = await renderToReadableStreamAsync(vnode); + } else { + html = await renderToPipeableStreamAsync(vnode); + } } else { - html = ReactDOM.renderToStaticMarkup(vnode); + if('renderToReadableStream' in ReactDOM) { + html = await renderToReadableStreamAsync(vnode); + } else { + html = await renderToStaticNodeStreamAsync(vnode); + } + } return { html }; } +async function renderToPipeableStreamAsync(vnode) { + const Writable = await getNodeWritable(); + let html = ''; + return new Promise((resolve, reject) => { + let error = undefined; + let stream = ReactDOM.renderToPipeableStream(vnode, { + onError(err) { + error = err; + reject(error); + }, + onAllReady() { + stream.pipe(new Writable({ + write(chunk, _encoding, callback) { + html += chunk.toString('utf-8'); + callback(); + }, + destroy() { + resolve(html); + } + })); + } + }); + }); +} + +async function renderToStaticNodeStreamAsync(vnode) { + const Writable = await getNodeWritable(); + let html = ''; + return new Promise((resolve) => { + let stream = ReactDOM.renderToStaticNodeStream(vnode); + stream.pipe(new Writable({ + write(chunk, _encoding, callback) { + html += chunk.toString('utf-8'); + callback(); + }, + destroy() { + resolve(html); + } + })); + }); +} + +async function renderToReadableStreamAsync(vnode) { + const decoder = new TextDecoder(); + const stream = await ReactDOM.renderToReadableStream(vnode); + let html = ''; + for await(const chunk of stream) { + html += decoder.decode(chunk); + } + return html; +} + export default { check, renderToStaticMarkup, |