Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@astrojs/react

Package Overview
Dependencies
Maintainers
3
Versions
116
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@astrojs/react - npm Package Compare versions

Comparing version 0.0.0-monorepos-20221010034923 to 0.0.0-non-admin-test-20240308195029

context.js

13

client-v17.js
import { createElement } from 'react';
import { render, hydrate } from 'react-dom';
import { hydrate, render, unmountComponentAtNode } from 'react-dom';
import StaticHtml from './static-html.js';

@@ -15,6 +15,9 @@

);
if (client === 'only') {
return render(componentEl, element);
}
return hydrate(componentEl, element);
const isHydrate = client !== 'only';
const bootstrap = isHydrate ? hydrate : render;
bootstrap(componentEl, element);
element.addEventListener('astro:unmount', () => unmountComponentAtNode(element), {
once: true,
});
};

@@ -13,15 +13,73 @@ import { createElement, startTransition } from 'react';

function createReactElementFromDOMElement(element) {
let attrs = {};
for (const attr of element.attributes) {
attrs[attr.name] = attr.value;
}
// If the element has no children, we can create a simple React element
if (element.firstChild === null) {
return createElement(element.localName, attrs);
}
return createElement(
element.localName,
attrs,
Array.from(element.childNodes)
.map((c) => {
if (c.nodeType === Node.TEXT_NODE) {
return c.data;
} else if (c.nodeType === Node.ELEMENT_NODE) {
return createReactElementFromDOMElement(c);
} else {
return undefined;
}
})
.filter((a) => !!a)
);
}
function getChildren(childString, experimentalReactChildren) {
if (experimentalReactChildren && childString) {
let children = [];
let template = document.createElement('template');
template.innerHTML = childString;
for (let child of template.content.children) {
children.push(createReactElementFromDOMElement(child));
}
return children;
} else if (childString) {
return createElement(StaticHtml, { value: childString });
} else {
return undefined;
}
}
// Keep a map of roots so we can reuse them on re-renders
let rootMap = new WeakMap();
const getOrCreateRoot = (element, creator) => {
let root = rootMap.get(element);
if (!root) {
root = creator();
rootMap.set(element, root);
}
return root;
};
export default (element) =>
(Component, props, { default: children, ...slotted }, { client }) => {
if (!element.hasAttribute('ssr')) return;
const renderOptions = {
identifierPrefix: element.getAttribute('prefix'),
};
for (const [key, value] of Object.entries(slotted)) {
props[key] = createElement(StaticHtml, { value, name: key });
}
const componentEl = createElement(
Component,
props,
children != null ? createElement(StaticHtml, { value: children }) : children
getChildren(children, element.hasAttribute('data-react-children'))
);
const rootKey = isAlreadyHydrated(element);
// HACK: delete internal react marker for nested components to suppress agressive warnings
// HACK: delete internal react marker for nested components to suppress aggressive warnings
if (rootKey) {

@@ -32,8 +90,18 @@ delete element[rootKey];

return startTransition(() => {
createRoot(element).render(componentEl);
const root = getOrCreateRoot(element, () => {
const r = createRoot(element);
element.addEventListener('astro:unmount', () => r.unmount(), { once: true });
return r;
});
root.render(componentEl);
});
}
return startTransition(() => {
hydrateRoot(element, componentEl);
startTransition(() => {
const root = getOrCreateRoot(element, () => {
const r = hydrateRoot(element, componentEl, renderOptions);
element.addEventListener('astro:unmount', () => r.unmount(), { once: true });
return r;
});
root.render(componentEl);
});
};

@@ -1,2 +0,6 @@

import { AstroIntegration } from 'astro';
export default function (): AstroIntegration;
import { type Options as ViteReactPluginOptions } from '@vitejs/plugin-react';
import type { AstroIntegration } from 'astro';
export type ReactIntegrationOptions = Pick<ViteReactPluginOptions, 'include' | 'exclude'> & {
experimentalReactChildren?: boolean;
};
export default function ({ include, exclude, experimentalReactChildren, }?: ReactIntegrationOptions): AstroIntegration;

@@ -0,2 +1,4 @@

import react, {} from "@vitejs/plugin-react";
import { version as ReactVersion } from "react-dom";
const FAST_REFRESH_PREAMBLE = react.preambleCode;
function getRenderer() {

@@ -6,23 +8,31 @@ return {

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 () => {
var _a;
const babelPluginTransformReactJsxModule = await import("@babel/plugin-transform-react-jsx");
const jsx = ((_a = babelPluginTransformReactJsxModule == null ? void 0 : babelPluginTransformReactJsxModule.default) == null ? void 0 : _a.default) ?? (babelPluginTransformReactJsxModule == null ? void 0 : babelPluginTransformReactJsxModule.default);
return {
plugins: [
jsx(
{},
{
runtime: "automatic",
importSource: ReactVersion.startsWith("18.") ? "react" : "@astrojs/react"
}
)
]
};
serverEntrypoint: ReactVersion.startsWith("18.") ? "@astrojs/react/server.js" : "@astrojs/react/server-v17.js"
};
}
function optionsPlugin(experimentalReactChildren) {
const virtualModule = "astro:react:opts";
const virtualModuleId = "\0" + virtualModule;
return {
name: "@astrojs/react:opts",
resolveId(id) {
if (id === virtualModule) {
return virtualModuleId;
}
},
load(id) {
if (id === virtualModuleId) {
return {
code: `export default {
experimentalReactChildren: ${JSON.stringify(experimentalReactChildren)}
}`
};
}
}
};
}
function getViteConfiguration() {
function getViteConfiguration({
include,
exclude,
experimentalReactChildren
} = {}) {
return {

@@ -41,4 +51,5 @@ optimizeDeps: {

},
plugins: [react({ include, exclude }), optionsPlugin(!!experimentalReactChildren)],
resolve: {
dedupe: ["react", "react-dom"]
dedupe: ["react", "react-dom", "react-dom/server"]
},

@@ -48,5 +59,8 @@ ssr: {

noExternal: [
// These are all needed to get mui to work.
"@mui/material",
"@mui/base",
"@babel/runtime"
"@babel/runtime",
"redoc",
"use-immer"
]

@@ -56,9 +70,19 @@ }

}
function src_default() {
function src_default({
include,
exclude,
experimentalReactChildren
} = {}) {
return {
name: "@astrojs/react",
hooks: {
"astro:config:setup": ({ addRenderer, updateConfig }) => {
"astro:config:setup": ({ command, addRenderer, updateConfig, injectScript }) => {
addRenderer(getRenderer());
updateConfig({ vite: getViteConfiguration() });
updateConfig({
vite: getViteConfiguration({ include, exclude, experimentalReactChildren })
});
if (command === "dev") {
const preamble = FAST_REFRESH_PREAMBLE.replace(`__BASE__`, "/");
injectScript("before-hydration", preamble);
}
}

@@ -65,0 +89,0 @@ }

{
"name": "@astrojs/react",
"description": "Use React components within Astro",
"version": "0.0.0-monorepos-20221010034923",
"version": "0.0.0-non-admin-test-20240308195029",
"type": "module",

@@ -31,15 +31,30 @@ "types": "./dist/index.d.ts",

},
"files": [
"dist",
"client.js",
"client-v17.js",
"context.js",
"jsx-runtime.js",
"server.js",
"server-v17.js",
"static-html.js",
"vnode-children.js"
],
"dependencies": {
"@babel/core": ">=7.0.0-0 <8.0.0",
"@babel/plugin-transform-react-jsx": "^7.17.12"
"@vitejs/plugin-react": "^4.2.0",
"ultrahtml": "^1.3.0"
},
"devDependencies": {
"@types/react": "^17.0.45",
"@types/react-dom": "^17.0.17",
"astro": "1.4.6",
"astro-scripts": "0.0.8",
"@types/react": "^18.2.37",
"@types/react-dom": "^18.2.15",
"cheerio": "1.0.0-rc.12",
"react": "^18.1.0",
"react-dom": "^18.1.0"
"react-dom": "^18.1.0",
"vite": "^5.1.4",
"astro": "0.0.0-non-admin-test-20240308195029",
"astro-scripts": "0.0.14"
},
"peerDependencies": {
"@types/react": "^17.0.50 || ^18.0.21",
"@types/react-dom": "^17.0.17 || ^18.0.6",
"react": "^17.0.2 || ^18.0.0",

@@ -49,9 +64,13 @@ "react-dom": "^17.0.2 || ^18.0.0"

"engines": {
"node": "^14.18.0 || >=16.12.0"
"node": ">=18.14.1"
},
"publishConfig": {
"provenance": true
},
"scripts": {
"build": "astro-scripts build \"src/**/*.ts\" && tsc",
"build:ci": "astro-scripts build \"src/**/*.ts\"",
"dev": "astro-scripts dev \"src/**/*.ts\""
"dev": "astro-scripts dev \"src/**/*.ts\"",
"test": "astro-scripts test \"test/**/*.test.js\""
}
}
# @astrojs/react ⚛️
This **[Astro integration][astro-integration]** enables server-side rendering and client-side hydration for your [React](https://reactjs.org/) components.
This **[Astro integration][astro-integration]** enables server-side rendering and client-side hydration for your [React](https://react.dev/) components.
## Installation
## Documentation
There are two ways to add integrations to your project. Let's try the most convenient option first!
Read the [`@astrojs/react` docs][docs]
### `astro add` command
## Support
Astro includes a CLI tool for adding first party integrations: `astro add`. This command will:
1. (Optionally) Install all necessary dependencies and peer dependencies
2. (Also optionally) Update your `astro.config.*` file to apply this integration
- Get help in the [Astro Discord][discord]. Post questions in our `#support` forum, or visit our dedicated `#dev` channel to discuss current development and more!
To install `@astrojs/react`, run the following from your project directory and follow the prompts:
- Check our [Astro Integration Documentation][astro-integration] for more on integrations.
```sh
# Using NPM
npx astro add react
# Using Yarn
yarn astro add react
# Using PNPM
pnpm astro add react
```
- Submit bug reports and feature requests as [GitHub issues][issues].
If you run into any issues, [feel free to report them to us on GitHub](https://github.com/withastro/astro/issues) and try the manual installation steps below.
## Contributing
### Install dependencies manually
This package is maintained by Astro's Core team. You're welcome to submit an issue or PR! These links will help you get started:
First, install the `@astrojs/react` integration like so:
- [Contributor Manual][contributing]
- [Code of Conduct][coc]
- [Community Guide][community]
```sh
npm install @astrojs/react
```
## License
Most package managers will install associated peer dependencies as well. Still, if you see a "Cannot find package 'react'" (or similar) warning when you start up Astro, you'll need to install `react` and `react-dom`:
MIT
```sh
npm install react react-dom
```
Copyright (c) 2023–present [Astro][astro]
Now, apply this integration to your `astro.config.*` file using the `integrations` property:
__`astro.config.mjs`__
```js
import react from '@astrojs/react';
export default {
// ...
integrations: [react()],
}
```
## Getting started
To use your first React component in Astro, head to our [UI framework documentation][astro-ui-frameworks]. You'll explore:
- 📦 how framework components are loaded,
- 💧 client-side hydration options, and
- 🤝 opportunities to mix and nest frameworks together
## Troubleshooting
For help, check out the `#support` channel on [Discord](https://astro.build/chat). Our friendly Support Squad members are here to help!
You can also check our [Astro Integration Documentation][astro-integration] for more on integrations.
## Contributing
This package is maintained by Astro's Core team. You're welcome to submit an issue or PR!
[astro]: https://astro.build/
[docs]: https://docs.astro.build/en/guides/integrations-guide/react/
[contributing]: https://github.com/withastro/astro/blob/main/CONTRIBUTING.md
[coc]: https://github.com/withastro/.github/blob/main/CODE_OF_CONDUCT.md
[community]: https://github.com/withastro/.github/blob/main/COMMUNITY_GUIDE.md
[discord]: https://astro.build/chat/
[issues]: https://github.com/withastro/astro/issues
[astro-integration]: https://docs.astro.build/en/guides/integrations-guide/
[astro-ui-frameworks]: https://docs.astro.build/en/core-concepts/framework-components/#using-framework-components

@@ -20,6 +20,6 @@ import React from 'react';

if (typeof Component === 'object') {
const $$typeof = Component['$$typeof'];
return $$typeof && $$typeof.toString().slice('Symbol('.length).startsWith('react');
return Component['$$typeof']?.toString().slice('Symbol('.length).startsWith('react');
}
if (typeof Component !== 'function') return false;
if (Component.name === 'QwikComponent') return false;

@@ -66,7 +66,14 @@ if (Component.prototype != null && typeof Component.prototype.render === 'function') {

...slots,
children: children != null ? React.createElement(StaticHtml, { value: children }) : undefined,
};
const newChildren = children ?? props.children;
if (newChildren != null) {
newProps.children = React.createElement(StaticHtml, {
// Adjust how this is hydrated only when the version of Astro supports `astroStaticSlot`
hydrate: metadata.astroStaticSlot ? !!metadata.hydrate : true,
value: newChildren,
});
}
const vnode = React.createElement(Component, newProps);
let html;
if (metadata && metadata.hydrate) {
if (metadata?.hydrate) {
html = ReactDOM.renderToString(vnode);

@@ -82,2 +89,3 @@ } else {

renderToStaticMarkup,
supportsAstroStaticSlot: true,
};
import React from 'react';
import ReactDOM from 'react-dom/server';
import { incrementId } from './context.js';
import StaticHtml from './static-html.js';
import opts from 'astro:react:opts';

@@ -20,7 +22,11 @@ const slotName = (str) => str.trim().replace(/[-_]([a-z])/g, (_, w) => w.toUpperCase());

if (typeof Component === 'object') {
const $$typeof = Component['$$typeof'];
return $$typeof && $$typeof.toString().slice('Symbol('.length).startsWith('react');
return Component['$$typeof'].toString().slice('Symbol('.length).startsWith('react');
}
if (typeof Component !== 'function') return false;
if (Component.name === 'QwikComponent') return false;
// Preact forwarded-ref components can be functions, which React does not support
if (typeof Component === 'function' && Component['$$typeof'] === Symbol.for('react.forward_ref'))
return false;
if (Component.prototype != null && typeof Component.prototype.render === 'function') {

@@ -56,3 +62,3 @@ return React.Component.isPrototypeOf(Component) || React.PureComponent.isPrototypeOf(Component);

async function getNodeWritable() {
let nodeStreamBuiltinModuleName = 'stream';
let nodeStreamBuiltinModuleName = 'node:stream';
let { Writable } = await import(/* @vite-ignore */ nodeStreamBuiltinModuleName);

@@ -62,3 +68,14 @@ return Writable;

function needsHydration(metadata) {
// Adjust how this is hydrated only when the version of Astro supports `astroStaticSlot`
return metadata.astroStaticSlot ? !!metadata.hydrate : true;
}
async function renderToStaticMarkup(Component, props, { default: children, ...slotted }, metadata) {
let prefix;
if (this && this.result) {
prefix = incrementId(this.result);
}
const attrs = { prefix };
delete props['class'];

@@ -68,3 +85,7 @@ const slots = {};

const name = slotName(key);
slots[name] = React.createElement(StaticHtml, { value, name });
slots[name] = React.createElement(StaticHtml, {
hydrate: needsHydration(metadata),
value,
name,
});
}

@@ -76,25 +97,35 @@ // Note: create newProps to avoid mutating `props` before they are serialized

};
if (children != null) {
newProps.children = React.createElement(StaticHtml, { value: children });
const newChildren = children ?? props.children;
if (children && opts.experimentalReactChildren) {
attrs['data-react-children'] = true;
const convert = await import('./vnode-children.js').then((mod) => mod.default);
newProps.children = convert(children);
} else if (newChildren != null) {
newProps.children = React.createElement(StaticHtml, {
hydrate: needsHydration(metadata),
value: newChildren,
});
}
const vnode = React.createElement(Component, newProps);
const renderOptions = {
identifierPrefix: prefix,
};
let html;
if (metadata && metadata.hydrate) {
html = ReactDOM.renderToString(vnode);
if (metadata?.hydrate) {
if ('renderToReadableStream' in ReactDOM) {
html = await renderToReadableStreamAsync(vnode);
html = await renderToReadableStreamAsync(vnode, renderOptions);
} else {
html = await renderToPipeableStreamAsync(vnode);
html = await renderToPipeableStreamAsync(vnode, renderOptions);
}
} else {
if ('renderToReadableStream' in ReactDOM) {
html = await renderToReadableStreamAsync(vnode);
html = await renderToReadableStreamAsync(vnode, renderOptions);
} else {
html = await renderToStaticNodeStreamAsync(vnode);
html = await renderToStaticNodeStreamAsync(vnode, renderOptions);
}
}
return { html };
return { html, attrs };
}
async function renderToPipeableStreamAsync(vnode) {
async function renderToPipeableStreamAsync(vnode, options) {
const Writable = await getNodeWritable();

@@ -105,2 +136,3 @@ let html = '';

let stream = ReactDOM.renderToPipeableStream(vnode, {
...options,
onError(err) {

@@ -127,7 +159,7 @@ error = err;

async function renderToStaticNodeStreamAsync(vnode) {
async function renderToStaticNodeStreamAsync(vnode, options) {
const Writable = await getNodeWritable();
let html = '';
return new Promise((resolve, reject) => {
let stream = ReactDOM.renderToStaticNodeStream(vnode);
let stream = ReactDOM.renderToStaticNodeStream(vnode, options);
stream.on('error', (err) => {

@@ -174,4 +206,4 @@ reject(err);

async function renderToReadableStreamAsync(vnode) {
return await readResult(await ReactDOM.renderToReadableStream(vnode));
async function renderToReadableStreamAsync(vnode, options) {
return await readResult(await ReactDOM.renderToReadableStream(vnode, options));
}

@@ -182,2 +214,3 @@

renderToStaticMarkup,
supportsAstroStaticSlot: true,
};

@@ -10,5 +10,6 @@ import { createElement as h } from 'react';

*/
const StaticHtml = ({ value, name }) => {
const StaticHtml = ({ value, name, hydrate = true }) => {
if (!value) return null;
return h('astro-slot', {
const tagName = hydrate ? 'astro-slot' : 'astro-static-slot';
return h(tagName, {
name,

@@ -15,0 +16,0 @@ suppressHydrationWarning: true,

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc