rari 0.2.1 → 0.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/vite/index.ts CHANGED
@@ -6,6 +6,7 @@ import fs from 'node:fs'
6
6
  import path from 'node:path'
7
7
  import process from 'node:process'
8
8
  import * as acorn from 'acorn'
9
+ import { minify } from 'rollup-plugin-esbuild'
9
10
  import { createServerBuildPlugin } from './server-build'
10
11
 
11
12
  interface RariOptions {
@@ -151,7 +152,10 @@ export function rari(options: RariOptions = {}): Plugin[] {
151
152
  }
152
153
  }
153
154
 
154
- function hasTopLevelDirective(code: string, directive: 'use client' | 'use server'): boolean {
155
+ function hasTopLevelDirective(
156
+ code: string,
157
+ directive: 'use client' | 'use server',
158
+ ): boolean {
155
159
  try {
156
160
  const ast = acorn.parse(code, {
157
161
  ecmaVersion: 2024,
@@ -224,7 +228,6 @@ export function rari(options: RariOptions = {}): Plugin[] {
224
228
 
225
229
  newCode += `
226
230
 
227
- // HMR acceptance for server components
228
231
  if (import.meta.hot) {
229
232
  import.meta.hot.accept(() => {
230
233
  // Server component updated, no need to reload
@@ -370,30 +373,50 @@ if (import.meta.hot) {
370
373
  config(config: UserConfig, { command }) {
371
374
  config.resolve = config.resolve || {}
372
375
  const existingDedupe = Array.isArray((config.resolve as any).dedupe)
373
- ? (config.resolve as any).dedupe as string[]
376
+ ? ((config.resolve as any).dedupe as string[])
374
377
  : []
375
- const toAdd = ['react', 'react-dom']
376
- ; (config.resolve as any).dedupe = Array.from(
378
+ const toAdd = ['react', 'react-dom'];
379
+ (config.resolve as any).dedupe = Array.from(
377
380
  new Set([...(existingDedupe || []), ...toAdd]),
378
381
  )
379
382
 
380
- const existingAlias: Array<{ find: string | RegExp, replacement: string }>
381
- = Array.isArray((config.resolve as any).alias)
382
- ? (config.resolve as any).alias
383
- : []
383
+ const existingResolveAlias = (config.resolve as any).alias || {};
384
+ (config.resolve as any).alias = {
385
+ ...existingResolveAlias,
386
+ 'react-dom/server': 'react-dom/server.browser',
387
+ 'react-dom$': 'react-dom/client',
388
+ 'react-dom/cjs/react-dom.production.min.js': 'react-dom/client',
389
+ 'react-dom/cjs/react-dom.development.js': 'react-dom/client',
390
+ }
391
+
392
+ const existingAlias: Array<{
393
+ find: string | RegExp
394
+ replacement: string
395
+ }> = Array.isArray((config.resolve as any).alias)
396
+ ? (config.resolve as any).alias
397
+ : []
384
398
  const aliasFinds = new Set(existingAlias.map(a => String(a.find)))
385
399
  try {
386
400
  const reactPath = require.resolve('react')
387
401
  const reactDomClientPath = require.resolve('react-dom/client')
388
402
  const reactJsxRuntimePath = require.resolve('react/jsx-runtime')
389
- const aliasesToAppend: Array<{ find: string, replacement: string }> = []
403
+ const aliasesToAppend: Array<{ find: string, replacement: string }>
404
+ = []
390
405
  if (!aliasFinds.has('react/jsx-runtime')) {
391
- aliasesToAppend.push({ find: 'react/jsx-runtime', replacement: reactJsxRuntimePath })
406
+ aliasesToAppend.push({
407
+ find: 'react/jsx-runtime',
408
+ replacement: reactJsxRuntimePath,
409
+ })
392
410
  }
393
411
  try {
394
- const reactJsxDevRuntimePath = require.resolve('react/jsx-dev-runtime')
412
+ const reactJsxDevRuntimePath = require.resolve(
413
+ 'react/jsx-dev-runtime',
414
+ )
395
415
  if (!aliasFinds.has('react/jsx-dev-runtime')) {
396
- aliasesToAppend.push({ find: 'react/jsx-dev-runtime', replacement: reactJsxDevRuntimePath })
416
+ aliasesToAppend.push({
417
+ find: 'react/jsx-dev-runtime',
418
+ replacement: reactJsxDevRuntimePath,
419
+ })
397
420
  }
398
421
  }
399
422
  catch { }
@@ -401,10 +424,16 @@ if (import.meta.hot) {
401
424
  aliasesToAppend.push({ find: 'react', replacement: reactPath })
402
425
  }
403
426
  if (!aliasFinds.has('react-dom/client')) {
404
- aliasesToAppend.push({ find: 'react-dom/client', replacement: reactDomClientPath })
427
+ aliasesToAppend.push({
428
+ find: 'react-dom/client',
429
+ replacement: reactDomClientPath,
430
+ })
405
431
  }
406
432
  if (aliasesToAppend.length > 0) {
407
- (config.resolve as any).alias = [...existingAlias, ...aliasesToAppend]
433
+ (config.resolve as any).alias = [
434
+ ...existingAlias,
435
+ ...aliasesToAppend,
436
+ ]
408
437
  }
409
438
  }
410
439
  catch { }
@@ -437,12 +466,22 @@ if (import.meta.hot) {
437
466
  if (!config.optimizeDeps.include.includes('react-dom/server')) {
438
467
  config.optimizeDeps.include.push('react-dom/server')
439
468
  }
469
+ if (!config.optimizeDeps.include.includes('react')) {
470
+ config.optimizeDeps.include.push('react')
471
+ }
472
+ if (!config.optimizeDeps.include.includes('react-dom/client')) {
473
+ config.optimizeDeps.include.push('react-dom/client')
474
+ }
475
+ config.optimizeDeps.exclude = config.optimizeDeps.exclude || []
476
+ if (!config.optimizeDeps.exclude.includes('virtual:rsc-integration')) {
477
+ config.optimizeDeps.exclude.push('virtual:rsc-integration')
478
+ }
440
479
 
441
480
  if (command === 'build') {
442
481
  for (const envName of ['rsc', 'ssr', 'client']) {
443
482
  const env = config.environments[envName]
444
483
  if (env && env.build) {
445
- env.build.rollupOptions = env.build.rollupOptions || {}
484
+ env.build.rolldownOptions = env.build.rolldownOptions || {}
446
485
  }
447
486
  }
448
487
  }
@@ -478,38 +517,329 @@ if (import.meta.hot) {
478
517
 
479
518
  if (command === 'build') {
480
519
  config.build = config.build || {}
481
- config.build.rollupOptions = config.build.rollupOptions || {}
520
+ config.build.rolldownOptions = config.build.rolldownOptions || {}
521
+
522
+ config.build.rolldownOptions.plugins
523
+ = config.build.rolldownOptions.plugins || []
524
+ if (Array.isArray(config.build.rolldownOptions.plugins)) {
525
+ config.build.rolldownOptions.plugins.push(minify())
526
+
527
+ config.build.rolldownOptions.plugins.push({
528
+ name: 'html-css-optimizer',
529
+ generateBundle(options, bundle) {
530
+ Object.keys(bundle).forEach((fileName) => {
531
+ const file = bundle[fileName]
532
+ if (file.type === 'asset' && fileName.endsWith('.html')) {
533
+ let html = file.source as string
534
+
535
+ html = html.replace(
536
+ /<link\s+rel="stylesheet"\s+crossorigin\s+href="([^"]+\.css)"\s*>/g,
537
+ (match, href) => {
538
+ return `<link rel="preload" as="style" crossorigin href="${href}" fetchpriority="high" onload="this.onload=null;this.rel='stylesheet'">
539
+ <noscript><link rel="stylesheet" crossorigin href="${href}"></noscript>`
540
+ },
541
+ )
542
+
543
+ const scriptMatch = html.match(
544
+ /<script\s+type="module"\s+crossorigin\s+src="([^"]+)"\s*><\/script>/,
545
+ )
546
+ if (scriptMatch) {
547
+ const mainJsHref = scriptMatch[1]
548
+ html = html.replace(
549
+ scriptMatch[0],
550
+ `<link rel="preload" as="script" crossorigin href="${mainJsHref}" fetchpriority="high">
551
+ <script type="module" crossorigin src="${mainJsHref}" fetchpriority="high"></script>`,
552
+ )
553
+ }
554
+
555
+ file.source = html
556
+ }
557
+ })
558
+ },
559
+ })
560
+ }
482
561
 
483
- if (!config.build.rollupOptions.input) {
484
- config.build.rollupOptions.input = {
562
+ if (!config.build.rolldownOptions.input) {
563
+ config.build.rolldownOptions.input = {
485
564
  main: './index.html',
486
565
  }
487
566
  }
567
+
568
+ config.build.rolldownOptions.output
569
+ = config.build.rolldownOptions.output || {}
570
+ const outputConfig = Array.isArray(config.build.rolldownOptions.output)
571
+ ? config.build.rolldownOptions.output[0] || {}
572
+ : config.build.rolldownOptions.output
573
+
574
+ outputConfig.manualChunks = (id) => {
575
+ if (
576
+ id.includes('node_modules/react-dom')
577
+ || id.includes('react-dom/client')
578
+ || id.includes('react-dom/server')
579
+ || id.includes('react-dom/')
580
+ ) {
581
+ return 'react-dom'
582
+ }
583
+ if (
584
+ (id.includes('node_modules/react') || id.includes('react/'))
585
+ && !id.includes('react-dom')
586
+ ) {
587
+ return 'react'
588
+ }
589
+ if (id.includes('scheduler') && id.includes('node_modules')) {
590
+ return 'scheduler'
591
+ }
592
+ if (id.includes('markdown-it') || id.includes('shiki')) {
593
+ return 'vendor'
594
+ }
595
+ if (id.includes('node_modules')) {
596
+ return 'vendor'
597
+ }
598
+ }
599
+
600
+ config.build.rolldownOptions.treeshake = config.build.rolldownOptions
601
+ .treeshake || {
602
+ moduleSideEffects: (id) => {
603
+ if (id.includes('.css') || id.includes('polyfill')) {
604
+ return true
605
+ }
606
+ if (
607
+ id.includes('react-dom')
608
+ || id.includes('react')
609
+ || id.includes('scheduler')
610
+ || id.includes('react-dom/client')
611
+ || id.includes('react-dom/server')
612
+ ) {
613
+ return false
614
+ }
615
+ return false
616
+ },
617
+ unknownGlobalSideEffects: false,
618
+ }
619
+
620
+ const existingExternal = config.build.rolldownOptions?.external || []
621
+ const reactDomExternals = [
622
+ 'react-dom/profiling',
623
+ 'react-dom/test-utils',
624
+ 'react-dom/server',
625
+ 'react-dom/server.browser',
626
+ 'react-dom/server.node',
627
+ 'react/jsx-dev-runtime',
628
+ 'scheduler/tracing',
629
+ 'scheduler/unstable_mock',
630
+ 'react/cjs/react.development.js',
631
+ 'react/cjs/react.production.min.js',
632
+ 'react-dom/cjs/react-dom.development.js',
633
+ 'react-dom/cjs/react-dom.production.min.js',
634
+ 'react-dom/src/client/ReactDOMRoot.js',
635
+ 'react-dom/src/events/plugins',
636
+ 'react-dom/src/shared/HTMLDOMPropertyConfig.js',
637
+ 'react-dom/src/shared/DOMPropertyOperations.js',
638
+ ]
639
+
640
+ if (Array.isArray(existingExternal)) {
641
+ const external = [...existingExternal]
642
+ external.push(
643
+ ...reactDomExternals.filter(dep => !external.includes(dep)),
644
+ )
645
+ config.build.rolldownOptions.external = external
646
+ }
647
+ else if (typeof existingExternal === 'function') {
648
+ const originalExternal = existingExternal
649
+ config.build.rolldownOptions.external = (
650
+ id,
651
+ parentId,
652
+ isResolved,
653
+ ) => {
654
+ if (reactDomExternals.includes(id))
655
+ return true
656
+ return originalExternal(id, parentId, isResolved)
657
+ }
658
+ }
659
+ else {
660
+ config.build.rolldownOptions.external = [
661
+ ...(Array.isArray(existingExternal)
662
+ ? existingExternal
663
+ : [existingExternal]),
664
+ ...reactDomExternals,
665
+ ].filter(Boolean)
666
+ }
667
+
668
+ config.build.minify = true
669
+ config.build.target = config.build.target || [
670
+ 'es2020',
671
+ 'edge88',
672
+ 'firefox78',
673
+ 'chrome87',
674
+ 'safari14',
675
+ ]
676
+ config.build.cssMinify
677
+ = config.build.cssMinify !== false ? 'esbuild' : false
678
+ config.build.cssCodeSplit = true
679
+ config.build.assetsInlineLimit = 4096
680
+ config.build.chunkSizeWarningLimit = 1000
681
+ config.build.sourcemap
682
+ = config.build.sourcemap !== undefined ? config.build.sourcemap : true
683
+
684
+ config.build.terserOptions = config.build.terserOptions || {
685
+ compress: {
686
+ drop_console: true,
687
+ drop_debugger: true,
688
+ pure_funcs: [
689
+ 'console.log',
690
+ 'console.info',
691
+ 'console.debug',
692
+ 'console.warn',
693
+ 'invariant',
694
+ 'warning',
695
+ '__DEV__',
696
+ 'ReactDOM.render',
697
+ 'ReactDOM.unmountComponentAtNode',
698
+ 'ReactDOM.findDOMNode',
699
+ 'ReactDOM.createPortal',
700
+ ],
701
+ passes: 3,
702
+ unsafe: true,
703
+ unsafe_comps: true,
704
+ unsafe_Function: true,
705
+ unsafe_math: true,
706
+ unsafe_symbols: true,
707
+ unsafe_methods: true,
708
+ unsafe_proto: true,
709
+ unsafe_regexp: true,
710
+ unsafe_undefined: true,
711
+ dead_code: true,
712
+ side_effects: false,
713
+ },
714
+ mangle: {
715
+ safari10: true,
716
+ properties: {
717
+ regex: /^_/,
718
+ },
719
+ },
720
+ format: {
721
+ comments: false,
722
+ },
723
+ }
724
+
725
+ outputConfig.format = outputConfig.format || 'es'
726
+ outputConfig.minify = true
727
+
728
+ if (Array.isArray(config.build.rolldownOptions.output)) {
729
+ config.build.rolldownOptions.output[0] = outputConfig
730
+ }
731
+ else {
732
+ config.build.rolldownOptions.output = outputConfig
733
+ }
488
734
  }
489
735
 
490
736
  if (config.environments && config.environments.client) {
491
737
  if (!config.environments.client.build) {
492
738
  config.environments.client.build = {}
493
739
  }
494
- if (!config.environments.client.build.rollupOptions) {
495
- config.environments.client.build.rollupOptions = {}
740
+ if (!config.environments.client.build.rolldownOptions) {
741
+ config.environments.client.build.rolldownOptions = {}
496
742
  }
497
- if (!config.environments.client.build.rollupOptions.input) {
498
- config.environments.client.build.rollupOptions.input = {}
743
+ if (!config.environments.client.build.rolldownOptions.input) {
744
+ config.environments.client.build.rolldownOptions.input = {}
499
745
  }
500
746
 
501
747
  if (
502
- typeof config.environments.client.build.rollupOptions.input
748
+ typeof config.environments.client.build.rolldownOptions.input
503
749
  === 'object'
504
- && !Array.isArray(config.environments.client.build.rollupOptions.input)
750
+ && !Array.isArray(config.environments.client.build.rolldownOptions.input)
505
751
  ) {
506
752
  (
507
- config.environments.client.build.rollupOptions.input as Record<
753
+ config.environments.client.build.rolldownOptions.input as Record<
508
754
  string,
509
755
  string
510
756
  >
511
757
  )['client-components'] = 'virtual:rsc-client-components'
512
758
  }
759
+
760
+ config.environments.client.build.rolldownOptions.plugins
761
+ = config.environments.client.build.rolldownOptions.plugins || []
762
+ if (
763
+ Array.isArray(
764
+ config.environments.client.build.rolldownOptions.plugins,
765
+ )
766
+ ) {
767
+ config.environments.client.build.rolldownOptions.plugins.push(
768
+ minify(),
769
+ )
770
+ }
771
+
772
+ config.environments.client.build.minify = true
773
+ config.environments.client.build.target = config.environments.client
774
+ .build
775
+ .target || [
776
+ 'es2020',
777
+ 'edge88',
778
+ 'firefox78',
779
+ 'chrome87',
780
+ 'safari14',
781
+ ]
782
+ config.environments.client.build.cssMinify = 'esbuild'
783
+ config.environments.client.build.cssCodeSplit = true
784
+ config.environments.client.build.assetsInlineLimit = 4096
785
+ config.environments.client.build.rolldownOptions.treeshake = {
786
+ moduleSideEffects: false,
787
+ unknownGlobalSideEffects: false,
788
+ }
789
+
790
+ config.environments.client.build.rolldownOptions.output
791
+ = config.environments.client.build.rolldownOptions.output || {}
792
+ const clientOutputConfig = Array.isArray(
793
+ config.environments.client.build.rolldownOptions.output,
794
+ )
795
+ ? config.environments.client.build.rolldownOptions.output[0] || {}
796
+ : config.environments.client.build.rolldownOptions.output
797
+
798
+ clientOutputConfig.manualChunks = (id) => {
799
+ if (
800
+ id.includes('node_modules/react-dom')
801
+ || id.includes('react-dom/client')
802
+ || id.includes('react-dom/server')
803
+ || id.includes('react-dom/')
804
+ ) {
805
+ return 'react-dom'
806
+ }
807
+ if (
808
+ (id.includes('node_modules/react') || id.includes('react/'))
809
+ && !id.includes('react-dom')
810
+ ) {
811
+ return 'react'
812
+ }
813
+ if (id.includes('scheduler') && id.includes('node_modules')) {
814
+ return 'scheduler'
815
+ }
816
+ if (
817
+ id.includes('rari')
818
+ && (id.includes('router') || id.includes('navigation'))
819
+ ) {
820
+ return 'router'
821
+ }
822
+ if (id.includes('markdown-it') || id.includes('shiki')) {
823
+ return 'vendor'
824
+ }
825
+ if (id.includes('node_modules')) {
826
+ return 'vendor'
827
+ }
828
+ }
829
+
830
+ clientOutputConfig.format = clientOutputConfig.format || 'es'
831
+ clientOutputConfig.minify = true
832
+
833
+ if (
834
+ Array.isArray(config.environments.client.build.rolldownOptions.output)
835
+ ) {
836
+ config.environments.client.build.rolldownOptions.output[0]
837
+ = clientOutputConfig
838
+ }
839
+ else {
840
+ config.environments.client.build.rolldownOptions.output
841
+ = clientOutputConfig
842
+ }
513
843
  }
514
844
 
515
845
  return config
@@ -520,6 +850,20 @@ if (import.meta.hot) {
520
850
  return null
521
851
  }
522
852
 
853
+ if (code.includes('react-dom')) {
854
+ code = code.replace(
855
+ /import\s+ReactDOM\s+from\s+['"]react-dom\/client['"];?/g,
856
+ 'import { createRoot, hydrateRoot } from \'react-dom/client\';',
857
+ )
858
+ code = code.replace(
859
+ /import\s+ReactDOM\s+from\s+['"]react-dom['"];?/g,
860
+ 'import { createRoot, hydrateRoot } from \'react-dom/client\';',
861
+ )
862
+
863
+ code = code.replace(/ReactDOM\.createRoot/g, 'createRoot')
864
+ code = code.replace(/ReactDOM\.hydrateRoot/g, 'hydrateRoot')
865
+ }
866
+
523
867
  const environment = (this as any).environment
524
868
 
525
869
  if (hasTopLevelDirective(code, 'use client')) {
@@ -1235,7 +1579,6 @@ export const __CLIENT_REFERENCE_REGISTRY__ = clientReferenceRegistry;
1235
1579
  export const __SERVER_REFERENCE_REGISTRY__ = serverReferenceRegistry;
1236
1580
  export const __CLIENT_COMPONENT_REGISTRY__ = clientComponentRegistry;
1237
1581
 
1238
- // Module map for React Server Components
1239
1582
  export function createClientModuleMap() {
1240
1583
  const moduleMap = {};
1241
1584
 
@@ -1261,7 +1604,6 @@ export function createClientModuleMap() {
1261
1604
  return `
1262
1605
  import React, { useState, useEffect, Suspense } from 'react';
1263
1606
 
1264
- // Client component registration for RSC system compatibility
1265
1607
  if (typeof globalThis.__clientComponents === 'undefined') {
1266
1608
  globalThis.__clientComponents = {};
1267
1609
  }
@@ -1279,7 +1621,6 @@ export function registerClientComponent(componentFunction, id, exportName) {
1279
1621
 
1280
1622
  const componentId = componentName;
1281
1623
 
1282
- // Register in global registry for RSC traversal
1283
1624
  globalThis.__clientComponents[componentId] = {
1284
1625
  id: componentId,
1285
1626
  path: id,
@@ -2040,7 +2381,7 @@ class RscClient {
2040
2381
  const processedChildren = value.map((child, index) => {
2041
2382
  const result = this.reconstructElementFromRscData(child, modules);
2042
2383
  return result;
2043
- }).filter(child => child !== null && child !== undefined); // Remove null/undefined children
2384
+ }).filter(child => child !== null && child !== undefined);
2044
2385
 
2045
2386
  if (processedChildren.length === 0) {
2046
2387
  processed[key] = null;
@@ -2185,7 +2526,6 @@ function ServerComponentWrapper({
2185
2526
  }
2186
2527
 
2187
2528
  function createServerComponentWrapper(componentName, importPath) {
2188
- // Use a global refresh counter to force re-mounting when components change
2189
2529
  let globalRefreshCounter = 0;
2190
2530
 
2191
2531
  if (typeof window !== 'undefined') {
@@ -2199,7 +2539,6 @@ function createServerComponentWrapper(componentName, importPath) {
2199
2539
  const ServerComponent = (props) => {
2200
2540
  const [mountKey, setMountKey] = useState(globalRefreshCounter);
2201
2541
 
2202
- // Force re-mount when component is invalidated
2203
2542
  useEffect(() => {
2204
2543
  const handleRscInvalidate = (event) => {
2205
2544
  const detail = event.detail;
@@ -2220,7 +2559,7 @@ function createServerComponentWrapper(componentName, importPath) {
2220
2559
  return React.createElement(Suspense, {
2221
2560
  fallback: null
2222
2561
  }, React.createElement(ServerComponentWrapper, {
2223
- key: componentName + '-' + mountKey, // Force re-mount with key change
2562
+ key: componentName + '-' + mountKey,
2224
2563
  componentId: componentName,
2225
2564
  props: props,
2226
2565
  fallback: null
@@ -2237,9 +2576,7 @@ function createServerComponentWrapper(componentName, importPath) {
2237
2576
  export const fetchServerComponent = (componentId, props) =>
2238
2577
  rscClient.fetchServerComponent(componentId, props);
2239
2578
 
2240
- // Helper function to check if a file is a server component (client-side)
2241
2579
  function isServerComponent(filePath) {
2242
- // Simple client-side check based on file path patterns
2243
2580
  return filePath && (
2244
2581
  filePath.includes('ServerWithClient') ||
2245
2582
  filePath.includes('server') ||
@@ -2247,32 +2584,26 @@ function isServerComponent(filePath) {
2247
2584
  );
2248
2585
  }
2249
2586
 
2250
- // HMR support for RSC cache invalidation
2251
2587
  if (import.meta.hot) {
2252
- // Listen for Vite's beforeFullReload event for server components
2253
2588
  import.meta.hot.on('vite:beforeFullReload', async (data) => {
2254
2589
  if (data?.path && isServerComponent(data.path)) {
2255
- // Immediately invalidate cache and trigger re-registration before reload
2256
2590
  await invalidateRscCache({ filePath: data.path, forceReload: true });
2257
2591
  }
2258
2592
  });
2259
2593
 
2260
2594
 
2261
2595
 
2262
- // Helper function to invalidate RSC cache and trigger component re-registration
2263
2596
  async function invalidateRscCache(data) {
2264
2597
  const filePath = data?.filePath || data;
2265
2598
 
2266
- // Wait for server to be ready
2267
2599
  const waitForServerReady = async () => {
2268
- for (let i = 0; i < 20; i++) { // Try for up to 2 seconds
2600
+ for (let i = 0; i < 20; i++) {
2269
2601
  try {
2270
2602
  const response = await fetch('/_rsc_status');
2271
2603
  if (response.ok) {
2272
2604
  return true;
2273
2605
  }
2274
2606
  } catch (e) {
2275
- // Server not ready yet
2276
2607
  }
2277
2608
  await new Promise(resolve => setTimeout(resolve, 100));
2278
2609
  }
@@ -2281,10 +2612,8 @@ if (import.meta.hot) {
2281
2612
 
2282
2613
  const serverReady = await waitForServerReady();
2283
2614
  if (serverReady) {
2284
- // Clear client-side RSC cache immediately
2285
2615
  rscClient.clearCache();
2286
2616
 
2287
- // Trigger immediate server component re-registration
2288
2617
  try {
2289
2618
  await fetch('/api/rsc/hmr-register', {
2290
2619
  method: 'POST',
@@ -2296,14 +2625,10 @@ if (import.meta.hot) {
2296
2625
  })
2297
2626
  });
2298
2627
 
2299
- // Wait a bit for the server to re-register the component
2300
- // The server now immediately reads and re-registers the component
2301
2628
  await new Promise(resolve => setTimeout(resolve, 300));
2302
2629
  } catch (error) {
2303
- // Fallback to existing timeout-based approach
2304
2630
  }
2305
2631
 
2306
- // Trigger re-render of active server components
2307
2632
  if (typeof window !== 'undefined') {
2308
2633
  const event = new CustomEvent('rari:rsc-invalidate', {
2309
2634
  detail: { filePath }
@@ -2388,6 +2713,108 @@ ${registrations.join('\n')}
2388
2713
  return [mainPlugin, serverBuildPlugin]
2389
2714
  }
2390
2715
 
2716
+ export function createReactDOMOptimization() {
2717
+ return {
2718
+ build: {
2719
+ rollupOptions: {
2720
+ output: {
2721
+ manualChunks: (id: string) => {
2722
+ if (
2723
+ id.includes('node_modules/react-dom')
2724
+ || id.includes('react-dom/client')
2725
+ || id.includes('react-dom/server')
2726
+ || id.includes('react-dom/')
2727
+ ) {
2728
+ return 'react-dom'
2729
+ }
2730
+
2731
+ if (
2732
+ (id.includes('node_modules/react') || id.includes('react/'))
2733
+ && !id.includes('react-dom')
2734
+ ) {
2735
+ return 'react'
2736
+ }
2737
+
2738
+ if (id.includes('scheduler') && id.includes('node_modules')) {
2739
+ return 'scheduler'
2740
+ }
2741
+
2742
+ if (id.includes('markdown-it') || id.includes('shiki')) {
2743
+ return 'vendor'
2744
+ }
2745
+
2746
+ if (id.includes('node_modules')) {
2747
+ return 'vendor'
2748
+ }
2749
+ },
2750
+ },
2751
+ treeshake: {
2752
+ moduleSideEffects: (id: string) => {
2753
+ if (id.includes('.css') || id.includes('polyfill')) {
2754
+ return true
2755
+ }
2756
+ if (
2757
+ id.includes('react-dom')
2758
+ || id.includes('react')
2759
+ || id.includes('scheduler')
2760
+ || id.includes('react-dom/client')
2761
+ || id.includes('react-dom/server')
2762
+ ) {
2763
+ return false
2764
+ }
2765
+ return false
2766
+ },
2767
+ unknownGlobalSideEffects: false,
2768
+ },
2769
+ },
2770
+ minify: 'terser',
2771
+ target: ['es2020', 'edge88', 'firefox78', 'chrome87', 'safari14'],
2772
+ cssMinify: 'esbuild',
2773
+ sourcemap: false,
2774
+ terserOptions: {
2775
+ compress: {
2776
+ drop_console: true,
2777
+ drop_debugger: true,
2778
+ pure_funcs: [
2779
+ 'console.log',
2780
+ 'console.info',
2781
+ 'console.debug',
2782
+ 'console.warn',
2783
+ 'invariant',
2784
+ 'warning',
2785
+ '__DEV__',
2786
+ 'ReactDOM.render',
2787
+ 'ReactDOM.unmountComponentAtNode',
2788
+ 'ReactDOM.findDOMNode',
2789
+ 'ReactDOM.createPortal',
2790
+ ],
2791
+ passes: 3,
2792
+ unsafe: true,
2793
+ unsafe_comps: true,
2794
+ unsafe_Function: true,
2795
+ unsafe_math: true,
2796
+ unsafe_symbols: true,
2797
+ unsafe_methods: true,
2798
+ unsafe_proto: true,
2799
+ unsafe_regexp: true,
2800
+ unsafe_undefined: true,
2801
+ dead_code: true,
2802
+ side_effects: false,
2803
+ },
2804
+ mangle: {
2805
+ safari10: true,
2806
+ properties: {
2807
+ regex: /^_/,
2808
+ },
2809
+ },
2810
+ format: {
2811
+ comments: false,
2812
+ },
2813
+ },
2814
+ },
2815
+ }
2816
+ }
2817
+
2391
2818
  export function defineRariConfig(
2392
2819
  config: UserConfig & { plugins?: Plugin[] },
2393
2820
  ): UserConfig {