From 25c1abff10a9b46468b750ab967e9b8be44ac38a Mon Sep 17 00:00:00 2001 From: FredKSchott Date: Thu, 31 Mar 2022 12:02:15 +0000 Subject: [PATCH 01/12] [ci] collect stats --- scripts/stats/stats.csv | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/stats/stats.csv b/scripts/stats/stats.csv index 3a8ec9bd1..7ab3641a8 100644 --- a/scripts/stats/stats.csv +++ b/scripts/stats/stats.csv @@ -1,4 +1,5 @@ Date,Commits (24hr),Issues (24hr),Issues:BUG (24hr),Issues:RFC (24hr),Issues:DOC (24hr),PRs (24hr),Open PRs,Open Issues,Bugs: Needs Triage,Bugs: Accepted,RFC: In Progress,RFC: Accepted,Date (ISO) +"Thursday, March 31, 2022",6,4,4,0,0,6,10,93,46,41,0,0,"2022-03-31T12:02:11.044Z" "Wednesday, March 30, 2022",9,2,2,0,0,10,10,90,43,41,0,0,"2022-03-30T12:02:39.303Z" "Tuesday, March 29, 2022",19,8,8,0,0,9,5,88,41,41,0,0,"2022-03-29T12:06:39.897Z" "Monday, March 28, 2022",1,7,7,0,0,2,8,83,36,41,0,0,"2022-03-28T12:02:00.954Z" From 57f48b27019bbad5c8d61808291dc8bc6cdedb52 Mon Sep 17 00:00:00 2001 From: "Fred K. Schott" Date: Thu, 31 Mar 2022 09:51:29 -0700 Subject: [PATCH 02/12] Add support for React 18 in @astrojs/react (#2947) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * First pass at supporting React 18 in @astrojs/react * Try marking React 18’s `react-dom/client` as external * Try a different approach to importing different React versions * Allow resolving JSON modules * Revert "Allow resolving JSON modules" This reverts commit 5279b7249c52b20fd74fe48f9f1047c9b3a117dc. * Try the separate client entrypoint approach from #2946 * Clean up diff * Trying to see something * Just keep swimming… 🐠 * update to support react 18 * add changeset * add docs Co-authored-by: delucis --- .changeset/ninety-jars-swim.md | 5 ++ .../fixtures/react-component/package.json | 5 +- packages/integrations/react/client-v17.js | 13 ++++ packages/integrations/react/client.js | 8 +-- packages/integrations/react/package.json | 8 ++- packages/integrations/react/server-v17.js | 67 +++++++++++++++++++ packages/integrations/react/server.js | 2 +- packages/integrations/react/src/index.ts | 17 +++-- pnpm-lock.yaml | 20 ++++-- 9 files changed, 127 insertions(+), 18 deletions(-) create mode 100644 .changeset/ninety-jars-swim.md create mode 100644 packages/integrations/react/client-v17.js create mode 100644 packages/integrations/react/server-v17.js diff --git a/.changeset/ninety-jars-swim.md b/.changeset/ninety-jars-swim.md new file mode 100644 index 000000000..dd7c79c13 --- /dev/null +++ b/.changeset/ninety-jars-swim.md @@ -0,0 +1,5 @@ +--- +'@astrojs/react': minor +--- + +Add support for React v18 diff --git a/packages/astro/test/fixtures/react-component/package.json b/packages/astro/test/fixtures/react-component/package.json index 020549b3f..7ab49d4c0 100644 --- a/packages/astro/test/fixtures/react-component/package.json +++ b/packages/astro/test/fixtures/react-component/package.json @@ -5,6 +5,9 @@ "dependencies": { "@astrojs/react": "workspace:*", "@astrojs/vue": "workspace:*", - "astro": "workspace:*" + "astro": "workspace:*", + "react": "^17.0.2", + "react-dom": "^17.0.2", + "vue": "^3.2.31" } } diff --git a/packages/integrations/react/client-v17.js b/packages/integrations/react/client-v17.js new file mode 100644 index 000000000..a6bc7d3bc --- /dev/null +++ b/packages/integrations/react/client-v17.js @@ -0,0 +1,13 @@ +import { createElement } from 'react'; +import { hydrate } from 'react-dom'; +import StaticHtml from './static-html.js'; + +export default (element) => (Component, props, children) => + hydrate( + createElement( + Component, + { ...props, suppressHydrationWarning: true }, + children != null ? createElement(StaticHtml, { value: children, suppressHydrationWarning: true }) : children + ), + element + ); diff --git a/packages/integrations/react/client.js b/packages/integrations/react/client.js index a6bc7d3bc..11d63cfcb 100644 --- a/packages/integrations/react/client.js +++ b/packages/integrations/react/client.js @@ -1,13 +1,13 @@ import { createElement } from 'react'; -import { hydrate } from 'react-dom'; +import { hydrateRoot } from 'react-dom/client'; import StaticHtml from './static-html.js'; export default (element) => (Component, props, children) => - hydrate( + hydrateRoot( + element, createElement( Component, { ...props, suppressHydrationWarning: true }, children != null ? createElement(StaticHtml, { value: children, suppressHydrationWarning: true }) : children - ), - element + ) ); diff --git a/packages/integrations/react/package.json b/packages/integrations/react/package.json index 64c79afe2..b1a2be46d 100644 --- a/packages/integrations/react/package.json +++ b/packages/integrations/react/package.json @@ -21,7 +21,9 @@ "exports": { ".": "./dist/index.js", "./client.js": "./client.js", + "./client-v17.js": "./client-v17.js", "./server.js": "./server.js", + "./server-v17.js": "./server-v17.js", "./package.json": "./package.json", "./jsx-runtime": "./jsx-runtime.js" }, @@ -34,14 +36,16 @@ "@babel/plugin-transform-react-jsx": "^7.17.3" }, "devDependencies": { + "@types/react": "^17.0.43", + "@types/react-dom": "^17.0.14", "astro": "workspace:*", "astro-scripts": "workspace:*", "react": "^17.0.2", "react-dom": "^17.0.2" }, "peerDependencies": { - "react": "^17.0.2", - "react-dom": "^17.0.2" + "react": "^17.0.2 || ^18.0.0", + "react-dom": "^17.0.2 || ^18.0.0" }, "engines": { "node": "^14.15.0 || >=16.0.0" diff --git a/packages/integrations/react/server-v17.js b/packages/integrations/react/server-v17.js new file mode 100644 index 000000000..1c0c41286 --- /dev/null +++ b/packages/integrations/react/server-v17.js @@ -0,0 +1,67 @@ +import React from 'react'; +import ReactDOM from 'react-dom/server.js'; +import StaticHtml from './static-html.js'; + +const reactTypeof = Symbol.for('react.element'); + +function errorIsComingFromPreactComponent(err) { + return err.message && (err.message.startsWith("Cannot read property '__H'") || err.message.includes("(reading '__H')")); +} + +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') { + const $$typeof = Component['$$typeof']; + return $$typeof && $$typeof.toString().slice('Symbol('.length).startsWith('react'); + } + if (typeof Component !== 'function') return false; + + if (Component.prototype != null && typeof Component.prototype.render === 'function') { + return React.Component.isPrototypeOf(Component) || React.PureComponent.isPrototypeOf(Component); + } + + let error = null; + let isReactComponent = false; + function Tester(...args) { + try { + const vnode = Component(...args); + if (vnode && vnode['$$typeof'] === reactTypeof) { + isReactComponent = true; + } + } catch (err) { + if (!errorIsComingFromPreactComponent(err)) { + error = err; + } + } + + return React.createElement('div'); + } + + renderToStaticMarkup(Tester, props, children, {}); + + if (error) { + throw error; + } + return isReactComponent; +} + +function renderToStaticMarkup(Component, props, children, metadata) { + delete props['class']; + const vnode = React.createElement(Component, { + ...props, + children: children != null ? React.createElement(StaticHtml, { value: children }) : undefined, + }); + let html; + if (metadata && metadata.hydrate) { + html = ReactDOM.renderToString(vnode); + } else { + html = ReactDOM.renderToStaticMarkup(vnode); + } + return { html }; +} + +export default { + check, + renderToStaticMarkup, +}; diff --git a/packages/integrations/react/server.js b/packages/integrations/react/server.js index 1c0c41286..e102b57fe 100644 --- a/packages/integrations/react/server.js +++ b/packages/integrations/react/server.js @@ -1,5 +1,5 @@ import React from 'react'; -import ReactDOM from 'react-dom/server.js'; +import ReactDOM from 'react-dom/server'; import StaticHtml from './static-html.js'; const reactTypeof = Symbol.for('react.element'); diff --git a/packages/integrations/react/src/index.ts b/packages/integrations/react/src/index.ts index 128c6406d..2ea2dd5fb 100644 --- a/packages/integrations/react/src/index.ts +++ b/packages/integrations/react/src/index.ts @@ -1,10 +1,11 @@ import { AstroIntegration } from 'astro'; +import { version as ReactVersion } from 'react-dom'; function getRenderer() { return { name: '@astrojs/react', - clientEntrypoint: '@astrojs/react/client.js', - serverEntrypoint: '@astrojs/react/server.js', + clientEntrypoint: ReactVersion.startsWith('18.') ? '@astrojs/react/client.js' : '@astrojs/react/client-v17.js', + serverEntrypoint: ReactVersion.startsWith('18.') ? '@astrojs/react/server.js' : '@astrojs/react/server-v17.js', jsxImportSource: 'react', jsxTransformOptions: async () => { const { @@ -17,7 +18,11 @@ function getRenderer() { {}, { runtime: 'automatic', - importSource: '@astrojs/react', + // This option tells the JSX transform how to construct the "*/jsx-runtime" import. + // In React v17, we had to shim this due to an export map issue in React. + // In React v18, this issue was fixed and we can import "react/jsx-runtime" directly. + // See `./jsx-runtime.js` for more details. + importSource: ReactVersion.startsWith('18.') ? 'react' : '@astrojs/react', } ), ], @@ -29,14 +34,14 @@ function getRenderer() { function getViteConfiguration() { return { optimizeDeps: { - include: ['@astrojs/react/client.js', 'react', 'react/jsx-runtime', 'react/jsx-dev-runtime', 'react-dom'], - exclude: ['@astrojs/react/server.js'], + include: [ReactVersion.startsWith('18.') ? '@astrojs/react/client.js' : '@astrojs/react/client-v17.js', 'react', 'react/jsx-runtime', 'react/jsx-dev-runtime', 'react-dom'], + exclude: [ReactVersion.startsWith('18.') ? '@astrojs/react/server.js' : '@astrojs/react/server-v17.js'], }, resolve: { dedupe: ['react', 'react-dom'], }, ssr: { - external: ['react-dom/server.js'], + external: ReactVersion.startsWith('18.') ? ['react-dom/server', 'react-dom/client'] : ['react-dom/server.js', 'react-dom/client.js'], }, }; } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d6fe40282..99da4e7df 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1011,10 +1011,16 @@ importers: '@astrojs/react': workspace:* '@astrojs/vue': workspace:* astro: workspace:* + react: ^17.0.2 + react-dom: ^17.0.2 + vue: ^3.2.31 dependencies: '@astrojs/react': link:../../../../integrations/react '@astrojs/vue': link:../../../../integrations/vue astro: link:../../.. + react: 17.0.2 + react-dom: 17.0.2_react@17.0.2 + vue: 3.2.31 packages/astro/test/fixtures/remote-css: specifiers: @@ -1276,6 +1282,8 @@ importers: packages/integrations/react: specifiers: '@babel/plugin-transform-react-jsx': ^7.17.3 + '@types/react': ^17.0.43 + '@types/react-dom': ^17.0.14 astro: workspace:* astro-scripts: workspace:* react: ^17.0.2 @@ -1283,6 +1291,8 @@ importers: dependencies: '@babel/plugin-transform-react-jsx': 7.17.3 devDependencies: + '@types/react': 17.0.43 + '@types/react-dom': 17.0.14 astro: link:../../astro astro-scripts: link:../../../scripts react: 17.0.2 @@ -4009,19 +4019,23 @@ packages: /@types/prop-types/15.7.4: resolution: {integrity: sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ==} - dev: false /@types/pug/2.0.6: resolution: {integrity: sha512-SnHmG9wN1UVmagJOnyo/qkk0Z7gejYxOYYmaAwr5u2yFYfsupN3sg10kyzN8Hep/2zbHxCnsumxOoRIRMBwKCg==} dev: false + /@types/react-dom/17.0.14: + resolution: {integrity: sha512-H03xwEP1oXmSfl3iobtmQ/2dHF5aBHr8aUMwyGZya6OW45G+xtdzmq6HkncefiBt5JU8DVyaWl/nWZbjZCnzAQ==} + dependencies: + '@types/react': 17.0.43 + dev: true + /@types/react/17.0.43: resolution: {integrity: sha512-8Q+LNpdxf057brvPu1lMtC5Vn7J119xrP1aq4qiaefNioQUYANF/CYeK4NsKorSZyUGJ66g0IM+4bbjwx45o2A==} dependencies: '@types/prop-types': 15.7.4 '@types/scheduler': 0.16.2 csstype: 3.0.11 - dev: false /@types/resolve/1.17.1: resolution: {integrity: sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==} @@ -4053,7 +4067,6 @@ packages: /@types/scheduler/0.16.2: resolution: {integrity: sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==} - dev: false /@types/semver/6.2.3: resolution: {integrity: sha512-KQf+QAMWKMrtBMsB8/24w53tEsxllMj6TuA80TT/5igJalLI/zm0L3oXRbIAl4Ohfc85gyHX/jhMwsVkmhLU4A==} @@ -5236,7 +5249,6 @@ packages: /csstype/3.0.11: resolution: {integrity: sha512-sa6P2wJ+CAbgyy4KFssIb/JNMLxFvKF1pCYCSXS8ZMuqZnMsrxqI2E5sPyoTpxoPU/gVZMzr2zjOfg8GIZOMsw==} - dev: false /csv-generate/3.4.3: resolution: {integrity: sha512-w/T+rqR0vwvHqWs/1ZyMDWtHHSJaN06klRqJXBEpDJaM/+dZkso0OKh1VcuuYvK3XM53KysVNq8Ko/epCK8wOw==} From bdb9ba1c34adbfd1d0dfdd6abc3db808f77683bd Mon Sep 17 00:00:00 2001 From: matthewp Date: Thu, 31 Mar 2022 16:52:34 +0000 Subject: [PATCH 03/12] [ci] format --- packages/integrations/react/src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/integrations/react/src/index.ts b/packages/integrations/react/src/index.ts index 2ea2dd5fb..25899a025 100644 --- a/packages/integrations/react/src/index.ts +++ b/packages/integrations/react/src/index.ts @@ -35,7 +35,7 @@ function getViteConfiguration() { return { optimizeDeps: { include: [ReactVersion.startsWith('18.') ? '@astrojs/react/client.js' : '@astrojs/react/client-v17.js', 'react', 'react/jsx-runtime', 'react/jsx-dev-runtime', 'react-dom'], - exclude: [ReactVersion.startsWith('18.') ? '@astrojs/react/server.js' : '@astrojs/react/server-v17.js'], + exclude: [ReactVersion.startsWith('18.') ? '@astrojs/react/server.js' : '@astrojs/react/server-v17.js'], }, resolve: { dedupe: ['react', 'react-dom'], From 3a4dc9e0a7a21493f36426814a6fbef4c95ed535 Mon Sep 17 00:00:00 2001 From: "Fred K. Schott" Date: Thu, 31 Mar 2022 10:01:05 -0700 Subject: [PATCH 04/12] React 18 monorepo upgrade (#2948) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * First pass at supporting React 18 in @astrojs/react * Try marking React 18’s `react-dom/client` as external * Try a different approach to importing different React versions * Allow resolving JSON modules * Revert "Allow resolving JSON modules" This reverts commit 5279b7249c52b20fd74fe48f9f1047c9b3a117dc. * Try the separate client entrypoint approach from #2946 * Clean up diff * Trying to see something * Just keep swimming… 🐠 * update to support react 18 * update React to React 18 across the board Co-authored-by: delucis Co-authored-by: Matthew Phillips --- examples/docs/package.json | 4 +- examples/framework-multiple/package.json | 4 +- examples/framework-react/package.json | 4 +- examples/integrations-playground/package.json | 4 +- examples/subpath/package.json | 4 +- examples/with-markdown/package.json | 4 +- examples/with-nanostores/package.json | 4 +- .../fixtures/react-component/package.json | 4 +- packages/integrations/react/package.json | 4 +- packages/integrations/react/src/index.ts | 2 +- .../renderers/renderer-react/package.json | 4 +- pnpm-lock.yaml | 118 +++++++++--------- 12 files changed, 79 insertions(+), 81 deletions(-) diff --git a/examples/docs/package.json b/examples/docs/package.json index dba62dc47..e7cf7282a 100644 --- a/examples/docs/package.json +++ b/examples/docs/package.json @@ -14,8 +14,8 @@ "@docsearch/react": "^3.0.0", "@types/react": "^17.0.43", "preact": "^10.6.6", - "react": "^17.0.2", - "react-dom": "^17.0.2" + "react": "^18.0.0", + "react-dom": "^18.0.0" }, "devDependencies": { "@astrojs/preact": "^0.0.2", diff --git a/examples/framework-multiple/package.json b/examples/framework-multiple/package.json index 8f95c6935..4328d130e 100644 --- a/examples/framework-multiple/package.json +++ b/examples/framework-multiple/package.json @@ -21,8 +21,8 @@ "@webcomponents/template-shadowroot": "^0.1.0", "lit": "^2.2.1", "preact": "^10.6.6", - "react": "^17.0.2", - "react-dom": "^17.0.2", + "react": "^18.0.0", + "react-dom": "^18.0.0", "solid-js": "^1.3.13", "svelte": "^3.46.4", "vue": "^3.2.31" diff --git a/examples/framework-react/package.json b/examples/framework-react/package.json index 69bfc446c..4cdd93049 100644 --- a/examples/framework-react/package.json +++ b/examples/framework-react/package.json @@ -13,7 +13,7 @@ "astro": "^0.25.4" }, "dependencies": { - "react": "^17.0.2", - "react-dom": "^17.0.2" + "react": "^18.0.0", + "react-dom": "^18.0.0" } } diff --git a/examples/integrations-playground/package.json b/examples/integrations-playground/package.json index 6c08c5f46..848bd2c4c 100644 --- a/examples/integrations-playground/package.json +++ b/examples/integrations-playground/package.json @@ -21,8 +21,8 @@ "@webcomponents/template-shadowroot": "^0.1.0", "lit": "^2.2.1", "preact": "^10.6.6", - "react": "^17.0.2", - "react-dom": "^17.0.2", + "react": "^18.0.0", + "react-dom": "^18.0.0", "solid-js": "^1.3.13", "svelte": "^3.46.4", "vue": "^3.2.31" diff --git a/examples/subpath/package.json b/examples/subpath/package.json index f48f47a11..ea792f73a 100644 --- a/examples/subpath/package.json +++ b/examples/subpath/package.json @@ -14,7 +14,7 @@ "sass": "^1.49.9" }, "dependencies": { - "react": "^17.0.2", - "react-dom": "^17.0.2" + "react": "^18.0.0", + "react-dom": "^18.0.0" } } diff --git a/examples/with-markdown/package.json b/examples/with-markdown/package.json index 843ee33ff..7f96d9ffa 100644 --- a/examples/with-markdown/package.json +++ b/examples/with-markdown/package.json @@ -18,8 +18,8 @@ }, "dependencies": { "preact": "^10.6.6", - "react": "^17.0.2", - "react-dom": "^17.0.2", + "react": "^18.0.0", + "react-dom": "^18.0.0", "svelte": "^3.46.4", "vue": "^3.2.31" } diff --git a/examples/with-nanostores/package.json b/examples/with-nanostores/package.json index 828a8a608..55a60cadb 100644 --- a/examples/with-nanostores/package.json +++ b/examples/with-nanostores/package.json @@ -14,8 +14,8 @@ "@nanostores/vue": "^0.4.1", "nanostores": "^0.5.12", "preact": "^10.6.6", - "react": "^17.0.2", - "react-dom": "^17.0.2", + "react": "^18.0.0", + "react-dom": "^18.0.0", "solid-nanostores": "0.0.6", "vue": "^3.2.31" }, diff --git a/packages/astro/test/fixtures/react-component/package.json b/packages/astro/test/fixtures/react-component/package.json index 7ab49d4c0..f90d42071 100644 --- a/packages/astro/test/fixtures/react-component/package.json +++ b/packages/astro/test/fixtures/react-component/package.json @@ -6,8 +6,8 @@ "@astrojs/react": "workspace:*", "@astrojs/vue": "workspace:*", "astro": "workspace:*", - "react": "^17.0.2", - "react-dom": "^17.0.2", + "react": "^18.0.0", + "react-dom": "^18.0.0", "vue": "^3.2.31" } } diff --git a/packages/integrations/react/package.json b/packages/integrations/react/package.json index b1a2be46d..1184ce8d3 100644 --- a/packages/integrations/react/package.json +++ b/packages/integrations/react/package.json @@ -40,8 +40,8 @@ "@types/react-dom": "^17.0.14", "astro": "workspace:*", "astro-scripts": "workspace:*", - "react": "^17.0.2", - "react-dom": "^17.0.2" + "react": "^18.0.0", + "react-dom": "^18.0.0" }, "peerDependencies": { "react": "^17.0.2 || ^18.0.0", diff --git a/packages/integrations/react/src/index.ts b/packages/integrations/react/src/index.ts index 25899a025..2ea2dd5fb 100644 --- a/packages/integrations/react/src/index.ts +++ b/packages/integrations/react/src/index.ts @@ -35,7 +35,7 @@ function getViteConfiguration() { return { optimizeDeps: { include: [ReactVersion.startsWith('18.') ? '@astrojs/react/client.js' : '@astrojs/react/client-v17.js', 'react', 'react/jsx-runtime', 'react/jsx-dev-runtime', 'react-dom'], - exclude: [ReactVersion.startsWith('18.') ? '@astrojs/react/server.js' : '@astrojs/react/server-v17.js'], + exclude: [ReactVersion.startsWith('18.') ? '@astrojs/react/server.js' : '@astrojs/react/server-v17.js'], }, resolve: { dedupe: ['react', 'react-dom'], diff --git a/packages/renderers/renderer-react/package.json b/packages/renderers/renderer-react/package.json index dece87056..ba35445e7 100644 --- a/packages/renderers/renderer-react/package.json +++ b/packages/renderers/renderer-react/package.json @@ -22,8 +22,8 @@ }, "dependencies": { "@babel/plugin-transform-react-jsx": "^7.17.3", - "react": "^17.0.2", - "react-dom": "^17.0.2" + "react": "^18.0.0", + "react-dom": "^18.0.0" }, "engines": { "node": "^14.15.0 || >=16.0.0" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 99da4e7df..93c0b6626 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -92,16 +92,16 @@ importers: '@types/react': ^17.0.43 astro: ^0.25.4 preact: ^10.6.6 - react: ^17.0.2 - react-dom: ^17.0.2 + react: ^18.0.0 + react-dom: ^18.0.0 dependencies: '@algolia/client-search': 4.13.0 '@docsearch/css': 3.0.0 - '@docsearch/react': 3.0.0_73997327e0ab5ab2aaf50785071cd6bd + '@docsearch/react': 3.0.0_9e0989ed96c3582fc46f3bba1f5ac769 '@types/react': 17.0.43 preact: 10.6.6 - react: 17.0.2 - react-dom: 17.0.2_react@17.0.2 + react: 18.0.0 + react-dom: 18.0.0_react@18.0.0 devDependencies: '@astrojs/preact': link:../../packages/integrations/preact '@astrojs/react': link:../../packages/integrations/react @@ -144,8 +144,8 @@ importers: astro: ^0.25.4 lit: ^2.2.1 preact: ^10.6.6 - react: ^17.0.2 - react-dom: ^17.0.2 + react: ^18.0.0 + react-dom: ^18.0.0 solid-js: ^1.3.13 svelte: ^3.46.4 vue: ^3.2.31 @@ -153,8 +153,8 @@ importers: '@webcomponents/template-shadowroot': 0.1.0 lit: 2.2.1 preact: 10.6.6 - react: 17.0.2 - react-dom: 17.0.2_react@17.0.2 + react: 18.0.0 + react-dom: 18.0.0_react@18.0.0 solid-js: 1.3.13 svelte: 3.46.4 vue: 3.2.31 @@ -182,11 +182,11 @@ importers: specifiers: '@astrojs/react': ^0.0.2 astro: ^0.25.4 - react: ^17.0.2 - react-dom: ^17.0.2 + react: ^18.0.0 + react-dom: ^18.0.0 dependencies: - react: 17.0.2 - react-dom: 17.0.2_react@17.0.2 + react: 18.0.0 + react-dom: 18.0.0_react@18.0.0 devDependencies: '@astrojs/react': link:../../packages/integrations/react astro: link:../../packages/astro @@ -236,8 +236,8 @@ importers: astro: ^0.25.4 lit: ^2.2.1 preact: ^10.6.6 - react: ^17.0.2 - react-dom: ^17.0.2 + react: ^18.0.0 + react-dom: ^18.0.0 solid-js: ^1.3.13 svelte: ^3.46.4 vue: ^3.2.31 @@ -245,8 +245,8 @@ importers: '@webcomponents/template-shadowroot': 0.1.0 lit: 2.2.1 preact: 10.6.6 - react: 17.0.2 - react-dom: 17.0.2_react@17.0.2 + react: 18.0.0 + react-dom: 18.0.0_react@18.0.0 solid-js: 1.3.13 svelte: 3.46.4 vue: 3.2.31 @@ -315,12 +315,12 @@ importers: specifiers: '@astrojs/react': ^0.0.2 astro: ^0.25.4 - react: ^17.0.2 - react-dom: ^17.0.2 + react: ^18.0.0 + react-dom: ^18.0.0 sass: ^1.49.9 dependencies: - react: 17.0.2 - react-dom: 17.0.2_react@17.0.2 + react: 18.0.0 + react-dom: 18.0.0_react@18.0.0 devDependencies: '@astrojs/react': link:../../packages/integrations/react astro: link:../../packages/astro @@ -335,14 +335,14 @@ importers: '@astrojs/vue': ^0.0.2 astro: ^0.25.4 preact: ^10.6.6 - react: ^17.0.2 - react-dom: ^17.0.2 + react: ^18.0.0 + react-dom: ^18.0.0 svelte: ^3.46.4 vue: ^3.2.31 dependencies: preact: 10.6.6 - react: 17.0.2 - react-dom: 17.0.2_react@17.0.2 + react: 18.0.0 + react-dom: 18.0.0_react@18.0.0 svelte: 3.46.4 vue: 3.2.31 devDependencies: @@ -392,18 +392,18 @@ importers: astro: ^0.25.4 nanostores: ^0.5.12 preact: ^10.6.6 - react: ^17.0.2 - react-dom: ^17.0.2 + react: ^18.0.0 + react-dom: ^18.0.0 solid-nanostores: 0.0.6 vue: ^3.2.31 dependencies: '@nanostores/preact': 0.1.3_nanostores@0.5.12+preact@10.6.6 - '@nanostores/react': 0.1.5_f66e5a41ef8212ca2b6be35009893a5b + '@nanostores/react': 0.1.5_33de46f26c75888291546388c72611d1 '@nanostores/vue': 0.4.1_nanostores@0.5.12+vue@3.2.31 nanostores: 0.5.12 preact: 10.6.6 - react: 17.0.2 - react-dom: 17.0.2_react@17.0.2 + react: 18.0.0 + react-dom: 18.0.0_react@18.0.0 solid-nanostores: 0.0.6 vue: 3.2.31 devDependencies: @@ -1011,15 +1011,15 @@ importers: '@astrojs/react': workspace:* '@astrojs/vue': workspace:* astro: workspace:* - react: ^17.0.2 - react-dom: ^17.0.2 + react: ^18.0.0 + react-dom: ^18.0.0 vue: ^3.2.31 dependencies: '@astrojs/react': link:../../../../integrations/react '@astrojs/vue': link:../../../../integrations/vue astro: link:../../.. - react: 17.0.2 - react-dom: 17.0.2_react@17.0.2 + react: 18.0.0 + react-dom: 18.0.0_react@18.0.0 vue: 3.2.31 packages/astro/test/fixtures/remote-css: @@ -1286,8 +1286,8 @@ importers: '@types/react-dom': ^17.0.14 astro: workspace:* astro-scripts: workspace:* - react: ^17.0.2 - react-dom: ^17.0.2 + react: ^18.0.0 + react-dom: ^18.0.0 dependencies: '@babel/plugin-transform-react-jsx': 7.17.3 devDependencies: @@ -1295,8 +1295,8 @@ importers: '@types/react-dom': 17.0.14 astro: link:../../astro astro-scripts: link:../../../scripts - react: 17.0.2 - react-dom: 17.0.2_react@17.0.2 + react: 18.0.0 + react-dom: 18.0.0_react@18.0.0 packages/integrations/sitemap: specifiers: @@ -1458,12 +1458,12 @@ importers: packages/renderers/renderer-react: specifiers: '@babel/plugin-transform-react-jsx': ^7.17.3 - react: ^17.0.2 - react-dom: ^17.0.2 + react: ^18.0.0 + react-dom: ^18.0.0 dependencies: '@babel/plugin-transform-react-jsx': 7.17.3 - react: 17.0.2 - react-dom: 17.0.2_react@17.0.2 + react: 18.0.0 + react-dom: 18.0.0_react@18.0.0 packages/renderers/renderer-solid: specifiers: @@ -3301,7 +3301,7 @@ packages: resolution: {integrity: sha512-1kkV7tkAsiuEd0shunYRByKJe3xQDG2q7wYg24SOw1nV9/2lwEd4WrUYRJC/ukGTl2/kHeFxsaUvtiOy0y6fFA==} dev: false - /@docsearch/react/3.0.0_73997327e0ab5ab2aaf50785071cd6bd: + /@docsearch/react/3.0.0_9e0989ed96c3582fc46f3bba1f5ac769: resolution: {integrity: sha512-yhMacqS6TVQYoBh/o603zszIb5Bl8MIXuOc6Vy617I74pirisDzzcNh0NEaYQt50fVVR3khUbeEhUEWEWipESg==} peerDependencies: '@types/react': '>= 16.8.0 < 18.0.0' @@ -3313,8 +3313,8 @@ packages: '@docsearch/css': 3.0.0 '@types/react': 17.0.43 algoliasearch: 4.13.0 - react: 17.0.2 - react-dom: 17.0.2_react@17.0.2 + react: 18.0.0 + react-dom: 18.0.0_react@18.0.0 transitivePeerDependencies: - '@algolia/client-search' dev: false @@ -3466,7 +3466,7 @@ packages: preact: 10.6.6 dev: false - /@nanostores/react/0.1.5_f66e5a41ef8212ca2b6be35009893a5b: + /@nanostores/react/0.1.5_33de46f26c75888291546388c72611d1: resolution: {integrity: sha512-1XEsszpCDcxNeX21QJ+4mFROdn45ulahJ9oLJEo0IA2HZPkwfjSzG+iSXImqFU5nzo0earvlD09z4C9olf8Sxw==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} peerDependencies: @@ -3475,8 +3475,8 @@ packages: react-dom: '>=16.8.0' dependencies: nanostores: 0.5.12 - react: 17.0.2 - react-dom: 17.0.2_react@17.0.2 + react: 18.0.0 + react-dom: 18.0.0_react@18.0.0 dev: false /@nanostores/vue/0.4.1_nanostores@0.5.12+vue@3.2.31: @@ -8278,6 +8278,7 @@ packages: /object-assign/4.1.1: resolution: {integrity: sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=} engines: {node: '>=0.10.0'} + dev: true /object-hash/2.2.0: resolution: {integrity: sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw==} @@ -8797,22 +8798,20 @@ packages: strip-json-comments: 2.0.1 dev: true - /react-dom/17.0.2_react@17.0.2: - resolution: {integrity: sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA==} + /react-dom/18.0.0_react@18.0.0: + resolution: {integrity: sha512-XqX7uzmFo0pUceWFCt7Gff6IyIMzFUn7QMZrbrQfGxtaxXZIcGQzoNpRLE3fQLnS4XzLLPMZX2T9TRcSrasicw==} peerDependencies: - react: 17.0.2 + react: ^18.0.0 dependencies: loose-envify: 1.4.0 - object-assign: 4.1.1 - react: 17.0.2 - scheduler: 0.20.2 + react: 18.0.0 + scheduler: 0.21.0 - /react/17.0.2: - resolution: {integrity: sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==} + /react/18.0.0: + resolution: {integrity: sha512-x+VL6wbT4JRVPm7EGxXhZ8w8LTROaxPXOqhlGyVSrv0sB1jkyFGgXxJ8LVoPRLvPR6/CIZGFmfzqUa2NYeMr2A==} engines: {node: '>=0.10.0'} dependencies: loose-envify: 1.4.0 - object-assign: 4.1.1 /read-pkg-up/7.0.1: resolution: {integrity: sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==} @@ -9205,11 +9204,10 @@ packages: resolution: {integrity: sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==} dev: false - /scheduler/0.20.2: - resolution: {integrity: sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ==} + /scheduler/0.21.0: + resolution: {integrity: sha512-1r87x5fz9MXqswA2ERLo0EbOAU74DpIUO090gIasYTqlVoJeMcl+Z1Rg7WHz+qtPujhS/hGIt9kxZOYBV3faRQ==} dependencies: loose-envify: 1.4.0 - object-assign: 4.1.1 /section-matter/1.0.0: resolution: {integrity: sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==} From 355c966f80d2557c1e09b50c39d2508751d8848f Mon Sep 17 00:00:00 2001 From: matthewp Date: Thu, 31 Mar 2022 17:02:05 +0000 Subject: [PATCH 05/12] [ci] format --- packages/integrations/react/src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/integrations/react/src/index.ts b/packages/integrations/react/src/index.ts index 2ea2dd5fb..25899a025 100644 --- a/packages/integrations/react/src/index.ts +++ b/packages/integrations/react/src/index.ts @@ -35,7 +35,7 @@ function getViteConfiguration() { return { optimizeDeps: { include: [ReactVersion.startsWith('18.') ? '@astrojs/react/client.js' : '@astrojs/react/client-v17.js', 'react', 'react/jsx-runtime', 'react/jsx-dev-runtime', 'react-dom'], - exclude: [ReactVersion.startsWith('18.') ? '@astrojs/react/server.js' : '@astrojs/react/server-v17.js'], + exclude: [ReactVersion.startsWith('18.') ? '@astrojs/react/server.js' : '@astrojs/react/server-v17.js'], }, resolve: { dedupe: ['react', 'react-dom'], From e8604086929c2807cd00591b5cc5c69cbf481026 Mon Sep 17 00:00:00 2001 From: gtnbssn Date: Fri, 1 Apr 2022 01:13:18 +0800 Subject: [PATCH 06/12] Fix the favicon for the starter example (#2940) --- examples/starter/public/favicon.ico | Bin 83 -> 4286 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/examples/starter/public/favicon.ico b/examples/starter/public/favicon.ico index 7b74f34ee432598897dbf5d8cd907cf71bb0ae90..578ad458b8906c08fbed84f42b045fea04db89d1 100644 GIT binary patch literal 4286 zcmchZF=!M)6ox0}Fc8GdTHG!cdIY>nA!3n2f|wxIl0rn}Hl#=uf>?-!2r&jMEF^_k zh**lGut*gwBmoNv7AaB&2~nbzULg{WBhPQ{ZVzvF_HL8Cb&hv$_s#qN|IO^o>?+mA zuTW6tU%k~z<&{z+7$G%*nRsTcEO|90xy<-G5&JTt%CgZZCDT4%R?+{Vd^wh>P8_)} z`+dF$HQb9!>1o`Ivn;GInlCw{9T@Rt%q+d^T3Ke%cxkk;$v`{s^zCB9nHAv6w$Vbn z8fb<+eQTNM`;rf9#obfGnV#3+OQEUv4gU;{oA@zol%keY9-e>4W>p7AHmH~&!P7f7!Uj` zwgFeQ=<3G4O;mwWO`L!=R-=y3_~-DPjH3W^3f&jjCfC$o#|oGaahSL`_=f?$&Aa+W z2h8oZ+@?NUcjGW|aWJfbM*ZzxzmCPY`b~RobNrrj=rd`=)8-j`iSW64@0_b6?;GYk zNB+-fzOxlqZ?`y{OA$WigtZXa8)#p#=DPYxH=VeC_Q5q9Cv`mvW6*zU&Gnp1;oPM6 zaK_B3j(l^FyJgYeE9RrmDyhE7W2}}nW%ic#0v@i1E!yTey$W)U>fyd+!@2hWQ!Wa==NAtKoj`f3tp4y$Al`e;?)76?AjdaRR>|?&r)~3Git> zb1)a?uiv|R0_{m#A9c;7)eZ1y6l@yQ#oE*>(Z2fG-&&smPa2QTW>m*^K65^~`coP$ z8y5Y?iS<4Gz{Zg##$1mk)u-0;X|!xu^FCr;ce~X<&UWE&pBgqfYmEJTzpK9I%vr%b z3Ksd6qlPJLI%HFfeXK_^|BXiKZC>Ocu(Kk6hD3G-8usLzVG^q00Qh gz)s7ge@$ApxGu7=(6IGIk+uG&HTev01^#CH3$(Wk5&!@I literal 83 zcmXBGOAdfA2nE0!_3gb4Vrz;01<-nYHEt%8-G?oJ(&Vj$T|5&XfqTXLZmu1_m82ow WR7Z&hb5f6rajr!ei7w&Z!pj3SOdsz6 From d10c3dea215bf0c7a4bfd037908c147d0cdffd05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juan=20Mart=C3=ADn=20Seery?= Date: Thu, 31 Mar 2022 14:58:03 -0300 Subject: [PATCH 07/12] fix: `--experimental-ssr` fixes (#2937) * Replaced `--experimental-ssr` with `isBuildingToSSR` * changest * Improved `isBuildingToSSR` a bit * Added `isBuildingToSSR` to more places!!1! * Added `@deprecated` tag * Replaced missing experimentalSsr * Added failing test * Removed test * Re-added experimental ssr flag * Fixed typo Co-authored-by: Matthew Phillips * Fixed deno tests Co-authored-by: Matthew Phillips --- .changeset/flat-radios-cheer.md | 5 +++++ examples/ssr/package.json | 4 ++-- packages/astro/src/@types/astro.ts | 3 ++- packages/astro/src/cli/index.ts | 2 +- packages/astro/src/core/build/generate.ts | 6 ++--- packages/astro/src/core/build/index.ts | 6 ++--- packages/astro/src/core/build/page-data.ts | 3 ++- packages/astro/src/core/build/static-build.ts | 2 +- packages/astro/src/core/config.ts | 7 +----- packages/astro/src/core/endpoint/dev/index.ts | 3 ++- packages/astro/src/core/render/dev/index.ts | 4 +++- packages/astro/src/core/util.ts | 22 ++++++++++++++++++- .../src/vite-plugin-astro-server/index.ts | 6 ++--- packages/astro/test/ssr-api-route.test.js | 4 +--- packages/astro/test/ssr-dynamic.test.js | 4 +--- .../test/fixtures/basics/astro.config.mjs | 3 ++- packages/integrations/deno/test/helpers.js | 2 +- 17 files changed, 54 insertions(+), 32 deletions(-) create mode 100644 .changeset/flat-radios-cheer.md diff --git a/.changeset/flat-radios-cheer.md b/.changeset/flat-radios-cheer.md new file mode 100644 index 000000000..ab01d34dd --- /dev/null +++ b/.changeset/flat-radios-cheer.md @@ -0,0 +1,5 @@ +--- +'astro': patch +--- + +`--experimental-ssr` now is only required when using a 3rd-party adapter diff --git a/examples/ssr/package.json b/examples/ssr/package.json index 401f7e06a..370e79972 100644 --- a/examples/ssr/package.json +++ b/examples/ssr/package.json @@ -3,9 +3,9 @@ "version": "0.0.1", "private": true, "scripts": { - "dev": "astro dev --experimental-ssr", + "dev": "astro dev", "start": "astro dev", - "build": "astro build --experimental-ssr", + "build": "astro build", "server": "node server/server.mjs" }, "devDependencies": { diff --git a/packages/astro/src/@types/astro.ts b/packages/astro/src/@types/astro.ts index 33b03a775..800ab9b23 100644 --- a/packages/astro/src/@types/astro.ts +++ b/packages/astro/src/@types/astro.ts @@ -345,7 +345,8 @@ export interface AstroUserConfig { */ experimentalStaticBuild?: boolean; /** - * Enable a build for SSR support. + * Enable SSR support for 3rd-party adapters. + * Not required when using a built-in adapter. * Default: false */ experimentalSsr?: boolean; diff --git a/packages/astro/src/cli/index.ts b/packages/astro/src/cli/index.ts index 534937d8c..c68a97a74 100644 --- a/packages/astro/src/cli/index.ts +++ b/packages/astro/src/cli/index.ts @@ -39,7 +39,7 @@ function printAstroHelp() { ['--project-root ', 'Specify the path to the project root folder.'], ['--no-sitemap', 'Disable sitemap generation (build only).'], ['--legacy-build', 'Use the build strategy prior to 0.24.0'], - ['--experimental-ssr', 'Enable SSR compilation.'], + ['--experimental-ssr', 'Enable SSR compilation fot 3rd-party adapters.'], ['--drafts', 'Include markdown draft pages in the build.'], ['--verbose', 'Enable verbose logging'], ['--silent', 'Disable logging'], diff --git a/packages/astro/src/core/build/generate.ts b/packages/astro/src/core/build/generate.ts index 7c8e92ce5..5d0c70a41 100644 --- a/packages/astro/src/core/build/generate.ts +++ b/packages/astro/src/core/build/generate.ts @@ -12,7 +12,7 @@ import { BEFORE_HYDRATION_SCRIPT_ID } from '../../vite-plugin-scripts/index.js'; import { call as callEndpoint } from '../endpoint/index.js'; import { render } from '../render/core.js'; import { createLinkStylesheetElementSet, createModuleScriptElementWithSrcSet } from '../render/ssr-element.js'; -import { getOutputFilename } from '../util.js'; +import { getOutputFilename, isBuildingToSSR } from '../util.js'; import { getOutFile, getOutFolder } from './common.js'; import { eachPageData, getPageDataByComponent } from './internal.js'; import type { PageBuildData, SingleFileBuiltModule, StaticBuildOptions } from './types'; @@ -71,7 +71,7 @@ export async function generatePages(result: RollupOutput, opts: StaticBuildOptio const timer = performance.now(); info(opts.logging, null, `\n${bgGreen(black(' generating static routes '))}`); - const ssr = !!opts.astroConfig._ctx.adapter?.serverEntrypoint; + const ssr = isBuildingToSSR(opts.astroConfig); const serverEntry = opts.buildConfig.serverEntry; const outFolder = ssr ? opts.buildConfig.server : opts.astroConfig.dist; const ssrEntryURL = new URL('./' + serverEntry + `?time=${Date.now()}`, outFolder); @@ -197,7 +197,7 @@ async function generatePath(pathname: string, opts: StaticBuildOptions, gopts: G route: pageData.route, routeCache, site: astroConfig.buildOptions.site, - ssr: opts.astroConfig.buildOptions.experimentalSsr, + ssr: isBuildingToSSR(opts.astroConfig), }; let body: string; diff --git a/packages/astro/src/core/build/index.ts b/packages/astro/src/core/build/index.ts index 02e1898f8..db876176a 100644 --- a/packages/astro/src/core/build/index.ts +++ b/packages/astro/src/core/build/index.ts @@ -17,7 +17,7 @@ import { staticBuild } from './static-build.js'; import { RouteCache } from '../render/route-cache.js'; import { runHookBuildDone, runHookBuildStart, runHookConfigDone, runHookConfigSetup } from '../../integrations/index.js'; import { getTimeStat } from './util.js'; -import { createSafeError } from '../util.js'; +import { createSafeError, isBuildingToSSR } from '../util.js'; import { fixViteErrorMessage } from '../errors.js'; export interface BuildOptions { @@ -101,7 +101,7 @@ class AstroBuilder { origin, routeCache: this.routeCache, viteServer, - ssr: this.config.buildOptions.experimentalSsr, + ssr: isBuildingToSSR(this.config), }); // Filter pages by using conditions based on their frontmatter. @@ -182,7 +182,7 @@ class AstroBuilder { await runHookBuildDone({ config: this.config, pages: pageNames, routes: Object.values(allPages).map((pd) => pd.route) }); if (this.logging.level && levels[this.logging.level] <= levels['info']) { - const buildMode = this.config.buildOptions.experimentalSsr ? 'ssr' : 'static'; + const buildMode = isBuildingToSSR(this.config) ? 'ssr' : 'static'; await this.printStats({ logging: this.logging, timeStart: this.timer.init, pageCount: pageNames.length, buildMode }); } } diff --git a/packages/astro/src/core/build/page-data.ts b/packages/astro/src/core/build/page-data.ts index 707c89fd7..c84e29588 100644 --- a/packages/astro/src/core/build/page-data.ts +++ b/packages/astro/src/core/build/page-data.ts @@ -10,6 +10,7 @@ import { debug } from '../logger/core.js'; import { preload as ssrPreload } from '../render/dev/index.js'; import { generateRssFunction } from '../render/rss.js'; import { callGetStaticPaths, RouteCache, RouteCacheEntry } from '../render/route-cache.js'; +import { isBuildingToSSR } from '../util.js'; export interface CollectPagesDataOptions { astroConfig: AstroConfig; @@ -33,7 +34,7 @@ export async function collectPagesData(opts: CollectPagesDataOptions): Promise = {}; const allPages: AllPagesData = {}; - const buildMode = astroConfig.buildOptions.experimentalSsr ? 'ssr' : 'static'; + const buildMode = isBuildingToSSR(astroConfig) ? 'ssr' : 'static'; const dataCollectionLogTimeout = setInterval(() => { info(opts.logging, 'build', 'The data collection step may take longer for larger projects...'); diff --git a/packages/astro/src/core/build/static-build.ts b/packages/astro/src/core/build/static-build.ts index 481d51cfa..4e475afb9 100644 --- a/packages/astro/src/core/build/static-build.ts +++ b/packages/astro/src/core/build/static-build.ts @@ -111,7 +111,7 @@ export async function staticBuild(opts: StaticBuildOptions) { async function ssrBuild(opts: StaticBuildOptions, internals: BuildInternals, input: Set) { const { astroConfig, viteConfig } = opts; - const ssr = astroConfig.buildOptions.experimentalSsr; + const ssr = isBuildingToSSR(astroConfig); const out = ssr ? opts.buildConfig.server : astroConfig.dist; const viteBuildConfig = { diff --git a/packages/astro/src/core/config.ts b/packages/astro/src/core/config.ts index 394c1c42d..97b467e9d 100644 --- a/packages/astro/src/core/config.ts +++ b/packages/astro/src/core/config.ts @@ -261,12 +261,7 @@ function mergeCLIFlags(astroConfig: AstroUserConfig, flags: CLIFlags) { if (typeof flags.host === 'string' || typeof flags.host === 'boolean') astroConfig.devOptions.host = flags.host; if (typeof flags.hostname === 'string') astroConfig.devOptions.hostname = flags.hostname; if (typeof flags.legacyBuild === 'boolean') astroConfig.buildOptions.legacyBuild = flags.legacyBuild; - if (typeof flags.experimentalSsr === 'boolean') { - astroConfig.buildOptions.experimentalSsr = flags.experimentalSsr; - if (flags.experimentalSsr) { - astroConfig.buildOptions.legacyBuild = false; - } - } + if (typeof flags.experimentalSsr === 'boolean') astroConfig.buildOptions.experimentalSsr = flags.experimentalSsr; if (typeof flags.experimentalIntegrations === 'boolean') astroConfig.experimentalIntegrations = flags.experimentalIntegrations; if (typeof flags.drafts === 'boolean') astroConfig.buildOptions.drafts = flags.drafts; return astroConfig; diff --git a/packages/astro/src/core/endpoint/dev/index.ts b/packages/astro/src/core/endpoint/dev/index.ts index da3671bc0..1e7abe8df 100644 --- a/packages/astro/src/core/endpoint/dev/index.ts +++ b/packages/astro/src/core/endpoint/dev/index.ts @@ -1,12 +1,13 @@ import type { EndpointHandler } from '../../../@types/astro'; import type { SSROptions } from '../../render/dev'; import { preload } from '../../render/dev/index.js'; +import { isBuildingToSSR } from '../../util.js'; import { call as callEndpoint } from '../index.js'; export async function call(ssrOpts: SSROptions) { const [, mod] = await preload(ssrOpts); return await callEndpoint(mod as unknown as EndpointHandler, { ...ssrOpts, - ssr: ssrOpts.astroConfig.buildOptions.experimentalSsr, + ssr: isBuildingToSSR(ssrOpts.astroConfig), }); } diff --git a/packages/astro/src/core/render/dev/index.ts b/packages/astro/src/core/render/dev/index.ts index 1ced45a40..b81ef6863 100644 --- a/packages/astro/src/core/render/dev/index.ts +++ b/packages/astro/src/core/render/dev/index.ts @@ -9,6 +9,8 @@ import { createModuleScriptElementWithSrcSet } from '../ssr-element.js'; import { getStylesForURL } from './css.js'; import { getHmrScript } from './hmr.js'; import { injectTags } from './html.js'; +import { isBuildingToSSR } from '../../util.js'; + export interface SSROptions { /** an instance of the AstroConfig */ astroConfig: AstroConfig; @@ -146,7 +148,7 @@ export async function render(renderers: SSRLoadedRenderer[], mod: ComponentInsta route, routeCache, site: astroConfig.buildOptions.site, - ssr: astroConfig.buildOptions.experimentalSsr, + ssr: isBuildingToSSR(astroConfig), }); if (route?.type === 'endpoint' || content.type === 'response') { diff --git a/packages/astro/src/core/util.ts b/packages/astro/src/core/util.ts index 45885e9e8..2ec2a1744 100644 --- a/packages/astro/src/core/util.ts +++ b/packages/astro/src/core/util.ts @@ -139,7 +139,27 @@ export function emptyDir(_dir: URL, skip?: Set): void { } export function isBuildingToSSR(config: AstroConfig): boolean { - return !!config._ctx.adapter?.serverEntrypoint; + const adapter = config._ctx.adapter; + if (!adapter) return false; + + if (typeof adapter.serverEntrypoint === 'string') { + if (!adapter.name.startsWith('@astrojs/') && !config.buildOptions.experimentalSsr) { + throw new Error( + [ + `Server-side rendering (SSR) is still experimental.`, + ``, + `Only official "@astrojs/*" adapters are currently supported.`, + `To enable SSR for 3rd-party adapters, use the "--experimental-ssr" flag.`, + `Breaking changes may occur in this API before Astro v1.0 is released.`, + ``, + ].join('\n') + ); + } else { + return true; + } + } else { + return false; + } } export function emoji(char: string, fallback: string) { diff --git a/packages/astro/src/vite-plugin-astro-server/index.ts b/packages/astro/src/vite-plugin-astro-server/index.ts index 67df56aeb..5d85555af 100644 --- a/packages/astro/src/vite-plugin-astro-server/index.ts +++ b/packages/astro/src/vite-plugin-astro-server/index.ts @@ -6,7 +6,7 @@ import { debug, info, warn, error, LogOptions } from '../core/logger/core.js'; import { getParamsAndProps, GetParamsAndPropsError } from '../core/render/core.js'; import { createRouteManifest, matchRoute } from '../core/routing/index.js'; import stripAnsi from 'strip-ansi'; -import { createSafeError } from '../core/util.js'; +import { createSafeError, isBuildingToSSR } from '../core/util.js'; import { ssr, preload } from '../core/render/dev/index.js'; import { call as callEndpoint } from '../core/endpoint/dev/index.js'; import * as msg from '../core/messages.js'; @@ -123,7 +123,7 @@ async function handleRequest( const site = config.buildOptions.site ? new URL(config.buildOptions.site) : undefined; const devRoot = site ? site.pathname : '/'; const origin = `${viteServer.config.server.https ? 'https' : 'http'}://${req.headers.host}`; - const buildingToSSR = !!config._ctx.adapter?.serverEntrypoint; + const buildingToSSR = isBuildingToSSR(config); const url = new URL(origin + req.url); const pathname = decodeURI(url.pathname); const rootRelativeUrl = pathname.substring(devRoot.length - 1); @@ -185,7 +185,7 @@ async function handleRequest( routeCache, pathname: rootRelativeUrl, logging, - ssr: config.buildOptions.experimentalSsr, + ssr: isBuildingToSSR(config), }); if (paramsAndPropsRes === GetParamsAndPropsError.NoMatchingStaticPath) { warn(logging, 'getStaticPaths', `Route pattern matched, but no matching static path found. (${pathname})`); diff --git a/packages/astro/test/ssr-api-route.test.js b/packages/astro/test/ssr-api-route.test.js index 54991e80a..6bf8fcd20 100644 --- a/packages/astro/test/ssr-api-route.test.js +++ b/packages/astro/test/ssr-api-route.test.js @@ -10,9 +10,7 @@ describe('API routes in SSR', () => { before(async () => { fixture = await loadFixture({ projectRoot: './fixtures/ssr-api-route/', - buildOptions: { - experimentalSsr: true, - }, + buildOptions: { experimentalSsr: true }, adapter: testAdapter(), }); await fixture.build(); diff --git a/packages/astro/test/ssr-dynamic.test.js b/packages/astro/test/ssr-dynamic.test.js index d938e5c95..98d73b98e 100644 --- a/packages/astro/test/ssr-dynamic.test.js +++ b/packages/astro/test/ssr-dynamic.test.js @@ -11,9 +11,7 @@ describe('Dynamic pages in SSR', () => { before(async () => { fixture = await loadFixture({ projectRoot: './fixtures/ssr-dynamic/', - buildOptions: { - experimentalSsr: true, - }, + buildOptions: { experimentalSsr: true }, adapter: testAdapter(), }); await fixture.build(); diff --git a/packages/integrations/deno/test/fixtures/basics/astro.config.mjs b/packages/integrations/deno/test/fixtures/basics/astro.config.mjs index dfdf9e182..38490926b 100644 --- a/packages/integrations/deno/test/fixtures/basics/astro.config.mjs +++ b/packages/integrations/deno/test/fixtures/basics/astro.config.mjs @@ -2,5 +2,6 @@ import { defineConfig } from 'astro/config'; import deno from '@astrojs/deno'; export default defineConfig({ - adapter: deno() + adapter: deno(), + buildOptions: { experimentalSsr: true } }) diff --git a/packages/integrations/deno/test/helpers.js b/packages/integrations/deno/test/helpers.js index 659d24d5e..bc2bc0622 100644 --- a/packages/integrations/deno/test/helpers.js +++ b/packages/integrations/deno/test/helpers.js @@ -13,7 +13,7 @@ export async function runBuild(fixturePath) { export async function runBuildAndStartApp(fixturePath, cb) { const url = new URL(fixturePath, dir); const close = await runBuild(fixturePath); - const mod = await import(new URL('./dist/entry.mjs', url)); + const mod = await import(new URL('./dist/server/entry.mjs', url)); await cb(); await mod.stop(); await close(); From 93e431967fa7c1ac71ccb64e064f10b1397de494 Mon Sep 17 00:00:00 2001 From: Nate Moore Date: Thu, 31 Mar 2022 12:58:49 -0500 Subject: [PATCH 08/12] chore: add code comment --- packages/astro/src/vite-plugin-astro/hmr.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/astro/src/vite-plugin-astro/hmr.ts b/packages/astro/src/vite-plugin-astro/hmr.ts index fbc52262a..c51047cd7 100644 --- a/packages/astro/src/vite-plugin-astro/hmr.ts +++ b/packages/astro/src/vite-plugin-astro/hmr.ts @@ -81,6 +81,9 @@ export async function handleHotUpdate(ctx: HmrContext, config: AstroConfig, logg const mod = ctx.modules.find((m) => m.file === ctx.file); const file = ctx.file.replace(config.projectRoot.pathname, '/'); + + // Note: this intentionally ONLY applies to Astro components + // HMR is handled for other file types by their respective plugins if (ctx.file.endsWith('.astro')) { ctx.server.ws.send({ type: 'custom', event: 'astro:update', data: { file } }); } From e044d99696ad344c7958ecab7314161ccc339f41 Mon Sep 17 00:00:00 2001 From: natemoo-re Date: Thu, 31 Mar 2022 17:59:39 +0000 Subject: [PATCH 09/12] [ci] format --- packages/astro/src/vite-plugin-astro/hmr.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/astro/src/vite-plugin-astro/hmr.ts b/packages/astro/src/vite-plugin-astro/hmr.ts index c51047cd7..b70efa2a8 100644 --- a/packages/astro/src/vite-plugin-astro/hmr.ts +++ b/packages/astro/src/vite-plugin-astro/hmr.ts @@ -81,7 +81,7 @@ export async function handleHotUpdate(ctx: HmrContext, config: AstroConfig, logg const mod = ctx.modules.find((m) => m.file === ctx.file); const file = ctx.file.replace(config.projectRoot.pathname, '/'); - + // Note: this intentionally ONLY applies to Astro components // HMR is handled for other file types by their respective plugins if (ctx.file.endsWith('.astro')) { From cebdc85428d0ed367c049a3ef5d9b0c77d78ad2e Mon Sep 17 00:00:00 2001 From: Matthew Phillips Date: Thu, 31 Mar 2022 14:04:09 -0400 Subject: [PATCH 10/12] SSR - copy public folder when there is no client JS (#2955) * SSR - copy public folder when there is no client JS * Changest * Use isBuildingToSSR Co-authored-by: JuanM04 --- .changeset/swift-trainers-suffer.md | 5 +++ packages/astro/src/core/build/static-build.ts | 26 ++++++++++++-- .../fixtures/ssr-request/public/cars.json | 7 ++++ .../ssr-request/src/pages/request.astro | 10 ++++++ packages/astro/test/ssr-request.test.js | 36 +++++++++++++++++++ 5 files changed, 82 insertions(+), 2 deletions(-) create mode 100644 .changeset/swift-trainers-suffer.md create mode 100644 packages/astro/test/fixtures/ssr-request/public/cars.json create mode 100644 packages/astro/test/fixtures/ssr-request/src/pages/request.astro create mode 100644 packages/astro/test/ssr-request.test.js diff --git a/.changeset/swift-trainers-suffer.md b/.changeset/swift-trainers-suffer.md new file mode 100644 index 000000000..c9f6fc9a8 --- /dev/null +++ b/.changeset/swift-trainers-suffer.md @@ -0,0 +1,5 @@ +--- +'astro': patch +--- + +Fix for copying public when using SSR and not client JS diff --git a/packages/astro/src/core/build/static-build.ts b/packages/astro/src/core/build/static-build.ts index 4e475afb9..afe41a01e 100644 --- a/packages/astro/src/core/build/static-build.ts +++ b/packages/astro/src/core/build/static-build.ts @@ -169,17 +169,22 @@ async function ssrBuild(opts: StaticBuildOptions, internals: BuildInternals, inp async function clientBuild(opts: StaticBuildOptions, internals: BuildInternals, input: Set) { const { astroConfig, viteConfig } = opts; const timer = performance.now(); + const ssr = isBuildingToSSR(astroConfig); + const out = ssr ? opts.buildConfig.client : astroConfig.dist; // Nothing to do if there is no client-side JS. if (!input.size) { + // If SSR, copy public over + if (ssr) { + await copyFiles(astroConfig.public, out); + } + return null; } // TODO: use vite.mergeConfig() here? info(opts.logging, null, `\n${bgGreen(black(' building client '))}`); - const out = isBuildingToSSR(astroConfig) ? opts.buildConfig.client : astroConfig.dist; - const viteBuildConfig = { logLevel: 'info', mode: 'production', @@ -236,6 +241,23 @@ async function cleanSsrOutput(opts: StaticBuildOptions) { ); } +async function copyFiles(fromFolder: URL, toFolder: URL) { + const files = await glob('**/*', { + cwd: fileURLToPath(fromFolder), + }); + + // Make the directory + await fs.promises.mkdir(toFolder, { recursive: true }); + + await Promise.all( + files.map(async (filename) => { + const from = new URL(filename, fromFolder); + const to = new URL(filename, toFolder); + return fs.promises.copyFile(from, to); + }) + ); +} + async function ssrMoveAssets(opts: StaticBuildOptions) { info(opts.logging, 'build', 'Rearranging server assets...'); const serverRoot = opts.buildConfig.staticMode ? opts.buildConfig.client : opts.buildConfig.server; diff --git a/packages/astro/test/fixtures/ssr-request/public/cars.json b/packages/astro/test/fixtures/ssr-request/public/cars.json new file mode 100644 index 000000000..48d4e4d79 --- /dev/null +++ b/packages/astro/test/fixtures/ssr-request/public/cars.json @@ -0,0 +1,7 @@ +[ + { "name": "One" }, + { "name": "Two" }, + { "name": "Three" }, + { "name": "Four" }, + { "name": "Five" } +] diff --git a/packages/astro/test/fixtures/ssr-request/src/pages/request.astro b/packages/astro/test/fixtures/ssr-request/src/pages/request.astro new file mode 100644 index 000000000..ae7cb0187 --- /dev/null +++ b/packages/astro/test/fixtures/ssr-request/src/pages/request.astro @@ -0,0 +1,10 @@ +--- +const origin = new URL(Astro.request.url).origin; +--- + + +Testing + +

{origin}

+ + diff --git a/packages/astro/test/ssr-request.test.js b/packages/astro/test/ssr-request.test.js new file mode 100644 index 000000000..30efb8ef8 --- /dev/null +++ b/packages/astro/test/ssr-request.test.js @@ -0,0 +1,36 @@ + +import { expect } from 'chai'; +import { load as cheerioLoad } from 'cheerio'; +import { loadFixture } from './test-utils.js'; +import testAdapter from './test-adapter.js'; + +// Asset bundling +describe('Using Astro.request in SSR', () => { + /** @type {import('./test-utils').Fixture} */ + let fixture; + + before(async () => { + fixture = await loadFixture({ + projectRoot: './fixtures/ssr-request/', + buildOptions: { + experimentalSsr: true, + }, + adapter: testAdapter(), + }); + await fixture.build(); + }); + + it('Gets the request pased in', async () => { + const app = await fixture.loadTestAdapterApp(); + const request = new Request('http://example.com/request'); + const response = await app.render(request); + const html = await response.text(); + const $ = cheerioLoad(html); + expect($('#origin').text()).to.equal('http://example.com'); + }); + + it('public file is copied over', async () => { + const json = await fixture.readFile('/client/cars.json'); + expect(json).to.not.be.undefined; + }); +}); From 50af480c7df6840217fbda198ead64cf3be541f1 Mon Sep 17 00:00:00 2001 From: matthewp Date: Thu, 31 Mar 2022 18:04:57 +0000 Subject: [PATCH 11/12] [ci] format --- packages/astro/test/ssr-request.test.js | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/astro/test/ssr-request.test.js b/packages/astro/test/ssr-request.test.js index 30efb8ef8..04a00a195 100644 --- a/packages/astro/test/ssr-request.test.js +++ b/packages/astro/test/ssr-request.test.js @@ -1,4 +1,3 @@ - import { expect } from 'chai'; import { load as cheerioLoad } from 'cheerio'; import { loadFixture } from './test-utils.js'; From d81b6d9ebc2176690aac3f538e84b5566acbdff4 Mon Sep 17 00:00:00 2001 From: Nate Moore Date: Thu, 31 Mar 2022 13:11:26 -0500 Subject: [PATCH 12/12] Add function-based slot support to `Astro.slots.render()` (#2954) * feat(slots): add function-based slot support to Astro.slots.render() * test(slots): add render tests --- .changeset/light-apricots-sort.md | 7 +++++ packages/astro/src/@types/astro.ts | 2 +- packages/astro/src/core/render/result.ts | 23 ++++++++++++--- packages/astro/test/astro-slots.test.js | 29 +++++++++++++++++++ .../astro-slots/src/components/Render.astro | 6 ++++ .../src/components/RenderArgs.astro | 6 ++++ .../astro-slots/src/components/RenderFn.astro | 6 ++++ .../src/pages/slottedapi-render.astro | 20 +++++++++++++ 8 files changed, 94 insertions(+), 5 deletions(-) create mode 100644 .changeset/light-apricots-sort.md create mode 100644 packages/astro/test/fixtures/astro-slots/src/components/Render.astro create mode 100644 packages/astro/test/fixtures/astro-slots/src/components/RenderArgs.astro create mode 100644 packages/astro/test/fixtures/astro-slots/src/components/RenderFn.astro create mode 100644 packages/astro/test/fixtures/astro-slots/src/pages/slottedapi-render.astro diff --git a/.changeset/light-apricots-sort.md b/.changeset/light-apricots-sort.md new file mode 100644 index 000000000..26a182a40 --- /dev/null +++ b/.changeset/light-apricots-sort.md @@ -0,0 +1,7 @@ +--- +'astro': patch +--- + +Improve `Astro.slots` API to support passing arguments to function-based slots. + +This allows for more ergonomic utility components that accept a callback function as a child. diff --git a/packages/astro/src/@types/astro.ts b/packages/astro/src/@types/astro.ts index 800ab9b23..0f1e48e13 100644 --- a/packages/astro/src/@types/astro.ts +++ b/packages/astro/src/@types/astro.ts @@ -60,7 +60,7 @@ export interface AstroGlobal extends AstroGlobalPartial { /** get information about this page */ request: Request; /** see if slots are used */ - slots: Record & { has(slotName: string): boolean; render(slotName: string): Promise }; + slots: Record & { has(slotName: string): boolean; render(slotName: string, args?: any[]): Promise }; } export interface AstroGlobalPartial { diff --git a/packages/astro/src/core/render/result.ts b/packages/astro/src/core/render/result.ts index c3552be3d..0b0f24336 100644 --- a/packages/astro/src/core/render/result.ts +++ b/packages/astro/src/core/render/result.ts @@ -28,6 +28,12 @@ export interface CreateResultArgs { request: Request; } +function getFunctionExpression(slot: any) { + if (!slot) return; + if (slot.expressions?.length !== 1) return; + return slot.expressions[0] as (...args: any[]) => any; +} + class Slots { #cache = new Map(); #result: SSRResult; @@ -56,15 +62,24 @@ class Slots { return Boolean(this.#slots[name]); } - public async render(name: string) { + public async render(name: string, args: any[] = []) { + const cacheable = args.length === 0; if (!this.#slots) return undefined; - if (this.#cache.has(name)) { + if (cacheable && this.#cache.has(name)) { const result = this.#cache.get(name); return result; } if (!this.has(name)) return undefined; - const content = await renderSlot(this.#result, this.#slots[name]).then((res) => (res != null ? res.toString() : res)); - this.#cache.set(name, content); + if (!cacheable) { + const component = await this.#slots[name](); + const expression = getFunctionExpression(component); + if (expression) { + const slot = expression(...args); + return await renderSlot(this.#result, slot).then((res) => res != null ? String(res) : res); + } + } + const content = await renderSlot(this.#result, this.#slots[name]).then((res) => res != null ? String(res) : res); + if (cacheable) this.#cache.set(name, content); return content; } } diff --git a/packages/astro/test/astro-slots.test.js b/packages/astro/test/astro-slots.test.js index f3b27aac3..dd4883708 100644 --- a/packages/astro/test/astro-slots.test.js +++ b/packages/astro/test/astro-slots.test.js @@ -112,4 +112,33 @@ describe('Slots', () => { expect($('#default')).to.have.lengthOf(1); // the default slot is filled } }); + + it('Slots.render() API', async () => { + // Simple imperative slot render + { + const html = await fixture.readFile('/slottedapi-render/index.html'); + const $ = cheerio.load(html); + + expect($('#render')).to.have.lengthOf(1); + expect($('#render').text()).to.equal('render'); + } + + // Child function render without args + { + const html = await fixture.readFile('/slottedapi-render/index.html'); + const $ = cheerio.load(html); + + expect($('#render-fn')).to.have.lengthOf(1); + expect($('#render-fn').text()).to.equal('render-fn'); + } + + // Child function render with args + { + const html = await fixture.readFile('/slottedapi-render/index.html'); + const $ = cheerio.load(html); + + expect($('#render-args')).to.have.lengthOf(1); + expect($('#render-args').text()).to.equal('render-args'); + } + }); }); diff --git a/packages/astro/test/fixtures/astro-slots/src/components/Render.astro b/packages/astro/test/fixtures/astro-slots/src/components/Render.astro new file mode 100644 index 000000000..c106c4d06 --- /dev/null +++ b/packages/astro/test/fixtures/astro-slots/src/components/Render.astro @@ -0,0 +1,6 @@ +--- +const { id } = Astro.props; +const content = await Astro.slots.render('default'); +--- + +
diff --git a/packages/astro/test/fixtures/astro-slots/src/components/RenderArgs.astro b/packages/astro/test/fixtures/astro-slots/src/components/RenderArgs.astro new file mode 100644 index 000000000..6936aaa10 --- /dev/null +++ b/packages/astro/test/fixtures/astro-slots/src/components/RenderArgs.astro @@ -0,0 +1,6 @@ +--- +const { id, text } = Astro.props; +const content = await Astro.slots.render('default', [text]); +--- + +
diff --git a/packages/astro/test/fixtures/astro-slots/src/components/RenderFn.astro b/packages/astro/test/fixtures/astro-slots/src/components/RenderFn.astro new file mode 100644 index 000000000..c106c4d06 --- /dev/null +++ b/packages/astro/test/fixtures/astro-slots/src/components/RenderFn.astro @@ -0,0 +1,6 @@ +--- +const { id } = Astro.props; +const content = await Astro.slots.render('default'); +--- + +
diff --git a/packages/astro/test/fixtures/astro-slots/src/pages/slottedapi-render.astro b/packages/astro/test/fixtures/astro-slots/src/pages/slottedapi-render.astro new file mode 100644 index 000000000..960ffa629 --- /dev/null +++ b/packages/astro/test/fixtures/astro-slots/src/pages/slottedapi-render.astro @@ -0,0 +1,20 @@ +--- +import Render from '../components/Render.astro'; +import RenderFn from '../components/RenderFn.astro'; +import RenderArgs from '../components/RenderArgs.astro'; +--- + + + + + + + render + {() => "render-fn"} + {(text: string) => text} + +