Skip to content

Commit 385b0a8

Browse files
fix source map issue and remove global variable React
1 parent f71f284 commit 385b0a8

File tree

11 files changed

+127
-91
lines changed

11 files changed

+127
-91
lines changed

example/index.html

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,24 +2,27 @@
22
<html lang="en">
33

44
<title>myPage</title>
5-
<script crossorigin src="https://unpkg.com/react@16/umd/react.production.min.js"></script>
6-
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js"></script>
7-
<script crossorigin src="https://unpkg.com/[email protected]/babel.min.js"></script>
8-
<script src="../dist/stringToReactComponent.umd.min.js"></script>
5+
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
6+
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
7+
<!-- <script crossorigin src="https://unpkg.com/[email protected]/babel.min.js"></script> -->
8+
<!-- <script crossorigin src="https://unpkg.com/babel-standalone@latest/babel.min.js"></script> -->
9+
<script crossorigin src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
10+
<script src="../build/stringToReactComponent.umd.js"></script>
911

1012
<body>
1113

1214
<div id="root"></div>
1315

1416
<script type="text/babel">
15-
const StringToReactComponent = window.StringToReactComponent;
17+
const StringToReactComponent = window.StringToReactComponent?.default||window.StringToReactComponent;
1618
const Welcome = function Welcome(props) {
1719

1820
return (<StringToReactComponent>
1921
{`(props)=>{
2022
const {useState}=React;
2123
const [counter,setCounter]=useState(0);
2224
const increase=()=>{
25+
2326
setCounter(counter+1);
2427
};
2528
return (<div>

example/stories/data-prop/README.md

Lines changed: 0 additions & 52 deletions
This file was deleted.

example/stories/source-map/README.md renamed to example/stories/filename-option/README.md

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,9 @@ import StringToReactComponent from 'string-to-react-component';
33

44
function App() {
55
return (
6-
<StringToReactComponent babelOptions={{filename: 'counter.js', sourceMaps: 'inline'}}>
6+
<StringToReactComponent babelOptions={{filename: 'counter.js'}}>
77
{`(props)=>{
8-
const {useState}=React;
9-
const [counter,setCounter]=useState(0);
8+
const [counter,setCounter]=React.useState(0);
109
const increase=()=>{
1110
setCounter(counter+1);
1211
};

example/stories/typescript/README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,10 @@ function App() {
55
return (
66
<StringToReactComponent
77
babelOptions={{filename: 'counter.ts', presets: [['typescript', {allExtensions: true, isTSX: true}]]}}>
8-
{`()=>{
8+
{`(props)=>{
99
const [counter,setCounter]=React.useState<number>(0);
1010
const increase=()=>{
11+
1112
setCounter(counter+1);
1213
};
1314
return (<>

example/stories/usage/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ function App() {
44
return (
55
<StringToReactComponent>
66
{`(props)=>{
7-
const {useState}=React; // React can be used as a global variable
8-
const [counter,setCounter]=useState(0);
7+
const [counter,setCounter]=React.useState(0);
98
const increase=()=>{
9+
1010
setCounter(counter+1);
1111
};
1212
return (<>
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
```jsx
2+
import StringToReactComponent from 'string-to-react-component';
3+
4+
function MyFirstComponent() {
5+
return <p>This is my first component.</p>;
6+
}
7+
function MySecondComponent() {
8+
return <p>This is my second component.</p>;
9+
}
10+
11+
function App() {
12+
return (
13+
<StringToReactComponent data={{MyFirstComponent, MySecondComponent}}>
14+
{`(props)=>{
15+
const {MyFirstComponent, MySecondComponent}=props;
16+
return (<>
17+
<MyFirstComponent/>
18+
<MySecondComponent/>
19+
</>);
20+
}`}
21+
</StringToReactComponent>
22+
);
23+
}
24+
<App />;
25+
```
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
Your imported object including `useState`, `useEffect`, `useRef` and ... are not accessible inside the string code but you can get them from `React` object ( by default `React` object is emmbed into your string code ) or pass them as the `data` prop
2+
3+
```jsx
4+
import {useState} from 'react';
5+
import StringToReactComponent from 'string-to-react-component';
6+
7+
function App() {
8+
return (
9+
<StringToReactComponent data={{useState}}>
10+
{`(props)=>{
11+
return (<>
12+
<p>type of imported useState is {typeof useState}</p>
13+
<p>type of React.useState is {typeof React.useState}</p>
14+
<p>type of React is {typeof React} ( by default React object is emmbed into your string code )</p>
15+
<p>type of props.useState is {typeof props.useState}</p>
16+
</>);
17+
}`}
18+
</StringToReactComponent>
19+
);
20+
}
21+
<App />;
22+
```

src/ctx.tsx

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,21 +8,27 @@ class Ctx implements IStringToReactApi {
88
return null;
99
};
1010
_getBabel: () => TBabel;
11+
_getReact: () => TReact;
1112
constructor(React: TReact, Babel: TBabel) {
12-
if (typeof window === 'object') {
13-
window.React = window.React || React;
14-
}
13+
this._getReact = () => React;
1514
if (!Babel) {
1615
throw new Error(
1716
`Package "string-to-react-component" has a missing peer dependency of "@babel/standalone" ( requires ">=7.6.3" )`,
1817
);
1918
}
2019
this._getBabel = () => Babel;
2120
}
21+
_getBabelDefaultOptions(): TransformOptions {
22+
return {
23+
sourceMaps: 'inline',
24+
sourceType: 'module',
25+
};
26+
}
2227
_checkBabelOptions(babelOptions: TransformOptions) {
2328
if (Object.prototype.toString.call(babelOptions) !== '[object Object]') {
2429
throw new Error(`babelOptions prop of string-to-react-component element should be an object.`);
2530
}
31+
Object.assign(babelOptions, this._getBabelDefaultOptions(), babelOptions);
2632
if (Object.prototype.hasOwnProperty.call(babelOptions, 'presets') === false) {
2733
babelOptions.presets = ['react'];
2834
} else {
@@ -35,6 +41,37 @@ class Ctx implements IStringToReactApi {
3541
}
3642
}
3743
}
44+
getModule(code: string): Promise<any> {
45+
code = `import React from "react";\nexport default ${code}`;
46+
const op: TransformOptions = {
47+
presets: ['react', ['env', {modules: false}]],
48+
filename: 'counter.js',
49+
sourceMaps: 'inline',
50+
sourceType: 'module',
51+
};
52+
const resultObj = this._getBabel().transform(code, op);
53+
// 1. Define your module code as a string
54+
code = resultObj.code || '';
55+
code = code
56+
.replace('export default', 'export default (React)=>')
57+
.replace('import React from "react";', '//import React from "react";');
58+
59+
// 2. Create a Blob containing the module code
60+
const blob = new Blob([code], {type: 'application/javascript'});
61+
// 3. Create a URL for the Blob
62+
const moduleUrl = URL.createObjectURL(blob);
63+
// 4. Dynamically import the module using import()
64+
return import(/* webpackIgnore: true */ moduleUrl)
65+
.then((module) => {
66+
// Clean up by revoking the object URL
67+
URL.revokeObjectURL(moduleUrl);
68+
69+
return Promise.resolve((module?.default || module)(this._getReact()));
70+
})
71+
.catch((error) => {
72+
console.error('Error loading module:', error);
73+
});
74+
}
3875
_transpile(babelOptions: TransformOptions): string {
3976
// make sure react presets is registered in babelOptions
4077
this._checkBabelOptions(babelOptions);

src/strintToReact.tsx

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {useRef} from 'react';
1+
import React, {useRef, useEffect, useCallback, useState, type FC} from 'react';
22
import type {StringToReactComponentProps, IStringToReactApi, TBabel, TReact} from './types.d';
33
function StringToReactComponent(
44
deps: {getCtx: (react: TReact, Babel: TBabel) => IStringToReactApi; react: TReact; Babel: TBabel},
@@ -8,10 +8,26 @@ function StringToReactComponent(
88
let ref = useRef<any>(null);
99
ref.current = ref.current || getCtx(react, Babel);
1010
const api = ref.current as IStringToReactApi;
11-
const babelOptions = props.babelOptions || {};
12-
const GeneratedComponent = api.updateTemplate(props.children || '', babelOptions).getComponent();
11+
//const babelOptions = props.babelOptions || {};
12+
//const GeneratedComponent = api.updateTemplate(props.children || '', babelOptions).getComponent();
1313
const data = props.data || {};
14-
return <GeneratedComponent {...data} />;
14+
//
15+
const ModuleComponent = useCallback(
16+
(data: any) => {
17+
const ref = useRef<{Com: FC<any>}>({Com: (props) => <p>hhhhhhhhhhhhhhhhhh</p>});
18+
const [, rerender] = useState<object>({});
19+
useEffect(() => {
20+
api.getModule(props.children).then((Mod: FC) => {
21+
ref.current.Com = Mod;
22+
rerender({});
23+
});
24+
}, []);
25+
const Com = ref.current.Com;
26+
return <Com {...data} />;
27+
},
28+
[props.children],
29+
);
30+
return <ModuleComponent {...data} />;
1531
}
1632

1733
export default StringToReactComponent;

styleguide.config.js

Lines changed: 5 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -32,26 +32,11 @@ module.exports = {
3232
require: [path.join(__dirname, './example/stories/styles.css')],
3333
// assetsDir: "example/stories/assets",
3434
sections: [
35-
{
36-
name: 'Minimal Usage',
37-
content: 'example/stories/usage/README.md',
38-
sectionDepth: 1,
39-
},
40-
{
41-
name: 'data prop',
42-
content: 'example/stories/data-prop/README.md',
43-
sectionDepth: 1,
44-
},
45-
{
46-
name: 'Using source map',
47-
content: 'example/stories/source-map/README.md',
48-
sectionDepth: 1,
49-
},
50-
{
51-
name: 'Using Typescript',
52-
content: 'example/stories/typescript/README.md',
53-
sectionDepth: 1,
54-
},
35+
{name: 'Minimal Usage', content: 'example/stories/usage/README.md', sectionDepth: 1},
36+
{name: 'Using useState, useEffect and ...', content: 'example/stories/using-useState-useEffect/README.md'},
37+
{name: 'Using Unknown Elements', content: 'example/stories/using-unkown-elements/README.md', sectionDepth: 1},
38+
{name: 'filename option', content: 'example/stories/filename-option/README.md', sectionDepth: 1},
39+
{name: 'Using Typescript', content: 'example/stories/typescript/README.md', sectionDepth: 1},
5540
],
5641
styleguideComponents: {},
5742
pagePerSection: true,

0 commit comments

Comments
 (0)