1
1
#![ allow( clippy:: redundant_allocation) ]
2
2
3
- use std:: { borrow:: Cow , iter, iter:: once, sync:: Arc } ;
3
+ use std:: {
4
+ borrow:: Cow ,
5
+ iter:: { self , once} ,
6
+ sync:: RwLock ,
7
+ } ;
4
8
9
+ use once_cell:: sync:: Lazy ;
10
+ use rustc_hash:: FxHashMap ;
5
11
use serde:: { Deserialize , Serialize } ;
6
12
use string_enum:: StringEnum ;
7
- use swc_atoms:: { Atom , JsWord } ;
13
+ use swc_atoms:: { atom , Atom , JsWord } ;
8
14
use swc_common:: {
9
15
comments:: { Comment , CommentKind , Comments } ,
10
16
errors:: HANDLER ,
@@ -56,12 +62,12 @@ pub struct Options {
56
62
57
63
/// For automatic runtime
58
64
#[ serde( default ) ]
59
- pub import_source : Option < String > ,
65
+ pub import_source : Option < Atom > ,
60
66
61
67
#[ serde( default ) ]
62
- pub pragma : Option < String > ,
68
+ pub pragma : Option < Lrc < String > > ,
63
69
#[ serde( default ) ]
64
- pub pragma_frag : Option < String > ,
70
+ pub pragma_frag : Option < Lrc < String > > ,
65
71
66
72
#[ serde( default ) ]
67
73
pub throw_if_namespace : Option < bool > ,
@@ -93,16 +99,31 @@ pub struct Options {
93
99
pub refresh : Option < RefreshOptions > ,
94
100
}
95
101
96
- pub fn default_import_source ( ) -> String {
97
- "react" . into ( )
102
+ #[ cfg( feature = "concurrent" ) ]
103
+ macro_rules! static_str {
104
+ ( $s: expr) => { {
105
+ static VAL : Lazy <Lrc <String >> = Lazy :: new( || Lrc :: new( $s. into( ) ) ) ;
106
+ VAL . clone( )
107
+ } } ;
108
+ }
109
+
110
+ #[ cfg( not( feature = "concurrent" ) ) ]
111
+ macro_rules! static_str {
112
+ ( $s: expr) => {
113
+ Lrc :: new( $s. into( ) )
114
+ } ;
115
+ }
116
+
117
+ pub fn default_import_source ( ) -> Atom {
118
+ atom ! ( "react" )
98
119
}
99
120
100
- pub fn default_pragma ( ) -> String {
101
- "React.createElement" . into ( )
121
+ pub fn default_pragma ( ) -> Lrc < String > {
122
+ static_str ! ( "React.createElement" )
102
123
}
103
124
104
- pub fn default_pragma_frag ( ) -> String {
105
- "React.Fragment" . into ( )
125
+ pub fn default_pragma_frag ( ) -> Lrc < String > {
126
+ static_str ! ( "React.Fragment" )
106
127
}
107
128
108
129
fn default_throw_if_namespace ( ) -> bool {
@@ -113,10 +134,10 @@ fn default_throw_if_namespace() -> bool {
113
134
pub fn parse_expr_for_jsx (
114
135
cm : & SourceMap ,
115
136
name : & str ,
116
- src : String ,
137
+ src : Lrc < String > ,
117
138
top_level_mark : Mark ,
118
- ) -> Arc < Box < Expr > > {
119
- let fm = cm. new_source_file (
139
+ ) -> Lrc < Box < Expr > > {
140
+ let fm = cm. new_source_file_from (
120
141
FileName :: Internal ( format ! ( "jsx-config-{}.js" , name) ) . into ( ) ,
121
142
src,
122
143
) ;
@@ -142,7 +163,7 @@ pub fn parse_expr_for_jsx(
142
163
apply_mark ( & mut expr, top_level_mark) ;
143
164
expr
144
165
} )
145
- . map ( Arc :: new)
166
+ . map ( Lrc :: new)
146
167
. unwrap_or_else ( |( ) | {
147
168
panic ! (
148
169
"failed to parse jsx option {}: '{}' is not an expression" ,
@@ -198,10 +219,7 @@ where
198
219
top_level_mark,
199
220
unresolved_mark,
200
221
runtime : options. runtime . unwrap_or_default ( ) ,
201
- import_source : options
202
- . import_source
203
- . unwrap_or_else ( default_import_source)
204
- . into ( ) ,
222
+ import_source : options. import_source . unwrap_or_else ( default_import_source) ,
205
223
import_jsx : None ,
206
224
import_jsxs : None ,
207
225
import_fragment : None ,
@@ -239,7 +257,7 @@ where
239
257
240
258
runtime : Runtime ,
241
259
/// For automatic runtime.
242
- import_source : JsWord ,
260
+ import_source : Atom ,
243
261
/// For automatic runtime.
244
262
import_jsx : Option < Ident > ,
245
263
/// For automatic runtime.
@@ -250,9 +268,9 @@ where
250
268
import_fragment : Option < Ident > ,
251
269
top_level_node : bool ,
252
270
253
- pragma : Arc < Box < Expr > > ,
271
+ pragma : Lrc < Box < Expr > > ,
254
272
comments : Option < C > ,
255
- pragma_frag : Arc < Box < Expr > > ,
273
+ pragma_frag : Lrc < Box < Expr > > ,
256
274
development : bool ,
257
275
throw_if_namespace : bool ,
258
276
}
@@ -262,13 +280,13 @@ pub struct JsxDirectives {
262
280
pub runtime : Option < Runtime > ,
263
281
264
282
/// For automatic runtime.
265
- pub import_source : Option < JsWord > ,
283
+ pub import_source : Option < Atom > ,
266
284
267
285
/// Parsed from `@jsx`
268
- pub pragma : Option < Arc < Box < Expr > > > ,
286
+ pub pragma : Option < Lrc < Box < Expr > > > ,
269
287
270
288
/// Parsed from `@jsxFrag`
271
- pub pragma_frag : Option < Arc < Box < Expr > > > ,
289
+ pub pragma_frag : Option < Lrc < Box < Expr > > > ,
272
290
}
273
291
274
292
fn respan ( e : & mut Expr , span : Span ) {
@@ -335,7 +353,7 @@ impl JsxDirectives {
335
353
Some ( "@jsxImportSource" ) => {
336
354
if let Some ( src) = val {
337
355
res. runtime = Some ( Runtime :: Automatic ) ;
338
- res. import_source = Some ( src . into ( ) ) ;
356
+ res. import_source = Some ( Atom :: new ( src ) ) ;
339
357
}
340
358
}
341
359
Some ( "@jsxFrag" ) => {
@@ -345,7 +363,7 @@ impl JsxDirectives {
345
363
let mut e = ( * parse_expr_for_jsx (
346
364
cm,
347
365
"module-jsx-pragma-frag" ,
348
- src . to_string ( ) ,
366
+ cache_source ( src ) ,
349
367
top_level_mark,
350
368
) )
351
369
. clone ( ) ;
@@ -361,7 +379,7 @@ impl JsxDirectives {
361
379
let mut e = ( * parse_expr_for_jsx (
362
380
cm,
363
381
"module-jsx-pragma" ,
364
- src . to_string ( ) ,
382
+ cache_source ( src ) ,
365
383
top_level_mark,
366
384
) )
367
385
. clone ( ) ;
@@ -380,6 +398,33 @@ impl JsxDirectives {
380
398
}
381
399
}
382
400
401
+ #[ cfg( feature = "concurrent" ) ]
402
+ fn cache_source ( src : & str ) -> Lrc < String > {
403
+ static CACHE : Lazy < RwLock < FxHashMap < String , Lrc < String > > > > =
404
+ Lazy :: new ( || RwLock :: new ( FxHashMap :: default ( ) ) ) ;
405
+
406
+ {
407
+ let cache = CACHE . write ( ) . unwrap ( ) ;
408
+
409
+ if let Some ( cached) = cache. get ( src) {
410
+ return cached. clone ( ) ;
411
+ }
412
+ }
413
+
414
+ let cached = Lrc :: new ( src. to_string ( ) ) ;
415
+ {
416
+ let mut cache = CACHE . write ( ) . unwrap ( ) ;
417
+ cache. insert ( src. to_string ( ) , cached. clone ( ) ) ;
418
+ }
419
+ cached
420
+ }
421
+
422
+ #[ cfg( not( feature = "concurrent" ) ) ]
423
+ fn cache_source ( src : & str ) -> Lrc < String > {
424
+ // We cannot cache because Rc does not implement Send.
425
+ Lrc :: new ( src. to_string ( ) )
426
+ }
427
+
383
428
fn is_valid_for_pragma ( s : & str ) -> bool {
384
429
if s. is_empty ( ) {
385
430
return false ;
0 commit comments