@@ -91,10 +91,18 @@ const createCallExpression = (
91
91
span : { start : 0 , end : 0 , ctxt : 0 } ,
92
92
} ) ;
93
93
94
- const serverActionsInitCode = swc . parseSync ( `
94
+ const serverInitCode = swc . parseSync ( `
95
95
import { registerServerReference as __waku_registerServerReference } from 'react-server-dom-webpack/server.edge';
96
96
` ) . body ;
97
97
98
+ const findLastImportIndex = ( mod : swc . Module ) => {
99
+ const lastImportIndex = mod . body . findIndex (
100
+ ( node ) =>
101
+ node . type !== 'ExpressionStatement' && node . type !== 'ImportDeclaration' ,
102
+ ) ;
103
+ return lastImportIndex === - 1 ? 0 : lastImportIndex ;
104
+ } ;
105
+
98
106
type FunctionWithBlockBody = (
99
107
| swc . FunctionDeclaration
100
108
| swc . FunctionExpression
@@ -323,62 +331,59 @@ const transformServerActions = (
323
331
if ( ! serverActionIndex ) {
324
332
return ;
325
333
}
326
- const serverActionsCode = [ ...serverActionsInitCode ] ;
327
- for ( const [ actionIndex , [ actionFn , closureVars ] ] of serverActions ) {
328
- if ( actionFn . type === 'FunctionDeclaration' ) {
329
- const stmt1 : swc . ExportDeclaration = {
330
- type : 'ExportDeclaration' ,
331
- declaration : prependArgsToFn ( actionFn , closureVars ) ,
332
- span : { start : 0 , end : 0 , ctxt : 0 } ,
333
- } ;
334
- const stmt2 : swc . ExpressionStatement = {
335
- type : 'ExpressionStatement' ,
336
- expression : createCallExpression (
337
- createIdentifier ( '__waku_registerServerReference' ) ,
338
- [
339
- createIdentifier ( actionFn . identifier . value ) ,
340
- createStringLiteral ( getActionId ( ) ) ,
341
- createStringLiteral ( '__waku_action' + actionIndex ) ,
342
- ] ,
343
- ) ,
344
- span : { start : 0 , end : 0 , ctxt : 0 } ,
345
- } ;
346
- serverActionsCode . push ( stmt1 , stmt2 ) ;
347
- } else {
348
- const stmt : swc . ExportDeclaration = {
349
- type : 'ExportDeclaration' ,
350
- declaration : {
351
- type : 'VariableDeclaration' ,
352
- kind : 'const' ,
353
- declare : false ,
354
- declarations : [
355
- {
356
- type : 'VariableDeclarator' ,
357
- id : createIdentifier ( '__waku_action' + actionIndex ) ,
358
- init : createCallExpression (
359
- createIdentifier ( '__waku_registerServerReference' ) ,
360
- [
361
- prependArgsToFn ( actionFn , closureVars ) ,
362
- createStringLiteral ( getActionId ( ) ) ,
363
- createStringLiteral ( '__waku_action' + actionIndex ) ,
364
- ] ,
365
- ) ,
366
- definite : false ,
367
- span : { start : 0 , end : 0 , ctxt : 0 } ,
368
- } ,
369
- ] ,
334
+ const serverActionsCode = Array . from ( serverActions ) . flatMap (
335
+ ( [ actionIndex , [ actionFn , closureVars ] ] ) => {
336
+ if ( actionFn . type === 'FunctionDeclaration' ) {
337
+ const stmt1 : swc . ExportDeclaration = {
338
+ type : 'ExportDeclaration' ,
339
+ declaration : prependArgsToFn ( actionFn , closureVars ) ,
370
340
span : { start : 0 , end : 0 , ctxt : 0 } ,
371
- } ,
372
- span : { start : 0 , end : 0 , ctxt : 0 } ,
373
- } ;
374
- serverActionsCode . push ( stmt ) ;
375
- }
376
- }
377
- const lastImportIndex = mod . body . findIndex (
378
- ( node ) =>
379
- node . type !== 'ExpressionStatement' && node . type !== 'ImportDeclaration' ,
341
+ } ;
342
+ const stmt2 : swc . ExpressionStatement = {
343
+ type : 'ExpressionStatement' ,
344
+ expression : createCallExpression (
345
+ createIdentifier ( '__waku_registerServerReference' ) ,
346
+ [
347
+ createIdentifier ( actionFn . identifier . value ) ,
348
+ createStringLiteral ( getActionId ( ) ) ,
349
+ createStringLiteral ( '__waku_action' + actionIndex ) ,
350
+ ] ,
351
+ ) ,
352
+ span : { start : 0 , end : 0 , ctxt : 0 } ,
353
+ } ;
354
+ return [ stmt1 , stmt2 ] ;
355
+ } else {
356
+ const stmt : swc . ExportDeclaration = {
357
+ type : 'ExportDeclaration' ,
358
+ declaration : {
359
+ type : 'VariableDeclaration' ,
360
+ kind : 'const' ,
361
+ declare : false ,
362
+ declarations : [
363
+ {
364
+ type : 'VariableDeclarator' ,
365
+ id : createIdentifier ( '__waku_action' + actionIndex ) ,
366
+ init : createCallExpression (
367
+ createIdentifier ( '__waku_registerServerReference' ) ,
368
+ [
369
+ prependArgsToFn ( actionFn , closureVars ) ,
370
+ createStringLiteral ( getActionId ( ) ) ,
371
+ createStringLiteral ( '__waku_action' + actionIndex ) ,
372
+ ] ,
373
+ ) ,
374
+ definite : false ,
375
+ span : { start : 0 , end : 0 , ctxt : 0 } ,
376
+ } ,
377
+ ] ,
378
+ span : { start : 0 , end : 0 , ctxt : 0 } ,
379
+ } ,
380
+ span : { start : 0 , end : 0 , ctxt : 0 } ,
381
+ } ;
382
+ return [ stmt ] ;
383
+ }
384
+ } ,
380
385
) ;
381
- mod . body . splice ( lastImportIndex , 0 , ...serverActionsCode ) ;
386
+ mod . body . splice ( findLastImportIndex ( mod ) , 0 , ...serverActionsCode ) ;
382
387
return mod ;
383
388
} ;
384
389
@@ -391,14 +396,18 @@ const transformServer = (
391
396
const ext = extname ( id ) ;
392
397
const mod = swc . parseSync ( code , parseOpts ( ext ) ) ;
393
398
let hasUseClient = false ;
394
- let hasUseServer : swc . ExpressionStatement | undefined ;
395
- for ( const item of mod . body ) {
399
+ let hasUseServer = false ;
400
+ for ( let i = 0 ; i < mod . body . length ; ++ i ) {
401
+ const item = mod . body [ i ] ! ;
396
402
if ( item . type === 'ExpressionStatement' ) {
397
403
if ( item . expression . type === 'StringLiteral' ) {
398
404
if ( item . expression . value === 'use client' ) {
399
405
hasUseClient = true ;
406
+ break ;
400
407
} else if ( item . expression . value === 'use server' ) {
401
- hasUseServer = item ;
408
+ hasUseServer = true ;
409
+ mod . body . splice ( i , 1 ) ; // remove this directive
410
+ break ;
402
411
}
403
412
}
404
413
} else {
@@ -417,42 +426,56 @@ export ${name === 'default' ? name : `const ${name} =`} registerClientReference(
417
426
` ;
418
427
}
419
428
return newCode ;
420
- } else if ( hasUseServer ) {
421
- const useServerPosStart = hasUseServer . span . start - mod . span . start ;
422
- const useServerPosEnd = hasUseServer . span . end - mod . span . start ;
423
- const lastImportIndex = mod . body . findIndex (
424
- ( node ) =>
425
- node . type !== 'ExpressionStatement' &&
426
- node . type !== 'ImportDeclaration' ,
427
- ) ;
428
- let lastImportPos =
429
- lastImportIndex === - 1 ? 0 : mod . body [ lastImportIndex ] ! . span . end ;
430
- if ( lastImportIndex < useServerPosEnd ) {
431
- lastImportPos = useServerPosEnd ;
432
- }
429
+ }
430
+ if ( hasUseServer ) {
433
431
const exportNames = collectExportNames ( mod ) ;
434
- const newCode = [
435
- code . slice ( 0 , useServerPosStart ) ,
436
- code . slice ( useServerPosEnd , lastImportPos ) ,
437
- `
438
- import { registerServerReference as __waku_registerServerReference } from 'react-server-dom-webpack/server.edge';
439
- ` ,
440
- code . slice ( lastImportPos ) ,
441
- ...[ ...exportNames ] . map (
442
- ( name ) => `
443
- if (typeof ${ name } === 'function') {
444
- __waku_registerServerReference(${ name } , '${ getServerId ( id ) } ', '${ name } ');
445
- }
446
- ` ,
447
- ) ,
448
- ] . join ( '' ) ;
449
- return newCode ;
432
+ const serverActionsCode = Array . from ( exportNames ) . map ( ( name ) => {
433
+ const blockStmt : swc . BlockStatement = {
434
+ type : 'BlockStatement' ,
435
+ stmts : [
436
+ {
437
+ type : 'ExpressionStatement' ,
438
+ expression : createCallExpression (
439
+ createIdentifier ( '__waku_registerServerReference' ) ,
440
+ [
441
+ createIdentifier ( name ) ,
442
+ createStringLiteral ( getServerId ( id ) ) ,
443
+ createStringLiteral ( name ) ,
444
+ ] ,
445
+ ) ,
446
+ span : { start : 0 , end : 0 , ctxt : 0 } ,
447
+ } ,
448
+ ] ,
449
+ span : { start : 0 , end : 0 , ctxt : 0 } ,
450
+ } ;
451
+ const ifStmt : swc . IfStatement = {
452
+ type : 'IfStatement' ,
453
+ test : {
454
+ type : 'BinaryExpression' ,
455
+ operator : '===' ,
456
+ left : {
457
+ type : 'UnaryExpression' ,
458
+ operator : 'typeof' ,
459
+ argument : createIdentifier ( name ) ,
460
+ span : { start : 0 , end : 0 , ctxt : 0 } ,
461
+ } ,
462
+ right : createStringLiteral ( 'function' ) ,
463
+ span : { start : 0 , end : 0 , ctxt : 0 } ,
464
+ } ,
465
+ consequent : blockStmt ,
466
+ span : { start : 0 , end : 0 , ctxt : 0 } ,
467
+ } ;
468
+ return ifStmt ;
469
+ } ) ;
470
+ mod . body . push ( ...serverActionsCode ) ;
450
471
}
451
472
// transform server actions in server components
452
473
const newMod =
453
- code . includes ( 'use server' ) &&
454
- transformServerActions ( mod , ( ) => getServerId ( id ) ) ;
474
+ ( code . includes ( 'use server' ) &&
475
+ transformServerActions ( mod , ( ) => getServerId ( id ) ) ) ||
476
+ ( hasUseServer && mod ) ;
455
477
if ( newMod ) {
478
+ newMod . body . splice ( findLastImportIndex ( newMod ) , 0 , ...serverInitCode ) ;
456
479
const newCode = swc . printSync ( newMod ) . code ;
457
480
return newCode ;
458
481
}
0 commit comments