diff --git a/bun.lockb b/bun.lockb index 06e3e32..043534e 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/mocks/app-alias-tsconfig-paths/SomeComponent.tsx b/mocks/app-alias-tsconfig-paths/SomeComponent.tsx new file mode 100644 index 0000000..7a59658 --- /dev/null +++ b/mocks/app-alias-tsconfig-paths/SomeComponent.tsx @@ -0,0 +1,5 @@ +import Counter from './islands/Counter' + +export default function SomeComponent() { + return +} diff --git a/mocks/app-alias-tsconfig-paths/islands/Counter.tsx b/mocks/app-alias-tsconfig-paths/islands/Counter.tsx new file mode 100644 index 0000000..9185146 --- /dev/null +++ b/mocks/app-alias-tsconfig-paths/islands/Counter.tsx @@ -0,0 +1,3 @@ +export default function Counter() { + return
Counter
+} diff --git a/mocks/app-alias-tsconfig-paths/routes/_renderer.tsx b/mocks/app-alias-tsconfig-paths/routes/_renderer.tsx new file mode 100644 index 0000000..32f0296 --- /dev/null +++ b/mocks/app-alias-tsconfig-paths/routes/_renderer.tsx @@ -0,0 +1,20 @@ +import { jsxRenderer } from 'hono/jsx-renderer' +import { HasIslands } from '../../../src/server' + +export default jsxRenderer( + ({ children }) => { + return ( + + + {children} + + + + + + ) + }, + { + docType: false, + } +) diff --git a/mocks/app-alias-tsconfig-paths/routes/has-islands.tsx b/mocks/app-alias-tsconfig-paths/routes/has-islands.tsx new file mode 100644 index 0000000..dd1d00c --- /dev/null +++ b/mocks/app-alias-tsconfig-paths/routes/has-islands.tsx @@ -0,0 +1,5 @@ +import Counter from '@mocks/SomeComponent' + +export default function HasIslands() { + return +} diff --git a/mocks/app-alias-tsconfig-paths/routes/has-no-islands.tsx b/mocks/app-alias-tsconfig-paths/routes/has-no-islands.tsx new file mode 100644 index 0000000..8b34c7d --- /dev/null +++ b/mocks/app-alias-tsconfig-paths/routes/has-no-islands.tsx @@ -0,0 +1,3 @@ +export default function HasNoIslands() { + return

No Islands

+} diff --git a/mocks/tsconfig.json b/mocks/tsconfig.json new file mode 100644 index 0000000..aabf0e3 --- /dev/null +++ b/mocks/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "../tsconfig.json", +} \ No newline at end of file diff --git a/package.json b/package.json index bf6fbad..08fcdbb 100644 --- a/package.json +++ b/package.json @@ -136,6 +136,7 @@ "tsup": "^8.1.0", "typescript": "^5.3.3", "vite": "^5.2.8", + "vite-tsconfig-paths": "^5.0.1", "vitest": "^1.4.0" }, "engines": { diff --git a/src/vite/inject-importing-islands.ts b/src/vite/inject-importing-islands.ts index 916e944..476fb70 100644 --- a/src/vite/inject-importing-islands.ts +++ b/src/vite/inject-importing-islands.ts @@ -2,7 +2,7 @@ import _generate from '@babel/generator' import { parse } from '@babel/parser' import precinct from 'precinct' import { normalizePath } from 'vite' -import type { Plugin } from 'vite' +import type { Plugin, ResolvedConfig } from 'vite' import { readFile } from 'fs/promises' import path from 'path' import { IMPORTING_ISLANDS_ID } from '../constants.js' @@ -27,6 +27,8 @@ export async function injectImportingIslands( let appPath = '' const islandDir = options?.islandDir ?? '/app/islands' let root = '' + let config: ResolvedConfig + const resolvedCache = new Map() const cache: Record = {} const walkDependencyTree: ( @@ -66,7 +68,8 @@ export async function injectImportingIslands( return { name: 'inject-importing-islands', - configResolved: async (config) => { + configResolved: async (resolveConfig) => { + config = resolveConfig appPath = path.join(config.root, options?.appDir ?? '/app') root = config.root }, @@ -75,14 +78,22 @@ export async function injectImportingIslands( return } + const resolve = async (importee: string, importer?: string) => { + if (resolvedCache.has(importee)) { + return this.resolve(importee) + } + const resolvedId = await this.resolve(importee, importer) + // Cache to prevent infinite loops in recursive calls. + resolvedCache.set(importee, true) + return resolvedId + } + const hasIslandsImport = ( await Promise.all( - (await walkDependencyTree(id, async (id: string) => await this.resolve(id))) - .flat() - .map(async (x) => { - const rootPath = '/' + path.relative(root, normalizePath(x)).replace(/\\/g, '/') - return matchIslandComponentId(rootPath, islandDir) - }) + (await walkDependencyTree(id, resolve)).flat().map(async (x) => { + const rootPath = '/' + path.relative(root, normalizePath(x)).replace(/\\/g, '/') + return matchIslandComponentId(rootPath, islandDir) + }) ) ).some((matched) => matched) diff --git a/test-integration/apps.test.ts b/test-integration/apps.test.ts index 1aaaed0..049191f 100644 --- a/test-integration/apps.test.ts +++ b/test-integration/apps.test.ts @@ -583,6 +583,38 @@ describe(' Component with path aliases', () => { }) }) +describe(' Component with path alias with vite-tsconfig-paths', () => { + const ROUES = import.meta.glob( + '../mocks/app-alias-tsconfig-paths/routes/**/[a-z[-][a-z-_[]*.(tsx|ts)', + { + eager: true, + } + ) + const RENDERER = import.meta.glob('../mocks/app-alias-tsconfig-paths/routes/**/_renderer.tsx', { + eager: true, + }) + + const app = createApp({ + root: '../mocks/app-alias-tsconfig-paths/routes', + ROUTES: ROUES as any, + RENDERER: RENDERER as any, + }) + + it('Should return a script tag with tagged HasIslands - /has-islands', async () => { + const res = await app.request('/has-islands') + expect(res.status).toBe(200) + expect(await res.text()).toBe( + '
Counter
' + ) + }) + + it('Should no return a script tag - /has-no-islands', async () => { + const res = await app.request('/has-no-islands') + expect(res.status).toBe(200) + expect(await res.text()).toBe('

No Islands

') + }) +}) + describe('Island Components with Preserved Files', () => { const ROUTES = import.meta.glob( '../mocks/app-islands-in-preserved/routes/**/[a-z[-][a-z-_[]*.(tsx|ts|mdx)', diff --git a/test-integration/vitest.config.ts b/test-integration/vitest.config.ts index eb198bf..923bef4 100644 --- a/test-integration/vitest.config.ts +++ b/test-integration/vitest.config.ts @@ -1,4 +1,5 @@ import mdx from '@mdx-js/rollup' +import tsconfigPaths from 'vite-tsconfig-paths' import { defineConfig } from 'vitest/config' import path from 'path' import { injectImportingIslands } from '../src/vite/inject-importing-islands' @@ -28,5 +29,6 @@ export default defineConfig({ mdx({ jsxImportSource: 'hono/jsx', }), + tsconfigPaths(), ], }) diff --git a/tsconfig.json b/tsconfig.json index dc6122e..5dc8496 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -13,13 +13,19 @@ "vitest/globals" ], "jsx": "react-jsx", - "jsxImportSource": "hono/jsx" + "jsxImportSource": "hono/jsx", + "baseUrl": ".", + "paths": { + "@mocks/*": [ + "./mocks/app-alias-tsconfig-paths/*" + ] + } }, "include": [ "src", "test-integration", "test-e2e", - "mocks", + "mocks" ], "exclude": [ "mocks/app-alias" diff --git a/yarn.lock b/yarn.lock index 06e77c1..a3ee083 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1,6 +1,6 @@ # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. # yarn lockfile v1 -# bun ./bun.lockb --hash: 01AE2360C20256F8-361f85d0cfaa2723-33B136C6C40B62C1-a2a2739cf72fa158 +# bun ./bun.lockb --hash: 543A293A66C80C95-f7ab18b32b9678e2-D7579C357F066BE3-94c80f775e73166d "@babel/code-frame@^7.0.0", "@babel/code-frame@^7.24.7": @@ -1567,7 +1567,7 @@ debug@^3.2.7: dependencies: ms "^2.1.1" -debug@^4.0.0, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@^4.3.5: +debug@^4.0.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@^4.3.5: version "4.3.7" resolved "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz" integrity sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ== @@ -2461,6 +2461,11 @@ globby@^11.0.1, globby@^11.1.0: fast-glob "^3.2.9" array-union "^2.1.0" +globrex@^0.1.2: + version "0.1.2" + resolved "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz" + integrity sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg== + gonzales-pe@^4.3.0: version "4.3.0" resolved "https://registry.npmjs.org/gonzales-pe/-/gonzales-pe-4.3.0.tgz" @@ -5183,6 +5188,11 @@ ts-interface-checker@^0.1.9: resolved "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz" integrity sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA== +tsconfck@^3.0.3: + version "3.1.3" + resolved "https://registry.npmjs.org/tsconfck/-/tsconfck-3.1.3.tgz" + integrity sha512-ulNZP1SVpRDesxeMLON/LtWM8HIgAJEIVpVVhBM6gsmvQ8+Rh+ZG7FWGvHh7Ah3pRABwVJWklWCr/BTZSv0xnQ== + tslib@^1.9.0: version "1.14.1" resolved "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz" @@ -5441,6 +5451,15 @@ vite-node@1.6.0: pathe "^1.1.1" picocolors "^1.0.0" +vite-tsconfig-paths@^5.0.1: + version "5.0.1" + resolved "https://registry.npmjs.org/vite-tsconfig-paths/-/vite-tsconfig-paths-5.0.1.tgz" + integrity sha512-yqwv+LstU7NwPeNqajZzLEBVpUFU6Dugtb2P84FXuvaoYA+/70l9MHE+GYfYAycVyPSDYZ7mjOFuYBRqlEpTig== + dependencies: + debug "^4.1.1" + globrex "^0.1.2" + tsconfck "^3.0.3" + vitest@^1.4.0: version "1.6.0" resolved "https://registry.npmjs.org/vitest/-/vitest-1.6.0.tgz"