summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.changeset/warm-panthers-clap.md5
-rw-r--r--packages/astro/e2e/fixtures/ts-resolution/astro.config.mjs7
-rw-r--r--packages/astro/e2e/fixtures/ts-resolution/package.json11
-rw-r--r--packages/astro/e2e/fixtures/ts-resolution/src/components/Counter.tsx18
-rw-r--r--packages/astro/e2e/fixtures/ts-resolution/src/pages/index.astro18
-rw-r--r--packages/astro/e2e/ts-resolution.test.js64
-rw-r--r--packages/astro/src/core/build/vite-plugin-analyzer.ts6
-rw-r--r--packages/astro/src/core/render/dev/index.ts3
-rw-r--r--packages/astro/src/core/render/dev/resolve.ts10
-rw-r--r--packages/astro/src/runtime/server/metadata.ts10
-rw-r--r--pnpm-lock.yaml21
11 files changed, 169 insertions, 4 deletions
diff --git a/.changeset/warm-panthers-clap.md b/.changeset/warm-panthers-clap.md
new file mode 100644
index 000000000..d773b1f5d
--- /dev/null
+++ b/.changeset/warm-panthers-clap.md
@@ -0,0 +1,5 @@
+---
+'astro': patch
+---
+
+Resolve .jsx -> .tsx in hydrated components
diff --git a/packages/astro/e2e/fixtures/ts-resolution/astro.config.mjs b/packages/astro/e2e/fixtures/ts-resolution/astro.config.mjs
new file mode 100644
index 000000000..8a6f1951c
--- /dev/null
+++ b/packages/astro/e2e/fixtures/ts-resolution/astro.config.mjs
@@ -0,0 +1,7 @@
+import { defineConfig } from 'astro/config';
+import react from '@astrojs/react';
+
+// https://astro.build/config
+export default defineConfig({
+ integrations: [react()],
+});
diff --git a/packages/astro/e2e/fixtures/ts-resolution/package.json b/packages/astro/e2e/fixtures/ts-resolution/package.json
new file mode 100644
index 000000000..7544800f9
--- /dev/null
+++ b/packages/astro/e2e/fixtures/ts-resolution/package.json
@@ -0,0 +1,11 @@
+{
+ "name": "@e2e/ts-resolution",
+ "version": "0.0.0",
+ "private": true,
+ "dependencies": {
+ "@astrojs/react": "workspace:*",
+ "astro": "workspace:*",
+ "react": "^18.1.0",
+ "react-dom": "^18.1.0"
+ }
+}
diff --git a/packages/astro/e2e/fixtures/ts-resolution/src/components/Counter.tsx b/packages/astro/e2e/fixtures/ts-resolution/src/components/Counter.tsx
new file mode 100644
index 000000000..9d91921f4
--- /dev/null
+++ b/packages/astro/e2e/fixtures/ts-resolution/src/components/Counter.tsx
@@ -0,0 +1,18 @@
+import React, { useState } from 'react';
+
+export default function Counter({ children, count: initialCount, id }) {
+ const [count, setCount] = useState(initialCount);
+ 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>
+ <div className="counter-message">{children}</div>
+ </>
+ );
+}
diff --git a/packages/astro/e2e/fixtures/ts-resolution/src/pages/index.astro b/packages/astro/e2e/fixtures/ts-resolution/src/pages/index.astro
new file mode 100644
index 000000000..38133a646
--- /dev/null
+++ b/packages/astro/e2e/fixtures/ts-resolution/src/pages/index.astro
@@ -0,0 +1,18 @@
+---
+import Counter from '../components/Counter.jsx';
+
+const someProps = {
+ count: 0,
+};
+---
+
+<html>
+ <head>
+ <!-- Head Stuff -->
+ </head>
+ <body>
+ <Counter id="client-idle" {...someProps} client:idle>
+ <h1>Hello, client:idle!</h1>
+ </Counter>
+ </body>
+</html>
diff --git a/packages/astro/e2e/ts-resolution.test.js b/packages/astro/e2e/ts-resolution.test.js
new file mode 100644
index 000000000..5fb729a5e
--- /dev/null
+++ b/packages/astro/e2e/ts-resolution.test.js
@@ -0,0 +1,64 @@
+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/ts-resolution/' });
+ await use(fixture);
+ },
+});
+
+function runTest(test) {
+ test('client:idle', async ({ page, astro }) => {
+ await page.goto(astro.resolveUrl('/'));
+
+ const counter = page.locator('#client-idle');
+ await expect(counter, 'component is visible').toBeVisible();
+
+ const count = counter.locator('pre');
+ await expect(count, 'initial count is 0').toHaveText('0');
+
+ const inc = counter.locator('.increment');
+ await inc.click();
+
+ await expect(count, 'count incremented by 1').toHaveText('1');
+ });
+}
+
+test.describe('TypeScript resolution -', () => {
+ test.describe('Development', () => {
+ const t = test.extend({});
+
+ let devServer;
+
+ t.beforeEach(async ({ astro }) => {
+ devServer = await astro.startDevServer();
+ });
+
+ t.afterEach(async () => {
+ await devServer.stop();
+ });
+
+ runTest(t);
+ });
+
+ test.describe('Production', () => {
+ const t = test.extend({});
+
+ let previewServer;
+
+ t.beforeAll(async ({ astro }) => {
+ await astro.build();
+ })
+
+ t.beforeEach(async ({ astro }) => {
+ previewServer = await astro.preview();
+ });
+
+ t.afterEach(async () => {
+ await previewServer.stop();
+ });
+
+ runTest(t);
+ })
+});
diff --git a/packages/astro/src/core/build/vite-plugin-analyzer.ts b/packages/astro/src/core/build/vite-plugin-analyzer.ts
index 5759cf6bd..04b439b69 100644
--- a/packages/astro/src/core/build/vite-plugin-analyzer.ts
+++ b/packages/astro/src/core/build/vite-plugin-analyzer.ts
@@ -5,6 +5,7 @@ import type { BuildInternals } from '../../core/build/internal.js';
import type { PluginMetadata as AstroPluginMetadata } from '../../vite-plugin-astro/types';
import { prependForwardSlash } from '../../core/path.js';
+import { resolveClientDevPath } from '../../core/render/dev/resolve.js';
import { getTopLevelPages } from './graph.js';
import { getPageDataByViteID, trackClientOnlyPageDatas } from './internal.js';
@@ -84,7 +85,8 @@ export function vitePluginAnalyzer(
const astro = info.meta.astro as AstroPluginMetadata['astro'];
for (const c of astro.hydratedComponents) {
- internals.discoveredHydratedComponents.add(c.resolvedPath || c.specifier);
+ const rid = c.resolvedPath ? resolveClientDevPath(c.resolvedPath) : c.specifier;
+ internals.discoveredHydratedComponents.add(rid);
}
// Scan hoisted scripts
@@ -94,7 +96,7 @@ export function vitePluginAnalyzer(
const clientOnlys: string[] = [];
for (const c of astro.clientOnlyComponents) {
- const cid = c.resolvedPath || c.specifier;
+ const cid = c.resolvedPath ? resolveClientDevPath(c.resolvedPath) : c.specifier;
internals.discoveredClientOnlyComponents.add(cid);
clientOnlys.push(cid);
}
diff --git a/packages/astro/src/core/render/dev/index.ts b/packages/astro/src/core/render/dev/index.ts
index 4921fb9d6..86e4840f8 100644
--- a/packages/astro/src/core/render/dev/index.ts
+++ b/packages/astro/src/core/render/dev/index.ts
@@ -18,6 +18,7 @@ import { createModuleScriptElementWithSrcSet } from '../ssr-element.js';
import { collectMdMetadata } from '../util.js';
import { getStylesForURL } from './css.js';
import { injectTags } from './html.js';
+import { resolveClientDevPath } from './resolve.js';
export interface SSROptions {
/** an instance of the AstroConfig */
@@ -178,7 +179,7 @@ export async function render(
// Resolves specifiers in the inline hydrated scripts, such as "@astrojs/preact/client.js"
async resolve(s: string) {
if (s.startsWith('/@fs')) {
- return s;
+ return resolveClientDevPath(s);
}
return '/@id' + prependForwardSlash(s);
},
diff --git a/packages/astro/src/core/render/dev/resolve.ts b/packages/astro/src/core/render/dev/resolve.ts
new file mode 100644
index 000000000..a36ea2a4b
--- /dev/null
+++ b/packages/astro/src/core/render/dev/resolve.ts
@@ -0,0 +1,10 @@
+
+export function resolveClientDevPath(id: string) {
+ if(id.startsWith('/@fs')) {
+ // Vite does not resolve .jsx -> .tsx when coming from the client, so clip the extension.
+ if(id.endsWith('.jsx')) {
+ return id.slice(0, id.length - 4);
+ }
+ }
+ return id;
+}
diff --git a/packages/astro/src/runtime/server/metadata.ts b/packages/astro/src/runtime/server/metadata.ts
index c2bf0407f..0cae29b63 100644
--- a/packages/astro/src/runtime/server/metadata.ts
+++ b/packages/astro/src/runtime/server/metadata.ts
@@ -37,7 +37,15 @@ export class Metadata {
}
resolvePath(specifier: string): string {
- return specifier.startsWith('.') ? new URL(specifier, this.mockURL).pathname : specifier;
+ if(specifier.startsWith('.')) {
+ const resolved = new URL(specifier, this.mockURL).pathname;
+ // Vite does not resolve .jsx -> .tsx when coming from the client, so clip the extension.
+ if(resolved.startsWith('/@fs') && resolved.endsWith('.jsx')) {
+ return resolved.slice(0, resolved.length - 4);
+ }
+ return resolved;
+ }
+ return specifier;
}
getPath(Component: any): string | null {
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 19663cb90..3bb507726 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -956,6 +956,18 @@ importers:
'@astrojs/tailwind': link:../../../../integrations/tailwind
astro: link:../../..
+ packages/astro/e2e/fixtures/ts-resolution:
+ specifiers:
+ '@astrojs/react': workspace:*
+ astro: workspace:*
+ react: ^18.1.0
+ react-dom: ^18.1.0
+ dependencies:
+ '@astrojs/react': link:../../../../integrations/react
+ astro: link:../../..
+ react: 18.1.0
+ react-dom: 18.1.0_react@18.1.0
+
packages/astro/e2e/fixtures/vue-component:
specifiers:
'@astrojs/vue': workspace:*
@@ -8188,6 +8200,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
@@ -11104,6 +11121,8 @@ packages:
debug: 3.2.7
iconv-lite: 0.4.24
sax: 1.2.4
+ transitivePeerDependencies:
+ - supports-color
dev: false
/netmask/2.0.2:
@@ -11187,6 +11206,8 @@ packages:
rimraf: 2.7.1
semver: 5.7.1
tar: 4.4.19
+ transitivePeerDependencies:
+ - supports-color
dev: false
/node-releases/2.0.5: