From 1c678f7ebff6b8ea843bf4b49ab73ca942a2a755 Mon Sep 17 00:00:00 2001 From: Bjorn Lu Date: Wed, 15 Feb 2023 09:49:57 +0100 Subject: [PATCH] Fix hydration path for circular imports (#6244) --- .changeset/selfish-frogs-tell.md | 5 ++++ .../fixtures/solid-circular/astro.config.mjs | 7 ++++++ .../e2e/fixtures/solid-circular/package.json | 12 ++++++++++ .../src/components/ContextProvider.tsx | 12 ++++++++++ .../src/components/SimpleDiv.tsx | 8 +++++++ .../e2e/fixtures/solid-circular/src/env.d.ts | 1 + .../solid-circular/src/pages/index.astro | 15 ++++++++++++ packages/astro/e2e/solid-circular.test.js | 23 +++++++++++++++++++ .../astro/src/core/render/dev/environment.ts | 2 +- packages/astro/src/core/render/dev/resolve.ts | 6 ++--- packages/astro/src/core/util.ts | 10 ++++++-- pnpm-lock.yaml | 11 +++++++++ 12 files changed, 106 insertions(+), 6 deletions(-) create mode 100644 .changeset/selfish-frogs-tell.md create mode 100644 packages/astro/e2e/fixtures/solid-circular/astro.config.mjs create mode 100644 packages/astro/e2e/fixtures/solid-circular/package.json create mode 100644 packages/astro/e2e/fixtures/solid-circular/src/components/ContextProvider.tsx create mode 100644 packages/astro/e2e/fixtures/solid-circular/src/components/SimpleDiv.tsx create mode 100644 packages/astro/e2e/fixtures/solid-circular/src/env.d.ts create mode 100644 packages/astro/e2e/fixtures/solid-circular/src/pages/index.astro create mode 100644 packages/astro/e2e/solid-circular.test.js diff --git a/.changeset/selfish-frogs-tell.md b/.changeset/selfish-frogs-tell.md new file mode 100644 index 000000000..0ed5b0b16 --- /dev/null +++ b/.changeset/selfish-frogs-tell.md @@ -0,0 +1,5 @@ +--- +'astro': patch +--- + +Fix hydrate loading path to prevent multiple instance loaded for circular imports diff --git a/packages/astro/e2e/fixtures/solid-circular/astro.config.mjs b/packages/astro/e2e/fixtures/solid-circular/astro.config.mjs new file mode 100644 index 000000000..a6c39b853 --- /dev/null +++ b/packages/astro/e2e/fixtures/solid-circular/astro.config.mjs @@ -0,0 +1,7 @@ +import { defineConfig } from 'astro/config'; +import solid from '@astrojs/solid-js'; + +// https://astro.build/config +export default defineConfig({ + integrations: [solid()], +}); diff --git a/packages/astro/e2e/fixtures/solid-circular/package.json b/packages/astro/e2e/fixtures/solid-circular/package.json new file mode 100644 index 000000000..a354ec9ec --- /dev/null +++ b/packages/astro/e2e/fixtures/solid-circular/package.json @@ -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" + } +} diff --git a/packages/astro/e2e/fixtures/solid-circular/src/components/ContextProvider.tsx b/packages/astro/e2e/fixtures/solid-circular/src/components/ContextProvider.tsx new file mode 100644 index 000000000..191a4cf8c --- /dev/null +++ b/packages/astro/e2e/fixtures/solid-circular/src/components/ContextProvider.tsx @@ -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 ( + + + + ); +}; diff --git a/packages/astro/e2e/fixtures/solid-circular/src/components/SimpleDiv.tsx b/packages/astro/e2e/fixtures/solid-circular/src/components/SimpleDiv.tsx new file mode 100644 index 000000000..0607149c4 --- /dev/null +++ b/packages/astro/e2e/fixtures/solid-circular/src/components/SimpleDiv.tsx @@ -0,0 +1,8 @@ +import { Component, useContext } from 'solid-js'; +import { ApplicationContext } from './ContextProvider'; + +export const SimpleDiv: Component = () => { + const [context] = useContext(ApplicationContext); + + return
{context.lng}
; +}; diff --git a/packages/astro/e2e/fixtures/solid-circular/src/env.d.ts b/packages/astro/e2e/fixtures/solid-circular/src/env.d.ts new file mode 100644 index 000000000..8c34fb45e --- /dev/null +++ b/packages/astro/e2e/fixtures/solid-circular/src/env.d.ts @@ -0,0 +1 @@ +/// \ No newline at end of file diff --git a/packages/astro/e2e/fixtures/solid-circular/src/pages/index.astro b/packages/astro/e2e/fixtures/solid-circular/src/pages/index.astro new file mode 100644 index 000000000..cafe1df49 --- /dev/null +++ b/packages/astro/e2e/fixtures/solid-circular/src/pages/index.astro @@ -0,0 +1,15 @@ +--- +import { ContextProvider } from "../components/ContextProvider.tsx"; +--- + + + + + + + +
+ +
+ + diff --git a/packages/astro/e2e/solid-circular.test.js b/packages/astro/e2e/solid-circular.test.js new file mode 100644 index 000000000..57e3fc5aa --- /dev/null +++ b/packages/astro/e2e/solid-circular.test.js @@ -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'); + }); +}); diff --git a/packages/astro/src/core/render/dev/environment.ts b/packages/astro/src/core/render/dev/environment.ts index 1704c6f29..7f9fe3195 100644 --- a/packages/astro/src/core/render/dev/environment.ts +++ b/packages/astro/src/core/render/dev/environment.ts @@ -29,7 +29,7 @@ export function createDevelopmentEnvironment( mode, // This will be overridden in the dev server renderers: [], - resolve: createResolve(loader), + resolve: createResolve(loader, settings.config.root), routeCache: new RouteCache(logging, mode), site: settings.config.site, ssr: settings.config.output === 'server', diff --git a/packages/astro/src/core/render/dev/resolve.ts b/packages/astro/src/core/render/dev/resolve.ts index b51e577fc..164333cdc 100644 --- a/packages/astro/src/core/render/dev/resolve.ts +++ b/packages/astro/src/core/render/dev/resolve.ts @@ -1,17 +1,17 @@ import type { ModuleLoader } from '../../module-loader/index'; 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: // - @astrojs/preact/client.js // - @/components/Foo.vue // - /Users/macos/project/src/Foo.vue // - C:/Windows/project/src/Foo.vue (normalized slash) 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, // 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); } else { return url; diff --git a/packages/astro/src/core/util.ts b/packages/astro/src/core/util.ts index f80eb5fe7..a7152e41a 100644 --- a/packages/astro/src/core/util.ts +++ b/packages/astro/src/core/util.ts @@ -161,7 +161,7 @@ export function emoji(char: string, fallback: string) { */ // NOTE: `/@id/` should only be used when the id is fully resolved // 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); // Try resolve jsx to tsx if (!resultId && id.endsWith('.jsx')) { @@ -171,7 +171,13 @@ export async function resolveIdToUrl(loader: ModuleLoader, id: string) { return VALID_ID_PREFIX + id; } 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; } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6d665afdb..95cac6a47 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1014,6 +1014,17 @@ importers: 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: specifiers: '@astrojs/mdx': workspace:*