mirror of
https://github.com/withastro/astro.git
synced 2025-01-20 22:12:38 -05:00
Fix hydration path for circular imports (#6244)
This commit is contained in:
parent
ac3649bb58
commit
1c678f7ebf
12 changed files with 106 additions and 6 deletions
5
.changeset/selfish-frogs-tell.md
Normal file
5
.changeset/selfish-frogs-tell.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
'astro': patch
|
||||||
|
---
|
||||||
|
|
||||||
|
Fix hydrate loading path to prevent multiple instance loaded for circular imports
|
|
@ -0,0 +1,7 @@
|
||||||
|
import { defineConfig } from 'astro/config';
|
||||||
|
import solid from '@astrojs/solid-js';
|
||||||
|
|
||||||
|
// https://astro.build/config
|
||||||
|
export default defineConfig({
|
||||||
|
integrations: [solid()],
|
||||||
|
});
|
12
packages/astro/e2e/fixtures/solid-circular/package.json
Normal file
12
packages/astro/e2e/fixtures/solid-circular/package.json
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
{
|
||||||
|
"name": "@e2e/solid-circular",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"private": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@astrojs/solid-js": "workspace:*",
|
||||||
|
"astro": "workspace:*"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"solid-js": "^1.4.3"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
import { Component, createContext } from 'solid-js';
|
||||||
|
import { SimpleDiv } from './SimpleDiv';
|
||||||
|
|
||||||
|
export const ApplicationContext = createContext([{ lng: 'en' }, {}]);
|
||||||
|
|
||||||
|
export const ContextProvider: Component = () => {
|
||||||
|
return (
|
||||||
|
<ApplicationContext.Provider value={[{ lng: 'fr' }]}>
|
||||||
|
<SimpleDiv />
|
||||||
|
</ApplicationContext.Provider>
|
||||||
|
);
|
||||||
|
};
|
|
@ -0,0 +1,8 @@
|
||||||
|
import { Component, useContext } from 'solid-js';
|
||||||
|
import { ApplicationContext } from './ContextProvider';
|
||||||
|
|
||||||
|
export const SimpleDiv: Component = () => {
|
||||||
|
const [context] = useContext(ApplicationContext);
|
||||||
|
|
||||||
|
return <div id="context">{context.lng}</div>;
|
||||||
|
};
|
1
packages/astro/e2e/fixtures/solid-circular/src/env.d.ts
vendored
Normal file
1
packages/astro/e2e/fixtures/solid-circular/src/env.d.ts
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
/// <reference types="astro/client" />
|
|
@ -0,0 +1,15 @@
|
||||||
|
---
|
||||||
|
import { ContextProvider } from "../components/ContextProvider.tsx";
|
||||||
|
---
|
||||||
|
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<main>
|
||||||
|
<ContextProvider client:only />
|
||||||
|
</main>
|
||||||
|
</body>
|
||||||
|
</html>
|
23
packages/astro/e2e/solid-circular.test.js
Normal file
23
packages/astro/e2e/solid-circular.test.js
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
import { expect } from '@playwright/test';
|
||||||
|
import { testFactory } from './test-utils.js';
|
||||||
|
|
||||||
|
const test = testFactory({ root: './fixtures/solid-circular/' });
|
||||||
|
|
||||||
|
let devServer;
|
||||||
|
|
||||||
|
test.beforeAll(async ({ astro }) => {
|
||||||
|
devServer = await astro.startDevServer();
|
||||||
|
});
|
||||||
|
|
||||||
|
test.afterAll(async () => {
|
||||||
|
await devServer.stop();
|
||||||
|
});
|
||||||
|
|
||||||
|
test.describe('Circular imports with Solid', () => {
|
||||||
|
test('Context', async ({ astro, page }) => {
|
||||||
|
await page.goto('/');
|
||||||
|
|
||||||
|
const wrapper = page.locator('#context');
|
||||||
|
await expect(wrapper, 'context should not be duplicated').toHaveText('fr');
|
||||||
|
});
|
||||||
|
});
|
|
@ -29,7 +29,7 @@ export function createDevelopmentEnvironment(
|
||||||
mode,
|
mode,
|
||||||
// This will be overridden in the dev server
|
// This will be overridden in the dev server
|
||||||
renderers: [],
|
renderers: [],
|
||||||
resolve: createResolve(loader),
|
resolve: createResolve(loader, settings.config.root),
|
||||||
routeCache: new RouteCache(logging, mode),
|
routeCache: new RouteCache(logging, mode),
|
||||||
site: settings.config.site,
|
site: settings.config.site,
|
||||||
ssr: settings.config.output === 'server',
|
ssr: settings.config.output === 'server',
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
import type { ModuleLoader } from '../../module-loader/index';
|
import type { ModuleLoader } from '../../module-loader/index';
|
||||||
import { resolveIdToUrl } from '../../util.js';
|
import { resolveIdToUrl } from '../../util.js';
|
||||||
|
|
||||||
export function createResolve(loader: ModuleLoader) {
|
export function createResolve(loader: ModuleLoader, root: URL) {
|
||||||
// Resolves specifiers in the inline hydrated scripts, such as:
|
// Resolves specifiers in the inline hydrated scripts, such as:
|
||||||
// - @astrojs/preact/client.js
|
// - @astrojs/preact/client.js
|
||||||
// - @/components/Foo.vue
|
// - @/components/Foo.vue
|
||||||
// - /Users/macos/project/src/Foo.vue
|
// - /Users/macos/project/src/Foo.vue
|
||||||
// - C:/Windows/project/src/Foo.vue (normalized slash)
|
// - C:/Windows/project/src/Foo.vue (normalized slash)
|
||||||
return async function (s: string) {
|
return async function (s: string) {
|
||||||
const url = await resolveIdToUrl(loader, s);
|
const url = await resolveIdToUrl(loader, s, root);
|
||||||
// Vite does not resolve .jsx -> .tsx when coming from hydration script import,
|
// Vite does not resolve .jsx -> .tsx when coming from hydration script import,
|
||||||
// clip it so Vite is able to resolve implicitly.
|
// clip it so Vite is able to resolve implicitly.
|
||||||
if (url.startsWith('/@fs') && url.endsWith('.jsx')) {
|
if (url.startsWith('/') && url.endsWith('.jsx')) {
|
||||||
return url.slice(0, -4);
|
return url.slice(0, -4);
|
||||||
} else {
|
} else {
|
||||||
return url;
|
return url;
|
||||||
|
|
|
@ -161,7 +161,7 @@ export function emoji(char: string, fallback: string) {
|
||||||
*/
|
*/
|
||||||
// NOTE: `/@id/` should only be used when the id is fully resolved
|
// NOTE: `/@id/` should only be used when the id is fully resolved
|
||||||
// TODO: Export a helper util from Vite
|
// TODO: Export a helper util from Vite
|
||||||
export async function resolveIdToUrl(loader: ModuleLoader, id: string) {
|
export async function resolveIdToUrl(loader: ModuleLoader, id: string, root?: URL) {
|
||||||
let resultId = await loader.resolveId(id, undefined);
|
let resultId = await loader.resolveId(id, undefined);
|
||||||
// Try resolve jsx to tsx
|
// Try resolve jsx to tsx
|
||||||
if (!resultId && id.endsWith('.jsx')) {
|
if (!resultId && id.endsWith('.jsx')) {
|
||||||
|
@ -171,7 +171,13 @@ export async function resolveIdToUrl(loader: ModuleLoader, id: string) {
|
||||||
return VALID_ID_PREFIX + id;
|
return VALID_ID_PREFIX + id;
|
||||||
}
|
}
|
||||||
if (path.isAbsolute(resultId)) {
|
if (path.isAbsolute(resultId)) {
|
||||||
return '/@fs' + prependForwardSlash(resultId);
|
const normalizedRoot = root && normalizePath(fileURLToPath(root));
|
||||||
|
// Convert to root-relative path if path is inside root
|
||||||
|
if (normalizedRoot && resultId.startsWith(normalizedRoot)) {
|
||||||
|
return resultId.slice(normalizedRoot.length - 1);
|
||||||
|
} else {
|
||||||
|
return '/@fs' + prependForwardSlash(resultId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return VALID_ID_PREFIX + resultId;
|
return VALID_ID_PREFIX + resultId;
|
||||||
}
|
}
|
||||||
|
|
11
pnpm-lock.yaml
generated
11
pnpm-lock.yaml
generated
|
@ -1014,6 +1014,17 @@ importers:
|
||||||
react: 18.2.0
|
react: 18.2.0
|
||||||
react-dom: 18.2.0_react@18.2.0
|
react-dom: 18.2.0_react@18.2.0
|
||||||
|
|
||||||
|
packages/astro/e2e/fixtures/solid-circular:
|
||||||
|
specifiers:
|
||||||
|
'@astrojs/solid-js': workspace:*
|
||||||
|
astro: workspace:*
|
||||||
|
solid-js: ^1.4.3
|
||||||
|
dependencies:
|
||||||
|
'@astrojs/solid-js': link:../../../../integrations/solid
|
||||||
|
astro: link:../../..
|
||||||
|
devDependencies:
|
||||||
|
solid-js: 1.6.10
|
||||||
|
|
||||||
packages/astro/e2e/fixtures/solid-component:
|
packages/astro/e2e/fixtures/solid-component:
|
||||||
specifiers:
|
specifiers:
|
||||||
'@astrojs/mdx': workspace:*
|
'@astrojs/mdx': workspace:*
|
||||||
|
|
Loading…
Add table
Reference in a new issue