aboutsummaryrefslogtreecommitdiff
path: root/packages/integrations/preact
diff options
context:
space:
mode:
Diffstat (limited to 'packages/integrations/preact')
-rw-r--r--packages/integrations/preact/CHANGELOG.md560
-rw-r--r--packages/integrations/preact/README.md38
-rw-r--r--packages/integrations/preact/package.json57
-rw-r--r--packages/integrations/preact/src/client-dev.ts4
-rw-r--r--packages/integrations/preact/src/client.ts67
-rw-r--r--packages/integrations/preact/src/context.ts32
-rw-r--r--packages/integrations/preact/src/index.ts88
-rw-r--r--packages/integrations/preact/src/server.ts153
-rw-r--r--packages/integrations/preact/src/signals.ts88
-rw-r--r--packages/integrations/preact/src/static-html.ts31
-rw-r--r--packages/integrations/preact/src/types.ts18
-rw-r--r--packages/integrations/preact/tsconfig.json7
12 files changed, 1143 insertions, 0 deletions
diff --git a/packages/integrations/preact/CHANGELOG.md b/packages/integrations/preact/CHANGELOG.md
new file mode 100644
index 000000000..b9ae26b93
--- /dev/null
+++ b/packages/integrations/preact/CHANGELOG.md
@@ -0,0 +1,560 @@
+# @astrojs/preact
+
+## 4.1.0
+
+### Minor Changes
+
+- [#13809](https://github.com/withastro/astro/pull/13809) [`3c3b492`](https://github.com/withastro/astro/commit/3c3b492375bd6a63f1fb6cede3685aff999be3c9) Thanks [@ascorbic](https://github.com/ascorbic)! - Increases minimum Node.js version to 18.20.8
+
+ Node.js 18 has now reached end-of-life and should not be used. For now, Astro will continue to support Node.js 18.20.8, which is the final LTS release of Node.js 18, as well as Node.js 20 and Node.js 22 or later. We will drop support for Node.js 18 in a future release, so we recommend upgrading to Node.js 22 as soon as possible. See Astro's [Node.js support policy](https://docs.astro.build/en/upgrade-astro/#support) for more details.
+
+ :warning: **Important note for users of Cloudflare Pages**: The current build image for Cloudflare Pages uses Node.js 18.17.1 by default, which is no longer supported by Astro. If you are using Cloudflare Pages you should [override the default Node.js version](https://developers.cloudflare.com/pages/configuration/build-image/#override-default-versions) to Node.js 22. This does not affect users of Cloudflare Workers, which uses Node.js 22 by default.
+
+## 4.0.11
+
+### Patch Changes
+
+- [#13731](https://github.com/withastro/astro/pull/13731) [`c3e80c2`](https://github.com/withastro/astro/commit/c3e80c25b90c803e2798b752583a8e77cdad3146) Thanks [@jsparkdev](https://github.com/jsparkdev)! - update vite to latest version for fixing CVE
+
+## 4.0.10
+
+### Patch Changes
+
+- [#13591](https://github.com/withastro/astro/pull/13591) [`5dd2d3f`](https://github.com/withastro/astro/commit/5dd2d3fde8a138ed611dedf39ffa5dfeeed315f8) Thanks [@florian-lefebvre](https://github.com/florian-lefebvre)! - Removes unused code
+
+## 4.0.9
+
+### Patch Changes
+
+- [#13596](https://github.com/withastro/astro/pull/13596) [`3752519`](https://github.com/withastro/astro/commit/375251966d1b28a570bff45ff0fe7e7d2fe46f72) Thanks [@jsparkdev](https://github.com/jsparkdev)! - update vite to latest version to fix CVE
+
+- [#13547](https://github.com/withastro/astro/pull/13547) [`360cb91`](https://github.com/withastro/astro/commit/360cb9199a4314f90825c5639ff4396760e9cfcc) Thanks [@jsparkdev](https://github.com/jsparkdev)! - Updates vite to the latest version
+
+## 4.0.8
+
+### Patch Changes
+
+- [#13526](https://github.com/withastro/astro/pull/13526) [`ff9d69e`](https://github.com/withastro/astro/commit/ff9d69e3443c80059c54f6296d19f66bb068ead3) Thanks [@jsparkdev](https://github.com/jsparkdev)! - update `vite` to the latest version
+
+## 4.0.7
+
+### Patch Changes
+
+- [#13505](https://github.com/withastro/astro/pull/13505) [`a98ae5b`](https://github.com/withastro/astro/commit/a98ae5b8f5c33900379012e9e253a755c0a8927e) Thanks [@ematipico](https://github.com/ematipico)! - Updates the dependency `vite` to the latest.
+
+## 4.0.6
+
+### Patch Changes
+
+- [#13470](https://github.com/withastro/astro/pull/13470) [`ecadb6b`](https://github.com/withastro/astro/commit/ecadb6b02e942feccf584547fe9c14d3d1e21ba6) Thanks [@ascorbic](https://github.com/ascorbic)! - Hides fallback content when rendering `client:only` island
+
+## 4.0.5
+
+### Patch Changes
+
+- [#13323](https://github.com/withastro/astro/pull/13323) [`80926fa`](https://github.com/withastro/astro/commit/80926fadc06492fcae55f105582b9dc8279da6b3) Thanks [@ematipico](https://github.com/ematipico)! - Updates `esbuild` and `vite` to the latest to avoid false positives audits warnings caused by `esbuild`.
+
+## 4.0.4
+
+### Patch Changes
+
+- [#12950](https://github.com/withastro/astro/pull/12950) [`c497491`](https://github.com/withastro/astro/commit/c497491cfe6a03f6a2118392d198ee1738754629) Thanks [@Marabyte](https://github.com/Marabyte)! - Upgrades `@preact/preset-vite`
+
+## 4.0.3
+
+### Patch Changes
+
+- [#13011](https://github.com/withastro/astro/pull/13011) [`cf30880`](https://github.com/withastro/astro/commit/cf3088060d45227dcb48e041c4ed5e0081d71398) Thanks [@ascorbic](https://github.com/ascorbic)! - Upgrades Vite
+
+## 4.0.2
+
+### Patch Changes
+
+- [#12887](https://github.com/withastro/astro/pull/12887) [`ea603ae`](https://github.com/withastro/astro/commit/ea603aec80531205d38fed11c525b3faa0271903) Thanks [@louisescher](https://github.com/louisescher)! - Adds a warning message when multiple JSX-based UI frameworks are being used without either the `include` or `exclude` property being set on the integration.
+
+## 4.0.1
+
+### Patch Changes
+
+- [#12799](https://github.com/withastro/astro/pull/12799) [`739dbfb`](https://github.com/withastro/astro/commit/739dbfba4214107cf8fc40c702834dad33eed3b0) Thanks [@ascorbic](https://github.com/ascorbic)! - Upgrades Vite to pin esbuild
+
+## 4.0.0
+
+### Major Changes
+
+- [#12524](https://github.com/withastro/astro/pull/12524) [`9f44019`](https://github.com/withastro/astro/commit/9f440196dc39f36fce0198bf4c97131160e5bcc1) Thanks [@bluwy](https://github.com/bluwy)! - Updates Vite dependency to v6 to match Astro v5
+
+### Minor Changes
+
+- [#12539](https://github.com/withastro/astro/pull/12539) [`827093e`](https://github.com/withastro/astro/commit/827093e6175549771f9d93ddf3f2be4c2c60f0b7) Thanks [@bluwy](https://github.com/bluwy)! - Drops node 21 support
+
+## 4.0.0-beta.1
+
+### Major Changes
+
+- [#12524](https://github.com/withastro/astro/pull/12524) [`9f44019`](https://github.com/withastro/astro/commit/9f440196dc39f36fce0198bf4c97131160e5bcc1) Thanks [@bluwy](https://github.com/bluwy)! - Updates Vite dependency to v6 to match Astro v5
+
+### Minor Changes
+
+- [#12539](https://github.com/withastro/astro/pull/12539) [`827093e`](https://github.com/withastro/astro/commit/827093e6175549771f9d93ddf3f2be4c2c60f0b7) Thanks [@bluwy](https://github.com/bluwy)! - Drops node 21 support
+
+## 3.5.4
+
+### Patch Changes
+
+- [#12481](https://github.com/withastro/astro/pull/12481) [`8a46e80`](https://github.com/withastro/astro/commit/8a46e8074d6afb4a23badbd59ed239d526294e8c) Thanks [@marbrex](https://github.com/marbrex)! - Resolve `vite` peer dependency problem for strict package managers like **Yarn in PnP mode**.
+
+## 3.5.3
+
+### Patch Changes
+
+- [#11930](https://github.com/withastro/astro/pull/11930) [`4a44e82`](https://github.com/withastro/astro/commit/4a44e82bbdf0572190618d8c5882c63a6525a198) Thanks [@lukasbachlechner](https://github.com/lukasbachlechner)! - Preact components no longer throw an error if a property is null.
+
+## 3.5.2
+
+### Patch Changes
+
+- [#11834](https://github.com/withastro/astro/pull/11834) [`5f2536b`](https://github.com/withastro/astro/commit/5f2536b51df93bfd51098c48220d647e7ad3954c) Thanks [@ph1p](https://github.com/ph1p)! - Preact signals are now serialized correctly in arrays when they are given to components.
+
+## 3.5.1
+
+### Patch Changes
+
+- [#11464](https://github.com/withastro/astro/pull/11464) [`2cdb685`](https://github.com/withastro/astro/commit/2cdb685ce757fc9932b67b8a52b465296dbaedcd) Thanks [@rschristian](https://github.com/rschristian)! - Swap out `preact-ssr-prepass` for `renderToStringAsync` from `preact-render-to-string`
+
+## 3.5.0
+
+### Minor Changes
+
+- [#11234](https://github.com/withastro/astro/pull/11234) [`4385bf7`](https://github.com/withastro/astro/commit/4385bf7a4dc9c65bff53a30c660f7a909fcabfc9) Thanks [@ematipico](https://github.com/ematipico)! - Adds a new function called `addServerRenderer` to the Container API. Use this function to manually store renderers inside the instance of your container.
+
+ This new function should be preferred when using the Container API in environments like on-demand pages:
+
+ ```ts
+ import type { APIRoute } from 'astro';
+ import { experimental_AstroContainer } from 'astro/container';
+ import reactRenderer from '@astrojs/react/server.js';
+ import vueRenderer from '@astrojs/vue/server.js';
+ import ReactComponent from '../components/button.jsx';
+ import VueComponent from '../components/button.vue';
+
+ // MDX runtime is contained inside the Astro core
+ import mdxRenderer from 'astro/jsx/server.js';
+
+ // In case you need to import a custom renderer
+ import customRenderer from '../renderers/customRenderer.js';
+
+ export const GET: APIRoute = async (ctx) => {
+ const container = await experimental_AstroContainer.create();
+ container.addServerRenderer({ renderer: reactRenderer });
+ container.addServerRenderer({ renderer: vueRenderer });
+ container.addServerRenderer({ renderer: customRenderer });
+ // You can pass a custom name too
+ container.addServerRenderer({
+ name: 'customRenderer',
+ renderer: customRenderer,
+ });
+ const vueComponent = await container.renderToString(VueComponent);
+ return await container.renderToResponse(Component);
+ };
+ ```
+
+## 3.4.0
+
+### Minor Changes
+
+- [#11144](https://github.com/withastro/astro/pull/11144) [`803dd80`](https://github.com/withastro/astro/commit/803dd8061df02138b4928442bcb76e77dcf6f5e7) Thanks [@ematipico](https://github.com/ematipico)! - The integration now exposes a function called `getContainerRenderer`, that can be used inside the Container APIs to load the relative renderer.
+
+ ```js
+ import { experimental_AstroContainer as AstroContainer } from 'astro/container';
+ import ReactWrapper from '../src/components/ReactWrapper.astro';
+ import { loadRenderers } from 'astro:container';
+ import { getContainerRenderer } from '@astrojs/react';
+
+ test('ReactWrapper with react renderer', async () => {
+ const renderers = await loadRenderers([getContainerRenderer()]);
+ const container = await AstroContainer.create({
+ renderers,
+ });
+ const result = await container.renderToString(ReactWrapper);
+
+ expect(result).toContain('Counter');
+ expect(result).toContain('Count: <!-- -->5');
+ });
+ ```
+
+## 3.3.0
+
+### Minor Changes
+
+- [#10938](https://github.com/withastro/astro/pull/10938) [`fd508a0`](https://github.com/withastro/astro/commit/fd508a0fbb5148aafc180f1b14d3e47974777248) Thanks [@florian-lefebvre](https://github.com/florian-lefebvre)! - Adds a `devtools` option
+
+ You can enable [Preact devtools](https://preactjs.github.io/preact-devtools/) in development by setting `devtools: true` in your `preact()` integration config:
+
+ ```js
+ import { defineConfig } from 'astro/config';
+ import preact from '@astrojs/preact';
+
+ export default defineConfig({
+ integrations: [preact({ devtools: true })],
+ });
+ ```
+
+## 3.2.0
+
+### Minor Changes
+
+- [#10689](https://github.com/withastro/astro/pull/10689) [`683d51a5eecafbbfbfed3910a3f1fbf0b3531b99`](https://github.com/withastro/astro/commit/683d51a5eecafbbfbfed3910a3f1fbf0b3531b99) Thanks [@ematipico](https://github.com/ematipico)! - Deprecate support for versions of Node.js older than `v18.17.1` for Node.js 18, older than `v20.0.3` for Node.js 20, and the complete Node.js v19 release line.
+
+ This change is in line with Astro's [Node.js support policy](https://docs.astro.build/en/upgrade-astro/#support).
+
+## 3.1.2
+
+### Patch Changes
+
+- [#10585](https://github.com/withastro/astro/pull/10585) [`ad50784adc6f262fc563999e97df3a5dc9087c88`](https://github.com/withastro/astro/commit/ad50784adc6f262fc563999e97df3a5dc9087c88) Thanks [@rschristian](https://github.com/rschristian)! - Fixes (theoretical) edge case in Preact integration's JSX aliases
+
+## 3.1.1
+
+### Patch Changes
+
+- [#10200](https://github.com/withastro/astro/pull/10200) [`c692d0c66a5062937e47402dc700d41c2a5dfc5c`](https://github.com/withastro/astro/commit/c692d0c66a5062937e47402dc700d41c2a5dfc5c) Thanks [@Princesseuh](https://github.com/Princesseuh)! - Fixes passing children to server-rendered components causing an error
+
+## 3.1.0
+
+### Minor Changes
+
+- [#9524](https://github.com/withastro/astro/pull/9524) [`0903ef90494e9c8bd0272347a0cdd51eca7f4648`](https://github.com/withastro/astro/commit/0903ef90494e9c8bd0272347a0cdd51eca7f4648) Thanks [@aleksandrjet](https://github.com/aleksandrjet)! - Allows rendering lazy components.
+
+ You can now use [lazy components](https://preactjs.com/guide/v10/switching-to-preact/#suspense-experimental) with Suspense:
+
+ ```jsx
+ import { lazy, Suspense } from 'preact/compat';
+
+ const HeavyComponent = lazy(() => import('./HeavyComponent'));
+
+ const Component = () => {
+ return (
+ <Suspense fallback={<p>Loading...</p>}>
+ <HeavyComponent foo="bar" />
+ </Suspense>
+ );
+ };
+ ```
+
+## 3.0.2
+
+### Patch Changes
+
+- [#9482](https://github.com/withastro/astro/pull/9482) [`72b26daf694b213918f02d0fcbf90ab5b7ebc31f`](https://github.com/withastro/astro/commit/72b26daf694b213918f02d0fcbf90ab5b7ebc31f) Thanks [@natemoo-re](https://github.com/natemoo-re)! - Improves compatibility with the [Qwik adapter](https://github.com/QwikDev/astro)
+
+- [#9479](https://github.com/withastro/astro/pull/9479) [`1baf0b0d3cbd0564954c2366a7278794fad6726e`](https://github.com/withastro/astro/commit/1baf0b0d3cbd0564954c2366a7278794fad6726e) Thanks [@sarah11918](https://github.com/sarah11918)! - Updates README
+
+## 3.0.1
+
+### Patch Changes
+
+- [#8737](https://github.com/withastro/astro/pull/8737) [`6f60da805`](https://github.com/withastro/astro/commit/6f60da805e0014bc50dd07bef972e91c73560c3c) Thanks [@ematipico](https://github.com/ematipico)! - Add provenance statement when publishing the library from CI
+
+## 3.0.0
+
+### Major Changes
+
+- [#8188](https://github.com/withastro/astro/pull/8188) [`d0679a666`](https://github.com/withastro/astro/commit/d0679a666f37da0fca396d42b9b32bbb25d29312) Thanks [@ematipico](https://github.com/ematipico)! - Remove support for Node 16. The lowest supported version by Astro and all integrations is now v18.14.1. As a reminder, Node 16 will be deprecated on the 11th September 2023.
+
+- [#8179](https://github.com/withastro/astro/pull/8179) [`6011d52d3`](https://github.com/withastro/astro/commit/6011d52d38e43c3e3d52bc3bc41a60e36061b7b7) Thanks [@matthewp](https://github.com/matthewp)! - Astro 3.0 Release Candidate
+
+- [#7924](https://github.com/withastro/astro/pull/7924) [`519a1c4e8`](https://github.com/withastro/astro/commit/519a1c4e8407c7abcb8d879b67a9f4b960652cae) Thanks [@matthewp](https://github.com/matthewp)! - New `include` and `exclude` config options
+
+ The Preact integration now has new `include` and `exclude` config options. Use these if you want to use Preact alongside another JSX framework; include specifies files to be compiled for Preact and `exclude` does the opposite.
+
+### Patch Changes
+
+- [#8264](https://github.com/withastro/astro/pull/8264) [`1f58a7a1b`](https://github.com/withastro/astro/commit/1f58a7a1bea6888868b689dac94801d554319b02) Thanks [@natemoo-re](https://github.com/natemoo-re)! - Automatically unmount islands when `astro:unmount` is fired
+
+## 3.0.0-rc.3
+
+### Patch Changes
+
+- [#8264](https://github.com/withastro/astro/pull/8264) [`1f58a7a1b`](https://github.com/withastro/astro/commit/1f58a7a1bea6888868b689dac94801d554319b02) Thanks [@natemoo-re](https://github.com/natemoo-re)! - Automatically unmount islands when `astro:unmount` is fired
+
+## 3.0.0-rc.2
+
+### Major Changes
+
+- [#8179](https://github.com/withastro/astro/pull/8179) [`6011d52d3`](https://github.com/withastro/astro/commit/6011d52d38e43c3e3d52bc3bc41a60e36061b7b7) Thanks [@matthewp](https://github.com/matthewp)! - Astro 3.0 Release Candidate
+
+## 3.0.0-beta.1
+
+### Major Changes
+
+- [#7924](https://github.com/withastro/astro/pull/7924) [`519a1c4e8`](https://github.com/withastro/astro/commit/519a1c4e8407c7abcb8d879b67a9f4b960652cae) Thanks [@matthewp](https://github.com/matthewp)! - New `include` and `exclude` config options
+
+ The Preact integration now has new `include` and `exclude` config options. Use these if you want to use Preact alongside another JSX framework; include specifies files to be compiled for Preact and `exclude` does the opposite.
+
+## 3.0.0-beta.0
+
+### Major Changes
+
+- [`1eae2e3f7`](https://github.com/withastro/astro/commit/1eae2e3f7d693c9dfe91c8ccfbe606d32bf2fb81) Thanks [@Princesseuh](https://github.com/Princesseuh)! - Remove support for Node 16. The lowest supported version by Astro and all integrations is now v18.14.1. As a reminder, Node 16 will be deprecated on the 11th September 2023.
+
+## 2.2.2
+
+### Patch Changes
+
+- [#8007](https://github.com/withastro/astro/pull/8007) [`58b121d42`](https://github.com/withastro/astro/commit/58b121d42a9f58a5a992f0c378b036f37e9715fc) Thanks [@paperdave](https://github.com/paperdave)! - Support Bun by adjusting how `@babel/plugin-transform-react-jsx` is imported.
+
+## 2.2.1
+
+### Patch Changes
+
+- [#7196](https://github.com/withastro/astro/pull/7196) [`1c77779dd`](https://github.com/withastro/astro/commit/1c77779dd66a6db77c81ed235da076a6118decde) Thanks [@bluwy](https://github.com/bluwy)! - Fix `astro-static-slot` hydration mismatch error
+
+## 2.2.0
+
+### Minor Changes
+
+- [#7093](https://github.com/withastro/astro/pull/7093) [`3d525efc9`](https://github.com/withastro/astro/commit/3d525efc95cfb2deb5d9e04856d02965d66901c9) Thanks [@matthewp](https://github.com/matthewp)! - Prevent removal of nested slots within islands
+
+ This change introduces a new flag that renderers can add called `supportsAstroStaticSlot`. What this does is let Astro know that the render is sending `<astro-static-slot>` as placeholder values for static (non-hydrated) slots which Astro will then remove.
+
+ This change is completely backwards compatible, but fixes bugs caused by combining ssr-only and client-side framework components like so:
+
+ ```astro
+ <Component>
+ <div>
+ <Component client:load>
+ <span>Nested</span>
+ </Component>
+ </div>
+ </Component>
+ ```
+
+### Patch Changes
+
+- [#7104](https://github.com/withastro/astro/pull/7104) [`826e02890`](https://github.com/withastro/astro/commit/826e0289005f645b902375b98d5549c6a95ccafa) Thanks [@bluwy](https://github.com/bluwy)! - Specify `"files"` field to only publish necessary files
+
+## 2.1.0
+
+### Minor Changes
+
+- [#6213](https://github.com/withastro/astro/pull/6213) [`afbbc4d5b`](https://github.com/withastro/astro/commit/afbbc4d5bfafc1779bac00b41c2a1cb1c90f2808) Thanks [@Princesseuh](https://github.com/Princesseuh)! - Updated compilation settings to disable downlevelling for Node 14
+
+## 2.0.3
+
+### Patch Changes
+
+- [#6215](https://github.com/withastro/astro/pull/6215) [`a7f18051b`](https://github.com/withastro/astro/commit/a7f18051b118b4f263ed9093ab17ed7eec0e4fd5) Thanks [@matthewp](https://github.com/matthewp)! - Prevent hydration mismatches in Preact
+
+## 2.0.2
+
+### Patch Changes
+
+- [#6108](https://github.com/withastro/astro/pull/6108) [`f9babc38b`](https://github.com/withastro/astro/commit/f9babc38b48049f73a3a282f48d8cb26969cb0a0) Thanks [@matthewp](https://github.com/matthewp)! - Upgrade babel dependency to fix security vuln
+
+## 2.0.1
+
+### Patch Changes
+
+- [#5478](https://github.com/withastro/astro/pull/5478) [`1c7eef308`](https://github.com/withastro/astro/commit/1c7eef308e808aa5ed4662b53e67ec8d1b814d1f) Thanks [@nemo0](https://github.com/nemo0)! - Update READMEs for consistency
+
+## 2.0.0
+
+### Major Changes
+
+- [#5782](https://github.com/withastro/astro/pull/5782) [`1f92d64ea`](https://github.com/withastro/astro/commit/1f92d64ea35c03fec43aff64eaf704dc5a9eb30a) Thanks [@Princesseuh](https://github.com/Princesseuh)! - Remove support for Node 14. Minimum supported Node version is now >=16.12.0
+
+## 2.0.0-beta.0
+
+<details>
+<summary>See changes in 2.0.0-beta.0</summary>
+
+### Major Changes
+
+- [#5782](https://github.com/withastro/astro/pull/5782) [`1f92d64ea`](https://github.com/withastro/astro/commit/1f92d64ea35c03fec43aff64eaf704dc5a9eb30a) Thanks [@Princesseuh](https://github.com/Princesseuh)! - Remove support for Node 14. Minimum supported Node version is now >=16.12.0
+
+</details>
+
+## 1.2.0
+
+### Minor Changes
+
+- [#5015](https://github.com/withastro/astro/pull/5015) [`b1964e9e1`](https://github.com/withastro/astro/commit/b1964e9e1b7f9178036e266b89d3c8b9cbffd1c6) Thanks [@matthewp](https://github.com/matthewp)! - Shared state in Preact components with signals
+
+ This makes it possible to share client state between Preact islands via signals.
+
+ For example, you can create a signals in an Astro component and then pass it to multiple islands:
+
+ ```astro
+ ---
+ // Component Imports
+ import Counter from '../components/Counter';
+ import { signal } from '@preact/signals';
+ const count = signal(0);
+ ---
+
+ <Count count={count} />
+ <Count count={count} />
+ ```
+
+## 1.1.1
+
+### Patch Changes
+
+- [#4842](https://github.com/withastro/astro/pull/4842) [`812658ad2`](https://github.com/withastro/astro/commit/812658ad2ab3732a99e35c4fd903e302e723db46) Thanks [@bluwy](https://github.com/bluwy)! - Add missing dependencies, support strict dependency installation (e.g. pnpm)
+
+## 1.1.0
+
+### Minor Changes
+
+- [#4515](https://github.com/withastro/astro/pull/4515) [`999250d65`](https://github.com/withastro/astro/commit/999250d651996c2833b747b84447aa4e97c91a38) Thanks [@marvinhagemeister](https://github.com/marvinhagemeister)! - Automatically set up Preact DevTools bridge when running `astro dev`.
+
+## 1.0.2
+
+### Patch Changes
+
+- [#4267](https://github.com/withastro/astro/pull/4267) [`5b1facfe2`](https://github.com/withastro/astro/commit/5b1facfe291b998c0c6814293b18df211a8f3cd3) Thanks [@bluwy](https://github.com/bluwy)! - README: Clarify `compat` docs
+
+## 1.0.1
+
+### Patch Changes
+
+- [#4213](https://github.com/withastro/astro/pull/4213) [`f8e385339`](https://github.com/withastro/astro/commit/f8e3853394c2f2f48fac4b5eb2284e1960e59a13) Thanks [@bluwy](https://github.com/bluwy)! - Fix compat support for libraries
+
+## 1.0.0
+
+### Major Changes
+
+- [`04ad44563`](https://github.com/withastro/astro/commit/04ad445632c67bdd60c1704e1e0dcbcaa27b9308) - > Astro v1.0 is out! Read the [official announcement post](https://astro.build/blog/astro-1/).
+
+ **No breaking changes**. This package is now officially stable and compatible with `astro@1.0.0`!
+
+## 0.5.2
+
+### Patch Changes
+
+- [#3937](https://github.com/withastro/astro/pull/3937) [`31f9c0bf0`](https://github.com/withastro/astro/commit/31f9c0bf029ffa4b470e620f2c32e1370643e81e) Thanks [@delucis](https://github.com/delucis)! - Roll back supported Node engines
+
+## 0.5.1
+
+### Patch Changes
+
+- [#3928](https://github.com/withastro/astro/pull/3928) [`d6dfef0ca`](https://github.com/withastro/astro/commit/d6dfef0caa25f4effd0ed548d92ff48ce7a39ab2) Thanks [@matthewp](https://github.com/matthewp)! - Removes @babel/core peerDependency warning
+
+## 0.5.0
+
+### Minor Changes
+
+- [#3914](https://github.com/withastro/astro/pull/3914) [`b48767985`](https://github.com/withastro/astro/commit/b48767985359bd359df8071324952ea5f2bc0d86) Thanks [@ran-dall](https://github.com/ran-dall)! - Rollback supported `node@16` version. Minimum versions are now `node@14.20.0` or `node@16.14.0`.
+
+## 0.4.1
+
+### Patch Changes
+
+- [#3885](https://github.com/withastro/astro/pull/3885) [`bf5d1cc1e`](https://github.com/withastro/astro/commit/bf5d1cc1e71da38a14658c615e9481f2145cc6e7) Thanks [@delucis](https://github.com/delucis)! - Integration README fixes
+
+## 0.4.0
+
+### Minor Changes
+
+- [#3871](https://github.com/withastro/astro/pull/3871) [`1cc5b7890`](https://github.com/withastro/astro/commit/1cc5b78905633608e5b07ad291f916f54e67feb1) Thanks [@natemoo-re](https://github.com/natemoo-re)! - Update supported `node` versions. Minimum versions are now `node@14.20.0` or `node@16.16.0`.
+
+## 0.3.2
+
+### Patch Changes
+
+- [#3854](https://github.com/withastro/astro/pull/3854) [`b012ee55`](https://github.com/withastro/astro/commit/b012ee55b107dea0730286263b27d83e530fad5d) Thanks [@bholmesdev](https://github.com/bholmesdev)! - [astro add] Support adapters and third party packages
+
+## 0.3.1
+
+### Patch Changes
+
+- [#3769](https://github.com/withastro/astro/pull/3769) [`b934ab5d`](https://github.com/withastro/astro/commit/b934ab5d860aa3adeec56a9c395f629ee7252ca4) Thanks [@hippotastic](https://github.com/hippotastic)! - Fix "Invalid hook call" warning
+
+## 0.3.0
+
+### Minor Changes
+
+- [#3712](https://github.com/withastro/astro/pull/3712) [`e3fdc9b4`](https://github.com/withastro/astro/commit/e3fdc9b4030b96e815c133a388a7625b7e8e4a2e) Thanks [@delucis](https://github.com/delucis)! - Add support for enabling `preact/compat` to Preact renderer
+
+ To use `preact/compat` to render React components, users can now set `compat` to `true` when using the Preact integration:
+
+ ```js
+ integrations: [
+ preact({ compat: true }),
+ ],
+ ```
+
+## 0.2.0
+
+### Minor Changes
+
+- [#3652](https://github.com/withastro/astro/pull/3652) [`7373d61c`](https://github.com/withastro/astro/commit/7373d61cdcaedd64bf5fd60521b157cfa4343558) Thanks [@natemoo-re](https://github.com/natemoo-re)! - Add support for passing named slots from `.astro` => framework components.
+
+ Each `slot` is be passed as a top-level prop. For example:
+
+ ```jsx
+ // From .astro
+ <Component>
+ <h2 slot="title">Hello world!</h2>
+ <h2 slot="slot-with-dash">Dash</h2>
+ <div>Default</div>
+ </Component>;
+
+ // For .jsx
+ export default function Component({ title, slotWithDash, children }) {
+ return (
+ <>
+ <div id="title">{title}</div>
+ <div id="slot-with-dash">{slotWithDash}</div>
+ <div id="main">{children}</div>
+ </>
+ );
+ }
+ ```
+
+## 0.1.3
+
+### Patch Changes
+
+- [#3455](https://github.com/withastro/astro/pull/3455) [`e9a77d86`](https://github.com/withastro/astro/commit/e9a77d861907adccfa75811f9aaa555f186d78f8) Thanks [@natemoo-re](https://github.com/natemoo-re)! - Update client hydration to check for `ssr` attribute. Requires `astro@^1.0.0-beta.36`.
+
+## 0.1.2
+
+### Patch Changes
+
+- [#3166](https://github.com/withastro/astro/pull/3166) [`70263cf7`](https://github.com/withastro/astro/commit/70263cf7481b11e42152c422acc6cfe90fe10ad2) Thanks [@natemoo-re](https://github.com/natemoo-re)! - Fix integration to use updateConfig rather than returning a partial config object
+
+## 0.1.1
+
+### Patch Changes
+
+- [`815d62f1`](https://github.com/withastro/astro/commit/815d62f151a36fef7d09590d4962ca71bda61b32) Thanks [@FredKSchott](https://github.com/FredKSchott)! - no changes.
+
+## 0.1.0
+
+### Minor Changes
+
+- [#2979](https://github.com/withastro/astro/pull/2979) [`9d7a4b59`](https://github.com/withastro/astro/commit/9d7a4b59b53f8cb274266f5036d1cef841750252) Thanks [@FredKSchott](https://github.com/FredKSchott)! - Welcome to the Astro v1.0.0 Beta! Read the [official announcement](https://astro.build/blog/astro-1-beta-release/) for more details.
+
+## 0.0.2
+
+### Patch Changes
+
+- [#2885](https://github.com/withastro/astro/pull/2885) [`6b004363`](https://github.com/withastro/astro/commit/6b004363f99f27e581d1e2d53a2ebff39d7afb8a) Thanks [@bholmesdev](https://github.com/bholmesdev)! - Add README across Astro built-in integrations
+
+* [#2847](https://github.com/withastro/astro/pull/2847) [`3b621f7a`](https://github.com/withastro/astro/commit/3b621f7a613b45983b090794fa7c015f23ed6140) Thanks [@tony-sull](https://github.com/tony-sull)! - Adds keywords to the official integrations to support discoverability on Astro's Integrations site
+
+- [#2872](https://github.com/withastro/astro/pull/2872) [`098f6f6b`](https://github.com/withastro/astro/commit/098f6f6b06396441c576dc689d8552629ef260e1) Thanks [@bholmesdev](https://github.com/bholmesdev)! - Fix `isSelfAccepting` errors when using the Preact integration with the Astro dev server
+
+## 0.0.2-next.1
+
+### Patch Changes
+
+- [#2872](https://github.com/withastro/astro/pull/2872) [`098f6f6b`](https://github.com/withastro/astro/commit/098f6f6b06396441c576dc689d8552629ef260e1) Thanks [@bholmesdev](https://github.com/bholmesdev)! - Fix `isSelfAccepting` errors when using the Preact integration with the Astro dev server
+
+## 0.0.2-next.0
+
+### Patch Changes
+
+- [#2847](https://github.com/withastro/astro/pull/2847) [`3b621f7a`](https://github.com/withastro/astro/commit/3b621f7a613b45983b090794fa7c015f23ed6140) Thanks [@tony-sull](https://github.com/tony-sull)! - Adds keywords to the official integrations to support discoverability on Astro's Integrations site
diff --git a/packages/integrations/preact/README.md b/packages/integrations/preact/README.md
new file mode 100644
index 000000000..4106ed2ab
--- /dev/null
+++ b/packages/integrations/preact/README.md
@@ -0,0 +1,38 @@
+# @astrojs/preact ⚛️
+
+This **[Astro integration][astro-integration]** enables server-side rendering and client-side hydration for your [Preact](https://preactjs.com/) components.
+
+## Documentation
+
+Read the [`@astrojs/preact` docs][docs]
+
+## Support
+
+- 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!
+
+- Check our [Astro Integration Documentation][astro-integration] for more on integrations.
+
+- Submit bug reports and feature requests as [GitHub issues][issues].
+
+## Contributing
+
+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:
+
+- [Contributor Manual][contributing]
+- [Code of Conduct][coc]
+- [Community Guide][community]
+
+## License
+
+MIT
+
+Copyright (c) 2023–present [Astro][astro]
+
+[astro]: https://astro.build/
+[docs]: https://docs.astro.build/en/guides/integrations-guide/preact/
+[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/
diff --git a/packages/integrations/preact/package.json b/packages/integrations/preact/package.json
new file mode 100644
index 000000000..111df4910
--- /dev/null
+++ b/packages/integrations/preact/package.json
@@ -0,0 +1,57 @@
+{
+ "name": "@astrojs/preact",
+ "description": "Use Preact components within Astro",
+ "version": "4.1.0",
+ "type": "module",
+ "types": "./dist/index.d.ts",
+ "author": "withastro",
+ "license": "MIT",
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/withastro/astro.git",
+ "directory": "packages/integrations/preact"
+ },
+ "keywords": [
+ "astro-integration",
+ "astro-component",
+ "renderer",
+ "preact"
+ ],
+ "bugs": "https://github.com/withastro/astro/issues",
+ "homepage": "https://docs.astro.build/en/guides/integrations-guide/preact/",
+ "exports": {
+ ".": "./dist/index.js",
+ "./client.js": "./dist/client.js",
+ "./client-dev.js": "./dist/client-dev.js",
+ "./server.js": "./dist/server.js",
+ "./package.json": "./package.json"
+ },
+ "files": [
+ "dist"
+ ],
+ "scripts": {
+ "build": "astro-scripts build \"src/**/*.ts\" && tsc",
+ "build:ci": "astro-scripts build \"src/**/*.ts\"",
+ "dev": "astro-scripts dev \"src/**/*.ts\""
+ },
+ "dependencies": {
+ "@preact/preset-vite": "^2.10.1",
+ "@preact/signals": "^2.2.0",
+ "preact-render-to-string": "^6.5.13",
+ "vite": "^6.3.5"
+ },
+ "devDependencies": {
+ "astro": "workspace:*",
+ "astro-scripts": "workspace:*",
+ "preact": "^10.26.8"
+ },
+ "peerDependencies": {
+ "preact": "^10.6.5"
+ },
+ "engines": {
+ "node": "18.20.8 || ^20.3.0 || >=22.0.0"
+ },
+ "publishConfig": {
+ "provenance": true
+ }
+}
diff --git a/packages/integrations/preact/src/client-dev.ts b/packages/integrations/preact/src/client-dev.ts
new file mode 100644
index 000000000..d37e6e0af
--- /dev/null
+++ b/packages/integrations/preact/src/client-dev.ts
@@ -0,0 +1,4 @@
+import 'preact/debug';
+import clientFn from './client.js';
+
+export default clientFn;
diff --git a/packages/integrations/preact/src/client.ts b/packages/integrations/preact/src/client.ts
new file mode 100644
index 000000000..40475acc8
--- /dev/null
+++ b/packages/integrations/preact/src/client.ts
@@ -0,0 +1,67 @@
+import { h, hydrate, render } from 'preact';
+import StaticHtml from './static-html.js';
+import type { SignalLike } from './types.js';
+
+const sharedSignalMap = new Map<string, SignalLike>();
+
+export default (element: HTMLElement) =>
+ async (
+ Component: any,
+ props: Record<string, any>,
+ { default: children, ...slotted }: Record<string, any>,
+ { client }: Record<string, string>,
+ ) => {
+ if (!element.hasAttribute('ssr')) return;
+ for (const [key, value] of Object.entries(slotted)) {
+ props[key] = h(StaticHtml, { value, name: key });
+ }
+ let signalsRaw = element.dataset.preactSignals;
+ if (signalsRaw) {
+ const { signal } = await import('@preact/signals');
+ let signals: Record<string, string | [string, number][]> = JSON.parse(
+ element.dataset.preactSignals!,
+ );
+ for (const [propName, signalId] of Object.entries(signals)) {
+ if (Array.isArray(signalId)) {
+ signalId.forEach(([id, indexOrKeyInProps]) => {
+ const mapValue = props[propName][indexOrKeyInProps];
+ let valueOfSignal = mapValue;
+
+ // not an property key
+ if (typeof indexOrKeyInProps !== 'string') {
+ valueOfSignal = mapValue[0];
+ indexOrKeyInProps = mapValue[1];
+ }
+
+ if (!sharedSignalMap.has(id)) {
+ const signalValue = signal(valueOfSignal);
+ sharedSignalMap.set(id, signalValue);
+ }
+ props[propName][indexOrKeyInProps] = sharedSignalMap.get(id);
+ });
+ } else {
+ if (!sharedSignalMap.has(signalId)) {
+ const signalValue = signal(props[propName]);
+ sharedSignalMap.set(signalId, signalValue);
+ }
+ props[propName] = sharedSignalMap.get(signalId);
+ }
+ }
+ }
+
+ const child = h(
+ Component,
+ props,
+ children != null ? h(StaticHtml, { value: children }) : children,
+ );
+
+ if (client === 'only') {
+ element.innerHTML = '';
+ render(child, element);
+ } else {
+ hydrate(child, element);
+ }
+
+ // Preact has no "unmount" option, but you can use `render(null, element)`
+ element.addEventListener('astro:unmount', () => render(null, element), { once: true });
+ };
diff --git a/packages/integrations/preact/src/context.ts b/packages/integrations/preact/src/context.ts
new file mode 100644
index 000000000..4d2398d28
--- /dev/null
+++ b/packages/integrations/preact/src/context.ts
@@ -0,0 +1,32 @@
+import type { PropNameToSignalMap, RendererContext, SignalLike } from './types.js';
+
+export type Context = {
+ id: string;
+ c: number;
+ signals: Map<SignalLike, string>;
+ propsToSignals: Map<Record<string, any>, PropNameToSignalMap>;
+};
+
+const contexts = new WeakMap<RendererContext['result'], Context>();
+
+export function getContext(result: RendererContext['result']): Context {
+ if (contexts.has(result)) {
+ return contexts.get(result)!;
+ }
+ let ctx = {
+ c: 0,
+ get id() {
+ return 'p' + this.c.toString();
+ },
+ signals: new Map(),
+ propsToSignals: new Map(),
+ };
+ contexts.set(result, ctx);
+ return ctx;
+}
+
+export function incrementId(ctx: Context): string {
+ let id = ctx.id;
+ ctx.c++;
+ return id;
+}
diff --git a/packages/integrations/preact/src/index.ts b/packages/integrations/preact/src/index.ts
new file mode 100644
index 000000000..fd16a9e4a
--- /dev/null
+++ b/packages/integrations/preact/src/index.ts
@@ -0,0 +1,88 @@
+import { fileURLToPath } from 'node:url';
+import { type PreactPluginOptions as VitePreactPluginOptions, preact } from '@preact/preset-vite';
+import type { AstroIntegration, AstroRenderer, ContainerRenderer, ViteUserConfig } from 'astro';
+
+const babelCwd = new URL('../', import.meta.url);
+
+function getRenderer(development: boolean): AstroRenderer {
+ return {
+ name: '@astrojs/preact',
+ clientEntrypoint: development ? '@astrojs/preact/client-dev.js' : '@astrojs/preact/client.js',
+ serverEntrypoint: '@astrojs/preact/server.js',
+ };
+}
+
+export function getContainerRenderer(): ContainerRenderer {
+ return {
+ name: '@astrojs/preact',
+ serverEntrypoint: '@astrojs/preact/server.js',
+ };
+}
+
+export interface Options extends Pick<VitePreactPluginOptions, 'include' | 'exclude'> {
+ compat?: boolean;
+ devtools?: boolean;
+}
+
+export default function ({ include, exclude, compat, devtools }: Options = {}): AstroIntegration {
+ return {
+ name: '@astrojs/preact',
+ hooks: {
+ 'astro:config:setup': ({ addRenderer, updateConfig, command, injectScript }) => {
+ const preactPlugin = preact({
+ reactAliasesEnabled: compat ?? false,
+ include,
+ exclude,
+ babel: {
+ cwd: fileURLToPath(babelCwd),
+ },
+ });
+
+ const viteConfig: ViteUserConfig = {
+ optimizeDeps: {
+ include: ['@astrojs/preact/client.js', 'preact', 'preact/jsx-runtime'],
+ exclude: ['@astrojs/preact/server.js'],
+ },
+ };
+
+ if (compat) {
+ viteConfig.optimizeDeps!.include!.push(
+ 'preact/compat',
+ 'preact/test-utils',
+ 'preact/compat/jsx-runtime',
+ );
+ viteConfig.resolve = {
+ dedupe: ['preact/compat', 'preact'],
+ };
+ // noExternal React entrypoints to be bundled, resolved, and aliased by Vite
+ viteConfig.ssr = {
+ noExternal: ['react', 'react-dom', 'react-dom/test-utils', 'react/jsx-runtime'],
+ };
+ }
+
+ viteConfig.plugins = [preactPlugin];
+
+ addRenderer(getRenderer(command === 'dev'));
+ updateConfig({
+ vite: viteConfig,
+ });
+
+ if (command === 'dev' && devtools) {
+ injectScript('page', 'import "preact/debug";');
+ }
+ },
+ 'astro:config:done': ({ logger, config }) => {
+ const knownJsxRenderers = ['@astrojs/react', '@astrojs/preact', '@astrojs/solid-js'];
+ const enabledKnownJsxRenderers = config.integrations.filter((renderer) =>
+ knownJsxRenderers.includes(renderer.name),
+ );
+
+ if (enabledKnownJsxRenderers.length > 1 && !include && !exclude) {
+ logger.warn(
+ 'More than one JSX renderer is enabled. This will lead to unexpected behavior unless you set the `include` or `exclude` option. See https://docs.astro.build/en/guides/integrations-guide/preact/#combining-multiple-jsx-frameworks for more information.',
+ );
+ }
+ },
+ },
+ };
+}
diff --git a/packages/integrations/preact/src/server.ts b/packages/integrations/preact/src/server.ts
new file mode 100644
index 000000000..5b38ff590
--- /dev/null
+++ b/packages/integrations/preact/src/server.ts
@@ -0,0 +1,153 @@
+import type { AstroComponentMetadata, NamedSSRLoadedRendererValue } from 'astro';
+import { Component as BaseComponent, type VNode, h } from 'preact';
+import { renderToStringAsync } from 'preact-render-to-string';
+import { getContext } from './context.js';
+import { restoreSignalsOnProps, serializeSignals } from './signals.js';
+import StaticHtml from './static-html.js';
+import type { AstroPreactAttrs, RendererContext } from './types.js';
+
+const slotName = (str: string) => str.trim().replace(/[-_]([a-z])/g, (_, w) => w.toUpperCase());
+
+let originalConsoleError: typeof console.error;
+let consoleFilterRefs = 0;
+
+async function check(
+ this: RendererContext,
+ Component: any,
+ props: Record<string, any>,
+ children: any,
+) {
+ if (typeof Component !== 'function') return false;
+ if (Component.name === 'QwikComponent') return false;
+
+ if (Component.prototype != null && typeof Component.prototype.render === 'function') {
+ return BaseComponent.isPrototypeOf(Component);
+ }
+
+ useConsoleFilter();
+
+ try {
+ const { html } = await renderToStaticMarkup.call(this, Component, props, children, undefined);
+ if (typeof html !== 'string') {
+ return false;
+ }
+
+ // There are edge cases (SolidJS) where Preact *might* render a string,
+ // but components would be <undefined></undefined>
+ // It also might render an empty sting.
+ return html == '' ? false : !html.includes('<undefined>');
+ } catch {
+ return false;
+ } finally {
+ finishUsingConsoleFilter();
+ }
+}
+
+function shouldHydrate(metadata: AstroComponentMetadata | undefined) {
+ // Adjust how this is hydrated only when the version of Astro supports `astroStaticSlot`
+ return metadata?.astroStaticSlot ? !!metadata.hydrate : true;
+}
+
+async function renderToStaticMarkup(
+ this: RendererContext,
+ Component: any,
+ props: Record<string, any>,
+ { default: children, ...slotted }: Record<string, any>,
+ metadata: AstroComponentMetadata | undefined,
+) {
+ const ctx = getContext(this.result);
+
+ const slots: Record<string, ReturnType<typeof h>> = {};
+ for (const [key, value] of Object.entries(slotted)) {
+ const name = slotName(key);
+ slots[name] = h(StaticHtml, {
+ hydrate: shouldHydrate(metadata),
+ value,
+ name,
+ }) as VNode<any>;
+ }
+
+ // Restore signals back onto props so that they will be passed as-is to components
+ let propsMap = restoreSignalsOnProps(ctx, props);
+
+ const newProps = { ...props, ...slots };
+
+ const attrs: AstroPreactAttrs = {};
+ serializeSignals(ctx, props, attrs, propsMap);
+
+ const vNode: VNode<any> = h(
+ Component,
+ newProps,
+ children != null
+ ? h(StaticHtml, {
+ hydrate: shouldHydrate(metadata),
+ value: children,
+ })
+ : children,
+ );
+
+ const html = await renderToStringAsync(vNode);
+ return { attrs, html };
+}
+
+/**
+ * Reduces console noise by filtering known non-problematic errors.
+ *
+ * Performs reference counting to allow parallel usage from async code.
+ *
+ * To stop filtering, please ensure that there always is a matching call
+ * to `finishUsingConsoleFilter` afterwards.
+ */
+function useConsoleFilter() {
+ consoleFilterRefs++;
+
+ if (!originalConsoleError) {
+ originalConsoleError = console.error;
+
+ try {
+ console.error = filteredConsoleError;
+ } catch {
+ // If we're unable to hook `console.error`, just accept it
+ }
+ }
+}
+
+/**
+ * Indicates that the filter installed by `useConsoleFilter`
+ * is no longer needed by the calling code.
+ */
+function finishUsingConsoleFilter() {
+ consoleFilterRefs--;
+
+ // Note: Instead of reverting `console.error` back to the original
+ // when the reference counter reaches 0, we leave our hook installed
+ // to prevent potential race conditions once `check` is made async
+}
+
+/**
+ * Hook/wrapper function for the global `console.error` function.
+ *
+ * Ignores known non-problematic errors while any code is using the console filter.
+ * Otherwise, simply forwards all arguments to the original function.
+ */
+function filteredConsoleError(msg: string, ...rest: any[]) {
+ if (consoleFilterRefs > 0 && typeof msg === 'string') {
+ // In `check`, we attempt to render JSX components through Preact.
+ // When attempting this on a React component, React may output
+ // the following error, which we can safely filter out:
+ const isKnownReactHookError =
+ msg.includes('Warning: Invalid hook call.') &&
+ msg.includes('https://reactjs.org/link/invalid-hook-call');
+ if (isKnownReactHookError) return;
+ }
+ originalConsoleError(msg, ...rest);
+}
+
+const renderer: NamedSSRLoadedRendererValue = {
+ name: '@astrojs/preact',
+ check,
+ renderToStaticMarkup,
+ supportsAstroStaticSlot: true,
+};
+
+export default renderer;
diff --git a/packages/integrations/preact/src/signals.ts b/packages/integrations/preact/src/signals.ts
new file mode 100644
index 000000000..88a50327a
--- /dev/null
+++ b/packages/integrations/preact/src/signals.ts
@@ -0,0 +1,88 @@
+import type { Context } from './context.js';
+import { incrementId } from './context.js';
+import type {
+ ArrayObjectMapping,
+ AstroPreactAttrs,
+ PropNameToSignalMap,
+ SignalLike,
+ SignalToKeyOrIndexMap,
+ Signals,
+} from './types.js';
+
+function isSignal(x: any): x is SignalLike {
+ return x != null && typeof x === 'object' && typeof x.peek === 'function' && 'value' in x;
+}
+
+export function restoreSignalsOnProps(ctx: Context, props: Record<string, any>) {
+ // Restore signal props that were mutated for serialization
+ let propMap: PropNameToSignalMap;
+ if (ctx.propsToSignals.has(props)) {
+ propMap = ctx.propsToSignals.get(props)!;
+ } else {
+ propMap = new Map();
+ ctx.propsToSignals.set(props, propMap);
+ }
+ for (const [key, signal] of propMap) {
+ props[key] = signal;
+ }
+ return propMap;
+}
+
+export function serializeSignals(
+ ctx: Context,
+ props: Record<string, any>,
+ attrs: AstroPreactAttrs,
+ map: PropNameToSignalMap,
+) {
+ // Check for signals
+ const signals: Signals = {};
+ for (const [key, value] of Object.entries(props)) {
+ const isPropArray = Array.isArray(value);
+ // `typeof null` is 'object' in JS, so we need to check for `null` specifically
+ const isPropObject =
+ !isSignal(value) && typeof props[key] === 'object' && props[key] !== null && !isPropArray;
+
+ if (isPropObject || isPropArray) {
+ const values = isPropObject ? Object.keys(props[key]) : value;
+ values.forEach((valueKey: number | string, valueIndex: number) => {
+ const signal = isPropObject ? props[key][valueKey] : valueKey;
+ if (isSignal(signal)) {
+ const keyOrIndex = isPropObject ? valueKey.toString() : valueIndex;
+
+ props[key] = isPropObject
+ ? Object.assign({}, props[key], { [keyOrIndex]: signal.peek() })
+ : props[key].map((v: SignalLike, i: number) =>
+ i === valueIndex ? [signal.peek(), i] : v,
+ );
+
+ const currentMap = (map.get(key) || []) as SignalToKeyOrIndexMap;
+ map.set(key, [...currentMap, [signal, keyOrIndex]]);
+
+ const currentSignals = (signals[key] || []) as ArrayObjectMapping;
+ signals[key] = [...currentSignals, [getSignalId(ctx, signal), keyOrIndex]];
+ }
+ });
+ } else if (isSignal(value)) {
+ // Set the value to the current signal value
+ // This mutates the props on purpose, so that it will be serialized correct.
+ props[key] = value.peek();
+ map.set(key, value);
+
+ signals[key] = getSignalId(ctx, value);
+ }
+ }
+
+ if (Object.keys(signals).length) {
+ attrs['data-preact-signals'] = JSON.stringify(signals);
+ }
+}
+
+function getSignalId(ctx: Context, item: SignalLike) {
+ let id = ctx.signals.get(item);
+ if (!id) {
+ id = incrementId(ctx);
+ ctx.signals.set(item, id);
+ }
+
+ return id;
+}
diff --git a/packages/integrations/preact/src/static-html.ts b/packages/integrations/preact/src/static-html.ts
new file mode 100644
index 000000000..453e72b7f
--- /dev/null
+++ b/packages/integrations/preact/src/static-html.ts
@@ -0,0 +1,31 @@
+import { h } from 'preact';
+
+type Props = {
+ value: string;
+ name?: string;
+ hydrate?: boolean;
+};
+
+/**
+ * Astro passes `children` as a string of HTML, so we need
+ * a wrapper `div` to render that content as VNodes.
+ *
+ * As a bonus, we can signal to Preact that this subtree is
+ * entirely static and will never change via `shouldComponentUpdate`.
+ */
+const StaticHtml = ({ value, name, hydrate = true }: Props) => {
+ if (!value) return null;
+ const tagName = hydrate ? 'astro-slot' : 'astro-static-slot';
+ return h(tagName, { name, dangerouslySetInnerHTML: { __html: value } });
+};
+
+/**
+ * This tells Preact to opt-out of re-rendering this subtree,
+ * In addition to being a performance optimization,
+ * this also allows other frameworks to attach to `children`.
+ *
+ * See https://preactjs.com/guide/v8/external-dom-mutations
+ */
+StaticHtml.shouldComponentUpdate = () => false;
+
+export default StaticHtml;
diff --git a/packages/integrations/preact/src/types.ts b/packages/integrations/preact/src/types.ts
new file mode 100644
index 000000000..e1c56ca30
--- /dev/null
+++ b/packages/integrations/preact/src/types.ts
@@ -0,0 +1,18 @@
+import type { SSRResult } from 'astro';
+export type RendererContext = {
+ result: SSRResult;
+};
+
+export type SignalLike = {
+ peek(): any;
+};
+
+export type ArrayObjectMapping = [string, number | string][];
+export type Signals = Record<string, string | ArrayObjectMapping>;
+
+export type SignalToKeyOrIndexMap = [SignalLike, number | string][];
+export type PropNameToSignalMap = Map<string, SignalLike | SignalToKeyOrIndexMap>;
+
+export type AstroPreactAttrs = {
+ ['data-preact-signals']?: string;
+};
diff --git a/packages/integrations/preact/tsconfig.json b/packages/integrations/preact/tsconfig.json
new file mode 100644
index 000000000..1504b4b6d
--- /dev/null
+++ b/packages/integrations/preact/tsconfig.json
@@ -0,0 +1,7 @@
+{
+ "extends": "../../../tsconfig.base.json",
+ "include": ["src"],
+ "compilerOptions": {
+ "outDir": "./dist"
+ }
+}