Merge branch 'main' into feat/vercel-adapter

This commit is contained in:
JuanM04 2022-03-31 15:11:56 -03:00
commit 764467a21d
No known key found for this signature in database
GPG key ID: 0171B712E406271A
48 changed files with 432 additions and 131 deletions

View file

@ -0,0 +1,5 @@
---
'astro': patch
---
`--experimental-ssr` now is only required when using a 3rd-party adapter

View file

@ -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.

View file

@ -0,0 +1,5 @@
---
'@astrojs/react': minor
---
Add support for React v18

View file

@ -0,0 +1,5 @@
---
'astro': patch
---
Fix for copying public when using SSR and not client JS

View file

@ -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",

View file

@ -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"

View file

@ -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"
}
}

View file

@ -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"

View file

@ -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": {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 83 B

After

Width:  |  Height:  |  Size: 4.2 KiB

View file

@ -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"
}
}

View file

@ -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"
}

View file

@ -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"
},

View file

@ -60,7 +60,7 @@ export interface AstroGlobal extends AstroGlobalPartial {
/** get information about this page */
request: Request;
/** see if slots are used */
slots: Record<string, true | undefined> & { has(slotName: string): boolean; render(slotName: string): Promise<string> };
slots: Record<string, true | undefined> & { has(slotName: string): boolean; render(slotName: string, args?: any[]): Promise<string> };
}
export interface AstroGlobalPartial {
@ -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;

View file

@ -39,7 +39,7 @@ function printAstroHelp() {
['--project-root <path>', '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'],

View file

@ -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;

View file

@ -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 });
}
}

View file

@ -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<C
const assets: Record<string, string> = {};
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...');

View file

@ -111,7 +111,7 @@ export async function staticBuild(opts: StaticBuildOptions) {
async function ssrBuild(opts: StaticBuildOptions, internals: BuildInternals, input: Set<string>) {
const { astroConfig, viteConfig } = opts;
const ssr = astroConfig.buildOptions.experimentalSsr;
const ssr = isBuildingToSSR(astroConfig);
const out = ssr ? opts.buildConfig.server : astroConfig.dist;
const viteBuildConfig = {
@ -169,17 +169,22 @@ async function ssrBuild(opts: StaticBuildOptions, internals: BuildInternals, inp
async function clientBuild(opts: StaticBuildOptions, internals: BuildInternals, input: Set<string>) {
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;

View file

@ -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;

View file

@ -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),
});
}

View file

@ -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') {

View file

@ -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<string, string>();
#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;
}
}

View file

@ -139,7 +139,27 @@ export function emptyDir(_dir: URL, skip?: Set<string>): 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) {

View file

@ -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})`);

View file

@ -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 } });
}

View file

@ -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');
}
});
});

View file

@ -0,0 +1,6 @@
---
const { id } = Astro.props;
const content = await Astro.slots.render('default');
---
<div id={id} set:html={content} />

View file

@ -0,0 +1,6 @@
---
const { id, text } = Astro.props;
const content = await Astro.slots.render('default', [text]);
---
<div id={id} set:html={content} />

View file

@ -0,0 +1,6 @@
---
const { id } = Astro.props;
const content = await Astro.slots.render('default');
---
<div id={id} set:html={content} />

View file

@ -0,0 +1,20 @@
---
import Render from '../components/Render.astro';
import RenderFn from '../components/RenderFn.astro';
import RenderArgs from '../components/RenderArgs.astro';
---
<html>
<head>
<!--
Test Astro.slots.render behavior.
- `Render` is basic imperative `render` call
- `RenderFn` is `render` that calls child function with arguments
-->
</head>
<body>
<Render id="render">render</Render>
<RenderFn id="render-fn">{() => "render-fn"}</RenderFn>
<RenderArgs id="render-args" text="render-args">{(text: string) => text}</RenderArgs>
</body>
</html>

View file

@ -5,6 +5,9 @@
"dependencies": {
"@astrojs/react": "workspace:*",
"@astrojs/vue": "workspace:*",
"astro": "workspace:*"
"astro": "workspace:*",
"react": "^18.0.0",
"react-dom": "^18.0.0",
"vue": "^3.2.31"
}
}

View file

@ -0,0 +1,7 @@
[
{ "name": "One" },
{ "name": "Two" },
{ "name": "Three" },
{ "name": "Four" },
{ "name": "Five" }
]

View file

@ -0,0 +1,10 @@
---
const origin = new URL(Astro.request.url).origin;
---
<html>
<head><title>Testing</title></head>
<body>
<h1 id="origin">{origin}</h1>
</body>
</html>

View file

@ -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();

View file

@ -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();

View file

@ -0,0 +1,35 @@
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;
});
});

View file

@ -2,5 +2,6 @@ import { defineConfig } from 'astro/config';
import deno from '@astrojs/deno';
export default defineConfig({
adapter: deno()
adapter: deno(),
buildOptions: { experimentalSsr: true }
})

View file

@ -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();

View file

@ -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
);

View file

@ -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
)
);

View file

@ -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"
"react": "^18.0.0",
"react-dom": "^18.0.0"
},
"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"

View file

@ -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,
};

View file

@ -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');

View file

@ -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'],
},
};
}

View file

@ -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"

View file

@ -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,10 +1011,16 @@ importers:
'@astrojs/react': workspace:*
'@astrojs/vue': workspace:*
astro: workspace:*
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: 18.0.0
react-dom: 18.0.0_react@18.0.0
vue: 3.2.31
packages/astro/test/fixtures/remote-css:
specifiers:
@ -1276,17 +1282,21 @@ 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
react-dom: ^17.0.2
react: ^18.0.0
react-dom: ^18.0.0
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
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:
@ -1461,12 +1471,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:
@ -3304,7 +3314,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'
@ -3316,8 +3326,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
@ -3469,7 +3479,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:
@ -3478,8 +3488,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:
@ -4022,19 +4032,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==}
@ -4066,7 +4080,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==}
@ -5249,7 +5262,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==}
@ -8279,6 +8291,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==}
@ -8798,22 +8811,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==}
@ -9206,11 +9217,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==}

View file

@ -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"

1 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)
2 Thursday, March 31, 2022 6 4 4 0 0 6 10 93 46 41 0 0 2022-03-31T12:02:11.044Z
3 Wednesday, March 30, 2022 9 2 2 0 0 10 10 90 43 41 0 0 2022-03-30T12:02:39.303Z
4 Tuesday, March 29, 2022 19 8 8 0 0 9 5 88 41 41 0 0 2022-03-29T12:06:39.897Z
5 Monday, March 28, 2022 1 7 7 0 0 2 8 83 36 41 0 0 2022-03-28T12:02:00.954Z