1
1
import { stripIndents , workspaceRoot } from '@nx/devkit' ;
2
2
import { existsSync } from 'node:fs' ;
3
3
import { relative , join , resolve } from 'node:path' ;
4
- import { loadConfig , createMatchPath , MatchPath } from 'tsconfig-paths' ;
4
+ import {
5
+ loadConfig ,
6
+ createMatchPath ,
7
+ MatchPath ,
8
+ ConfigLoaderSuccessResult ,
9
+ } from 'tsconfig-paths' ;
5
10
6
- export function nxViteTsPaths ( ) {
11
+ export interface nxViteTsPathsOptions {
12
+ /**
13
+ * Enable debug logging
14
+ * @default false
15
+ **/
16
+ debug ?: boolean ;
17
+ /**
18
+ * export fields in package.json to use for resolving
19
+ * @default [['exports', '.', 'import'], 'module', 'main']
20
+ *
21
+ * fallback resolution will use ['main', 'module']
22
+ **/
23
+ mainFields ?: ( string | string [ ] ) [ ] ;
24
+ /**
25
+ * extensions to check when resolving files when package.json resolution fails
26
+ * @default ['.ts', '.tsx', '.js', '.jsx', '.json', '.mjs', '.cjs']
27
+ **/
28
+ extensions ?: string [ ] ;
29
+ }
30
+
31
+ export function nxViteTsPaths ( options : nxViteTsPathsOptions = { } ) {
7
32
let matchTsPathEsm : MatchPath ;
8
33
let matchTsPathFallback : MatchPath | undefined ;
34
+ let tsConfigPathsEsm : ConfigLoaderSuccessResult ;
35
+ let tsConfigPathsFallback : ConfigLoaderSuccessResult ;
36
+
37
+ options . extensions ??= [
38
+ '.ts' ,
39
+ '.tsx' ,
40
+ '.js' ,
41
+ '.jsx' ,
42
+ '.json' ,
43
+ '.mjs' ,
44
+ '.cjs' ,
45
+ ] ;
46
+ options . mainFields ??= [ [ 'exports' , '.' , 'import' ] , 'module' , 'main' ] ;
9
47
10
48
return {
11
49
name : 'nx-vite-ts-paths' ,
@@ -31,59 +69,104 @@ There should at least be a tsconfig.base.json or tsconfig.json in the root of th
31
69
if ( parsed . resultType === 'failed' ) {
32
70
throw new Error ( `Failed loading tsonfig at ${ foundTsConfigPath } ` ) ;
33
71
}
72
+ tsConfigPathsEsm = parsed ;
34
73
35
- matchTsPathEsm = createMatchPath ( parsed . absoluteBaseUrl , parsed . paths , [
36
- [ 'exports' , '.' , 'import' ] ,
37
- 'module' ,
38
- 'main' ,
39
- ] ) ;
74
+ matchTsPathEsm = createMatchPath (
75
+ parsed . absoluteBaseUrl ,
76
+ parsed . paths ,
77
+ options . mainFields
78
+ ) ;
40
79
41
80
const rootLevelTsConfig = getTsConfig (
42
81
join ( workspaceRoot , 'tsconfig.base.json' )
43
82
) ;
44
83
const rootLevelParsed = loadConfig ( rootLevelTsConfig ) ;
45
84
logIt ( 'fallback parsed tsconfig: ' , rootLevelParsed ) ;
46
85
if ( rootLevelParsed . resultType === 'success' ) {
86
+ tsConfigPathsFallback = rootLevelParsed ;
47
87
matchTsPathFallback = createMatchPath (
48
88
rootLevelParsed . absoluteBaseUrl ,
49
89
rootLevelParsed . paths ,
50
90
[ 'main' , 'module' ]
51
91
) ;
52
92
}
53
93
} ,
54
- resolveId ( source : string ) {
94
+ resolveId ( importPath : string ) {
55
95
let resolvedFile : string ;
56
96
try {
57
- resolvedFile = matchTsPathEsm ( source ) ;
97
+ resolvedFile = matchTsPathEsm ( importPath ) ;
58
98
} catch ( e ) {
59
99
logIt ( 'Using fallback path matching.' ) ;
60
- resolvedFile = matchTsPathFallback ?.( source ) ;
100
+ resolvedFile = matchTsPathFallback ?.( importPath ) ;
61
101
}
62
102
63
103
if ( ! resolvedFile ) {
64
- logIt ( `Unable to resolve ${ source } with tsconfig paths` ) ;
104
+ if ( tsConfigPathsEsm || tsConfigPathsFallback ) {
105
+ logIt (
106
+ `Unable to resolve ${ importPath } with tsconfig paths. Using fallback file matching.`
107
+ ) ;
108
+ resolvedFile =
109
+ loadFileFromPaths ( tsConfigPathsEsm , importPath ) ||
110
+ loadFileFromPaths ( tsConfigPathsFallback , importPath ) ;
111
+ } else {
112
+ logIt ( `Unable to resolve ${ importPath } with tsconfig paths` ) ;
113
+ }
65
114
}
66
115
67
- return resolvedFile ;
116
+ logIt ( `Resolved ${ importPath } to ${ resolvedFile } ` ) ;
117
+ // Returning null defers to other resolveId functions and eventually the default resolution behavior
118
+ // https://rollupjs.org/plugin-development/#resolveid
119
+ return resolvedFile || null ;
68
120
} ,
69
121
} ;
70
- }
71
122
72
- function getTsConfig ( preferredTsConfigPath : string ) : string {
73
- return [
74
- resolve ( preferredTsConfigPath ) ,
75
- resolve ( join ( workspaceRoot , 'tsconfig.base.json' ) ) ,
76
- resolve ( join ( workspaceRoot , 'tsconfig.json' ) ) ,
77
- ] . find ( ( tsPath ) => {
78
- if ( existsSync ( tsPath ) ) {
79
- logIt ( 'Found tsconfig at' , tsPath ) ;
80
- return tsPath ;
123
+ function getTsConfig ( preferredTsConfigPath : string ) : string {
124
+ return [
125
+ resolve ( preferredTsConfigPath ) ,
126
+ resolve ( join ( workspaceRoot , 'tsconfig.base.json' ) ) ,
127
+ resolve ( join ( workspaceRoot , 'tsconfig.json' ) ) ,
128
+ ] . find ( ( tsPath ) => {
129
+ if ( existsSync ( tsPath ) ) {
130
+ logIt ( 'Found tsconfig at' , tsPath ) ;
131
+ return tsPath ;
132
+ }
133
+ } ) ;
134
+ }
135
+
136
+ function logIt ( ...msg : any [ ] ) {
137
+ if ( process . env . NX_VERBOSE_LOGGING === 'true' || options ?. debug ) {
138
+ console . debug ( '\n[Nx Vite TsPaths]' , ...msg ) ;
81
139
}
82
- } ) ;
83
- }
140
+ }
84
141
85
- function logIt ( ...msg : any [ ] ) {
86
- if ( process . env . NX_VERBOSE_LOGGING === 'true' ) {
87
- console . debug ( '[Nx Vite TsPaths]' , ...msg ) ;
142
+ function loadFileFromPaths (
143
+ tsconfig : ConfigLoaderSuccessResult ,
144
+ importPath : string
145
+ ) {
146
+ logIt (
147
+ `Trying to resolve file from config in ${ tsconfig . configFileAbsolutePath } `
148
+ ) ;
149
+ let resolvedFile : string ;
150
+ for ( const alias in tsconfig . paths ) {
151
+ const paths = tsconfig . paths [ alias ] ;
152
+
153
+ const normalizedImport = alias . replace ( / \/ \* $ / , '' ) ;
154
+
155
+ if ( importPath . startsWith ( normalizedImport ) ) {
156
+ const path = ( tsconfig . absoluteBaseUrl , paths [ 0 ] . replace ( / \/ \* $ / , '' ) ) ;
157
+ resolvedFile = findFile ( importPath . replace ( normalizedImport , path ) ) ;
158
+ }
159
+ }
160
+
161
+ return resolvedFile ;
162
+ }
163
+
164
+ function findFile ( path : string ) : string {
165
+ for ( const ext of options . extensions ) {
166
+ const r = resolve ( path + ext ) ;
167
+ if ( existsSync ( r ) ) {
168
+ return r ;
169
+ }
170
+ }
88
171
}
89
172
}
0 commit comments