@astrojs/solid-js
Advanced tools
Comparing version 0.0.0-propagation-metadata-20230907174633 to 0.0.0-sessions-20241122114539
@@ -0,9 +1,9 @@ | ||
import { Suspense } from "solid-js"; | ||
import { createStore, reconcile } from "solid-js/store"; | ||
import { createComponent, hydrate, render } from "solid-js/web"; | ||
const alreadyInitializedElements = /* @__PURE__ */ new WeakMap(); | ||
var client_default = (element) => (Component, props, slotted, { client }) => { | ||
if (!window._$HY) { | ||
window._$HY = { events: [], completed: /* @__PURE__ */ new WeakSet(), r: {} }; | ||
} | ||
if (!element.hasAttribute("ssr")) | ||
return; | ||
const boostrap = client === "only" ? render : hydrate; | ||
if (!element.hasAttribute("ssr")) return; | ||
const isHydrate = client !== "only"; | ||
const bootstrap = isHydrate ? hydrate : render; | ||
let slot; | ||
@@ -14,8 +14,5 @@ let _slots = {}; | ||
const iterator = document.createTreeWalker(element, NodeFilter.SHOW_ELEMENT, (node) => { | ||
if (node === element) | ||
return NodeFilter.FILTER_SKIP; | ||
if (node.nodeName === "ASTRO-SLOT") | ||
return NodeFilter.FILTER_ACCEPT; | ||
if (node.nodeName === "ASTRO-ISLAND") | ||
return NodeFilter.FILTER_REJECT; | ||
if (node === element) return NodeFilter.FILTER_SKIP; | ||
if (node.nodeName === "ASTRO-SLOT") return NodeFilter.FILTER_ACCEPT; | ||
if (node.nodeName === "ASTRO-ISLAND") return NodeFilter.FILTER_REJECT; | ||
return NodeFilter.FILTER_SKIP; | ||
@@ -27,7 +24,5 @@ }); | ||
for (const [key, value] of Object.entries(slotted)) { | ||
if (_slots[key]) | ||
continue; | ||
if (_slots[key]) continue; | ||
_slots[key] = document.createElement("astro-slot"); | ||
if (key !== "default") | ||
_slots[key].setAttribute("name", key); | ||
if (key !== "default") _slots[key].setAttribute("name", key); | ||
_slots[key].innerHTML = value; | ||
@@ -38,14 +33,38 @@ } | ||
const renderId = element.dataset.solidRenderId; | ||
const dispose = boostrap( | ||
() => createComponent(Component, { | ||
if (alreadyInitializedElements.has(element)) { | ||
alreadyInitializedElements.get(element)( | ||
// reconcile will make sure to apply as little updates as possible, and also remove missing values w/o breaking reactivity | ||
reconcile({ | ||
...props, | ||
...slots, | ||
children | ||
}) | ||
); | ||
} else { | ||
const [store, setStore] = createStore({ | ||
...props, | ||
...slots, | ||
children | ||
}), | ||
element, | ||
{ | ||
renderId | ||
} | ||
); | ||
element.addEventListener("astro:unmount", () => dispose(), { once: true }); | ||
}); | ||
alreadyInitializedElements.set(element, setStore); | ||
const dispose = bootstrap( | ||
() => { | ||
const inner = () => createComponent(Component, store); | ||
if (isHydrate) { | ||
return createComponent(Suspense, { | ||
get children() { | ||
return inner(); | ||
} | ||
}); | ||
} else { | ||
return inner(); | ||
} | ||
}, | ||
element, | ||
{ | ||
renderId | ||
} | ||
); | ||
element.addEventListener("astro:unmount", () => dispose(), { once: true }); | ||
} | ||
}; | ||
@@ -52,0 +71,0 @@ export { |
@@ -1,2 +0,2 @@ | ||
import type { RendererContext } from './types'; | ||
import type { RendererContext } from './types.js'; | ||
type Context = { | ||
@@ -3,0 +3,0 @@ id: string; |
@@ -1,4 +0,7 @@ | ||
import type { AstroIntegration } from 'astro'; | ||
import type { AstroIntegration, ContainerRenderer } from 'astro'; | ||
import { type Options as ViteSolidPluginOptions } from 'vite-plugin-solid'; | ||
export type Options = Pick<ViteSolidPluginOptions, 'include' | 'exclude'>; | ||
export default function (opts?: Options): AstroIntegration; | ||
export declare function getContainerRenderer(): ContainerRenderer; | ||
export interface Options extends Pick<ViteSolidPluginOptions, 'include' | 'exclude'> { | ||
devtools?: boolean; | ||
} | ||
export default function (options?: Options): AstroIntegration; |
import solid, {} from "vite-plugin-solid"; | ||
async function getViteConfiguration(isDev, { include, exclude } = {}) { | ||
async function getDevtoolsPlugin(logger, retrieve) { | ||
if (!retrieve) { | ||
return null; | ||
} | ||
try { | ||
return (await import("solid-devtools/vite")).default; | ||
} catch (_) { | ||
logger.warn( | ||
"Solid Devtools requires `solid-devtools` as a peer dependency, add it to your project." | ||
); | ||
return null; | ||
} | ||
} | ||
async function getViteConfiguration(isDev, { include, exclude }, devtoolsPlugin) { | ||
const nestedDeps = ["solid-js", "solid-js/web", "solid-js/store", "solid-js/html", "solid-js/h"]; | ||
return { | ||
const config = { | ||
resolve: { | ||
@@ -34,2 +47,6 @@ conditions: ["solid", ...isDev ? ["development"] : []], | ||
}; | ||
if (devtoolsPlugin) { | ||
config.plugins?.push(devtoolsPlugin({ autoname: true })); | ||
} | ||
return config; | ||
} | ||
@@ -43,11 +60,30 @@ function getRenderer() { | ||
} | ||
function src_default(opts = {}) { | ||
function getContainerRenderer() { | ||
return { | ||
name: "@astrojs/solid", | ||
serverEntrypoint: "@astrojs/solid-js/server.js" | ||
}; | ||
} | ||
function src_default(options = {}) { | ||
return { | ||
name: "@astrojs/solid-js", | ||
hooks: { | ||
"astro:config:setup": async ({ command, addRenderer, updateConfig }) => { | ||
"astro:config:setup": async ({ | ||
command, | ||
addRenderer, | ||
updateConfig, | ||
injectScript, | ||
logger | ||
}) => { | ||
const devtoolsPlugin = await getDevtoolsPlugin( | ||
logger, | ||
!!options.devtools && command === "dev" | ||
); | ||
addRenderer(getRenderer()); | ||
updateConfig({ | ||
vite: await getViteConfiguration(command === "dev", opts) | ||
vite: await getViteConfiguration(command === "dev", options, devtoolsPlugin) | ||
}); | ||
if (devtoolsPlugin) { | ||
injectScript("page", 'import "solid-devtools";'); | ||
} | ||
} | ||
@@ -58,3 +94,4 @@ } | ||
export { | ||
src_default as default | ||
src_default as default, | ||
getContainerRenderer | ||
}; |
@@ -1,14 +0,3 @@ | ||
import type { RendererContext } from './types'; | ||
declare function check(this: RendererContext, Component: any, props: Record<string, any>, children: any): boolean; | ||
declare function renderToStaticMarkup(this: RendererContext, Component: any, props: Record<string, any>, { default: children, ...slotted }: any, metadata?: undefined | Record<string, any>): { | ||
attrs: { | ||
'data-solid-render-id': string; | ||
}; | ||
html: string; | ||
}; | ||
declare const _default: { | ||
check: typeof check; | ||
renderToStaticMarkup: typeof renderToStaticMarkup; | ||
supportsAstroStaticSlot: boolean; | ||
}; | ||
export default _default; | ||
import type { NamedSSRLoadedRendererValue } from 'astro'; | ||
declare const renderer: NamedSSRLoadedRendererValue; | ||
export default renderer; |
@@ -1,33 +0,77 @@ | ||
import { createComponent, renderToString, ssr } from "solid-js/web"; | ||
import { | ||
NoHydration, | ||
Suspense, | ||
createComponent, | ||
generateHydrationScript, | ||
renderToString, | ||
renderToStringAsync, | ||
ssr | ||
} from "solid-js/web"; | ||
import { getContext, incrementId } from "./context.js"; | ||
const slotName = (str) => str.trim().replace(/[-_]([a-z])/g, (_, w) => w.toUpperCase()); | ||
function check(Component, props, children) { | ||
if (typeof Component !== "function") | ||
return false; | ||
const { html } = renderToStaticMarkup.call(this, Component, props, children); | ||
async function check(Component, props, children) { | ||
if (typeof Component !== "function") return false; | ||
if (Component.name === "QwikComponent") return false; | ||
if (Component.toString().includes("$$payload")) return false; | ||
let html; | ||
try { | ||
const result = await renderToStaticMarkup.call(this, Component, props, children, { | ||
// The purpose of check() is just to validate that this is a Solid component and not | ||
// React, etc. We should render in sync mode which should skip Suspense boundaries | ||
// or loading resources like external API calls. | ||
renderStrategy: "sync" | ||
}); | ||
html = result.html; | ||
} catch { | ||
} | ||
return typeof html === "string"; | ||
} | ||
function renderToStaticMarkup(Component, props, { default: children, ...slotted }, metadata) { | ||
const renderId = metadata?.hydrate ? incrementId(getContext(this.result)) : ""; | ||
async function renderToStaticMarkup(Component, props, { default: children, ...slotted }, metadata) { | ||
const ctx = getContext(this.result); | ||
const renderId = metadata?.hydrate ? incrementId(ctx) : ""; | ||
const needsHydrate = metadata?.astroStaticSlot ? !!metadata.hydrate : true; | ||
const tagName = needsHydrate ? "astro-slot" : "astro-static-slot"; | ||
const html = renderToString( | ||
() => { | ||
const slots = {}; | ||
for (const [key, value] of Object.entries(slotted)) { | ||
const name = slotName(key); | ||
slots[name] = ssr(`<${tagName} name="${name}">${value}</${tagName}>`); | ||
const renderStrategy = metadata?.renderStrategy ?? "async"; | ||
const renderFn = () => { | ||
const slots = {}; | ||
for (const [key, value] of Object.entries(slotted)) { | ||
const name = slotName(key); | ||
slots[name] = ssr(`<${tagName} name="${name}">${value}</${tagName}>`); | ||
} | ||
const newProps = { | ||
...props, | ||
...slots, | ||
// In Solid SSR mode, `ssr` creates the expected structure for `children`. | ||
children: children != null ? ssr(`<${tagName}>${children}</${tagName}>`) : children | ||
}; | ||
if (renderStrategy === "sync") { | ||
return createComponent(Component, newProps); | ||
} else { | ||
if (needsHydrate) { | ||
return createComponent(Suspense, { | ||
get children() { | ||
return createComponent(Component, newProps); | ||
} | ||
}); | ||
} else { | ||
return createComponent(NoHydration, { | ||
get children() { | ||
return createComponent(Suspense, { | ||
get children() { | ||
return createComponent(Component, newProps); | ||
} | ||
}); | ||
} | ||
}); | ||
} | ||
const newProps = { | ||
...props, | ||
...slots, | ||
// In Solid SSR mode, `ssr` creates the expected structure for `children`. | ||
children: children != null ? ssr(`<${tagName}>${children}</${tagName}>`) : children | ||
}; | ||
return createComponent(Component, newProps); | ||
}, | ||
{ | ||
renderId | ||
} | ||
); | ||
}; | ||
const componentHtml = renderStrategy === "async" ? await renderToStringAsync(renderFn, { | ||
renderId, | ||
// New setting since Solid 1.8.4 that fixes an errant hydration event appearing in | ||
// server only components. Not available in TypeScript types yet. | ||
// https://github.com/solidjs/solid/issues/1931 | ||
// https://github.com/ryansolid/dom-expressions/commit/e09e255ac725fd59195aa0f3918065d4bd974e6b | ||
...{ noScripts: !needsHydrate } | ||
}) : renderToString(renderFn, { renderId }); | ||
return { | ||
@@ -37,12 +81,15 @@ attrs: { | ||
}, | ||
html | ||
html: componentHtml | ||
}; | ||
} | ||
var server_default = { | ||
const renderer = { | ||
name: "@astrojs/solid", | ||
check, | ||
renderToStaticMarkup, | ||
supportsAstroStaticSlot: true | ||
supportsAstroStaticSlot: true, | ||
renderHydrationScript: () => generateHydrationScript() | ||
}; | ||
var server_default = renderer; | ||
export { | ||
server_default as default | ||
}; |
{ | ||
"name": "@astrojs/solid-js", | ||
"version": "0.0.0-propagation-metadata-20230907174633", | ||
"version": "0.0.0-sessions-20241122114539", | ||
"description": "Use Solid components within Astro", | ||
@@ -11,3 +11,3 @@ "type": "module", | ||
"type": "git", | ||
"url": "https://github.com/withastro/astro.git", | ||
"url": "git+https://github.com/withastro/astro.git", | ||
"directory": "packages/integrations/solid" | ||
@@ -34,15 +34,25 @@ }, | ||
"dependencies": { | ||
"vite-plugin-solid": "^2.7.0" | ||
"vite-plugin-solid": "^2.10.2", | ||
"vite": "6.0.0-beta.6" | ||
}, | ||
"devDependencies": { | ||
"solid-js": "^1.7.11", | ||
"astro": "0.0.0-propagation-metadata-20230907174633", | ||
"solid-js": "^1.9.3", | ||
"astro": "0.0.0-sessions-20241122114539", | ||
"astro-scripts": "0.0.14" | ||
}, | ||
"peerDependencies": { | ||
"solid-js": "^1.4.3" | ||
"solid-devtools": "^0.30.1", | ||
"solid-js": "^1.8.5" | ||
}, | ||
"peerDependenciesMeta": { | ||
"solid-devtools": { | ||
"optional": true | ||
} | ||
}, | ||
"engines": { | ||
"node": ">=18.14.1" | ||
"node": "^18.17.1 || ^20.3.0 || >=21.0.0" | ||
}, | ||
"publishConfig": { | ||
"provenance": true | ||
}, | ||
"scripts": { | ||
@@ -49,0 +59,0 @@ "build": "astro-scripts build \"src/**/*.ts\" && tsc", |
114
README.md
@@ -5,107 +5,35 @@ # @astrojs/solid-js π | ||
## Installation | ||
## Documentation | ||
There are two ways to add integrations to your project. Let's try the most convenient option first! | ||
Read the [`@astrojs/solid-js` docs][docs] | ||
### `astro add` command | ||
## Support | ||
Astro includes a CLI tool for adding first party integrations: `astro add`. This command will: | ||
- 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! | ||
1. (Optionally) Install all necessary dependencies and peer dependencies | ||
2. (Also optionally) Update your `astro.config.*` file to apply this integration | ||
- Check our [Astro Integration Documentation][astro-integration] for more on integrations. | ||
To install `@astrojs/solid-js`, run the following from your project directory and follow the prompts: | ||
- Submit bug reports and feature requests as [GitHub issues][issues]. | ||
```sh | ||
# Using NPM | ||
npx astro add solid | ||
# Using Yarn | ||
yarn astro add solid | ||
# Using PNPM | ||
pnpm astro add solid | ||
``` | ||
## Contributing | ||
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. | ||
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: | ||
### Install dependencies manually | ||
- [Contributor Manual][contributing] | ||
- [Code of Conduct][coc] | ||
- [Community Guide][community] | ||
First, install the `@astrojs/solid-js` integration like so: | ||
## License | ||
```sh | ||
npm install @astrojs/solid-js | ||
``` | ||
MIT | ||
Most package managers will install associated peer dependencies as well. Still, if you see a "Cannot find package 'solid-js'" (or similar) warning when you start up Astro, you'll need to install SolidJS: | ||
Copyright (c) 2023βpresent [Astro][astro] | ||
```sh | ||
npm install solid-js | ||
``` | ||
Now, apply this integration to your `astro.config.*` file using the `integrations` property: | ||
```js ins={3} "solid()" | ||
// astro.config.mjs | ||
import { defineConfig } from 'astro/config'; | ||
import solid from '@astrojs/solid-js'; | ||
export default defineConfig({ | ||
// ... | ||
integrations: [solid()], | ||
}); | ||
``` | ||
## Getting started | ||
To use your first SolidJS 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 | ||
## Options | ||
### Combining multiple JSX frameworks | ||
When you are using multiple JSX frameworks (React, Preact, Solid) in the same project, Astro needs to determine which JSX framework-specific transformations should be used for each of your components. If you have only added one JSX framework integration to your project, no extra configuration is needed. | ||
Use the `include` (required) and `exclude` (optional) configuration options to specify which files belong to which framework. Provide an array of files and/or folders to `include` for each framework you are using. Wildcards may be used to include multiple file paths. | ||
We recommend placing common framework components in the same folder (e.g. `/components/react/` and `/components/solid/`) to make specifying your includes easier, but this is not required: | ||
```js | ||
import { defineConfig } from 'astro/config'; | ||
import preact from '@astrojs/preact'; | ||
import react from '@astrojs/react'; | ||
import svelte from '@astrojs/svelte'; | ||
import vue from '@astrojs/vue'; | ||
import solid from '@astrojs/solid-js'; | ||
export default defineConfig({ | ||
// Enable many frameworks to support all different kinds of components. | ||
// No `include` is needed if you are only using a single JSX framework! | ||
integrations: [ | ||
preact({ | ||
include: ['**/preact/*'], | ||
}), | ||
react({ | ||
include: ['**/react/*'], | ||
}), | ||
solid({ | ||
include: ['**/solid/*'], | ||
}), | ||
], | ||
}); | ||
``` | ||
## 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/solid-js/ | ||
[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 |
Sorry, the diff of this file is not supported yet
16072
307
4
39
+ Addedvite@6.0.0-beta.6
+ Added@babel/plugin-syntax-typescript@7.25.9(transitive)
+ Added@nothing-but/utils@0.12.1(transitive)
+ Added@solid-devtools/debugger@0.23.4(transitive)
+ Added@solid-devtools/shared@0.13.2(transitive)
+ Added@solid-primitives/bounds@0.0.118(transitive)
+ Added@solid-primitives/cursor@0.0.112(transitive)
+ Added@solid-primitives/event-bus@1.1.0(transitive)
+ Added@solid-primitives/event-listener@2.4.0(transitive)
+ Added@solid-primitives/keyboard@1.3.0(transitive)
+ Added@solid-primitives/media@2.3.0(transitive)
+ Added@solid-primitives/platform@0.1.2(transitive)
+ Added@solid-primitives/refs@1.1.0(transitive)
+ Added@solid-primitives/resize-observer@2.1.0(transitive)
+ Added@solid-primitives/rootless@1.5.0(transitive)
+ Added@solid-primitives/scheduled@1.5.0(transitive)
+ Added@solid-primitives/static-store@0.0.50.1.0(transitive)
+ Added@solid-primitives/styles@0.0.111(transitive)
+ Added@solid-primitives/utils@6.3.0(transitive)
+ Addedsolid-devtools@0.30.1(transitive)
+ Addedvite@6.0.0-beta.6(transitive)
Updatedvite-plugin-solid@^2.10.2