Skip to content

Commit 23effcc

Browse files
authored
improve(transform): use sucrase instead of @swc/wasm-web to improve transcoding performance (#38)
1 parent e4b58de commit 23effcc

File tree

7 files changed

+84
-68
lines changed

7 files changed

+84
-68
lines changed

README.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,12 +99,11 @@ The source code is written in markdown, refer to [example.md](https://raw.github
9999
| afterCompile | (code: string) => string | | Executed after compiling the code |
100100
| beforeCompile | (code: string) => string | | Executed before compiling the code |
101101
| children | any | | The code to be rendered is executed. Usually imported via markdown-loader |
102-
| compiler | (code: string) => string | | A compiler that transforms the code. Use swc.transformSync by default |
103102
| dependencies | object | | Dependent objects required by the executed code |
104103
| editable | boolean | false | Renders a code editor that can modify the source code |
105104
| editor | object | | Editor properties |
106105
| onChange | (code?: string) => void | | Callback triggered after code change |
107106
| renderToolbar | (buttons: ReactNode) => ReactNode | | Customize the rendering toolbar |
108107
| sourceCode | string | | The code to be rendered is executed |
109108
| theme | 'light' , 'dark' | 'light' | Code editor theme, applied to CodeMirror |
110-
| compileOptions | object | defaultTransformOptions | swc configuration https://swc.rs/docs/configuration/compilation |
109+
| compileOptions | object | defaultTransformOptions | https://github.com/alangpierce/sucrase#transforms |

docs/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ const App = () => {
1515
theme="dark"
1616
dependencies={{ Button }}
1717
afterCompile={(code: string) => {
18-
return code.replace(/import\ [\w\,\{\}\ ]+\ from\ "[\w-]+";/gi, '');
18+
return code.replace(/import\ [\*\w\,\{\}\ ]+\ from\ ?[\."'@/\w-]+;/gi, '');
1919
}}
2020
>
2121
{example}

package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,13 +43,13 @@
4343
"dependencies": {
4444
"@babel/runtime": "^7.18.6",
4545
"@rsuite/icons": "^1.0.2",
46-
"@swc/wasm-web": "^1.2.208",
4746
"@types/codemirror": "5.60.5",
4847
"classnames": "^2.2.5",
4948
"codemirror": "5.65.6",
5049
"highlight.js": "^11.5.1",
5150
"html-loader": "^3.1.2",
52-
"marked": "^4.0.17"
51+
"marked": "^4.0.17",
52+
"sucrase": "^3.24.0"
5353
},
5454
"peerDependencies": {
5555
"react": ">=16.8.0",

pnpm-lock.yaml

Lines changed: 55 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/CodeView.tsx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@ const CodeView = React.forwardRef((props: CodeViewProps, ref: React.Ref<HTMLDivE
2424
renderToolbar,
2525
onChange,
2626
beforeCompile,
27-
compiler,
2827
afterCompile,
2928
...rest
3029
} = props;
@@ -47,7 +46,6 @@ const CodeView = React.forwardRef((props: CodeViewProps, ref: React.Ref<HTMLDivE
4746
renderToolbar={renderToolbar}
4847
onChange={onChange}
4948
beforeCompile={beforeCompile}
50-
compiler={compiler}
5149
afterCompile={afterCompile}
5250
editor={editor}
5351
/>

src/Renderer.tsx

Lines changed: 18 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
/* eslint-disable @typescript-eslint/no-var-requires */
2-
import { useEffect, useState, useCallback, useRef } from 'react';
2+
import { useEffect, useState, useCallback } from 'react';
33
import CodeIcon from '@rsuite/icons/Code';
44
import classNames from 'classnames';
5+
import { transform as transformCode, Options } from 'sucrase';
56
import CodeEditor from './CodeEditor';
67
import Preview from './Preview';
78
import canUseDOM from './utils/canUseDOM';
9+
import evalCode from './utils/evalCode';
810

911
const React = require('react');
1012
const ReactDOM = require('react-dom');
@@ -37,38 +39,24 @@ export interface RendererProps extends Omit<React.HTMLAttributes<HTMLElement>, '
3739
};
3840

3941
/**
40-
* swc configuration
41-
* https://swc.rs/docs/configuration/compilation
42+
* https://github.com/alangpierce/sucrase#transforms
4243
*/
43-
transformOptions?: object;
44+
transformOptions?: Options;
4445

4546
/** Customize the rendering toolbar */
4647
renderToolbar?: (buttons: React.ReactNode) => React.ReactNode;
4748

4849
/** Callback triggered after code change */
4950
onChange?: (code?: string) => void;
5051

51-
/**
52-
* A compiler that transforms the code. Use swc.transformSync by default
53-
* See https://swc.rs/docs/usage/wasm
54-
*/
55-
compiler?: (code: string) => string;
56-
5752
/** Executed before compiling the code */
5853
beforeCompile?: (code: string) => string;
5954

6055
/** Executed after compiling the code */
6156
afterCompile?: (code: string) => string;
6257
}
6358

64-
const defaultTransformOptions = {
65-
jsc: {
66-
parser: {
67-
syntax: 'ecmascript',
68-
jsx: true
69-
}
70-
}
71-
};
59+
const defaultTransformOptions: Options = { transforms: ['jsx'] };
7260

7361
const Renderer = React.forwardRef((props: RendererProps, ref: React.Ref<HTMLDivElement>) => {
7462
const {
@@ -81,7 +69,6 @@ const Renderer = React.forwardRef((props: RendererProps, ref: React.Ref<HTMLDivE
8169
renderToolbar,
8270
onChange,
8371
beforeCompile,
84-
compiler,
8572
afterCompile,
8673
...rest
8774
} = props;
@@ -94,21 +81,6 @@ const Renderer = React.forwardRef((props: RendererProps, ref: React.Ref<HTMLDivE
9481
...editorProps
9582
} = editor;
9683

97-
const [initialized, setInitialized] = useState(false);
98-
const transfrom = useRef<any>(null);
99-
100-
useEffect(() => {
101-
if (!canUseDOM) {
102-
return;
103-
}
104-
105-
import('@swc/wasm-web').then(async module => {
106-
await module.default();
107-
transfrom.current = module.transformSync;
108-
setInitialized(true);
109-
});
110-
}, []);
111-
11284
const [editable, setEditable] = useState(isEditable);
11385
const [hasError, setHasError] = useState(false);
11486
const [errorMessage, setErrorMessage] = useState(null);
@@ -139,18 +111,16 @@ const Renderer = React.forwardRef((props: RendererProps, ref: React.Ref<HTMLDivE
139111
};
140112

141113
try {
142-
const statement = dependencies
143-
? Object.keys(dependencies).map(key => `var ${key}= dependencies.${key};`)
144-
: [];
145-
146114
const beforeCompileCode = beforeCompile?.(pendCode) || pendCode;
147115

148116
if (beforeCompileCode) {
149-
const { code: compiledCode } = compiler
150-
? compiler(beforeCompileCode)
151-
: transfrom.current?.(beforeCompileCode, transformOptions);
117+
const { code: compiledCode } = transformCode(beforeCompileCode, transformOptions);
152118

153-
eval(`${statement.join('\n')} ${afterCompile?.(compiledCode) || compiledCode}`);
119+
evalCode(afterCompile?.(compiledCode) || compiledCode, {
120+
React,
121+
ReactDOM,
122+
...dependencies
123+
});
154124
}
155125
} catch (err) {
156126
console.error(err);
@@ -159,26 +129,22 @@ const Renderer = React.forwardRef((props: RendererProps, ref: React.Ref<HTMLDivE
159129
ReactDOM.render = originalRender;
160130
}
161131
},
162-
[code, dependencies, beforeCompile, compiler, transformOptions, afterCompile]
132+
[code, dependencies, beforeCompile, transformOptions, afterCompile]
163133
);
164134

165135
useEffect(() => {
166-
if (initialized) {
167-
executeCode(code);
168-
}
169-
}, [initialized, code, executeCode]);
136+
executeCode(code);
137+
}, [code, executeCode]);
170138

171139
const handleCodeChange = useCallback(
172140
(code?: string) => {
173141
setHasError(false);
174142
setErrorMessage(null);
175143
onChange?.(code);
176144

177-
if (initialized) {
178-
executeCode(code);
179-
}
145+
executeCode(code);
180146
},
181-
[executeCode, initialized, onChange]
147+
[executeCode, onChange]
182148
);
183149

184150
const codeButton = (
@@ -197,7 +163,7 @@ const Renderer = React.forwardRef((props: RendererProps, ref: React.Ref<HTMLDivE
197163
</button>
198164
);
199165

200-
const showCodeEditor = editable && code && initialized;
166+
const showCodeEditor = editable && code;
201167

202168
return (
203169
<div className="rcv-container" {...rest} ref={ref}>

src/utils/evalCode.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
const evalCode = (code, scope) => {
2+
const scopeKeys = Object.keys(scope);
3+
const scopeValues = scopeKeys.map(key => scope[key]);
4+
return new Function(...scopeKeys, code)(...scopeValues);
5+
};
6+
7+
export default evalCode;

0 commit comments

Comments
 (0)