1
1
use anyhow:: Result ;
2
- use once_cell:: sync:: Lazy ;
3
- use regex:: Regex ;
4
2
use turbo_tasks:: Vc ;
5
3
use turbopack_binding:: {
6
4
turbo:: tasks_fs:: { glob:: Glob , FileJsonContent , FileSystemPath } ,
@@ -33,15 +31,25 @@ pub enum ExternalPredicate {
33
31
/// possible to resolve them at runtime.
34
32
#[ turbo_tasks:: value]
35
33
pub ( crate ) struct ExternalCjsModulesResolvePlugin {
34
+ project_path : Vc < FileSystemPath > ,
36
35
root : Vc < FileSystemPath > ,
37
36
predicate : Vc < ExternalPredicate > ,
38
37
}
39
38
40
39
#[ turbo_tasks:: value_impl]
41
40
impl ExternalCjsModulesResolvePlugin {
42
41
#[ turbo_tasks:: function]
43
- pub fn new ( root : Vc < FileSystemPath > , predicate : Vc < ExternalPredicate > ) -> Vc < Self > {
44
- ExternalCjsModulesResolvePlugin { root, predicate } . cell ( )
42
+ pub fn new (
43
+ project_path : Vc < FileSystemPath > ,
44
+ root : Vc < FileSystemPath > ,
45
+ predicate : Vc < ExternalPredicate > ,
46
+ ) -> Vc < Self > {
47
+ ExternalCjsModulesResolvePlugin {
48
+ project_path,
49
+ root,
50
+ predicate,
51
+ }
52
+ . cell ( )
45
53
}
46
54
}
47
55
@@ -66,11 +74,9 @@ async fn is_node_resolveable(
66
74
Ok ( Vc :: cell ( true ) )
67
75
}
68
76
69
- static PNPM : Lazy < Regex > = Lazy :: new ( || Regex :: new ( r"(?:/|^)node_modules/(.pnpm/.+)" ) . unwrap ( ) ) ;
70
-
71
77
#[ turbo_tasks:: function]
72
78
fn condition ( root : Vc < FileSystemPath > ) -> Vc < ResolvePluginCondition > {
73
- ResolvePluginCondition :: new ( root. root ( ) , Glob :: new ( "**/node_modules/**" . to_string ( ) ) )
79
+ ResolvePluginCondition :: new ( root, Glob :: new ( "**/node_modules/**" . to_string ( ) ) )
74
80
}
75
81
76
82
#[ turbo_tasks:: value_impl]
@@ -101,14 +107,20 @@ impl ResolvePlugin for ExternalCjsModulesResolvePlugin {
101
107
ExternalPredicate :: AllExcept ( exceptions) => {
102
108
let exception_glob = packages_glob ( * exceptions) . await ?;
103
109
104
- if exception_glob. execute ( & raw_fs_path. path ) {
105
- return Ok ( ResolveResultOption :: none ( ) ) ;
110
+ if let Some ( exception_glob) = * exception_glob {
111
+ if exception_glob. await ?. execute ( & raw_fs_path. path ) {
112
+ return Ok ( ResolveResultOption :: none ( ) ) ;
113
+ }
106
114
}
107
115
}
108
116
ExternalPredicate :: Only ( externals) => {
109
117
let external_glob = packages_glob ( * externals) . await ?;
110
118
111
- if !external_glob. execute ( & raw_fs_path. path ) {
119
+ if let Some ( external_glob) = * external_glob {
120
+ if !external_glob. await ?. execute ( & raw_fs_path. path ) {
121
+ return Ok ( ResolveResultOption :: none ( ) ) ;
122
+ }
123
+ } else {
112
124
return Ok ( ResolveResultOption :: none ( ) ) ;
113
125
}
114
126
}
@@ -141,42 +153,30 @@ impl ResolvePlugin for ExternalCjsModulesResolvePlugin {
141
153
142
154
// check if we can resolve the package from the project dir with node.js resolve
143
155
// options (might be hidden by pnpm)
144
- if * is_node_resolveable ( self . root . root ( ) , request, fs_path) . await ? {
156
+ if * is_node_resolveable ( self . project_path , request, fs_path) . await ? {
145
157
// mark as external
146
158
return Ok ( ResolveResultOption :: some (
147
159
ResolveResult :: primary ( ResolveResultItem :: OriginalReferenceExternal ) . cell ( ) ,
148
160
) ) ;
149
161
}
150
162
151
- // Special behavior for pnpm as we could reference all .pnpm modules by
152
- // referencing the `.pnpm` folder as module, e. g.
153
- // /node_modules/.pnpm/[email protected] /node_modules/some-package/dir/file.js
154
- // becomes
155
- // .pnpm/[email protected] /node_modules/some-package/dir/file.js
156
- if let Some ( captures) = PNPM . captures ( & fs_path. await ?. path ) {
157
- if let Some ( import_path) = captures. get ( 1 ) {
158
- // we could load it directly as external, but we want to make sure node.js would
159
- // resolve it the same way e. g. that we didn't follow any special resolve
160
- // options, to come here like the `module` field in package.json
161
- if * is_node_resolveable ( context, request, fs_path) . await ? {
162
- // mark as external
163
- return Ok ( ResolveResultOption :: some (
164
- ResolveResult :: primary ( ResolveResultItem :: OriginalReferenceTypeExternal (
165
- import_path. as_str ( ) . to_string ( ) ,
166
- ) )
167
- . cell ( ) ,
168
- ) ) ;
169
- }
170
- }
171
- }
172
163
Ok ( ResolveResultOption :: none ( ) )
173
164
}
174
165
}
175
166
167
+ // TODO move that to turbo
168
+ #[ turbo_tasks:: value( transparent) ]
169
+ pub struct OptionGlob ( Option < Vc < Glob > > ) ;
170
+
176
171
#[ turbo_tasks:: function]
177
- async fn packages_glob ( packages : Vc < Vec < String > > ) -> Result < Vc < Glob > > {
178
- Ok ( Glob :: new ( format ! (
179
- "**/node_modules/{{{}}}/**" ,
180
- packages. await ?. join( "," )
172
+ async fn packages_glob ( packages : Vc < Vec < String > > ) -> Result < Vc < OptionGlob > > {
173
+ let packages = packages. await ?;
174
+ if packages. is_empty ( ) {
175
+ return Ok ( Vc :: cell ( None ) ) ;
176
+ }
177
+ Ok ( Vc :: cell ( Some (
178
+ Glob :: new ( format ! ( "**/node_modules/{{{}}}/**" , packages. join( "," ) ) )
179
+ . resolve ( )
180
+ . await ?,
181
181
) ) )
182
182
}
0 commit comments