Skip to content

Commit 243cdb1

Browse files
authored
refactor: more reliable import map generation, supporting turbopack and tsconfig basePath (#11618)
This simplifies and cleans up import map generation and adds support for turbopack, as well as the tsconfig `compilerOptions.basePath` property. Previously, relative import paths looked like this: ```ts import { TestComponent as ___ } from 'test/admin/components/TestComponent.js' ``` Paths like these will be resolved based on the `compilerOptions.baseUrl` path of your tsconfig. This had 2 problems: ### baseUrl support If your tsconfig baseUrl was not `"."`, this did not work, as the import map generator does not respect it ### Turbopack support If Turbopack was used, certain import paths were not able to be resolved. For example, if your component is outside the `baseDir`, the generated path looked like this: ```ts import { TestComponent as ___ } from '/../test/admin/components/TestComponent.js' ``` This works fine in webpack, but breaks in turbopack. ## Solution This PR ensures all import paths are relative, making them more predictable and reliable. The same component will now generate the following import path which works in Turbopack and if a different `compilerOptions.basePath` property is set: ```ts import { TestComponent as ___ } from '../../../test/admin/components/TestComponent.js' ``` It also adds unit tests
1 parent c7bb694 commit 243cdb1

File tree

9 files changed

+404
-132
lines changed

9 files changed

+404
-132
lines changed
Lines changed: 214 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,214 @@
1+
import type { PayloadComponent } from '../../index.js'
2+
import { addPayloadComponentToImportMap } from './utilities/addPayloadComponentToImportMap.js'
3+
import { getImportMapToBaseDirPath } from './utilities/getImportMapToBaseDirPath.js'
4+
5+
describe('addPayloadComponentToImportMap', () => {
6+
let importMap: Record<string, string>
7+
let imports: Record<
8+
string,
9+
{
10+
path: string
11+
specifier: string
12+
}
13+
>
14+
15+
beforeEach(() => {
16+
importMap = {}
17+
imports = {}
18+
jest.restoreAllMocks()
19+
})
20+
21+
function componentPathTest({
22+
baseDir,
23+
importMapFilePath,
24+
payloadComponent,
25+
expectedPath,
26+
expectedSpecifier,
27+
expectedImportMapToBaseDirPath,
28+
}: {
29+
baseDir: string
30+
importMapFilePath: string
31+
payloadComponent: PayloadComponent
32+
expectedPath: string
33+
expectedImportMapToBaseDirPath: string
34+
expectedSpecifier: string
35+
}) {
36+
const importMapToBaseDirPath = getImportMapToBaseDirPath({
37+
baseDir,
38+
importMapPath: importMapFilePath,
39+
})
40+
41+
expect(importMapToBaseDirPath).toBe(expectedImportMapToBaseDirPath)
42+
43+
const { path, specifier } =
44+
addPayloadComponentToImportMap({
45+
importMapToBaseDirPath,
46+
importMap,
47+
imports,
48+
payloadComponent,
49+
}) ?? {}
50+
51+
expect(path).toBe(expectedPath)
52+
expect(specifier).toBe(expectedSpecifier)
53+
}
54+
55+
it('relative path with import map partially in base dir', () => {
56+
componentPathTest({
57+
baseDir: '/myPackage/test/myTest',
58+
importMapFilePath: '/myPackage/app/(payload)/importMap.js',
59+
payloadComponent: './MyComponent.js#MyExport',
60+
expectedImportMapToBaseDirPath: '../../test/myTest/',
61+
expectedPath: '../../test/myTest/MyComponent.js',
62+
expectedSpecifier: 'MyExport',
63+
})
64+
})
65+
66+
it('relative path with import map partially in base dir 2', () => {
67+
componentPathTest({
68+
baseDir: '/myPackage/test/myTest',
69+
importMapFilePath: '/myPackage/test/prod/app/(payload)/importMap.js',
70+
payloadComponent: {
71+
path: './MyComponent.js#MyExport',
72+
},
73+
expectedImportMapToBaseDirPath: '../../../myTest/',
74+
expectedPath: '../../../myTest/MyComponent.js',
75+
expectedSpecifier: 'MyExport',
76+
})
77+
})
78+
79+
it('relative path with import map partially in base dir 3', () => {
80+
componentPathTest({
81+
baseDir: '/myPackage/test/myTest',
82+
importMapFilePath: '/myPackage/test/prod/app/(payload)/importMap.js',
83+
payloadComponent: {
84+
path: '../otherTest/MyComponent.js',
85+
exportName: 'MyExport',
86+
},
87+
expectedImportMapToBaseDirPath: '../../../myTest/',
88+
expectedPath: '../../../otherTest/MyComponent.js',
89+
expectedSpecifier: 'MyExport',
90+
})
91+
})
92+
93+
it('relative path with import map within base dir', () => {
94+
componentPathTest({
95+
baseDir: '/myPackage/test/myTest',
96+
importMapFilePath: '/myPackage/test/myTest/prod/app/(payload)/importMap.js',
97+
payloadComponent: './MyComponent.js#MyExport',
98+
expectedImportMapToBaseDirPath: '../../../',
99+
expectedPath: '../../../MyComponent.js',
100+
expectedSpecifier: 'MyExport',
101+
})
102+
})
103+
104+
it('relative path with import map not in base dir', () => {
105+
componentPathTest({
106+
baseDir: '/test/myTest',
107+
importMapFilePath: '/app/(payload)/importMap.js',
108+
payloadComponent: './MyComponent.js#MyExport',
109+
expectedImportMapToBaseDirPath: '../../test/myTest/',
110+
expectedPath: '../../test/myTest/MyComponent.js',
111+
expectedSpecifier: 'MyExport',
112+
})
113+
})
114+
115+
it('relative path with import map not in base dir 2', () => {
116+
componentPathTest({
117+
baseDir: '/test/myTest',
118+
importMapFilePath: '/app/(payload)/importMap.js',
119+
payloadComponent: '../myOtherTest/MyComponent.js#MyExport',
120+
expectedImportMapToBaseDirPath: '../../test/myTest/',
121+
expectedPath: '../../test/myOtherTest/MyComponent.js',
122+
expectedSpecifier: 'MyExport',
123+
})
124+
})
125+
126+
it('relative path with import map not in base dir, baseDir ending with slash', () => {
127+
componentPathTest({
128+
baseDir: '/test/myTest/',
129+
importMapFilePath: '/app/(payload)/importMap.js',
130+
payloadComponent: './MyComponent.js#MyExport',
131+
expectedImportMapToBaseDirPath: '../../test/myTest/',
132+
expectedPath: '../../test/myTest/MyComponent.js',
133+
expectedSpecifier: 'MyExport',
134+
})
135+
})
136+
137+
it('relative path with import map not in base dir, component starting with slash', () => {
138+
componentPathTest({
139+
baseDir: '/test/myTest',
140+
importMapFilePath: '/app/(payload)/importMap.js',
141+
payloadComponent: '/MyComponent.js#MyExport',
142+
expectedImportMapToBaseDirPath: '../../test/myTest/',
143+
expectedPath: '../../test/myTest/MyComponent.js',
144+
expectedSpecifier: 'MyExport',
145+
})
146+
})
147+
148+
it('aliased path', () => {
149+
componentPathTest({
150+
baseDir: '/test/myTest',
151+
importMapFilePath: '/app/(payload)/importMap.js',
152+
payloadComponent: '@components/MyComponent.js#MyExport',
153+
expectedImportMapToBaseDirPath: '../../test/myTest/',
154+
expectedPath: '@components/MyComponent.js',
155+
expectedSpecifier: 'MyExport',
156+
})
157+
})
158+
it('aliased path in PayloadComponent object', () => {
159+
componentPathTest({
160+
baseDir: '/test/',
161+
importMapFilePath: '/app/(payload)/importMap.js',
162+
payloadComponent: {
163+
path: '@components/MyComponent.js',
164+
},
165+
expectedImportMapToBaseDirPath: '../../test/',
166+
expectedPath: '@components/MyComponent.js',
167+
expectedSpecifier: 'default',
168+
})
169+
})
170+
171+
it('relative path import starting with slash, going up', () => {
172+
componentPathTest({
173+
baseDir: '/test/myTest',
174+
importMapFilePath: '/test/myTest/app/importMap.js',
175+
payloadComponent: '/../MyComponent.js#MyExport',
176+
expectedImportMapToBaseDirPath: '../',
177+
expectedPath: '../../MyComponent.js',
178+
expectedSpecifier: 'MyExport',
179+
})
180+
})
181+
182+
it('relative path import starting with dot-slash, going up', () => {
183+
componentPathTest({
184+
baseDir: '/test/myTest',
185+
importMapFilePath: '/test/myTest/app/importMap.js',
186+
payloadComponent: './../MyComponent.js#MyExport',
187+
expectedImportMapToBaseDirPath: '../',
188+
expectedPath: '../../MyComponent.js',
189+
expectedSpecifier: 'MyExport',
190+
})
191+
})
192+
193+
it('importMap and baseDir in same directory', () => {
194+
componentPathTest({
195+
baseDir: '/test/myTest',
196+
importMapFilePath: '/test/myTest/importMap.js',
197+
payloadComponent: './MyComponent.js#MyExport',
198+
expectedImportMapToBaseDirPath: './',
199+
expectedPath: './MyComponent.js',
200+
expectedSpecifier: 'MyExport',
201+
})
202+
})
203+
204+
it('baseDir within importMap dir', () => {
205+
componentPathTest({
206+
baseDir: '/test/myTest/components',
207+
importMapFilePath: '/test/myTest/importMap.js',
208+
payloadComponent: './MyComponent.js#MyExport',
209+
expectedImportMapToBaseDirPath: './components/',
210+
expectedPath: './components/MyComponent.js',
211+
expectedSpecifier: 'MyExport',
212+
})
213+
})
214+
})

0 commit comments

Comments
 (0)