Improve nested and client:only
hydration (#3455)
* wip: fix nested islands
* fix: improve hydration for dynamic content
* chore: fix bundle-size script for new files
* chore: allow-list client:* directive files
* fix(#3362): fix client:only behavior for React, Vue, Solid
* test: add client-only e2e test
* chore: update lockfile
* test: fix e2e tests
* test: add framework nesting e2e tests
* Update packages/astro/src/runtime/client/events.ts
Co-authored-by: Matthew Phillips <matthew@skypack.dev>
* chore: add changeset
* fix(preact): ignore hydrate roots
* chore: remove `ssr` check in integrations
* Revert "chore: remove `ssr` check in integrations"
This reverts commit ba27eaae55
.
* chore: add changeset
Co-authored-by: Matthew Phillips <matthew@skypack.dev>
This commit is contained in:
parent
40614597cc
commit
e9a77d8619
71 changed files with 2114 additions and 152 deletions
9
.changeset/polite-hounds-lick.md
Normal file
9
.changeset/polite-hounds-lick.md
Normal file
|
@ -0,0 +1,9 @@
|
|||
---
|
||||
'@astrojs/preact': patch
|
||||
'@astrojs/react': patch
|
||||
'@astrojs/solid-js': patch
|
||||
'@astrojs/svelte': patch
|
||||
'@astrojs/vue': patch
|
||||
---
|
||||
|
||||
Update client hydration to check for `ssr` attribute. Requires `astro@^1.0.0-beta.36`.
|
5
.changeset/unlucky-gorillas-beg.md
Normal file
5
.changeset/unlucky-gorillas-beg.md
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
'astro': patch
|
||||
---
|
||||
|
||||
Implements improved hydration event system, meaning hydration for client:only and nested frameworks should be see significant stability improvements
|
10
.github/scripts/bundle-size.mjs
vendored
10
.github/scripts/bundle-size.mjs
vendored
|
@ -1,4 +1,5 @@
|
|||
import { build } from 'esbuild';
|
||||
import { existsSync } from 'fs';
|
||||
|
||||
const CLIENT_RUNTIME_PATH = 'packages/astro/src/runtime/client/';
|
||||
|
||||
|
@ -32,7 +33,7 @@ export default async function checkBundleSize({ github, context }) {
|
|||
const output = await bundle(clientRuntimeFiles);
|
||||
|
||||
for (let [filename, { oldSize, newSize, sourceFile }] of Object.entries(output)) {
|
||||
filename = filename !== 'hmr' ? `client:${filename}` : filename;
|
||||
filename = ['idle', 'load', 'media', 'only', 'visible'].includes(filename) ? `client:${filename}` : filename;
|
||||
const prefix = (newSize - oldSize) === 0 ? '' : (newSize - oldSize) > 0 ? '+ ' : '- ';
|
||||
const change = `${prefix}${formatBytes(newSize - oldSize)}`;
|
||||
table.push(`| [\`${filename}\`](https://github.com/${context.repo.owner}/${context.repo.repo}/tree/${context.payload.pull_request.head.ref}/${sourceFile}) | ${formatBytes(oldSize)} | ${formatBytes(newSize)} | ${change} |`);
|
||||
|
@ -57,8 +58,9 @@ ${table.join('\n')}`,
|
|||
}
|
||||
|
||||
async function bundle(files) {
|
||||
|
||||
const { metafile } = await build({
|
||||
entryPoints: [...files.map(({ filename }) => filename), ...files.map(({ filename }) => `main/${filename}`)],
|
||||
entryPoints: [...files.map(({ filename }) => filename), ...files.map(({ filename }) => `main/${filename}`).filter(f => existsSync(f))],
|
||||
bundle: true,
|
||||
minify: true,
|
||||
sourcemap: false,
|
||||
|
@ -72,10 +74,10 @@ async function bundle(files) {
|
|||
if (filename.startsWith('main/')) {
|
||||
filename = filename.slice('main/'.length).replace(CLIENT_RUNTIME_PATH, '').replace('.js', '');
|
||||
const oldSize = info.bytes;
|
||||
return Object.assign(acc, { [filename]: Object.assign(acc[filename] ?? {}, { oldSize }) });
|
||||
return Object.assign(acc, { [filename]: Object.assign(acc[filename] ?? { oldSize: 0, newSize: 0 }, { oldSize }) });
|
||||
}
|
||||
filename = filename.replace(CLIENT_RUNTIME_PATH, '').replace('.js', '');
|
||||
const newSize = info.bytes;
|
||||
return Object.assign(acc, { [filename]: Object.assign(acc[filename] ?? {}, { newSize, sourceFile: Object.keys(info.inputs).find(src => src.endsWith('.ts')) }) });
|
||||
return Object.assign(acc, { [filename]: Object.assign(acc[filename] ?? { oldSize: 0, newSize: 0 }, { newSize, sourceFile: Object.keys(info.inputs).find(src => src.endsWith('.ts')) }) });
|
||||
}, {});
|
||||
}
|
||||
|
|
111
packages/astro/e2e/client-only.test.js
Normal file
111
packages/astro/e2e/client-only.test.js
Normal file
|
@ -0,0 +1,111 @@
|
|||
import { test as base, expect } from '@playwright/test';
|
||||
import { loadFixture } from './test-utils.js';
|
||||
|
||||
const test = base.extend({
|
||||
astro: async ({}, use) => {
|
||||
const fixture = await loadFixture({ root: './fixtures/client-only/' });
|
||||
await use(fixture);
|
||||
},
|
||||
});
|
||||
|
||||
let devServer;
|
||||
|
||||
test.beforeEach(async ({ astro }) => {
|
||||
devServer = await astro.startDevServer();
|
||||
});
|
||||
|
||||
test.afterEach(async () => {
|
||||
await devServer.stop();
|
||||
});
|
||||
|
||||
test.describe('Client only', () => {
|
||||
test('React counter', async ({ astro, page }) => {
|
||||
await page.goto('/');
|
||||
|
||||
const counter = await page.locator('#react-counter');
|
||||
await expect(counter, 'component is visible').toBeVisible();
|
||||
|
||||
const count = await counter.locator('pre');
|
||||
await expect(count, 'initial count is 0').toHaveText('0');
|
||||
|
||||
const children = await counter.locator('.children');
|
||||
await expect(children, 'children exist').toHaveText('react');
|
||||
|
||||
const increment = await counter.locator('.increment');
|
||||
await increment.click();
|
||||
|
||||
await expect(count, 'count incremented by 1').toHaveText('1');
|
||||
});
|
||||
|
||||
test('Preact counter', async ({ astro, page }) => {
|
||||
await page.goto('/');
|
||||
|
||||
const counter = await page.locator('#preact-counter');
|
||||
await expect(counter, 'component is visible').toBeVisible();
|
||||
|
||||
const count = await counter.locator('pre');
|
||||
await expect(count, 'initial count is 0').toHaveText('0');
|
||||
|
||||
const children = await counter.locator('.children');
|
||||
await expect(children, 'children exist').toHaveText('preact');
|
||||
|
||||
const increment = await counter.locator('.increment');
|
||||
await increment.click();
|
||||
|
||||
await expect(count, 'count incremented by 1').toHaveText('1');
|
||||
});
|
||||
|
||||
test('Solid counter', async ({ astro, page }) => {
|
||||
await page.goto('/');
|
||||
|
||||
const counter = await page.locator('#solid-counter');
|
||||
await expect(counter, 'component is visible').toBeVisible();
|
||||
|
||||
const count = await counter.locator('pre');
|
||||
await expect(count, 'initial count is 0').toHaveText('0');
|
||||
|
||||
const children = await counter.locator('.children');
|
||||
await expect(children, 'children exist').toHaveText('solid');
|
||||
|
||||
const increment = await counter.locator('.increment');
|
||||
await increment.click();
|
||||
|
||||
await expect(count, 'count incremented by 1').toHaveText('1');
|
||||
});
|
||||
|
||||
test('Vue counter', async ({ astro, page }) => {
|
||||
await page.goto('/');
|
||||
|
||||
const counter = await page.locator('#vue-counter');
|
||||
await expect(counter, 'component is visible').toBeVisible();
|
||||
|
||||
const count = await counter.locator('pre');
|
||||
await expect(count, 'initial count is 0').toHaveText('0');
|
||||
|
||||
const children = await counter.locator('.children');
|
||||
await expect(children, 'children exist').toHaveText('vue');
|
||||
|
||||
const increment = await counter.locator('.increment');
|
||||
await increment.click();
|
||||
|
||||
await expect(count, 'count incremented by 1').toHaveText('1');
|
||||
});
|
||||
|
||||
test('Svelte counter', async ({ astro, page }) => {
|
||||
await page.goto('/');
|
||||
|
||||
const counter = await page.locator('#svelte-counter');
|
||||
await expect(counter, 'component is visible').toBeVisible();
|
||||
|
||||
const count = await counter.locator('pre');
|
||||
await expect(count, 'initial count is 0').toHaveText('0');
|
||||
|
||||
const children = await counter.locator('.children');
|
||||
await expect(children, 'children exist').toHaveText('svelte');
|
||||
|
||||
const increment = await counter.locator('.increment');
|
||||
await increment.click();
|
||||
|
||||
await expect(count, 'count incremented by 1').toHaveText('1');
|
||||
});
|
||||
});
|
12
packages/astro/e2e/fixtures/client-only/astro.config.mjs
Normal file
12
packages/astro/e2e/fixtures/client-only/astro.config.mjs
Normal file
|
@ -0,0 +1,12 @@
|
|||
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';
|
||||
|
||||
// https://astro.build/config
|
||||
export default defineConfig({
|
||||
// Enable many frameworks to support all different kinds of components.
|
||||
integrations: [preact(), react(), svelte(), vue(), solid()],
|
||||
});
|
21
packages/astro/e2e/fixtures/client-only/package.json
Normal file
21
packages/astro/e2e/fixtures/client-only/package.json
Normal file
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"name": "@e2e/client-only",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"devDependencies": {
|
||||
"@astrojs/preact": "^0.1.2",
|
||||
"@astrojs/react": "^0.1.2",
|
||||
"@astrojs/solid-js": "^0.1.2",
|
||||
"@astrojs/svelte": "^0.1.3",
|
||||
"@astrojs/vue": "^0.1.4",
|
||||
"astro": "^1.0.0-beta.32"
|
||||
},
|
||||
"dependencies": {
|
||||
"preact": "^10.7.2",
|
||||
"react": "^18.1.0",
|
||||
"react-dom": "^18.1.0",
|
||||
"solid-js": "^1.4.2",
|
||||
"svelte": "^3.48.0",
|
||||
"vue": "^3.2.36"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
import { useState } from 'preact/hooks';
|
||||
|
||||
/** a counter written in Preact */
|
||||
export function PreactCounter({ children, id }) {
|
||||
const [count, setCount] = useState(0);
|
||||
const add = () => setCount((i) => i + 1);
|
||||
const subtract = () => setCount((i) => i - 1);
|
||||
|
||||
return (
|
||||
<div id={id} class="counter">
|
||||
<button class="decrement" onClick={subtract}>-</button>
|
||||
<pre>{count}</pre>
|
||||
<button class="increment" onClick={add}>+</button>
|
||||
<div class="children">{children}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
import { useState } from 'react';
|
||||
|
||||
/** a counter written in React */
|
||||
export function Counter({ children, id }) {
|
||||
const [count, setCount] = useState(0);
|
||||
const add = () => setCount((i) => i + 1);
|
||||
const subtract = () => setCount((i) => i - 1);
|
||||
|
||||
return (
|
||||
<div id={id} className="counter">
|
||||
<button className="decrement" onClick={subtract}>-</button>
|
||||
<pre>{count}</pre>
|
||||
<button className="increment" onClick={add}>+</button>
|
||||
<div className="children">{children}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
import { createSignal } from 'solid-js';
|
||||
|
||||
/** a counter written with Solid */
|
||||
export default function SolidCounter({ children, id }) {
|
||||
const [count, setCount] = createSignal(0);
|
||||
const add = () => setCount(count() + 1);
|
||||
const subtract = () => setCount(count() - 1);
|
||||
|
||||
return (
|
||||
<div id={id} class="counter">
|
||||
<button class="decrement" onClick={subtract}>-</button>
|
||||
<pre>{count()}</pre>
|
||||
<button class="increment" onClick={add}>+</button>
|
||||
<div class="children">{children}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
|
||||
<script>
|
||||
export let id;
|
||||
let children;
|
||||
let count = 0;
|
||||
|
||||
function add() {
|
||||
count += 1;
|
||||
}
|
||||
|
||||
function subtract() {
|
||||
count -= 1;
|
||||
}
|
||||
</script>
|
||||
|
||||
<div {id} class="counter">
|
||||
<button class="decrement" on:click={subtract}>-</button>
|
||||
<pre>{ count }</pre>
|
||||
<button class="increment" on:click={add}>+</button>
|
||||
<div class="children">
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.counter {
|
||||
background: white;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,34 @@
|
|||
<template>
|
||||
<div :id="id" class="counter">
|
||||
<button class="decrement" @click="subtract()">-</button>
|
||||
<pre>{{ count }}</pre>
|
||||
<button class="increment" @click="add()">+</button>
|
||||
<div class="children">
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { ref } from 'vue';
|
||||
export default {
|
||||
props: {
|
||||
id: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
setup(props) {
|
||||
const count = ref(0);
|
||||
const add = () => (count.value = count.value + 1);
|
||||
const subtract = () => (count.value = count.value - 1);
|
||||
|
||||
return {
|
||||
id: props.id,
|
||||
count,
|
||||
add,
|
||||
subtract,
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
|
@ -0,0 +1,41 @@
|
|||
---
|
||||
import * as react from '../components/ReactCounter.jsx';
|
||||
import { PreactCounter } from '../components/PreactCounter.tsx';
|
||||
import SolidCounter from '../components/SolidCounter.tsx';
|
||||
import VueCounter from '../components/VueCounter.vue';
|
||||
import SvelteCounter from '../components/SvelteCounter.svelte';
|
||||
|
||||
// Full Astro Component Syntax:
|
||||
// https://docs.astro.build/core-concepts/astro-components/
|
||||
---
|
||||
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
<link rel="icon" type="image/x-icon" href="/favicon.ico" />
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<react.Counter id="react-counter" client:only="react">
|
||||
<h1>react</h1>
|
||||
</react.Counter>
|
||||
|
||||
<PreactCounter id="preact-counter" client:only="preact">
|
||||
<h1>preact</h1>
|
||||
</PreactCounter>
|
||||
|
||||
<SolidCounter id="solid-counter" client:only="solid-js">
|
||||
<h1>solid</h1>
|
||||
</SolidCounter>
|
||||
|
||||
<VueCounter id="vue-counter" client:only="vue">
|
||||
<h1>vue</h1>
|
||||
</VueCounter>
|
||||
|
||||
<SvelteCounter id="svelte-counter" client:only="svelte">
|
||||
<h1>svelte</h1>
|
||||
</SvelteCounter>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,12 @@
|
|||
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';
|
||||
|
||||
// https://astro.build/config
|
||||
export default defineConfig({
|
||||
// Enable many frameworks to support all different kinds of components.
|
||||
integrations: [preact(), react(), svelte(), vue(), solid()],
|
||||
});
|
21
packages/astro/e2e/fixtures/nested-in-preact/package.json
Normal file
21
packages/astro/e2e/fixtures/nested-in-preact/package.json
Normal file
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"name": "@e2e/nested-in-preact",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"devDependencies": {
|
||||
"@astrojs/preact": "^0.1.2",
|
||||
"@astrojs/react": "^0.1.2",
|
||||
"@astrojs/solid-js": "^0.1.2",
|
||||
"@astrojs/svelte": "^0.1.3",
|
||||
"@astrojs/vue": "^0.1.4",
|
||||
"astro": "^1.0.0-beta.32"
|
||||
},
|
||||
"dependencies": {
|
||||
"preact": "^10.7.2",
|
||||
"react": "^18.1.0",
|
||||
"react-dom": "^18.1.0",
|
||||
"solid-js": "^1.4.2",
|
||||
"svelte": "^3.48.0",
|
||||
"vue": "^3.2.36"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
import { useState } from 'preact/hooks';
|
||||
|
||||
/** a counter written in Preact */
|
||||
export function PreactCounter({ children, id }) {
|
||||
const [count, setCount] = useState(0);
|
||||
const add = () => setCount((i) => i + 1);
|
||||
const subtract = () => setCount((i) => i - 1);
|
||||
|
||||
return (
|
||||
<div id={id} class="counter">
|
||||
<button class="decrement" onClick={subtract}>-</button>
|
||||
<pre id={`${id}-count`}>{count}</pre>
|
||||
<button id={`${id}-increment`} class="increment" onClick={add}>+</button>
|
||||
<div class="children">{children}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
import { useState } from 'react';
|
||||
|
||||
/** a counter written in React */
|
||||
export default function Counter({ children, id }) {
|
||||
const [count, setCount] = useState(0);
|
||||
const add = () => setCount((i) => i + 1);
|
||||
const subtract = () => setCount((i) => i - 1);
|
||||
|
||||
return (
|
||||
<div id={id} className="counter">
|
||||
<button className="decrement" onClick={subtract}>-</button>
|
||||
<pre id={`${id}-count`}>{count}</pre>
|
||||
<button id={`${id}-increment`} className="increment" onClick={add}>+</button>
|
||||
<div className="children">{children}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
import { createSignal } from 'solid-js';
|
||||
|
||||
/** a counter written with Solid */
|
||||
export default function SolidCounter({ children, id }) {
|
||||
const [count, setCount] = createSignal(0);
|
||||
const add = () => setCount(count() + 1);
|
||||
const subtract = () => setCount(count() - 1);
|
||||
|
||||
return (
|
||||
<div id={id} class="counter">
|
||||
<button class="decrement" onClick={subtract}>-</button>
|
||||
<pre id={`${id}-count`}>{count()}</pre>
|
||||
<button id={`${id}-increment`} class="increment" onClick={add}>+</button>
|
||||
<div class="children">{children}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
|
||||
<script>
|
||||
export let id;
|
||||
let children;
|
||||
let count = 0;
|
||||
|
||||
function add() {
|
||||
count += 1;
|
||||
}
|
||||
|
||||
function subtract() {
|
||||
count -= 1;
|
||||
}
|
||||
</script>
|
||||
|
||||
<div {id} class="counter">
|
||||
<button class="decrement" on:click={subtract}>-</button>
|
||||
<pre id={`${id}-count`}>{ count }</pre>
|
||||
<button id={`${id}-increment`} class="increment" on:click={add}>+</button>
|
||||
<div class="children">
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.counter {
|
||||
background: white;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,34 @@
|
|||
<template>
|
||||
<div :id="id" class="counter">
|
||||
<button class="decrement" @click="subtract()">-</button>
|
||||
<pre :id="`${id}-count`">{{ count }}</pre>
|
||||
<button :id="`${id}-increment`" class="increment" @click="add()">+</button>
|
||||
<div class="children">
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { ref } from 'vue';
|
||||
export default {
|
||||
props: {
|
||||
id: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
setup(props) {
|
||||
const count = ref(0);
|
||||
const add = () => (count.value = count.value + 1);
|
||||
const subtract = () => (count.value = count.value - 1);
|
||||
|
||||
return {
|
||||
id: props.id,
|
||||
count,
|
||||
add,
|
||||
subtract,
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
|
@ -0,0 +1,28 @@
|
|||
---
|
||||
import ReactCounter from '../components/ReactCounter.jsx';
|
||||
import { PreactCounter } from '../components/PreactCounter.tsx';
|
||||
import SolidCounter from '../components/SolidCounter.tsx';
|
||||
import VueCounter from '../components/VueCounter.vue';
|
||||
import SvelteCounter from '../components/SvelteCounter.svelte';
|
||||
|
||||
// Full Astro Component Syntax:
|
||||
// https://docs.astro.build/core-concepts/astro-components/
|
||||
---
|
||||
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
<link rel="icon" type="image/x-icon" href="/favicon.ico" />
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<PreactCounter id="preact-counter" client:load>
|
||||
<ReactCounter id="react-counter" client:load />
|
||||
<SolidCounter id="solid-counter" client:load />
|
||||
<SvelteCounter id="svelte-counter" client:load />
|
||||
<VueCounter id="vue-counter" client:load />
|
||||
</PreactCounter>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
12
packages/astro/e2e/fixtures/nested-in-react/astro.config.mjs
Normal file
12
packages/astro/e2e/fixtures/nested-in-react/astro.config.mjs
Normal file
|
@ -0,0 +1,12 @@
|
|||
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';
|
||||
|
||||
// https://astro.build/config
|
||||
export default defineConfig({
|
||||
// Enable many frameworks to support all different kinds of components.
|
||||
integrations: [preact(), react(), svelte(), vue(), solid()],
|
||||
});
|
21
packages/astro/e2e/fixtures/nested-in-react/package.json
Normal file
21
packages/astro/e2e/fixtures/nested-in-react/package.json
Normal file
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"name": "@e2e/nested-in-react",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"devDependencies": {
|
||||
"@astrojs/preact": "^0.1.2",
|
||||
"@astrojs/react": "^0.1.2",
|
||||
"@astrojs/solid-js": "^0.1.2",
|
||||
"@astrojs/svelte": "^0.1.3",
|
||||
"@astrojs/vue": "^0.1.4",
|
||||
"astro": "^1.0.0-beta.32"
|
||||
},
|
||||
"dependencies": {
|
||||
"preact": "^10.7.2",
|
||||
"react": "^18.1.0",
|
||||
"react-dom": "^18.1.0",
|
||||
"solid-js": "^1.4.2",
|
||||
"svelte": "^3.48.0",
|
||||
"vue": "^3.2.36"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
import { useState } from 'preact/hooks';
|
||||
|
||||
/** a counter written in Preact */
|
||||
export function PreactCounter({ children, id }) {
|
||||
const [count, setCount] = useState(0);
|
||||
const add = () => setCount((i) => i + 1);
|
||||
const subtract = () => setCount((i) => i - 1);
|
||||
|
||||
return (
|
||||
<div id={id} class="counter">
|
||||
<button class="decrement" onClick={subtract}>-</button>
|
||||
<pre id={`${id}-count`}>{count}</pre>
|
||||
<button id={`${id}-increment`} class="increment" onClick={add}>+</button>
|
||||
<div class="children">{children}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
import { useState } from 'react';
|
||||
|
||||
/** a counter written in React */
|
||||
export default function Counter({ children, id }) {
|
||||
const [count, setCount] = useState(0);
|
||||
const add = () => setCount((i) => i + 1);
|
||||
const subtract = () => setCount((i) => i - 1);
|
||||
|
||||
return (
|
||||
<div id={id} className="counter">
|
||||
<button className="decrement" onClick={subtract}>-</button>
|
||||
<pre id={`${id}-count`}>{count}</pre>
|
||||
<button id={`${id}-increment`} className="increment" onClick={add}>+</button>
|
||||
<div className="children">{children}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
import { createSignal } from 'solid-js';
|
||||
|
||||
/** a counter written with Solid */
|
||||
export default function SolidCounter({ children, id }) {
|
||||
const [count, setCount] = createSignal(0);
|
||||
const add = () => setCount(count() + 1);
|
||||
const subtract = () => setCount(count() - 1);
|
||||
|
||||
return (
|
||||
<div id={id} class="counter">
|
||||
<button class="decrement" onClick={subtract}>-</button>
|
||||
<pre id={`${id}-count`}>{count()}</pre>
|
||||
<button id={`${id}-increment`} class="increment" onClick={add}>+</button>
|
||||
<div class="children">{children}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
|
||||
<script>
|
||||
export let id;
|
||||
let children;
|
||||
let count = 0;
|
||||
|
||||
function add() {
|
||||
count += 1;
|
||||
}
|
||||
|
||||
function subtract() {
|
||||
count -= 1;
|
||||
}
|
||||
</script>
|
||||
|
||||
<div {id} class="counter">
|
||||
<button class="decrement" on:click={subtract}>-</button>
|
||||
<pre id={`${id}-count`}>{ count }</pre>
|
||||
<button id={`${id}-increment`} class="increment" on:click={add}>+</button>
|
||||
<div class="children">
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.counter {
|
||||
background: white;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,34 @@
|
|||
<template>
|
||||
<div :id="id" class="counter">
|
||||
<button class="decrement" @click="subtract()">-</button>
|
||||
<pre :id="`${id}-count`">{{ count }}</pre>
|
||||
<button :id="`${id}-increment`" class="increment" @click="add()">+</button>
|
||||
<div class="children">
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { ref } from 'vue';
|
||||
export default {
|
||||
props: {
|
||||
id: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
setup(props) {
|
||||
const count = ref(0);
|
||||
const add = () => (count.value = count.value + 1);
|
||||
const subtract = () => (count.value = count.value - 1);
|
||||
|
||||
return {
|
||||
id: props.id,
|
||||
count,
|
||||
add,
|
||||
subtract,
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
|
@ -0,0 +1,28 @@
|
|||
---
|
||||
import ReactCounter from '../components/ReactCounter.jsx';
|
||||
import { PreactCounter } from '../components/PreactCounter.tsx';
|
||||
import SolidCounter from '../components/SolidCounter.tsx';
|
||||
import VueCounter from '../components/VueCounter.vue';
|
||||
import SvelteCounter from '../components/SvelteCounter.svelte';
|
||||
|
||||
// Full Astro Component Syntax:
|
||||
// https://docs.astro.build/core-concepts/astro-components/
|
||||
---
|
||||
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
<link rel="icon" type="image/x-icon" href="/favicon.ico" />
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<ReactCounter id="react-counter" client:load>
|
||||
<SolidCounter id="solid-counter" client:load />
|
||||
<SvelteCounter id="svelte-counter" client:load />
|
||||
<PreactCounter id="preact-counter" client:load />
|
||||
<VueCounter id="vue-counter" client:load />
|
||||
</ReactCounter>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
12
packages/astro/e2e/fixtures/nested-in-solid/astro.config.mjs
Normal file
12
packages/astro/e2e/fixtures/nested-in-solid/astro.config.mjs
Normal file
|
@ -0,0 +1,12 @@
|
|||
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';
|
||||
|
||||
// https://astro.build/config
|
||||
export default defineConfig({
|
||||
// Enable many frameworks to support all different kinds of components.
|
||||
integrations: [preact(), react(), svelte(), vue(), solid()],
|
||||
});
|
21
packages/astro/e2e/fixtures/nested-in-solid/package.json
Normal file
21
packages/astro/e2e/fixtures/nested-in-solid/package.json
Normal file
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"name": "@e2e/nested-in-solid",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"devDependencies": {
|
||||
"@astrojs/preact": "^0.1.2",
|
||||
"@astrojs/react": "^0.1.2",
|
||||
"@astrojs/solid-js": "^0.1.2",
|
||||
"@astrojs/svelte": "^0.1.3",
|
||||
"@astrojs/vue": "^0.1.4",
|
||||
"astro": "^1.0.0-beta.32"
|
||||
},
|
||||
"dependencies": {
|
||||
"preact": "^10.7.2",
|
||||
"react": "^18.1.0",
|
||||
"react-dom": "^18.1.0",
|
||||
"solid-js": "^1.4.2",
|
||||
"svelte": "^3.48.0",
|
||||
"vue": "^3.2.36"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
import { useState } from 'preact/hooks';
|
||||
|
||||
/** a counter written in Preact */
|
||||
export function PreactCounter({ children, id }) {
|
||||
const [count, setCount] = useState(0);
|
||||
const add = () => setCount((i) => i + 1);
|
||||
const subtract = () => setCount((i) => i - 1);
|
||||
|
||||
return (
|
||||
<div id={id} class="counter">
|
||||
<button class="decrement" onClick={subtract}>-</button>
|
||||
<pre id={`${id}-count`}>{count}</pre>
|
||||
<button id={`${id}-increment`} class="increment" onClick={add}>+</button>
|
||||
<div class="children">{children}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
import { useState } from 'react';
|
||||
|
||||
/** a counter written in React */
|
||||
export function Counter({ children, id }) {
|
||||
const [count, setCount] = useState(0);
|
||||
const add = () => setCount((i) => i + 1);
|
||||
const subtract = () => setCount((i) => i - 1);
|
||||
|
||||
return (
|
||||
<div id={id} className="counter">
|
||||
<button className="decrement" onClick={subtract}>-</button>
|
||||
<pre id={`${id}-count`}>{count}</pre>
|
||||
<button id={`${id}-increment`} className="increment" onClick={add}>+</button>
|
||||
<div className="children">{children}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
import { createSignal } from 'solid-js';
|
||||
|
||||
/** a counter written with Solid */
|
||||
export default function SolidCounter({ children, id }) {
|
||||
const [count, setCount] = createSignal(0);
|
||||
const add = () => setCount(count() + 1);
|
||||
const subtract = () => setCount(count() - 1);
|
||||
|
||||
return (
|
||||
<div id={id} class="counter">
|
||||
<button class="decrement" onClick={subtract}>-</button>
|
||||
<pre id={`${id}-count`}>{count()}</pre>
|
||||
<button id={`${id}-increment`} class="increment" onClick={add}>+</button>
|
||||
<div class="children">{children}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
|
||||
<script>
|
||||
export let id;
|
||||
let children;
|
||||
let count = 0;
|
||||
|
||||
function add() {
|
||||
count += 1;
|
||||
}
|
||||
|
||||
function subtract() {
|
||||
count -= 1;
|
||||
}
|
||||
</script>
|
||||
|
||||
<div {id} class="counter">
|
||||
<button class="decrement" on:click={subtract}>-</button>
|
||||
<pre id={`${id}-count`}>{ count }</pre>
|
||||
<button id={`${id}-increment`} class="increment" on:click={add}>+</button>
|
||||
<div class="children">
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.counter {
|
||||
background: white;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,34 @@
|
|||
<template>
|
||||
<div :id="id" class="counter">
|
||||
<button class="decrement" @click="subtract()">-</button>
|
||||
<pre :id="`${id}-count`">{{ count }}</pre>
|
||||
<button :id="`${id}-increment`" class="increment" @click="add()">+</button>
|
||||
<div class="children">
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { ref } from 'vue';
|
||||
export default {
|
||||
props: {
|
||||
id: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
setup(props) {
|
||||
const count = ref(0);
|
||||
const add = () => (count.value = count.value + 1);
|
||||
const subtract = () => (count.value = count.value - 1);
|
||||
|
||||
return {
|
||||
id: props.id,
|
||||
count,
|
||||
add,
|
||||
subtract,
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
|
@ -0,0 +1,28 @@
|
|||
---
|
||||
import { Counter as ReactCounter } from '../components/ReactCounter.jsx';
|
||||
import { PreactCounter } from '../components/PreactCounter.tsx';
|
||||
import SolidCounter from '../components/SolidCounter.tsx';
|
||||
import VueCounter from '../components/VueCounter.vue';
|
||||
import SvelteCounter from '../components/SvelteCounter.svelte';
|
||||
|
||||
// Full Astro Component Syntax:
|
||||
// https://docs.astro.build/core-concepts/astro-components/
|
||||
---
|
||||
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
<link rel="icon" type="image/x-icon" href="/favicon.ico" />
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<SolidCounter id="solid-counter" client:load>
|
||||
<SvelteCounter id="svelte-counter" client:load />
|
||||
<ReactCounter id="react-counter" client:load />
|
||||
<PreactCounter id="preact-counter" client:load />
|
||||
<VueCounter id="vue-counter" client:load />
|
||||
</SolidCounter>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,12 @@
|
|||
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';
|
||||
|
||||
// https://astro.build/config
|
||||
export default defineConfig({
|
||||
// Enable many frameworks to support all different kinds of components.
|
||||
integrations: [preact(), react(), svelte(), vue(), solid()],
|
||||
});
|
21
packages/astro/e2e/fixtures/nested-in-svelte/package.json
Normal file
21
packages/astro/e2e/fixtures/nested-in-svelte/package.json
Normal file
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"name": "@e2e/nested-in-svelte",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"devDependencies": {
|
||||
"@astrojs/preact": "^0.1.2",
|
||||
"@astrojs/react": "^0.1.2",
|
||||
"@astrojs/solid-js": "^0.1.2",
|
||||
"@astrojs/svelte": "^0.1.3",
|
||||
"@astrojs/vue": "^0.1.4",
|
||||
"astro": "^1.0.0-beta.32"
|
||||
},
|
||||
"dependencies": {
|
||||
"preact": "^10.7.2",
|
||||
"react": "^18.1.0",
|
||||
"react-dom": "^18.1.0",
|
||||
"solid-js": "^1.4.2",
|
||||
"svelte": "^3.48.0",
|
||||
"vue": "^3.2.36"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
import { useState } from 'preact/hooks';
|
||||
|
||||
/** a counter written in Preact */
|
||||
export function PreactCounter({ children, id }) {
|
||||
const [count, setCount] = useState(0);
|
||||
const add = () => setCount((i) => i + 1);
|
||||
const subtract = () => setCount((i) => i - 1);
|
||||
|
||||
return (
|
||||
<div id={id} class="counter">
|
||||
<button class="decrement" onClick={subtract}>-</button>
|
||||
<pre id={`${id}-count`}>{count}</pre>
|
||||
<button id={`${id}-increment`} class="increment" onClick={add}>+</button>
|
||||
<div class="children">{children}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
import { useState } from 'react';
|
||||
|
||||
/** a counter written in React */
|
||||
export function Counter({ children, id }) {
|
||||
const [count, setCount] = useState(0);
|
||||
const add = () => setCount((i) => i + 1);
|
||||
const subtract = () => setCount((i) => i - 1);
|
||||
|
||||
return (
|
||||
<div id={id} className="counter">
|
||||
<button className="decrement" onClick={subtract}>-</button>
|
||||
<pre id={`${id}-count`}>{count}</pre>
|
||||
<button id={`${id}-increment`} className="increment" onClick={add}>+</button>
|
||||
<div className="children">{children}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
import { createSignal } from 'solid-js';
|
||||
|
||||
/** a counter written with Solid */
|
||||
export default function SolidCounter({ children, id }) {
|
||||
const [count, setCount] = createSignal(0);
|
||||
const add = () => setCount(count() + 1);
|
||||
const subtract = () => setCount(count() - 1);
|
||||
|
||||
return (
|
||||
<div id={id} class="counter">
|
||||
<button class="decrement" onClick={subtract}>-</button>
|
||||
<pre id={`${id}-count`}>{count()}</pre>
|
||||
<button id={`${id}-increment`} class="increment" onClick={add}>+</button>
|
||||
<div class="children">{children}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
|
||||
<script>
|
||||
export let id;
|
||||
let children;
|
||||
let count = 0;
|
||||
|
||||
function add() {
|
||||
count += 1;
|
||||
}
|
||||
|
||||
function subtract() {
|
||||
count -= 1;
|
||||
}
|
||||
</script>
|
||||
|
||||
<div {id} class="counter">
|
||||
<button class="decrement" on:click={subtract}>-</button>
|
||||
<pre id={`${id}-count`}>{ count }</pre>
|
||||
<button id={`${id}-increment`} class="increment" on:click={add}>+</button>
|
||||
<div class="children">
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.counter {
|
||||
background: white;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,34 @@
|
|||
<template>
|
||||
<div :id="id" class="counter">
|
||||
<button class="decrement" @click="subtract()">-</button>
|
||||
<pre :id="`${id}-count`">{{ count }}</pre>
|
||||
<button :id="`${id}-increment`" class="increment" @click="add()">+</button>
|
||||
<div class="children">
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { ref } from 'vue';
|
||||
export default {
|
||||
props: {
|
||||
id: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
setup(props) {
|
||||
const count = ref(0);
|
||||
const add = () => (count.value = count.value + 1);
|
||||
const subtract = () => (count.value = count.value - 1);
|
||||
|
||||
return {
|
||||
id: props.id,
|
||||
count,
|
||||
add,
|
||||
subtract,
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
|
@ -0,0 +1,28 @@
|
|||
---
|
||||
import { Counter as ReactCounter } from '../components/ReactCounter.jsx';
|
||||
import { PreactCounter } from '../components/PreactCounter.tsx';
|
||||
import SolidCounter from '../components/SolidCounter.tsx';
|
||||
import VueCounter from '../components/VueCounter.vue';
|
||||
import SvelteCounter from '../components/SvelteCounter.svelte';
|
||||
|
||||
// Full Astro Component Syntax:
|
||||
// https://docs.astro.build/core-concepts/astro-components/
|
||||
---
|
||||
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
<link rel="icon" type="image/x-icon" href="/favicon.ico" />
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<SvelteCounter id="svelte-counter" client:load>
|
||||
<SolidCounter id="solid-counter" client:load />
|
||||
<ReactCounter id="react-counter" client:load />
|
||||
<PreactCounter id="preact-counter" client:load />
|
||||
<VueCounter id="vue-counter" client:load />
|
||||
</SvelteCounter>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
12
packages/astro/e2e/fixtures/nested-in-vue/astro.config.mjs
Normal file
12
packages/astro/e2e/fixtures/nested-in-vue/astro.config.mjs
Normal file
|
@ -0,0 +1,12 @@
|
|||
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';
|
||||
|
||||
// https://astro.build/config
|
||||
export default defineConfig({
|
||||
// Enable many frameworks to support all different kinds of components.
|
||||
integrations: [preact(), react(), svelte(), vue(), solid()],
|
||||
});
|
21
packages/astro/e2e/fixtures/nested-in-vue/package.json
Normal file
21
packages/astro/e2e/fixtures/nested-in-vue/package.json
Normal file
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"name": "@e2e/nested-in-vue",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"devDependencies": {
|
||||
"@astrojs/preact": "^0.1.2",
|
||||
"@astrojs/react": "^0.1.2",
|
||||
"@astrojs/solid-js": "^0.1.2",
|
||||
"@astrojs/svelte": "^0.1.3",
|
||||
"@astrojs/vue": "^0.1.4",
|
||||
"astro": "^1.0.0-beta.32"
|
||||
},
|
||||
"dependencies": {
|
||||
"preact": "^10.7.2",
|
||||
"react": "^18.1.0",
|
||||
"react-dom": "^18.1.0",
|
||||
"solid-js": "^1.4.2",
|
||||
"svelte": "^3.48.0",
|
||||
"vue": "^3.2.36"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
import { useState } from 'preact/hooks';
|
||||
|
||||
/** a counter written in Preact */
|
||||
export function PreactCounter({ children, id }) {
|
||||
const [count, setCount] = useState(0);
|
||||
const add = () => setCount((i) => i + 1);
|
||||
const subtract = () => setCount((i) => i - 1);
|
||||
|
||||
return (
|
||||
<div id={id} class="counter">
|
||||
<button class="decrement" onClick={subtract}>-</button>
|
||||
<pre id={`${id}-count`}>{count}</pre>
|
||||
<button id={`${id}-increment`} class="increment" onClick={add}>+</button>
|
||||
<div class="children">{children}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
import { useState } from 'react';
|
||||
|
||||
/** a counter written in React */
|
||||
export function Counter({ children, id }) {
|
||||
const [count, setCount] = useState(0);
|
||||
const add = () => setCount((i) => i + 1);
|
||||
const subtract = () => setCount((i) => i - 1);
|
||||
|
||||
return (
|
||||
<div id={id} className="counter">
|
||||
<button className="decrement" onClick={subtract}>-</button>
|
||||
<pre id={`${id}-count`}>{count}</pre>
|
||||
<button id={`${id}-increment`} className="increment" onClick={add}>+</button>
|
||||
<div className="children">{children}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
import { createSignal } from 'solid-js';
|
||||
|
||||
/** a counter written with Solid */
|
||||
export default function SolidCounter({ children, id }) {
|
||||
const [count, setCount] = createSignal(0);
|
||||
const add = () => setCount(count() + 1);
|
||||
const subtract = () => setCount(count() - 1);
|
||||
|
||||
return (
|
||||
<div id={id} class="counter">
|
||||
<button class="decrement" onClick={subtract}>-</button>
|
||||
<pre id={`${id}-count`}>{count()}</pre>
|
||||
<button id={`${id}-increment`} class="increment" onClick={add}>+</button>
|
||||
<div class="children">{children}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
|
||||
<script>
|
||||
export let id;
|
||||
let children;
|
||||
let count = 0;
|
||||
|
||||
function add() {
|
||||
count += 1;
|
||||
}
|
||||
|
||||
function subtract() {
|
||||
count -= 1;
|
||||
}
|
||||
</script>
|
||||
|
||||
<div {id} class="counter">
|
||||
<button class="decrement" on:click={subtract}>-</button>
|
||||
<pre id={`${id}-count`}>{ count }</pre>
|
||||
<button id={`${id}-increment`} class="increment" on:click={add}>+</button>
|
||||
<div class="children">
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.counter {
|
||||
background: white;
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,34 @@
|
|||
<template>
|
||||
<div :id="id" class="counter">
|
||||
<button class="decrement" @click="subtract()">-</button>
|
||||
<pre :id="`${id}-count`">{{ count }}</pre>
|
||||
<button :id="`${id}-increment`" class="increment" @click="add()">+</button>
|
||||
<div class="children">
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { ref } from 'vue';
|
||||
export default {
|
||||
props: {
|
||||
id: {
|
||||
type: String,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
setup(props) {
|
||||
const count = ref(0);
|
||||
const add = () => (count.value = count.value + 1);
|
||||
const subtract = () => (count.value = count.value - 1);
|
||||
|
||||
return {
|
||||
id: props.id,
|
||||
count,
|
||||
add,
|
||||
subtract,
|
||||
};
|
||||
},
|
||||
};
|
||||
</script>
|
|
@ -0,0 +1,28 @@
|
|||
---
|
||||
import { Counter as ReactCounter } from '../components/ReactCounter.jsx';
|
||||
import { PreactCounter } from '../components/PreactCounter.tsx';
|
||||
import SolidCounter from '../components/SolidCounter.tsx';
|
||||
import VueCounter from '../components/VueCounter.vue';
|
||||
import SvelteCounter from '../components/SvelteCounter.svelte';
|
||||
|
||||
// Full Astro Component Syntax:
|
||||
// https://docs.astro.build/core-concepts/astro-components/
|
||||
---
|
||||
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
<link rel="icon" type="image/x-icon" href="/favicon.ico" />
|
||||
</head>
|
||||
<body>
|
||||
<main>
|
||||
<VueCounter id="vue-counter" client:load>
|
||||
<ReactCounter id="react-counter" client:load />
|
||||
<SolidCounter id="solid-counter" client:load />
|
||||
<SvelteCounter id="svelte-counter" client:load />
|
||||
<PreactCounter id="preact-counter" client:load />
|
||||
</VueCounter>
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
96
packages/astro/e2e/nested-in-preact.test.js
Normal file
96
packages/astro/e2e/nested-in-preact.test.js
Normal file
|
@ -0,0 +1,96 @@
|
|||
import { test as base, expect } from '@playwright/test';
|
||||
import { loadFixture } from './test-utils.js';
|
||||
|
||||
const test = base.extend({
|
||||
astro: async ({}, use) => {
|
||||
const fixture = await loadFixture({ root: './fixtures/nested-in-preact/' });
|
||||
await use(fixture);
|
||||
},
|
||||
});
|
||||
|
||||
let devServer;
|
||||
|
||||
test.beforeEach(async ({ astro }) => {
|
||||
devServer = await astro.startDevServer();
|
||||
});
|
||||
|
||||
test.afterEach(async () => {
|
||||
await devServer.stop();
|
||||
});
|
||||
|
||||
test.describe('Nested Frameworks in Preact', () => {
|
||||
test('React counter', async ({ astro, page }) => {
|
||||
await page.goto('/');
|
||||
|
||||
const counter = await page.locator('#react-counter');
|
||||
await expect(counter, 'component is visible').toBeVisible();
|
||||
|
||||
const count = await counter.locator('#react-counter-count');
|
||||
await expect(count, 'initial count is 0').toHaveText('0');
|
||||
|
||||
const increment = await counter.locator('#react-counter-increment');
|
||||
await increment.click();
|
||||
|
||||
await expect(count, 'count incremented by 1').toHaveText('1');
|
||||
});
|
||||
|
||||
test('Preact counter', async ({ astro, page }) => {
|
||||
await page.goto('/');
|
||||
|
||||
const counter = await page.locator('#preact-counter');
|
||||
await expect(counter, 'component is visible').toBeVisible();
|
||||
|
||||
const count = await counter.locator('#preact-counter-count');
|
||||
await expect(count, 'initial count is 0').toHaveText('0');
|
||||
|
||||
const increment = await counter.locator('#preact-counter-increment');
|
||||
await increment.click();
|
||||
|
||||
await expect(count, 'count incremented by 1').toHaveText('1');
|
||||
});
|
||||
|
||||
test('Solid counter', async ({ astro, page }) => {
|
||||
await page.goto('/');
|
||||
|
||||
const counter = await page.locator('#solid-counter');
|
||||
await expect(counter, 'component is visible').toBeVisible();
|
||||
|
||||
const count = await counter.locator('#solid-counter-count');
|
||||
await expect(count, 'initial count is 0').toHaveText('0');
|
||||
|
||||
const increment = await counter.locator('#solid-counter-increment');
|
||||
await increment.click();
|
||||
|
||||
await expect(count, 'count incremented by 1').toHaveText('1');
|
||||
});
|
||||
|
||||
test('Vue counter', async ({ astro, page }) => {
|
||||
await page.goto('/');
|
||||
|
||||
const counter = await page.locator('#vue-counter');
|
||||
await expect(counter, 'component is visible').toBeVisible();
|
||||
|
||||
const count = await counter.locator('#vue-counter-count');
|
||||
await expect(count, 'initial count is 0').toHaveText('0');
|
||||
|
||||
const increment = await counter.locator('#vue-counter-increment');
|
||||
await increment.click();
|
||||
|
||||
await expect(count, 'count incremented by 1').toHaveText('1');
|
||||
});
|
||||
|
||||
test('Svelte counter', async ({ astro, page }) => {
|
||||
await page.goto('/');
|
||||
|
||||
const counter = await page.locator('#svelte-counter');
|
||||
await expect(counter, 'component is visible').toBeVisible();
|
||||
|
||||
const count = await counter.locator('#svelte-counter-count');
|
||||
await expect(count, 'initial count is 0').toHaveText('0');
|
||||
|
||||
const increment = await counter.locator('#svelte-counter-increment');
|
||||
await increment.click();
|
||||
|
||||
await expect(count, 'count incremented by 1').toHaveText('1');
|
||||
});
|
||||
});
|
96
packages/astro/e2e/nested-in-react.test.js
Normal file
96
packages/astro/e2e/nested-in-react.test.js
Normal file
|
@ -0,0 +1,96 @@
|
|||
import { test as base, expect } from '@playwright/test';
|
||||
import { loadFixture } from './test-utils.js';
|
||||
|
||||
const test = base.extend({
|
||||
astro: async ({}, use) => {
|
||||
const fixture = await loadFixture({ root: './fixtures/nested-in-react/' });
|
||||
await use(fixture);
|
||||
},
|
||||
});
|
||||
|
||||
let devServer;
|
||||
|
||||
test.beforeEach(async ({ astro }) => {
|
||||
devServer = await astro.startDevServer();
|
||||
});
|
||||
|
||||
test.afterEach(async () => {
|
||||
await devServer.stop();
|
||||
});
|
||||
|
||||
test.describe('Nested Frameworks in React', () => {
|
||||
test('React counter', async ({ astro, page }) => {
|
||||
await page.goto('/');
|
||||
|
||||
const counter = await page.locator('#react-counter');
|
||||
await expect(counter, 'component is visible').toBeVisible();
|
||||
|
||||
const count = await counter.locator('#react-counter-count');
|
||||
await expect(count, 'initial count is 0').toHaveText('0');
|
||||
|
||||
const increment = await counter.locator('#react-counter-increment');
|
||||
await increment.click();
|
||||
|
||||
await expect(count, 'count incremented by 1').toHaveText('1');
|
||||
});
|
||||
|
||||
test('Preact counter', async ({ astro, page }) => {
|
||||
await page.goto('/');
|
||||
|
||||
const counter = await page.locator('#preact-counter');
|
||||
await expect(counter, 'component is visible').toBeVisible();
|
||||
|
||||
const count = await counter.locator('#preact-counter-count');
|
||||
await expect(count, 'initial count is 0').toHaveText('0');
|
||||
|
||||
const increment = await counter.locator('#preact-counter-increment');
|
||||
await increment.click();
|
||||
|
||||
await expect(count, 'count incremented by 1').toHaveText('1');
|
||||
});
|
||||
|
||||
test('Solid counter', async ({ astro, page }) => {
|
||||
await page.goto('/');
|
||||
|
||||
const counter = await page.locator('#solid-counter');
|
||||
await expect(counter, 'component is visible').toBeVisible();
|
||||
|
||||
const count = await counter.locator('#solid-counter-count');
|
||||
await expect(count, 'initial count is 0').toHaveText('0');
|
||||
|
||||
const increment = await counter.locator('#solid-counter-increment');
|
||||
await increment.click();
|
||||
|
||||
await expect(count, 'count incremented by 1').toHaveText('1');
|
||||
});
|
||||
|
||||
test('Vue counter', async ({ astro, page }) => {
|
||||
await page.goto('/');
|
||||
|
||||
const counter = await page.locator('#vue-counter');
|
||||
await expect(counter, 'component is visible').toBeVisible();
|
||||
|
||||
const count = await counter.locator('#vue-counter-count');
|
||||
await expect(count, 'initial count is 0').toHaveText('0');
|
||||
|
||||
const increment = await counter.locator('#vue-counter-increment');
|
||||
await increment.click();
|
||||
|
||||
await expect(count, 'count incremented by 1').toHaveText('1');
|
||||
});
|
||||
|
||||
test('Svelte counter', async ({ astro, page }) => {
|
||||
await page.goto('/');
|
||||
|
||||
const counter = await page.locator('#svelte-counter');
|
||||
await expect(counter, 'component is visible').toBeVisible();
|
||||
|
||||
const count = await counter.locator('#svelte-counter-count');
|
||||
await expect(count, 'initial count is 0').toHaveText('0');
|
||||
|
||||
const increment = await counter.locator('#svelte-counter-increment');
|
||||
await increment.click();
|
||||
|
||||
await expect(count, 'count incremented by 1').toHaveText('1');
|
||||
});
|
||||
});
|
97
packages/astro/e2e/nested-in-solid.test.js
Normal file
97
packages/astro/e2e/nested-in-solid.test.js
Normal file
|
@ -0,0 +1,97 @@
|
|||
import { test as base, expect } from '@playwright/test';
|
||||
import { loadFixture } from './test-utils.js';
|
||||
|
||||
const test = base.extend({
|
||||
astro: async ({}, use) => {
|
||||
const fixture = await loadFixture({ root: './fixtures/nested-in-solid/' });
|
||||
await use(fixture);
|
||||
},
|
||||
});
|
||||
|
||||
let devServer;
|
||||
|
||||
test.beforeEach(async ({ astro }) => {
|
||||
devServer = await astro.startDevServer();
|
||||
});
|
||||
|
||||
test.afterEach(async () => {
|
||||
await devServer.stop();
|
||||
});
|
||||
|
||||
test.describe('Nested Frameworks in Solid', () => {
|
||||
test('React counter', async ({ astro, page }) => {
|
||||
await page.goto('/');
|
||||
|
||||
const counter = await page.locator('#react-counter');
|
||||
await expect(counter, 'component is visible').toBeVisible();
|
||||
|
||||
const count = await counter.locator('#react-counter-count');
|
||||
await expect(count, 'initial count is 0').toHaveText('0');
|
||||
|
||||
const increment = await counter.locator('#react-counter-increment');
|
||||
await increment.click();
|
||||
|
||||
await expect(count, 'count incremented by 1').toHaveText('1');
|
||||
});
|
||||
|
||||
test('Preact counter', async ({ astro, page }) => {
|
||||
await page.goto('/');
|
||||
|
||||
const counter = await page.locator('#preact-counter');
|
||||
await expect(counter, 'component is visible').toBeVisible();
|
||||
|
||||
const count = await counter.locator('#preact-counter-count');
|
||||
await expect(count, 'initial count is 0').toHaveText('0');
|
||||
|
||||
const increment = await counter.locator('#preact-counter-increment');
|
||||
await increment.click();
|
||||
|
||||
await expect(count, 'count incremented by 1').toHaveText('1');
|
||||
});
|
||||
|
||||
test('Solid counter', async ({ astro, page }) => {
|
||||
await page.goto('/');
|
||||
|
||||
const counter = await page.locator('#solid-counter');
|
||||
await expect(counter, 'component is visible').toBeVisible();
|
||||
|
||||
const count = await counter.locator('#solid-counter-count');
|
||||
await expect(count, 'initial count is 0').toHaveText('0');
|
||||
|
||||
const increment = await counter.locator('#solid-counter-increment');
|
||||
await increment.click();
|
||||
|
||||
await expect(count, 'count incremented by 1').toHaveText('1');
|
||||
});
|
||||
|
||||
test('Vue counter', async ({ astro, page }) => {
|
||||
await page.goto('/');
|
||||
|
||||
const counter = await page.locator('#vue-counter');
|
||||
await expect(counter, 'component is visible').toBeVisible();
|
||||
|
||||
const count = await counter.locator('#vue-counter-count');
|
||||
await expect(count, 'initial count is 0').toHaveText('0');
|
||||
|
||||
const increment = await counter.locator('#vue-counter-increment');
|
||||
await increment.click();
|
||||
|
||||
await expect(count, 'count incremented by 1').toHaveText('1');
|
||||
});
|
||||
|
||||
test('Svelte counter', async ({ astro, page }) => {
|
||||
await page.goto('/');
|
||||
|
||||
const counter = await page.locator('#svelte-counter');
|
||||
await expect(counter, 'component is visible').toBeVisible();
|
||||
|
||||
const count = await counter.locator('#svelte-counter-count');
|
||||
await expect(count, 'initial count is 0').toHaveText('0');
|
||||
|
||||
const increment = await counter.locator('#svelte-counter-increment');
|
||||
await increment.click();
|
||||
|
||||
await expect(count, 'count incremented by 1').toHaveText('1');
|
||||
});
|
||||
});
|
||||
|
96
packages/astro/e2e/nested-in-svelte.test.js
Normal file
96
packages/astro/e2e/nested-in-svelte.test.js
Normal file
|
@ -0,0 +1,96 @@
|
|||
import { test as base, expect } from '@playwright/test';
|
||||
import { loadFixture } from './test-utils.js';
|
||||
|
||||
const test = base.extend({
|
||||
astro: async ({}, use) => {
|
||||
const fixture = await loadFixture({ root: './fixtures/nested-in-svelte/' });
|
||||
await use(fixture);
|
||||
},
|
||||
});
|
||||
|
||||
let devServer;
|
||||
|
||||
test.beforeEach(async ({ astro }) => {
|
||||
devServer = await astro.startDevServer();
|
||||
});
|
||||
|
||||
test.afterEach(async () => {
|
||||
await devServer.stop();
|
||||
});
|
||||
|
||||
test.describe('Nested Frameworks in Svelte', () => {
|
||||
test('React counter', async ({ astro, page }) => {
|
||||
await page.goto('/');
|
||||
|
||||
const counter = await page.locator('#react-counter');
|
||||
await expect(counter, 'component is visible').toBeVisible();
|
||||
|
||||
const count = await counter.locator('#react-counter-count');
|
||||
await expect(count, 'initial count is 0').toHaveText('0');
|
||||
|
||||
const increment = await counter.locator('#react-counter-increment');
|
||||
await increment.click();
|
||||
|
||||
await expect(count, 'count incremented by 1').toHaveText('1');
|
||||
});
|
||||
|
||||
test('Preact counter', async ({ astro, page }) => {
|
||||
await page.goto('/');
|
||||
|
||||
const counter = await page.locator('#preact-counter');
|
||||
await expect(counter, 'component is visible').toBeVisible();
|
||||
|
||||
const count = await counter.locator('#preact-counter-count');
|
||||
await expect(count, 'initial count is 0').toHaveText('0');
|
||||
|
||||
const increment = await counter.locator('#preact-counter-increment');
|
||||
await increment.click();
|
||||
|
||||
await expect(count, 'count incremented by 1').toHaveText('1');
|
||||
});
|
||||
|
||||
test('Solid counter', async ({ astro, page }) => {
|
||||
await page.goto('/');
|
||||
|
||||
const counter = await page.locator('#solid-counter');
|
||||
await expect(counter, 'component is visible').toBeVisible();
|
||||
|
||||
const count = await counter.locator('#solid-counter-count');
|
||||
await expect(count, 'initial count is 0').toHaveText('0');
|
||||
|
||||
const increment = await counter.locator('#solid-counter-increment');
|
||||
await increment.click();
|
||||
|
||||
await expect(count, 'count incremented by 1').toHaveText('1');
|
||||
});
|
||||
|
||||
test('Vue counter', async ({ astro, page }) => {
|
||||
await page.goto('/');
|
||||
|
||||
const counter = await page.locator('#vue-counter');
|
||||
await expect(counter, 'component is visible').toBeVisible();
|
||||
|
||||
const count = await counter.locator('#vue-counter-count');
|
||||
await expect(count, 'initial count is 0').toHaveText('0');
|
||||
|
||||
const increment = await counter.locator('#vue-counter-increment');
|
||||
await increment.click();
|
||||
|
||||
await expect(count, 'count incremented by 1').toHaveText('1');
|
||||
});
|
||||
|
||||
test('Svelte counter', async ({ astro, page }) => {
|
||||
await page.goto('/');
|
||||
|
||||
const counter = await page.locator('#svelte-counter');
|
||||
await expect(counter, 'component is visible').toBeVisible();
|
||||
|
||||
const count = await counter.locator('#svelte-counter-count');
|
||||
await expect(count, 'initial count is 0').toHaveText('0');
|
||||
|
||||
const increment = await counter.locator('#svelte-counter-increment');
|
||||
await increment.click();
|
||||
|
||||
await expect(count, 'count incremented by 1').toHaveText('1');
|
||||
});
|
||||
});
|
96
packages/astro/e2e/nested-in-vue.test.js
Normal file
96
packages/astro/e2e/nested-in-vue.test.js
Normal file
|
@ -0,0 +1,96 @@
|
|||
import { test as base, expect } from '@playwright/test';
|
||||
import { loadFixture } from './test-utils.js';
|
||||
|
||||
const test = base.extend({
|
||||
astro: async ({}, use) => {
|
||||
const fixture = await loadFixture({ root: './fixtures/nested-in-vue/' });
|
||||
await use(fixture);
|
||||
},
|
||||
});
|
||||
|
||||
let devServer;
|
||||
|
||||
test.beforeEach(async ({ astro }) => {
|
||||
devServer = await astro.startDevServer();
|
||||
});
|
||||
|
||||
test.afterEach(async () => {
|
||||
await devServer.stop();
|
||||
});
|
||||
|
||||
test.describe('Nested Frameworks in Vue', () => {
|
||||
test('React counter', async ({ astro, page }) => {
|
||||
await page.goto('/');
|
||||
|
||||
const counter = await page.locator('#react-counter');
|
||||
await expect(counter, 'component is visible').toBeVisible();
|
||||
|
||||
const count = await counter.locator('#react-counter-count');
|
||||
await expect(count, 'initial count is 0').toHaveText('0');
|
||||
|
||||
const increment = await counter.locator('#react-counter-increment');
|
||||
await increment.click();
|
||||
|
||||
await expect(count, 'count incremented by 1').toHaveText('1');
|
||||
});
|
||||
|
||||
test('Preact counter', async ({ astro, page }) => {
|
||||
await page.goto('/');
|
||||
|
||||
const counter = await page.locator('#preact-counter');
|
||||
await expect(counter, 'component is visible').toBeVisible();
|
||||
|
||||
const count = await counter.locator('#preact-counter-count');
|
||||
await expect(count, 'initial count is 0').toHaveText('0');
|
||||
|
||||
const increment = await counter.locator('#preact-counter-increment');
|
||||
await increment.click();
|
||||
|
||||
await expect(count, 'count incremented by 1').toHaveText('1');
|
||||
});
|
||||
|
||||
test('Solid counter', async ({ astro, page }) => {
|
||||
await page.goto('/');
|
||||
|
||||
const counter = await page.locator('#solid-counter');
|
||||
await expect(counter, 'component is visible').toBeVisible();
|
||||
|
||||
const count = await counter.locator('#solid-counter-count');
|
||||
await expect(count, 'initial count is 0').toHaveText('0');
|
||||
|
||||
const increment = await counter.locator('#solid-counter-increment');
|
||||
await increment.click();
|
||||
|
||||
await expect(count, 'count incremented by 1').toHaveText('1');
|
||||
});
|
||||
|
||||
test('Vue counter', async ({ astro, page }) => {
|
||||
await page.goto('/');
|
||||
|
||||
const counter = await page.locator('#vue-counter');
|
||||
await expect(counter, 'component is visible').toBeVisible();
|
||||
|
||||
const count = await counter.locator('#vue-counter-count');
|
||||
await expect(count, 'initial count is 0').toHaveText('0');
|
||||
|
||||
const increment = await counter.locator('#vue-counter-increment');
|
||||
await increment.click();
|
||||
|
||||
await expect(count, 'count incremented by 1').toHaveText('1');
|
||||
});
|
||||
|
||||
test('Svelte counter', async ({ astro, page }) => {
|
||||
await page.goto('/');
|
||||
|
||||
const counter = await page.locator('#svelte-counter');
|
||||
await expect(counter, 'component is visible').toBeVisible();
|
||||
|
||||
const count = await counter.locator('#svelte-counter-count');
|
||||
await expect(count, 'initial count is 0').toHaveText('0');
|
||||
|
||||
const increment = await counter.locator('#svelte-counter-increment');
|
||||
await increment.click();
|
||||
|
||||
await expect(count, 'count incremented by 1').toHaveText('1');
|
||||
});
|
||||
});
|
|
@ -767,7 +767,7 @@ export interface MarkdownInstance<T extends Record<string, any>> {
|
|||
}
|
||||
|
||||
export type GetHydrateCallback = () => Promise<
|
||||
(element: Element, innerHTML: string | null) => void
|
||||
(element: Element, innerHTML: string | null) => void | Promise<void>
|
||||
>;
|
||||
|
||||
/**
|
||||
|
|
24
packages/astro/src/runtime/client/events.ts
Normal file
24
packages/astro/src/runtime/client/events.ts
Normal file
|
@ -0,0 +1,24 @@
|
|||
const HYDRATE_KEY = `astro:hydrate`;
|
||||
function debounce<T extends (...args: any[]) => any>(cb: T, wait = 20) {
|
||||
let h = 0;
|
||||
let callable = (...args: any) => {
|
||||
clearTimeout(h);
|
||||
h = setTimeout(() => cb(...args), wait) as unknown as number;
|
||||
};
|
||||
return callable as T;
|
||||
}
|
||||
|
||||
export const notify = debounce(() => {
|
||||
if (document.querySelector('astro-root[ssr]')) {
|
||||
window.dispatchEvent(new CustomEvent(HYDRATE_KEY));
|
||||
}
|
||||
});
|
||||
|
||||
export const listen = (cb: (...args: any[]) => any) => window.addEventListener(HYDRATE_KEY, cb, { once: true });
|
||||
|
||||
if (!(window as any)[HYDRATE_KEY]) {
|
||||
if ('MutationObserver' in window) {
|
||||
new MutationObserver(notify).observe(document.body, { subtree: true, childList: true });
|
||||
}
|
||||
(window as any)[HYDRATE_KEY] = true;
|
||||
}
|
|
@ -1,7 +1,8 @@
|
|||
import type { GetHydrateCallback, HydrateOptions } from '../../@types/astro';
|
||||
import { notify, listen } from './events';
|
||||
|
||||
/**
|
||||
* Hydrate this component as soon as the main thread is free!
|
||||
* Hydrate this component as soon as the main thread is free
|
||||
* (or after a short delay, if `requestIdleCallback`) isn't supported
|
||||
*/
|
||||
export default async function onIdle(
|
||||
|
@ -9,35 +10,44 @@ export default async function onIdle(
|
|||
options: HydrateOptions,
|
||||
getHydrateCallback: GetHydrateCallback
|
||||
) {
|
||||
const cb = async () => {
|
||||
const roots = document.querySelectorAll(`astro-root[uid="${astroId}"]`);
|
||||
if (roots.length === 0) {
|
||||
throw new Error(`Unable to find the root for the component ${options.name}`);
|
||||
}
|
||||
let innerHTML: string | null = null;
|
||||
let hydrate: Awaited<ReturnType<GetHydrateCallback>>;
|
||||
|
||||
let innerHTML: string | null = null;
|
||||
let fragment = roots[0].querySelector(`astro-fragment`);
|
||||
if (fragment == null && roots[0].hasAttribute('tmpl')) {
|
||||
// If there is no child fragment, check to see if there is a template.
|
||||
// This happens if children were passed but the client component did not render any.
|
||||
let template = roots[0].querySelector(`template[data-astro-template]`);
|
||||
if (template) {
|
||||
innerHTML = template.innerHTML;
|
||||
template.remove();
|
||||
async function idle() {
|
||||
listen(idle)
|
||||
const cb = async () => {
|
||||
const roots = document.querySelectorAll(`astro-root[ssr][uid="${astroId}"]`);
|
||||
if (roots.length === 0) return;
|
||||
if (typeof innerHTML !== 'string') {
|
||||
let fragment = roots[0].querySelector(`astro-fragment`);
|
||||
if (fragment == null && roots[0].hasAttribute('tmpl')) {
|
||||
// If there is no child fragment, check to see if there is a template.
|
||||
// This happens if children were passed but the client component did not render any.
|
||||
let template = roots[0].querySelector(`template[data-astro-template]`);
|
||||
if (template) {
|
||||
innerHTML = template.innerHTML;
|
||||
template.remove();
|
||||
}
|
||||
} else if (fragment) {
|
||||
innerHTML = fragment.innerHTML;
|
||||
}
|
||||
}
|
||||
} else if (fragment) {
|
||||
innerHTML = fragment.innerHTML;
|
||||
}
|
||||
const hydrate = await getHydrateCallback();
|
||||
if (!hydrate) {
|
||||
hydrate = await getHydrateCallback();
|
||||
}
|
||||
for (const root of roots) {
|
||||
if (root.parentElement?.closest('astro-root[ssr]')) continue;
|
||||
await hydrate(root, innerHTML);
|
||||
root.removeAttribute('ssr');
|
||||
}
|
||||
notify();
|
||||
};
|
||||
|
||||
for (const root of roots) {
|
||||
hydrate(root, innerHTML);
|
||||
if ('requestIdleCallback' in window) {
|
||||
(window as any).requestIdleCallback(cb);
|
||||
} else {
|
||||
setTimeout(cb, 200);
|
||||
}
|
||||
};
|
||||
|
||||
if ('requestIdleCallback' in window) {
|
||||
(window as any).requestIdleCallback(cb);
|
||||
} else {
|
||||
setTimeout(cb, 200);
|
||||
}
|
||||
idle();
|
||||
}
|
||||
|
|
|
@ -1,36 +1,44 @@
|
|||
import type { GetHydrateCallback, HydrateOptions } from '../../@types/astro';
|
||||
import { notify, listen } from './events';
|
||||
|
||||
/**
|
||||
* Hydrate this component immediately!
|
||||
* Hydrate this component immediately
|
||||
*/
|
||||
export default async function onLoad(
|
||||
astroId: string,
|
||||
options: HydrateOptions,
|
||||
getHydrateCallback: GetHydrateCallback
|
||||
) {
|
||||
const roots = document.querySelectorAll(`astro-root[uid="${astroId}"]`);
|
||||
if (roots.length === 0) {
|
||||
throw new Error(`Unable to find the root for the component ${options.name}`);
|
||||
}
|
||||
|
||||
let innerHTML: string | null = null;
|
||||
let fragment = roots[0].querySelector(`astro-fragment`);
|
||||
if (fragment == null && roots[0].hasAttribute('tmpl')) {
|
||||
// If there is no child fragment, check to see if there is a template.
|
||||
// This happens if children were passed but the client component did not render any.
|
||||
let template = roots[0].querySelector(`template[data-astro-template]`);
|
||||
if (template) {
|
||||
innerHTML = template.innerHTML;
|
||||
template.remove();
|
||||
let hydrate: Awaited<ReturnType<GetHydrateCallback>>;
|
||||
|
||||
async function load() {
|
||||
listen(load);
|
||||
const roots = document.querySelectorAll(`astro-root[ssr][uid="${astroId}"]`);
|
||||
if (roots.length === 0) return;
|
||||
if (typeof innerHTML !== 'string') {
|
||||
let fragment = roots[0].querySelector(`astro-fragment`);
|
||||
if (fragment == null && roots[0].hasAttribute('tmpl')) {
|
||||
// If there is no child fragment, check to see if there is a template.
|
||||
// This happens if children were passed but the client component did not render any.
|
||||
let template = roots[0].querySelector(`template[data-astro-template]`);
|
||||
if (template) {
|
||||
innerHTML = template.innerHTML;
|
||||
template.remove();
|
||||
}
|
||||
} else if (fragment) {
|
||||
innerHTML = fragment.innerHTML;
|
||||
}
|
||||
}
|
||||
} else if (fragment) {
|
||||
innerHTML = fragment.innerHTML;
|
||||
}
|
||||
|
||||
//const innerHTML = roots[0].querySelector(`astro-fragment`)?.innerHTML ?? null;
|
||||
const hydrate = await getHydrateCallback();
|
||||
|
||||
for (const root of roots) {
|
||||
hydrate(root, innerHTML);
|
||||
if (!hydrate) {
|
||||
hydrate = await getHydrateCallback();
|
||||
}
|
||||
for (const root of roots) {
|
||||
if (root.parentElement?.closest('astro-root[ssr]')) continue;
|
||||
await hydrate(root, innerHTML);
|
||||
root.removeAttribute('ssr');
|
||||
}
|
||||
notify();
|
||||
}
|
||||
load();
|
||||
}
|
||||
|
|
|
@ -1,45 +1,55 @@
|
|||
import type { GetHydrateCallback, HydrateOptions } from '../../@types/astro';
|
||||
import { notify, listen } from './events';
|
||||
|
||||
/**
|
||||
* Hydrate this component when a matching media query is found!
|
||||
* Hydrate this component when a matching media query is found
|
||||
*/
|
||||
export default async function onMedia(
|
||||
astroId: string,
|
||||
options: HydrateOptions,
|
||||
getHydrateCallback: GetHydrateCallback
|
||||
) {
|
||||
const roots = document.querySelectorAll(`astro-root[uid="${astroId}"]`);
|
||||
if (roots.length === 0) {
|
||||
throw new Error(`Unable to find the root for the component ${options.name}`);
|
||||
}
|
||||
|
||||
let innerHTML: string | null = null;
|
||||
let fragment = roots[0].querySelector(`astro-fragment`);
|
||||
if (fragment == null && roots[0].hasAttribute('tmpl')) {
|
||||
// If there is no child fragment, check to see if there is a template.
|
||||
// This happens if children were passed but the client component did not render any.
|
||||
let template = roots[0].querySelector(`template[data-astro-template]`);
|
||||
if (template) {
|
||||
innerHTML = template.innerHTML;
|
||||
template.remove();
|
||||
}
|
||||
} else if (fragment) {
|
||||
innerHTML = fragment.innerHTML;
|
||||
}
|
||||
let hydrate: Awaited<ReturnType<GetHydrateCallback>>;
|
||||
|
||||
const cb = async () => {
|
||||
const hydrate = await getHydrateCallback();
|
||||
for (const root of roots) {
|
||||
hydrate(root, innerHTML);
|
||||
}
|
||||
};
|
||||
async function media() {
|
||||
listen(media)
|
||||
const cb = async () => {
|
||||
const roots = document.querySelectorAll(`astro-root[ssr][uid="${astroId}"]`);
|
||||
if (roots.length === 0) return;
|
||||
if (typeof innerHTML !== 'string') {
|
||||
let fragment = roots[0].querySelector(`astro-fragment`);
|
||||
if (fragment == null && roots[0].hasAttribute('tmpl')) {
|
||||
// If there is no child fragment, check to see if there is a template.
|
||||
// This happens if children were passed but the client component did not render any.
|
||||
let template = roots[0].querySelector(`template[data-astro-template]`);
|
||||
if (template) {
|
||||
innerHTML = template.innerHTML;
|
||||
template.remove();
|
||||
}
|
||||
} else if (fragment) {
|
||||
innerHTML = fragment.innerHTML;
|
||||
}
|
||||
}
|
||||
if (!hydrate) {
|
||||
hydrate = await getHydrateCallback();
|
||||
}
|
||||
for (const root of roots) {
|
||||
if (root.parentElement?.closest('astro-root[ssr]')) continue;
|
||||
await hydrate(root, innerHTML);
|
||||
root.removeAttribute('ssr');
|
||||
}
|
||||
notify();
|
||||
};
|
||||
|
||||
if (options.value) {
|
||||
const mql = matchMedia(options.value);
|
||||
if (mql.matches) {
|
||||
cb();
|
||||
} else {
|
||||
mql.addEventListener('change', cb, { once: true });
|
||||
if (options.value) {
|
||||
const mql = matchMedia(options.value);
|
||||
if (mql.matches) {
|
||||
cb();
|
||||
} else {
|
||||
mql.addEventListener('change', cb, { once: true });
|
||||
}
|
||||
}
|
||||
}
|
||||
media();
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import type { GetHydrateCallback, HydrateOptions } from '../../@types/astro';
|
||||
import { listen, notify } from './events';
|
||||
|
||||
/**
|
||||
* Hydrate this component only on the client
|
||||
|
@ -8,27 +9,36 @@ export default async function onOnly(
|
|||
options: HydrateOptions,
|
||||
getHydrateCallback: GetHydrateCallback
|
||||
) {
|
||||
const roots = document.querySelectorAll(`astro-root[uid="${astroId}"]`);
|
||||
if (roots.length === 0) {
|
||||
throw new Error(`Unable to find the root for the component ${options.name}`);
|
||||
}
|
||||
|
||||
let innerHTML: string | null = null;
|
||||
let fragment = roots[0].querySelector(`astro-fragment`);
|
||||
if (fragment == null && roots[0].hasAttribute('tmpl')) {
|
||||
// If there is no child fragment, check to see if there is a template.
|
||||
// This happens if children were passed but the client component did not render any.
|
||||
let template = roots[0].querySelector(`template[data-astro-template]`);
|
||||
if (template) {
|
||||
innerHTML = template.innerHTML;
|
||||
template.remove();
|
||||
}
|
||||
} else if (fragment) {
|
||||
innerHTML = fragment.innerHTML;
|
||||
}
|
||||
const hydrate = await getHydrateCallback();
|
||||
let hydrate: Awaited<ReturnType<GetHydrateCallback>>;
|
||||
|
||||
for (const root of roots) {
|
||||
hydrate(root, innerHTML);
|
||||
async function only() {
|
||||
listen(only);
|
||||
const roots = document.querySelectorAll(`astro-root[ssr][uid="${astroId}"]`);
|
||||
if (roots.length === 0) return;
|
||||
if (typeof innerHTML !== 'string') {
|
||||
let fragment = roots[0].querySelector(`astro-fragment`);
|
||||
if (fragment == null && roots[0].hasAttribute('tmpl')) {
|
||||
// If there is no child fragment, check to see if there is a template.
|
||||
// This happens if children were passed but the client component did not render any.
|
||||
let template = roots[0].querySelector(`template[data-astro-template]`);
|
||||
if (template) {
|
||||
innerHTML = template.innerHTML;
|
||||
template.remove();
|
||||
}
|
||||
} else if (fragment) {
|
||||
innerHTML = fragment.innerHTML;
|
||||
}
|
||||
}
|
||||
if (!hydrate) {
|
||||
hydrate = await getHydrateCallback();
|
||||
}
|
||||
for (const root of roots) {
|
||||
if (root.parentElement?.closest('astro-root[ssr]')) continue;
|
||||
await hydrate(root, innerHTML);
|
||||
root.removeAttribute('ssr');
|
||||
}
|
||||
notify();
|
||||
}
|
||||
only();
|
||||
}
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import type { GetHydrateCallback, HydrateOptions } from '../../@types/astro';
|
||||
import { notify, listen } from './events';
|
||||
|
||||
/**
|
||||
* Hydrate this component when one of it's children becomes visible!
|
||||
* Hydrate this component when one of it's children becomes visible
|
||||
* We target the children because `astro-root` is set to `display: contents`
|
||||
* which doesn't work with IntersectionObserver
|
||||
*/
|
||||
|
@ -10,46 +11,61 @@ export default async function onVisible(
|
|||
options: HydrateOptions,
|
||||
getHydrateCallback: GetHydrateCallback
|
||||
) {
|
||||
const roots = document.querySelectorAll(`astro-root[uid="${astroId}"]`);
|
||||
if (roots.length === 0) {
|
||||
throw new Error(`Unable to find the root for the component ${options.name}`);
|
||||
}
|
||||
|
||||
let io: IntersectionObserver;
|
||||
let innerHTML: string | null = null;
|
||||
let fragment = roots[0].querySelector(`astro-fragment`);
|
||||
if (fragment == null && roots[0].hasAttribute('tmpl')) {
|
||||
// If there is no child fragment, check to see if there is a template.
|
||||
// This happens if children were passed but the client component did not render any.
|
||||
let template = roots[0].querySelector(`template[data-astro-template]`);
|
||||
if (template) {
|
||||
innerHTML = template.innerHTML;
|
||||
template.remove();
|
||||
}
|
||||
} else if (fragment) {
|
||||
innerHTML = fragment.innerHTML;
|
||||
}
|
||||
let hydrate: Awaited<ReturnType<GetHydrateCallback>>;
|
||||
|
||||
const cb = async () => {
|
||||
const hydrate = await getHydrateCallback();
|
||||
for (const root of roots) {
|
||||
hydrate(root, innerHTML);
|
||||
}
|
||||
};
|
||||
async function visible() {
|
||||
listen(visible)
|
||||
const roots = document.querySelectorAll(`astro-root[ssr][uid="${astroId}"]`);
|
||||
const cb = async () => {
|
||||
if (roots.length === 0) return;
|
||||
if (typeof innerHTML !== 'string') {
|
||||
let fragment = roots[0].querySelector(`astro-fragment`);
|
||||
if (fragment == null && roots[0].hasAttribute('tmpl')) {
|
||||
// If there is no child fragment, check to see if there is a template.
|
||||
// This happens if children were passed but the client component did not render any.
|
||||
let template = roots[0].querySelector(`template[data-astro-template]`);
|
||||
if (template) {
|
||||
innerHTML = template.innerHTML;
|
||||
template.remove();
|
||||
}
|
||||
} else if (fragment) {
|
||||
innerHTML = fragment.innerHTML;
|
||||
}
|
||||
}
|
||||
if (!hydrate) {
|
||||
hydrate = await getHydrateCallback();
|
||||
}
|
||||
for (const root of roots) {
|
||||
if (root.parentElement?.closest('astro-root[ssr]')) continue;
|
||||
await hydrate(root, innerHTML);
|
||||
root.removeAttribute('ssr');
|
||||
}
|
||||
notify();
|
||||
};
|
||||
|
||||
const io = new IntersectionObserver((entries) => {
|
||||
for (const entry of entries) {
|
||||
if (!entry.isIntersecting) continue;
|
||||
// As soon as we hydrate, disconnect this IntersectionObserver for every `astro-root`
|
||||
if (io) {
|
||||
io.disconnect();
|
||||
cb();
|
||||
break; // break loop on first match
|
||||
}
|
||||
});
|
||||
|
||||
for (const root of roots) {
|
||||
for (let i = 0; i < root.children.length; i++) {
|
||||
const child = root.children[i];
|
||||
io.observe(child);
|
||||
io = new IntersectionObserver((entries) => {
|
||||
for (const entry of entries) {
|
||||
if (!entry.isIntersecting) continue;
|
||||
// As soon as we hydrate, disconnect this IntersectionObserver for every `astro-root`
|
||||
io.disconnect();
|
||||
cb();
|
||||
break; // break loop on first match
|
||||
}
|
||||
});
|
||||
|
||||
for (const root of roots) {
|
||||
for (let i = 0; i < root.children.length; i++) {
|
||||
const child = root.children[i];
|
||||
io.observe(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
visible();
|
||||
}
|
||||
|
|
|
@ -330,7 +330,7 @@ If you're still stuck, please open an issue on GitHub or join us at https://astr
|
|||
const template = needsAstroTemplate ? `<template data-astro-template>${children}</template>` : '';
|
||||
|
||||
return markHTMLString(
|
||||
`<astro-root uid="${astroId}"${needsAstroTemplate ? ' tmpl' : ''}>${
|
||||
`<astro-root ssr uid="${astroId}"${needsAstroTemplate ? ' tmpl' : ''}>${
|
||||
html ?? ''
|
||||
}${template}</astro-root>`
|
||||
);
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
import { h, render } from 'preact';
|
||||
import StaticHtml from './static-html.js';
|
||||
|
||||
export default (element) => (Component, props, children) =>
|
||||
export default (element) => (Component, props, children) => {
|
||||
if (!element.hasAttribute('ssr')) return;
|
||||
render(
|
||||
h(Component, props, children != null ? h(StaticHtml, { value: children }) : children),
|
||||
element
|
||||
);
|
||||
}
|
||||
|
|
|
@ -2,13 +2,27 @@ import { createElement } from 'react';
|
|||
import { createRoot, hydrateRoot } from 'react-dom/client';
|
||||
import StaticHtml from './static-html.js';
|
||||
|
||||
function isAlreadyHydrated(element) {
|
||||
for (const key in element) {
|
||||
if (key.startsWith('__reactContainer')) {
|
||||
return key;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default (element) =>
|
||||
(Component, props, children, { client }) => {
|
||||
if (!element.hasAttribute('ssr')) return;
|
||||
const componentEl = createElement(
|
||||
Component,
|
||||
props,
|
||||
children != null ? createElement(StaticHtml, { value: children }) : children
|
||||
);
|
||||
const rootKey = isAlreadyHydrated(element);
|
||||
// HACK: delete internal react marker for nested components to suppress agressive warnings
|
||||
if (rootKey) {
|
||||
delete element[rootKey];
|
||||
}
|
||||
if (client === 'only') {
|
||||
return createRoot(element).render(componentEl);
|
||||
}
|
||||
|
|
|
@ -1,21 +1,27 @@
|
|||
import { sharedConfig } from 'solid-js';
|
||||
import { hydrate, createComponent } from 'solid-js/web';
|
||||
import { hydrate, render, createComponent } from 'solid-js/web';
|
||||
|
||||
export default (element) => (Component, props, childHTML) => {
|
||||
export default (element) => (Component, props, childHTML, { client }) => {
|
||||
// Prepare global object expected by Solid's hydration logic
|
||||
if (!window._$HY) {
|
||||
window._$HY = { events: [], completed: new WeakSet(), r: {} };
|
||||
}
|
||||
if (!element.hasAttribute('ssr')) return;
|
||||
|
||||
const fn = client === 'only' ? render : hydrate;
|
||||
|
||||
// Perform actual hydration
|
||||
let children;
|
||||
hydrate(
|
||||
fn(
|
||||
() =>
|
||||
createComponent(Component, {
|
||||
...props,
|
||||
get children() {
|
||||
if (childHTML != null) {
|
||||
// hydrating
|
||||
if (sharedConfig.context) children = element.querySelector('astro-fragment');
|
||||
if (sharedConfig.context) {
|
||||
children = element.querySelector('astro-fragment');
|
||||
}
|
||||
|
||||
if (children == null) {
|
||||
children = document.createElement('astro-fragment');
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
import SvelteWrapper from './Wrapper.svelte';
|
||||
|
||||
export default (target) => {
|
||||
return (component, props, children) => {
|
||||
return (component, props, children, { client }) => {
|
||||
if (!target.hasAttribute('ssr')) return;
|
||||
delete props['class'];
|
||||
try {
|
||||
new SvelteWrapper({
|
||||
target,
|
||||
props: { __astro_component: component, __astro_children: children, ...props },
|
||||
hydrate: true,
|
||||
hydrate: client !== 'only',
|
||||
});
|
||||
} catch (e) {}
|
||||
};
|
||||
|
|
|
@ -1,14 +1,21 @@
|
|||
import { h, createSSRApp } from 'vue';
|
||||
import { h, createSSRApp, createApp } from 'vue';
|
||||
import StaticHtml from './static-html.js';
|
||||
|
||||
export default (element) => (Component, props, children) => {
|
||||
export default (element) => (Component, props, children, { client }) => {
|
||||
delete props['class'];
|
||||
if (!element.hasAttribute('ssr')) return;
|
||||
|
||||
// Expose name on host component for Vue devtools
|
||||
const name = Component.name ? `${Component.name} Host` : undefined;
|
||||
const slots = {};
|
||||
if (children != null) {
|
||||
slots.default = () => h(StaticHtml, { value: children });
|
||||
}
|
||||
const app = createSSRApp({ name, render: () => h(Component, props, slots) });
|
||||
app.mount(element, true);
|
||||
if (client === 'only') {
|
||||
const app = createApp({ name, render: () => h(Component, props, slots) });
|
||||
app.mount(element, false);
|
||||
} else {
|
||||
const app = createSSRApp({ name, render: () => h(Component, props, slots) });
|
||||
app.mount(element, true);
|
||||
}
|
||||
};
|
||||
|
|
183
pnpm-lock.yaml
generated
183
pnpm-lock.yaml
generated
|
@ -665,6 +665,35 @@ importers:
|
|||
dependencies:
|
||||
astro: link:../../..
|
||||
|
||||
packages/astro/e2e/fixtures/client-only:
|
||||
specifiers:
|
||||
'@astrojs/preact': ^0.1.2
|
||||
'@astrojs/react': ^0.1.2
|
||||
'@astrojs/solid-js': ^0.1.2
|
||||
'@astrojs/svelte': ^0.1.3
|
||||
'@astrojs/vue': ^0.1.4
|
||||
astro: ^1.0.0-beta.32
|
||||
preact: ^10.7.2
|
||||
react: ^18.1.0
|
||||
react-dom: ^18.1.0
|
||||
solid-js: ^1.4.2
|
||||
svelte: ^3.48.0
|
||||
vue: ^3.2.36
|
||||
dependencies:
|
||||
preact: 10.7.2
|
||||
react: 18.1.0
|
||||
react-dom: 18.1.0_react@18.1.0
|
||||
solid-js: 1.4.2
|
||||
svelte: 3.48.0
|
||||
vue: 3.2.36
|
||||
devDependencies:
|
||||
'@astrojs/preact': link:../../../../integrations/preact
|
||||
'@astrojs/react': link:../../../../integrations/react
|
||||
'@astrojs/solid-js': link:../../../../integrations/solid
|
||||
'@astrojs/svelte': link:../../../../integrations/svelte
|
||||
'@astrojs/vue': link:../../../../integrations/vue
|
||||
astro: link:../../..
|
||||
|
||||
packages/astro/e2e/fixtures/lit-component:
|
||||
specifiers:
|
||||
'@astrojs/lit': workspace:*
|
||||
|
@ -712,6 +741,151 @@ importers:
|
|||
'@astrojs/vue': link:../../../../integrations/vue
|
||||
astro: link:../../..
|
||||
|
||||
packages/astro/e2e/fixtures/nested-in-preact:
|
||||
specifiers:
|
||||
'@astrojs/preact': ^0.1.2
|
||||
'@astrojs/react': ^0.1.2
|
||||
'@astrojs/solid-js': ^0.1.2
|
||||
'@astrojs/svelte': ^0.1.3
|
||||
'@astrojs/vue': ^0.1.4
|
||||
astro: ^1.0.0-beta.32
|
||||
preact: ^10.7.2
|
||||
react: ^18.1.0
|
||||
react-dom: ^18.1.0
|
||||
solid-js: ^1.4.2
|
||||
svelte: ^3.48.0
|
||||
vue: ^3.2.36
|
||||
dependencies:
|
||||
preact: 10.7.2
|
||||
react: 18.1.0
|
||||
react-dom: 18.1.0_react@18.1.0
|
||||
solid-js: 1.4.2
|
||||
svelte: 3.48.0
|
||||
vue: 3.2.36
|
||||
devDependencies:
|
||||
'@astrojs/preact': link:../../../../integrations/preact
|
||||
'@astrojs/react': link:../../../../integrations/react
|
||||
'@astrojs/solid-js': link:../../../../integrations/solid
|
||||
'@astrojs/svelte': link:../../../../integrations/svelte
|
||||
'@astrojs/vue': link:../../../../integrations/vue
|
||||
astro: link:../../..
|
||||
|
||||
packages/astro/e2e/fixtures/nested-in-react:
|
||||
specifiers:
|
||||
'@astrojs/preact': ^0.1.2
|
||||
'@astrojs/react': ^0.1.2
|
||||
'@astrojs/solid-js': ^0.1.2
|
||||
'@astrojs/svelte': ^0.1.3
|
||||
'@astrojs/vue': ^0.1.4
|
||||
astro: ^1.0.0-beta.32
|
||||
preact: ^10.7.2
|
||||
react: ^18.1.0
|
||||
react-dom: ^18.1.0
|
||||
solid-js: ^1.4.2
|
||||
svelte: ^3.48.0
|
||||
vue: ^3.2.36
|
||||
dependencies:
|
||||
preact: 10.7.2
|
||||
react: 18.1.0
|
||||
react-dom: 18.1.0_react@18.1.0
|
||||
solid-js: 1.4.2
|
||||
svelte: 3.48.0
|
||||
vue: 3.2.36
|
||||
devDependencies:
|
||||
'@astrojs/preact': link:../../../../integrations/preact
|
||||
'@astrojs/react': link:../../../../integrations/react
|
||||
'@astrojs/solid-js': link:../../../../integrations/solid
|
||||
'@astrojs/svelte': link:../../../../integrations/svelte
|
||||
'@astrojs/vue': link:../../../../integrations/vue
|
||||
astro: link:../../..
|
||||
|
||||
packages/astro/e2e/fixtures/nested-in-solid:
|
||||
specifiers:
|
||||
'@astrojs/preact': ^0.1.2
|
||||
'@astrojs/react': ^0.1.2
|
||||
'@astrojs/solid-js': ^0.1.2
|
||||
'@astrojs/svelte': ^0.1.3
|
||||
'@astrojs/vue': ^0.1.4
|
||||
astro: ^1.0.0-beta.32
|
||||
preact: ^10.7.2
|
||||
react: ^18.1.0
|
||||
react-dom: ^18.1.0
|
||||
solid-js: ^1.4.2
|
||||
svelte: ^3.48.0
|
||||
vue: ^3.2.36
|
||||
dependencies:
|
||||
preact: 10.7.2
|
||||
react: 18.1.0
|
||||
react-dom: 18.1.0_react@18.1.0
|
||||
solid-js: 1.4.2
|
||||
svelte: 3.48.0
|
||||
vue: 3.2.36
|
||||
devDependencies:
|
||||
'@astrojs/preact': link:../../../../integrations/preact
|
||||
'@astrojs/react': link:../../../../integrations/react
|
||||
'@astrojs/solid-js': link:../../../../integrations/solid
|
||||
'@astrojs/svelte': link:../../../../integrations/svelte
|
||||
'@astrojs/vue': link:../../../../integrations/vue
|
||||
astro: link:../../..
|
||||
|
||||
packages/astro/e2e/fixtures/nested-in-svelte:
|
||||
specifiers:
|
||||
'@astrojs/preact': ^0.1.2
|
||||
'@astrojs/react': ^0.1.2
|
||||
'@astrojs/solid-js': ^0.1.2
|
||||
'@astrojs/svelte': ^0.1.3
|
||||
'@astrojs/vue': ^0.1.4
|
||||
astro: ^1.0.0-beta.32
|
||||
preact: ^10.7.2
|
||||
react: ^18.1.0
|
||||
react-dom: ^18.1.0
|
||||
solid-js: ^1.4.2
|
||||
svelte: ^3.48.0
|
||||
vue: ^3.2.36
|
||||
dependencies:
|
||||
preact: 10.7.2
|
||||
react: 18.1.0
|
||||
react-dom: 18.1.0_react@18.1.0
|
||||
solid-js: 1.4.2
|
||||
svelte: 3.48.0
|
||||
vue: 3.2.36
|
||||
devDependencies:
|
||||
'@astrojs/preact': link:../../../../integrations/preact
|
||||
'@astrojs/react': link:../../../../integrations/react
|
||||
'@astrojs/solid-js': link:../../../../integrations/solid
|
||||
'@astrojs/svelte': link:../../../../integrations/svelte
|
||||
'@astrojs/vue': link:../../../../integrations/vue
|
||||
astro: link:../../..
|
||||
|
||||
packages/astro/e2e/fixtures/nested-in-vue:
|
||||
specifiers:
|
||||
'@astrojs/preact': ^0.1.2
|
||||
'@astrojs/react': ^0.1.2
|
||||
'@astrojs/solid-js': ^0.1.2
|
||||
'@astrojs/svelte': ^0.1.3
|
||||
'@astrojs/vue': ^0.1.4
|
||||
astro: ^1.0.0-beta.32
|
||||
preact: ^10.7.2
|
||||
react: ^18.1.0
|
||||
react-dom: ^18.1.0
|
||||
solid-js: ^1.4.2
|
||||
svelte: ^3.48.0
|
||||
vue: ^3.2.36
|
||||
dependencies:
|
||||
preact: 10.7.2
|
||||
react: 18.1.0
|
||||
react-dom: 18.1.0_react@18.1.0
|
||||
solid-js: 1.4.2
|
||||
svelte: 3.48.0
|
||||
vue: 3.2.36
|
||||
devDependencies:
|
||||
'@astrojs/preact': link:../../../../integrations/preact
|
||||
'@astrojs/react': link:../../../../integrations/react
|
||||
'@astrojs/solid-js': link:../../../../integrations/solid
|
||||
'@astrojs/svelte': link:../../../../integrations/svelte
|
||||
'@astrojs/vue': link:../../../../integrations/vue
|
||||
astro: link:../../..
|
||||
|
||||
packages/astro/e2e/fixtures/nested-styles:
|
||||
specifiers:
|
||||
astro: workspace:*
|
||||
|
@ -7938,6 +8112,11 @@ packages:
|
|||
|
||||
/debug/3.2.7:
|
||||
resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==}
|
||||
peerDependencies:
|
||||
supports-color: '*'
|
||||
peerDependenciesMeta:
|
||||
supports-color:
|
||||
optional: true
|
||||
dependencies:
|
||||
ms: 2.1.3
|
||||
dev: false
|
||||
|
@ -10851,6 +11030,8 @@ packages:
|
|||
debug: 3.2.7
|
||||
iconv-lite: 0.4.24
|
||||
sax: 1.2.4
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
dev: false
|
||||
|
||||
/netmask/2.0.2:
|
||||
|
@ -10934,6 +11115,8 @@ packages:
|
|||
rimraf: 2.7.1
|
||||
semver: 5.7.1
|
||||
tar: 4.4.19
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
dev: false
|
||||
|
||||
/node-releases/2.0.5:
|
||||
|
|
Loading…
Add table
Reference in a new issue