@@ -3,13 +3,15 @@ import type {TBabel, TReact, IStringToReactApi} from './types.d';
3
3
import { FC } from 'react' ;
4
4
class Ctx implements IStringToReactApi {
5
5
_temp : string = '' ;
6
- _parentTemp : string = `"use strict";\nreturn @temp;` ;
6
+ _blob : Blob | undefined = undefined ;
7
+ _rerender : ( state : { } ) => void = ( ) => { } ;
7
8
_com : FC = function ( ) {
8
9
return null ;
9
10
} ;
10
11
_getBabel : ( ) => TBabel ;
11
12
_getReact : ( ) => TReact ;
12
- constructor ( React : TReact , Babel : TBabel ) {
13
+ constructor ( React : TReact , Babel : TBabel , rerender : ( state : { } ) => void ) {
14
+ this . _rerender = rerender ;
13
15
this . _getReact = ( ) => React ;
14
16
if ( ! Babel ) {
15
17
throw new Error (
@@ -22,6 +24,9 @@ class Ctx implements IStringToReactApi {
22
24
if ( Object . prototype . toString . call ( babelOptions ) !== '[object Object]' ) {
23
25
throw new Error ( `babelOptions prop of string-to-react-component element should be an object.` ) ;
24
26
}
27
+ if ( Object . prototype . hasOwnProperty . call ( babelOptions , 'sourceMaps' ) === false ) {
28
+ babelOptions . sourceMaps = 'inline' ;
29
+ }
25
30
if ( Object . prototype . hasOwnProperty . call ( babelOptions , 'presets' ) === false ) {
26
31
babelOptions . presets = [ 'react' ] ;
27
32
} else {
@@ -34,49 +39,44 @@ class Ctx implements IStringToReactApi {
34
39
}
35
40
}
36
41
}
37
- getModule ( code : string , babelOptions : TransformOptions ) : Promise < any > {
38
- this . _checkBabelOptions ( babelOptions ) ;
39
- code = `import React from "react";\nexport default ${ code } ` ;
40
- const resultObj = this . _getBabel ( ) . transform ( code , babelOptions ) ;
41
- // 1. Define your module code as a string
42
- code = resultObj . code || '' ;
43
- code = code
42
+ _prependCode ( template : string ) : IStringToReactApi {
43
+ this . _temp = `import React from "react";\nexport default ${ template } ` ;
44
+ return this ;
45
+ }
46
+ _postpendCode ( ) : string {
47
+ return this . _temp
44
48
. replace ( 'export default' , 'export default (React)=>' )
45
49
. replace ( 'import React from "react";' , '//import React from "react";' ) ;
46
-
47
- // 2. Create a Blob containing the module code
48
- const blob = new Blob ( [ code ] , { type : 'application/javascript' } ) ;
49
- // 3. Create a URL for the Blob
50
+ }
51
+ _getBlob ( temp : string ) : Blob {
52
+ return new Blob ( [ temp ] , { type : 'application/javascript' } ) ;
53
+ }
54
+ _getModule ( blob : Blob ) : Promise < FC > {
50
55
const moduleUrl = URL . createObjectURL ( blob ) ;
51
- // 4. Dynamically import the module using import()
52
56
return import ( /* webpackIgnore: true */ moduleUrl )
53
57
. then ( ( module ) => {
54
- // Clean up by revoking the object URL
55
58
URL . revokeObjectURL ( moduleUrl ) ;
56
-
57
59
return Promise . resolve ( ( module ?. default || module ) ( this . _getReact ( ) ) ) ;
58
60
} )
59
61
. catch ( ( error ) => {
60
- console . error ( 'Error loading module:' , error ) ;
62
+ URL . revokeObjectURL ( moduleUrl ) ;
63
+ const errorTitle : string = 'string-to-react-component loading module is failed:' ;
64
+ console . error ( errorTitle , error ) ;
65
+ throw new Error ( errorTitle ) ;
61
66
} ) ;
62
67
}
63
- _transpile ( babelOptions : TransformOptions ) : string {
64
- // make sure react presets is registered in babelOptions
68
+ _transpile ( babelOptions : TransformOptions ) : IStringToReactApi {
65
69
this . _checkBabelOptions ( babelOptions ) ;
66
70
const resultObj = this . _getBabel ( ) . transform ( this . _temp , babelOptions ) ;
67
- const filename = babelOptions . filename ;
68
71
let code = resultObj . code ;
69
- if ( filename ) {
70
- code = resultObj . code + `\n//# sourceURL=${ filename } ` ;
71
- }
72
- return code || 'null' ;
73
- }
74
- _generateCom ( babelOptions : any ) {
75
- this . _com = Function ( this . _parentTemp . replace ( '@temp' , this . _transpile ( babelOptions ) ) ) ( ) ;
76
- this . _validateCodeInsideTheTemp ( ) ;
72
+ // if (babelOptions.filename) {
73
+ // code = resultObj.code + `\n//# sourceURL=${babelOptions.filename}`;
74
+ // }
75
+ this . _temp = code || 'null' ;
76
+ return this ;
77
77
}
78
- _validateCodeInsideTheTemp ( ) {
79
- if ( typeof this . _com !== 'function' ) {
78
+ _validateCodeInsideTheTemp ( com : any ) : void {
79
+ if ( typeof com !== 'function' ) {
80
80
throw new Error ( `code inside the passed string into string-to-react-component, should be a function` ) ;
81
81
}
82
82
}
@@ -88,13 +88,26 @@ class Ctx implements IStringToReactApi {
88
88
throw new Error ( `passed string into string-to-react-component element can not be empty` ) ;
89
89
}
90
90
}
91
- updateTemplate ( template : string , babelOptions : TransformOptions ) : IStringToReactApi {
92
- this . _validateTemplate ( template ) ;
91
+ /** update transpiled code */
92
+ _updateTemplate ( template : string , babelOptions : TransformOptions ) : string {
93
93
if ( template !== this . _temp ) {
94
- this . _temp = template ;
95
- this . _generateCom ( babelOptions ) ;
94
+ this . _validateTemplate ( template ) ;
95
+ return this . _prependCode ( template ) . _transpile ( babelOptions ) . _postpendCode ( ) ;
96
96
}
97
- return this ;
97
+ return this . _temp ;
98
+ }
99
+ update ( template : string , babelOptions : TransformOptions ) : void {
100
+ this . _updateComponent ( this . _updateTemplate ( template , babelOptions ) , babelOptions ) ;
101
+ }
102
+ _onChangeComponent ( ) : void {
103
+ this . _rerender ( { } ) ;
104
+ }
105
+ _updateComponent ( template : string , babelOptions : TransformOptions ) : void {
106
+ this . _getModule ( this . _getBlob ( template ) ) . then ( ( com : FC ) => {
107
+ this . _validateCodeInsideTheTemp ( com ) ;
108
+ this . _com = com ;
109
+ this . _onChangeComponent ( ) ;
110
+ } ) ;
98
111
}
99
112
getComponent ( ) : FC {
100
113
return this . _com ;
0 commit comments