@@ -4,6 +4,7 @@ use std::{
4
4
convert:: { TryFrom , TryInto } ,
5
5
mem:: { replace, take} ,
6
6
rc:: Rc ,
7
+ sync:: Arc ,
7
8
} ;
8
9
9
10
use hex:: encode as hex_encode;
@@ -12,23 +13,32 @@ use rustc_hash::{FxHashMap, FxHashSet};
12
13
use serde:: Deserialize ;
13
14
use sha1:: { Digest , Sha1 } ;
14
15
use swc_core:: {
15
- atoms:: Atom ,
16
+ atoms:: { atom , Atom } ,
16
17
common:: {
17
18
comments:: { Comment , CommentKind , Comments } ,
18
19
errors:: HANDLER ,
19
20
source_map:: PURE_SP ,
20
21
util:: take:: Take ,
21
- BytePos , FileName , Mark , Span , SyntaxContext , DUMMY_SP ,
22
+ BytePos , FileName , Mark , SourceMap , Span , SyntaxContext , DUMMY_SP ,
22
23
} ,
23
24
ecma:: {
24
25
ast:: * ,
26
+ codegen:: { text_writer:: JsWriter , Emitter } ,
25
27
utils:: { private_ident, quote_ident, ExprFactory } ,
26
28
visit:: { noop_visit_mut_type, visit_mut_pass, VisitMut , VisitMutWith } ,
27
29
} ,
28
30
quote,
29
31
} ;
30
32
use turbo_rcstr:: RcStr ;
31
33
34
+ use crate :: FxIndexMap ;
35
+
36
+ #[ derive( Clone , Copy , Debug , Deserialize ) ]
37
+ pub enum ServerActionsMode {
38
+ Webpack ,
39
+ Turbopack ,
40
+ }
41
+
32
42
#[ derive( Clone , Debug , Deserialize ) ]
33
43
#[ serde( deny_unknown_fields, rename_all = "camelCase" ) ]
34
44
pub struct Config {
@@ -127,9 +137,11 @@ pub fn server_actions<C: Comments>(
127
137
config : Config ,
128
138
comments : C ,
129
139
use_cache_telemetry_tracker : Rc < RefCell < FxHashMap < String , usize > > > ,
140
+ mode : ServerActionsMode ,
130
141
) -> impl Pass {
131
142
visit_mut_pass ( ServerActions {
132
143
config,
144
+ mode,
133
145
comments,
134
146
file_name : file_name. to_string ( ) ,
135
147
start_pos : BytePos ( 0 ) ,
@@ -184,6 +196,7 @@ struct ServerActions<C: Comments> {
184
196
config : Config ,
185
197
file_name : String ,
186
198
comments : C ,
199
+ mode : ServerActionsMode ,
187
200
188
201
start_pos : BytePos ,
189
202
file_directive : Option < Directive > ,
@@ -1809,46 +1822,49 @@ impl<C: Comments> VisitMut for ServerActions<C> {
1809
1822
let call_server_ident = private_ident ! ( "callServer" ) ;
1810
1823
let find_source_map_url_ident = private_ident ! ( "findSourceMapURL" ) ;
1811
1824
1812
- if ( self . has_action || self . has_cache ) && !self . config . is_react_server_layer {
1813
- // import {
1814
- // createServerReference,
1815
- // callServer,
1816
- // findSourceMapURL
1817
- // } from 'private-next-rsc-action-client-wrapper'
1818
- // createServerReference("action_id")
1819
- new. push ( ModuleItem :: ModuleDecl ( ModuleDecl :: Import ( ImportDecl {
1820
- span : DUMMY_SP ,
1821
- specifiers : vec ! [
1822
- ImportSpecifier :: Named ( ImportNamedSpecifier {
1823
- span: DUMMY_SP ,
1824
- local: create_ref_ident. clone( ) ,
1825
- imported: None ,
1826
- is_type_only: false ,
1827
- } ) ,
1828
- ImportSpecifier :: Named ( ImportNamedSpecifier {
1825
+ let client_layer_import = ( ( self . has_action || self . has_cache )
1826
+ && !self . config . is_react_server_layer )
1827
+ . then ( || {
1828
+ // import {
1829
+ // createServerReference,
1830
+ // callServer,
1831
+ // findSourceMapURL
1832
+ // } from 'private-next-rsc-action-client-wrapper'
1833
+ // createServerReference("action_id")
1834
+ ModuleItem :: ModuleDecl ( ModuleDecl :: Import ( ImportDecl {
1835
+ span : DUMMY_SP ,
1836
+ specifiers : vec ! [
1837
+ ImportSpecifier :: Named ( ImportNamedSpecifier {
1838
+ span: DUMMY_SP ,
1839
+ local: create_ref_ident. clone( ) ,
1840
+ imported: None ,
1841
+ is_type_only: false ,
1842
+ } ) ,
1843
+ ImportSpecifier :: Named ( ImportNamedSpecifier {
1844
+ span: DUMMY_SP ,
1845
+ local: call_server_ident. clone( ) ,
1846
+ imported: None ,
1847
+ is_type_only: false ,
1848
+ } ) ,
1849
+ ImportSpecifier :: Named ( ImportNamedSpecifier {
1850
+ span: DUMMY_SP ,
1851
+ local: find_source_map_url_ident. clone( ) ,
1852
+ imported: None ,
1853
+ is_type_only: false ,
1854
+ } ) ,
1855
+ ] ,
1856
+ src : Box :: new ( Str {
1829
1857
span : DUMMY_SP ,
1830
- local: call_server_ident. clone( ) ,
1831
- imported: None ,
1832
- is_type_only: false ,
1858
+ value : "private-next-rsc-action-client-wrapper" . into ( ) ,
1859
+ raw : None ,
1833
1860
} ) ,
1834
- ImportSpecifier :: Named ( ImportNamedSpecifier {
1835
- span: DUMMY_SP ,
1836
- local: find_source_map_url_ident. clone( ) ,
1837
- imported: None ,
1838
- is_type_only: false ,
1839
- } ) ,
1840
- ] ,
1841
- src : Box :: new ( Str {
1842
- span : DUMMY_SP ,
1843
- value : "private-next-rsc-action-client-wrapper" . into ( ) ,
1844
- raw : None ,
1845
- } ) ,
1846
- type_only : false ,
1847
- with : None ,
1848
- phase : Default :: default ( ) ,
1849
- } ) ) ) ;
1850
- new. rotate_right ( 1 ) ;
1851
- }
1861
+ type_only : false ,
1862
+ with : None ,
1863
+ phase : Default :: default ( ) ,
1864
+ } ) )
1865
+ } ) ;
1866
+
1867
+ let mut client_layer_exports = FxIndexMap :: default ( ) ;
1852
1868
1853
1869
// If it's a "use server" or a "use cache" file, all exports need to be annotated.
1854
1870
if should_track_exports {
@@ -1885,7 +1901,7 @@ impl<C: Comments> VisitMut for ServerActions<C> {
1885
1901
} ) ) ,
1886
1902
} ,
1887
1903
) ) ;
1888
- new . push ( export_expr) ;
1904
+ client_layer_exports . insert ( atom ! ( "default" ) , export_expr) ;
1889
1905
} else {
1890
1906
let export_expr =
1891
1907
ModuleItem :: ModuleDecl ( ModuleDecl :: ExportDecl ( ExportDecl {
@@ -1932,7 +1948,7 @@ impl<C: Comments> VisitMut for ServerActions<C> {
1932
1948
..Default :: default ( )
1933
1949
} ) ) ,
1934
1950
} ) ) ;
1935
- new . push ( export_expr) ;
1951
+ client_layer_exports . insert ( export_name . clone ( ) , export_expr) ;
1936
1952
}
1937
1953
} else if !in_cache_file {
1938
1954
self . annotations . push ( Stmt :: Expr ( ExprStmt {
@@ -2098,6 +2114,50 @@ impl<C: Comments> VisitMut for ServerActions<C> {
2098
2114
new. rotate_right ( 2 ) ;
2099
2115
}
2100
2116
2117
+ if ( self . has_action || self . has_cache ) && !self . config . is_react_server_layer {
2118
+ match self . mode {
2119
+ ServerActionsMode :: Webpack => {
2120
+ new. push ( client_layer_import. unwrap ( ) ) ;
2121
+ new. rotate_right ( 1 ) ;
2122
+ new. extend ( client_layer_exports. into_iter ( ) . map ( |( _, v) | v) ) ;
2123
+ }
2124
+ ServerActionsMode :: Turbopack => {
2125
+ for ( export, stmt) in client_layer_exports {
2126
+ new. push ( ModuleItem :: ModuleDecl ( ModuleDecl :: ExportNamed (
2127
+ NamedExport {
2128
+ specifiers : vec ! [ ExportSpecifier :: Named ( ExportNamedSpecifier {
2129
+ span: DUMMY_SP ,
2130
+ orig: ModuleExportName :: Ident ( export. into( ) ) ,
2131
+ exported: None ,
2132
+ is_type_only: false ,
2133
+ } ) ] ,
2134
+ src : Some ( Box :: new (
2135
+ program_to_data_url ( & Program :: Module ( Module {
2136
+ span : DUMMY_SP ,
2137
+ body : vec ! [
2138
+ ModuleItem :: Stmt ( Stmt :: Expr ( ExprStmt {
2139
+ expr: Box :: new( Expr :: Lit ( Lit :: Str (
2140
+ "use turbopack no side effects" . into( ) ,
2141
+ ) ) ) ,
2142
+ span: DUMMY_SP ,
2143
+ } ) ) ,
2144
+ client_layer_import. clone( ) . unwrap( ) ,
2145
+ stmt,
2146
+ ] ,
2147
+ shebang : None ,
2148
+ } ) )
2149
+ . into ( ) ,
2150
+ ) ) ,
2151
+ span : DUMMY_SP ,
2152
+ type_only : false ,
2153
+ with : None ,
2154
+ } ,
2155
+ ) ) ) ;
2156
+ }
2157
+ }
2158
+ }
2159
+ }
2160
+
2101
2161
* stmts = new;
2102
2162
2103
2163
self . annotations = old_annotations;
@@ -3102,3 +3162,21 @@ fn emit_error(error_kind: ServerActionsErrorKind) {
3102
3162
3103
3163
HANDLER . with ( |handler| handler. struct_span_err ( span, & msg) . emit ( ) ) ;
3104
3164
}
3165
+
3166
+ fn program_to_data_url ( program : & Program ) -> String {
3167
+ let mut output = vec ! [ ] ;
3168
+ let sourcemap = Arc :: new ( SourceMap :: default ( ) ) ;
3169
+ let mut emitter = Emitter {
3170
+ cfg : Default :: default ( ) ,
3171
+ cm : sourcemap. clone ( ) ,
3172
+ wr : Box :: new ( JsWriter :: new ( sourcemap. clone ( ) , " " , & mut output, None ) ) ,
3173
+ comments : None ,
3174
+ } ;
3175
+
3176
+ // println!("Emitting: {:?}", module);
3177
+ emitter. emit_program ( program) . unwrap ( ) ;
3178
+ drop ( emitter) ;
3179
+
3180
+ let output = String :: from_utf8 ( output) . expect ( "codegen generated non-utf8 output" ) ;
3181
+ format ! ( "data:text/javascript,{}" , urlencoding:: encode( & output) )
3182
+ }
0 commit comments