@@ -2,54 +2,89 @@ import { readFileSync } from "node:fs";
22import { join } from "node:path" ;
33import type { PluginOption } from "vite" ;
44
5- let root = "" ;
6- let base = "" ;
5+ export const reactClickToComponent = ( ) : PluginOption => {
6+ let root = "" ;
7+ let base = "" ;
8+ let isServe = false ;
9+ let clientCode : string | undefined ;
710
8- export const reactClickToComponent = ( ) : PluginOption => ( {
9- name : "react-click-to-component" ,
10- apply : "serve" ,
11- configResolved ( config ) {
12- root = config . root ;
13- base = config . base ;
14- } ,
15- transformIndexHtml : ( ) => [
16- {
17- tag : "script" ,
18- attrs : { type : "module" } ,
19- children : readFileSync ( join ( import . meta. dirname , "client.js" ) , "utf-8" )
20- . replace ( "__ROOT__" , root )
21- . replace ( "__BASE__" , base ) ,
11+ return {
12+ name : "react-click-to-component" ,
13+ configResolved ( config ) {
14+ root = config . root ;
15+ base = config . base ;
16+ isServe = config . command === "serve" ;
2217 } ,
23- ] ,
24- transform : {
25- filter : { id : / j s x - d e v - r u n t i m e \. j s / u } ,
26- handler ( code ) {
27- if ( code . includes ( "_source" ) ) return ; // React <19, no hack needed
28- // React 19, inject source into _debugInfo
29- const defineIndex = code . indexOf ( '"_debugInfo"' ) ;
30- if ( defineIndex === - 1 ) return ;
31- const valueIndex = code . indexOf ( "value: null" , defineIndex ) ;
32- if ( valueIndex === - 1 ) return ;
33- let newCode =
34- code . slice ( 0 , valueIndex )
35- + "value: source"
36- + code . slice ( valueIndex + 11 ) ;
37- if ( code . includes ( "function ReactElement(type, key, self, source," ) ) {
18+
19+ // Fix React 19 not injecting source in jsxDEV
20+ transform : {
21+ filter : { id : / j s x - d e v - r u n t i m e \. j s / u } ,
22+ handler ( code ) {
23+ if ( ! isServe ) return ;
24+ if ( code . includes ( "_source" ) ) return ; // React <19, no hack needed
25+
26+ // React 19, inject source into _debugInfo
27+ const defineIndex = code . indexOf ( '"_debugInfo"' ) ;
28+ if ( defineIndex === - 1 ) return ;
29+ const valueIndex = code . indexOf ( "value: null" , defineIndex ) ;
30+ if ( valueIndex === - 1 ) return ;
31+ let newCode =
32+ code . slice ( 0 , valueIndex )
33+ + "value: source"
34+ + code . slice ( valueIndex + 11 ) ;
35+ if ( code . includes ( "function ReactElement(type, key, self, source," ) ) {
36+ return newCode ;
37+ }
38+
39+ // React 19.2: we need to inject source jsxDEV -> jsxDEVImpl -> ReactElement
40+ newCode = newCode . replaceAll (
41+ / m a y b e K e y , \s * i s S t a t i c C h i l d r e n / gu,
42+ "maybeKey, isStaticChildren, source" ,
43+ ) ;
44+ newCode = newCode . replaceAll (
45+ / ( \w + ) ? , \s * d e b u g S t a c k , \s * d e b u g T a s k / gu,
46+ ( m , previousArg ) => {
47+ if ( previousArg === "source" ) return m ;
48+ return m . replace ( "debugTask" , "debugTask, source" ) ;
49+ } ,
50+ ) ;
3851 return newCode ;
39- }
40- // React 19.2: we need to inject source jsxDEV -> jsxDEVImpl -> ReactElement
41- newCode = newCode . replaceAll (
42- / m a y b e K e y , \s * i s S t a t i c C h i l d r e n / gu,
43- "maybeKey, isStaticChildren, source" ,
44- ) ;
45- newCode = newCode . replaceAll (
46- / ( \w + ) ? , \s * d e b u g S t a c k , \s * d e b u g T a s k / gu,
47- ( m , previousArg ) => {
48- if ( previousArg === "source" ) return m ;
49- return m . replace ( "debugTask" , "debugTask, source" ) ;
52+ } ,
53+ } ,
54+
55+ // Default: Inject client via transformIndexHtml (no source code modification required)
56+ transformIndexHtml ( ) {
57+ if ( ! isServe ) return ;
58+ return [
59+ {
60+ tag : "script" ,
61+ attrs : { type : "module" } ,
62+ children :
63+ 'import "/@id/__x00__vite-plugin-react-click-to-component/client";' ,
5064 } ,
51- ) ;
52- return newCode ;
65+ ] ;
66+ } ,
67+
68+ // Inject with `import "vite-plugin-react-click-to-component/client"` for SSR frameworks
69+ resolveId : {
70+ order : "pre" ,
71+ filter : { id : / ^ v i t e - p l u g i n - r e a c t - c l i c k - t o - c o m p o n e n t \/ c l i e n t $ / u } ,
72+ handler ( source ) {
73+ return "\0" + source ;
74+ } ,
75+ } ,
76+ load : {
77+ filter : { id : / ^ \0 v i t e - p l u g i n - r e a c t - c l i c k - t o - c o m p o n e n t \/ c l i e n t $ / u } ,
78+ handler ( ) {
79+ if ( ! isServe ) return "" ;
80+ if ( ! clientCode ) {
81+ clientCode = readFileSync (
82+ join ( import . meta. dirname , "client.js" ) ,
83+ "utf-8" ,
84+ ) ;
85+ }
86+ return clientCode . replace ( "__ROOT__" , root ) . replace ( "__BASE__" , base ) ;
87+ } ,
5388 } ,
54- } ,
55- } ) ;
89+ } ;
90+ } ;
0 commit comments