mirror of
https://github.com/danbulant/oxc
synced 2026-05-19 04:08:41 +00:00
feat(transformer): support react fast refresh (#4587)
close: #3943
## Further improvements
There is a double visit here. We need to collect all react hooks calling in `Function` and `ArrowFunctionExpression`. If we want to remove this implementation, we may wait for #4188.
d797e595d2/crates/oxc_transformer/src/react/refresh.rs (L744-L947)
## Tests
All tests copy from https://github.com/facebook/react/blob/main/packages/react-refresh/src/__tests__/ReactFresh-test.js
There are still 4 tests that have not been passed
**1. refresh/can-handle-implicit-arrow-returns/input.jsx**
Related to #4767. transform correct, just output doesn't match the expected output
**2. refresh/registers-identifiers-used-in-jsx-at-definition-site/input.jsx**
**3. refresh/registers-identifiers-used-in-react-create-element-at-definition-site/input.jsx**
Blocked by #4746
**4. refresh/supports-typescript-namespace-syntax/input.tsx**
oxc transforms ts to js first, so probably we can ignore this case. If we really want to pass this test, we also need to turn off `TypeScript` plugin.
## What's next?
### Options:
1. Support transform `refresh_reg` and `refresh_sig` options to `MemberExpression`. Currently `import.meta.xxxx` still is an `Identifier`
2. Support `emit_full_signatures` option
### Other
NAPI, testing in `monitor-oxc`, etc..
This commit is contained in:
parent
b3ec9e50bd
commit
f1fcdde593
62 changed files with 1972 additions and 7 deletions
|
|
@ -45,7 +45,7 @@ pub use crate::{
|
|||
env::EnvOptions,
|
||||
es2015::{ArrowFunctionsOptions, ES2015Options},
|
||||
options::{BabelOptions, TransformOptions},
|
||||
react::{ReactJsxRuntime, ReactOptions},
|
||||
react::{ReactJsxRuntime, ReactOptions, ReactRefreshOptions},
|
||||
typescript::TypeScriptOptions,
|
||||
};
|
||||
use crate::{
|
||||
|
|
@ -127,6 +127,7 @@ impl<'a> Transformer<'a> {
|
|||
impl<'a> Traverse<'a> for Transformer<'a> {
|
||||
fn enter_program(&mut self, program: &mut Program<'a>, ctx: &mut TraverseCtx<'a>) {
|
||||
self.x0_typescript.transform_program(program, ctx);
|
||||
self.x1_react.transform_program(program, ctx);
|
||||
}
|
||||
|
||||
fn exit_program(&mut self, program: &mut Program<'a>, ctx: &mut TraverseCtx<'a>) {
|
||||
|
|
@ -183,6 +184,7 @@ impl<'a> Traverse<'a> for Transformer<'a> {
|
|||
}
|
||||
|
||||
fn exit_expression(&mut self, expr: &mut Expression<'a>, ctx: &mut TraverseCtx<'a>) {
|
||||
self.x1_react.transform_expression_on_exit(expr, ctx);
|
||||
self.x3_es2015.transform_expression_on_exit(expr, ctx);
|
||||
}
|
||||
|
||||
|
|
@ -265,6 +267,7 @@ impl<'a> Traverse<'a> for Transformer<'a> {
|
|||
|
||||
fn enter_statements(&mut self, stmts: &mut Vec<'a, Statement<'a>>, ctx: &mut TraverseCtx<'a>) {
|
||||
self.x0_typescript.transform_statements(stmts);
|
||||
self.x1_react.transform_statements(stmts, ctx);
|
||||
self.x2_es2021.transform_statements(stmts, ctx);
|
||||
self.x2_es2020.transform_statements(stmts, ctx);
|
||||
self.x2_es2016.transform_statements(stmts, ctx);
|
||||
|
|
@ -273,6 +276,7 @@ impl<'a> Traverse<'a> for Transformer<'a> {
|
|||
|
||||
fn exit_statements(&mut self, stmts: &mut Vec<'a, Statement<'a>>, ctx: &mut TraverseCtx<'a>) {
|
||||
self.x0_typescript.transform_statements_on_exit(stmts, ctx);
|
||||
self.x1_react.transform_statements_on_exit(stmts, ctx);
|
||||
self.x2_es2021.transform_statements_on_exit(stmts, ctx);
|
||||
self.x2_es2020.transform_statements_on_exit(stmts, ctx);
|
||||
self.x2_es2016.transform_statements_on_exit(stmts, ctx);
|
||||
|
|
|
|||
|
|
@ -4,17 +4,20 @@ mod jsx;
|
|||
mod jsx_self;
|
||||
mod jsx_source;
|
||||
mod options;
|
||||
mod refresh;
|
||||
mod utils;
|
||||
|
||||
use std::rc::Rc;
|
||||
|
||||
use oxc_allocator::Vec;
|
||||
use oxc_ast::ast::*;
|
||||
use oxc_traverse::TraverseCtx;
|
||||
use refresh::ReactRefresh;
|
||||
|
||||
pub use self::{
|
||||
display_name::ReactDisplayName,
|
||||
jsx::ReactJsx,
|
||||
options::{ReactJsxRuntime, ReactOptions},
|
||||
options::{ReactJsxRuntime, ReactOptions, ReactRefreshOptions},
|
||||
};
|
||||
use crate::context::Ctx;
|
||||
|
||||
|
|
@ -29,10 +32,12 @@ use crate::context::Ctx;
|
|||
pub struct React<'a> {
|
||||
jsx: ReactJsx<'a>,
|
||||
display_name: ReactDisplayName<'a>,
|
||||
refresh: ReactRefresh<'a>,
|
||||
jsx_plugin: bool,
|
||||
display_name_plugin: bool,
|
||||
jsx_self_plugin: bool,
|
||||
jsx_source_plugin: bool,
|
||||
refresh_plugin: bool,
|
||||
}
|
||||
|
||||
// Constructors
|
||||
|
|
@ -49,29 +54,61 @@ impl<'a> React<'a> {
|
|||
jsx_source_plugin,
|
||||
..
|
||||
} = options;
|
||||
let refresh = options.refresh.clone();
|
||||
Self {
|
||||
jsx: ReactJsx::new(options, Rc::clone(&ctx)),
|
||||
display_name: ReactDisplayName::new(ctx),
|
||||
display_name: ReactDisplayName::new(Rc::clone(&ctx)),
|
||||
jsx_plugin,
|
||||
display_name_plugin,
|
||||
jsx_self_plugin,
|
||||
jsx_source_plugin,
|
||||
refresh_plugin: refresh.is_some(),
|
||||
refresh: ReactRefresh::new(&refresh.unwrap_or_default(), ctx),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Transforms
|
||||
impl<'a> React<'a> {
|
||||
pub fn transform_program(&mut self, program: &mut Program<'a>, ctx: &mut TraverseCtx<'a>) {
|
||||
if self.refresh_plugin {
|
||||
self.refresh.transform_program(program, ctx);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn transform_program_on_exit(
|
||||
&mut self,
|
||||
program: &mut Program<'a>,
|
||||
ctx: &mut TraverseCtx<'a>,
|
||||
) {
|
||||
if self.refresh_plugin {
|
||||
self.refresh.transform_program_on_exit(program, ctx);
|
||||
}
|
||||
if self.jsx_plugin {
|
||||
self.jsx.transform_program_on_exit(program, ctx);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn transform_statements(
|
||||
&mut self,
|
||||
stmts: &mut Vec<'a, Statement<'a>>,
|
||||
ctx: &mut TraverseCtx<'a>,
|
||||
) {
|
||||
if self.refresh_plugin {
|
||||
self.refresh.transform_statements(stmts, ctx);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn transform_statements_on_exit(
|
||||
&mut self,
|
||||
stmts: &mut Vec<'a, Statement<'a>>,
|
||||
ctx: &mut TraverseCtx<'a>,
|
||||
) {
|
||||
if self.refresh_plugin {
|
||||
self.refresh.transform_statements_on_exit(stmts, ctx);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn transform_expression(&mut self, expr: &mut Expression<'a>, ctx: &mut TraverseCtx<'a>) {
|
||||
if self.jsx_plugin {
|
||||
match expr {
|
||||
|
|
@ -87,9 +124,9 @@ impl<'a> React<'a> {
|
|||
}
|
||||
|
||||
pub fn transform_call_expression(
|
||||
&self,
|
||||
&mut self,
|
||||
call_expr: &mut CallExpression<'a>,
|
||||
ctx: &TraverseCtx<'a>,
|
||||
ctx: &mut TraverseCtx<'a>,
|
||||
) {
|
||||
if self.display_name_plugin {
|
||||
self.display_name.transform_call_expression(call_expr, ctx);
|
||||
|
|
@ -108,4 +145,14 @@ impl<'a> React<'a> {
|
|||
self.jsx.jsx_source.transform_jsx_opening_element(elem, ctx);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn transform_expression_on_exit(
|
||||
&mut self,
|
||||
expr: &mut Expression<'a>,
|
||||
ctx: &mut TraverseCtx<'a>,
|
||||
) {
|
||||
if self.refresh_plugin {
|
||||
self.refresh.transform_expression_on_exit(expr, ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -104,6 +104,9 @@ pub struct ReactOptions {
|
|||
///
|
||||
/// This value is used to skip Babel tests, and is not used in oxc.
|
||||
pub use_spread: Option<bool>,
|
||||
|
||||
/// Fast Refresh
|
||||
pub refresh: Option<ReactRefreshOptions>,
|
||||
}
|
||||
|
||||
impl Default for ReactOptions {
|
||||
|
|
@ -122,6 +125,7 @@ impl Default for ReactOptions {
|
|||
pragma_frag: None,
|
||||
use_built_ins: None,
|
||||
use_spread: None,
|
||||
refresh: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -186,3 +190,38 @@ impl ReactOptions {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
#[serde(default, rename_all = "camelCase", deny_unknown_fields)]
|
||||
pub struct ReactRefreshOptions {
|
||||
/// Specify the identifier of the refresh registration variable.
|
||||
/// Defaults to `$RefreshReg$`.
|
||||
#[serde(default = "default_refresh_reg")]
|
||||
pub refresh_reg: String,
|
||||
|
||||
/// Specify the identifier of the refresh signature variable.
|
||||
/// Defaults to `$RefreshSig$`.
|
||||
#[serde(default = "default_refresh_sig")]
|
||||
pub refresh_sig: String,
|
||||
|
||||
#[serde(default)]
|
||||
pub emit_full_signatures: bool,
|
||||
}
|
||||
|
||||
impl Default for ReactRefreshOptions {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
refresh_reg: default_refresh_reg(),
|
||||
refresh_sig: default_refresh_sig(),
|
||||
emit_full_signatures: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn default_refresh_reg() -> String {
|
||||
String::from("$RefreshReg$")
|
||||
}
|
||||
|
||||
fn default_refresh_sig() -> String {
|
||||
String::from("$RefreshSig$")
|
||||
}
|
||||
|
|
|
|||
1036
crates/oxc_transformer/src/react/refresh.rs
Normal file
1036
crates/oxc_transformer/src/react/refresh.rs
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -1,10 +1,9 @@
|
|||
commit: 12619ffe
|
||||
|
||||
Passed: 6/9
|
||||
Passed: 28/35
|
||||
|
||||
# All Passed:
|
||||
* babel-plugin-transform-optional-catch-binding
|
||||
* babel-plugin-transform-react-jsx
|
||||
|
||||
|
||||
# babel-plugin-transform-typescript (4/7)
|
||||
|
|
@ -12,3 +11,9 @@ Passed: 6/9
|
|||
* enum-member-reference/input.ts
|
||||
* export-elimination/input.ts
|
||||
|
||||
# babel-plugin-transform-react-jsx (23/27)
|
||||
* refresh/can-handle-implicit-arrow-returns/input.jsx
|
||||
* refresh/registers-identifiers-used-in-jsx-at-definition-site/input.jsx
|
||||
* refresh/registers-identifiers-used-in-react-create-element-at-definition-site/input.jsx
|
||||
* refresh/supports-typescript-namespace-syntax/input.tsx
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,6 @@
|
|||
export default () => useContext(X);
|
||||
export const Foo = () => useContext(X);
|
||||
module.exports = () => useContext(X);
|
||||
const Bar = () => useContext(X);
|
||||
const Baz = memo(() => useContext(X));
|
||||
const Qux = () => (0, useContext(X));
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
var _s = $RefreshSig$(), _s2 = $RefreshSig$(), _s3 = $RefreshSig$(), _s4 = $RefreshSig$(), _s5 = $RefreshSig$(), _s6 = $RefreshSig$();
|
||||
export default _s(() => {
|
||||
_s();
|
||||
return useContext(X);
|
||||
}, "useContext{}");
|
||||
export const Foo = () => {
|
||||
_s2();
|
||||
return useContext(X);
|
||||
};
|
||||
_s2(Foo, "useContext{}");
|
||||
_c = Foo;
|
||||
module.exports = _s3(() => {
|
||||
_s3();
|
||||
return useContext(X);
|
||||
}, "useContext{}");
|
||||
const Bar = () => {
|
||||
_s4();
|
||||
return useContext(X);
|
||||
};
|
||||
_s4(Bar, "useContext{}");
|
||||
_c2 = Bar;
|
||||
const Baz = _s5(memo(_c3 = _s5(() => {
|
||||
_s5();
|
||||
return useContext(X);
|
||||
}, "useContext{}")), "useContext{}");
|
||||
_c4 = Baz;
|
||||
const Qux = () => {
|
||||
_s6();
|
||||
return 0, useContext(X);
|
||||
};
|
||||
_s6(Qux, "useContext{}");
|
||||
_c5 = Qux;
|
||||
var _c, _c2, _c3, _c4, _c5;
|
||||
$RefreshReg$(_c, "Foo");
|
||||
$RefreshReg$(_c2, "Bar");
|
||||
$RefreshReg$(_c3, "Baz$memo");
|
||||
$RefreshReg$(_c4, "Baz");
|
||||
$RefreshReg$(_c5, "Qux");
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
// None of these were declared in this file.
|
||||
// It's bad to register them because that would trigger
|
||||
// modules to execute in an environment with inline requires.
|
||||
// So we expect the transform to skip all of them even though
|
||||
// they are used in JSX.
|
||||
|
||||
const A = require('A');
|
||||
const B = foo ? require('X') : require('Y');
|
||||
const C = requireCond(gk, 'C');
|
||||
const D = import('D');
|
||||
|
||||
export default function App() {
|
||||
return (
|
||||
<div>
|
||||
<A />
|
||||
<B />
|
||||
<C />
|
||||
<D />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
||||
const A = require("A");
|
||||
const B = foo ? require("X") : require("Y");
|
||||
const C = requireCond(gk, "C");
|
||||
const D = import("D");
|
||||
export default function App() {
|
||||
return _jsxs("div", { children: [_jsx(A, {}), _jsx(B, {}), _jsx(C, {}), _jsx(D, {})] });
|
||||
}
|
||||
_c = App;
|
||||
var _c;
|
||||
$RefreshReg$(_c, "App");
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
while (item) {
|
||||
(item => {
|
||||
useFoo();
|
||||
})(item);
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
while (item) {
|
||||
var _s = $RefreshSig$();
|
||||
_s((item) => {
|
||||
_s();
|
||||
useFoo();
|
||||
}, "useFoo{}", true)(item);
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
export default function App() {
|
||||
const [foo, setFoo] = useState(0);
|
||||
React.useEffect(() => {});
|
||||
return <h1>{foo}</h1>;
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
import { jsx as _jsx } from "react/jsx-runtime";
|
||||
var _s = $RefreshSig$();
|
||||
export default function App() {
|
||||
_s();
|
||||
const [foo, setFoo] = useState(0);
|
||||
React.useEffect(() => {});
|
||||
return _jsx("h1", { children: foo });
|
||||
}
|
||||
_s(App, "useState{[foo, setFoo](0)}\\nuseEffect{}");
|
||||
_c = App;
|
||||
var _c;
|
||||
$RefreshReg$(_c, "App");
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
// Unlike __register__, we want to sign all functions -- not just top level.
|
||||
// This lets us support editing HOCs better.
|
||||
// For function declarations, __signature__ is called on next line.
|
||||
// For function expressions, it wraps the expression.
|
||||
// In order for this to work, __signature__ returns its first argument.
|
||||
|
||||
export const A = React.memo(React.forwardRef((props, ref) => {
|
||||
const [foo, setFoo] = useState(0);
|
||||
React.useEffect(() => {});
|
||||
return <h1 ref={ref}>{foo}</h1>;
|
||||
}));
|
||||
|
||||
export const B = React.memo(React.forwardRef(function(props, ref) {
|
||||
const [foo, setFoo] = useState(0);
|
||||
React.useEffect(() => {});
|
||||
return <h1 ref={ref}>{foo}</h1>;
|
||||
}));
|
||||
|
||||
function hoc() {
|
||||
return function Inner() {
|
||||
const [foo, setFoo] = useState(0);
|
||||
React.useEffect(() => {});
|
||||
return <h1 ref={ref}>{foo}</h1>;
|
||||
};
|
||||
}
|
||||
|
||||
export let C = hoc();
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
import { jsx as _jsx } from "react/jsx-runtime";
|
||||
var _s = $RefreshSig$(), _s2 = $RefreshSig$();
|
||||
export const A = _s(React.memo(_c2 = _s(React.forwardRef(_c = _s((props, ref) => {
|
||||
_s();
|
||||
const [foo, setFoo] = useState(0);
|
||||
React.useEffect(() => {});
|
||||
return _jsx("h1", {
|
||||
ref,
|
||||
children: foo
|
||||
});
|
||||
}, "useState{[foo, setFoo](0)}\\nuseEffect{}")), "useState{[foo, setFoo](0)}\\nuseEffect{}")), "useState{[foo, setFoo](0)}\\nuseEffect{}");
|
||||
_c3 = A;
|
||||
export const B = _s2(React.memo(_c5 = _s2(React.forwardRef(_c4 = _s2(function(props, ref) {
|
||||
_s2();
|
||||
const [foo, setFoo] = useState(0);
|
||||
React.useEffect(() => {});
|
||||
return _jsx("h1", {
|
||||
ref,
|
||||
children: foo
|
||||
});
|
||||
}, "useState{[foo, setFoo](0)}\\nuseEffect{}")), "useState{[foo, setFoo](0)}\\nuseEffect{}")), "useState{[foo, setFoo](0)}\\nuseEffect{}");
|
||||
_c6 = B;
|
||||
function hoc() {
|
||||
var _s3 = $RefreshSig$();
|
||||
return _s3(function Inner() {
|
||||
_s3();
|
||||
const [foo, setFoo] = useState(0);
|
||||
React.useEffect(() => {});
|
||||
return _jsx("h1", {
|
||||
ref,
|
||||
children: foo
|
||||
});
|
||||
}, "useState{[foo, setFoo](0)}\\nuseEffect{}");
|
||||
}
|
||||
export let C = hoc();
|
||||
var _c, _c2, _c3, _c4, _c5, _c6;
|
||||
$RefreshReg$(_c, "A$React.memo$React.forwardRef");
|
||||
$RefreshReg$(_c2, "A$React.memo");
|
||||
$RefreshReg$(_c3, "A");
|
||||
$RefreshReg$(_c4, "B$React.memo$React.forwardRef");
|
||||
$RefreshReg$(_c5, "B$React.memo");
|
||||
$RefreshReg$(_c6, "B");
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
import FancyHook from 'fancy';
|
||||
|
||||
export default function App() {
|
||||
function useFancyState() {
|
||||
const [foo, setFoo] = React.useState(0);
|
||||
useFancyEffect();
|
||||
return foo;
|
||||
}
|
||||
const bar = useFancyState();
|
||||
const baz = FancyHook.useThing();
|
||||
React.useState();
|
||||
useThePlatform();
|
||||
return <h1>{bar}{baz}</h1>;
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
var _s2 = $RefreshSig$();
|
||||
import FancyHook from "fancy";
|
||||
import { jsxs as _jsxs } from "react/jsx-runtime";
|
||||
export default function App() {
|
||||
_s2();
|
||||
var _s = $RefreshSig$();
|
||||
function useFancyState() {
|
||||
_s();
|
||||
const [foo, setFoo] = React.useState(0);
|
||||
useFancyEffect();
|
||||
return foo;
|
||||
}
|
||||
_s(useFancyState, "useState{[foo, setFoo](0)}\\nuseFancyEffect{}", true);
|
||||
const bar = useFancyState();
|
||||
const baz = FancyHook.useThing();
|
||||
React.useState();
|
||||
useThePlatform();
|
||||
return _jsxs("h1", { children: [bar, baz] });
|
||||
}
|
||||
_s2(App, "useFancyState{bar}\\nuseThing{baz}\\nuseState{}\\nuseThePlatform{}", true, function() {
|
||||
return [FancyHook.useThing];
|
||||
});
|
||||
_c = App;
|
||||
var _c;
|
||||
$RefreshReg$(_c, "App");
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
let A = foo ? () => {
|
||||
return <h1>Hi</h1>;
|
||||
} : null
|
||||
const B = (function Foo() {
|
||||
return <h1>Hi</h1>;
|
||||
})();
|
||||
let C = () => () => {
|
||||
return <h1>Hi</h1>;
|
||||
};
|
||||
let D = bar && (() => {
|
||||
return <h1>Hi</h1>;
|
||||
});
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
import { jsx as _jsx } from "react/jsx-runtime";
|
||||
let A = foo ? () => {
|
||||
return _jsx("h1", { children: "Hi" });
|
||||
} : null;
|
||||
const B = function Foo() {
|
||||
return _jsx("h1", { children: "Hi" });
|
||||
}();
|
||||
let C = () => () => {
|
||||
return _jsx("h1", { children: "Hi" });
|
||||
};
|
||||
let D = bar && (() => {
|
||||
return _jsx("h1", { children: "Hi" });
|
||||
});
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
const throttledAlert = throttle(function() {
|
||||
alert('Hi');
|
||||
});
|
||||
const TooComplex = (function() { return hello })(() => {});
|
||||
if (cond) {
|
||||
const Foo = thing(() => {});
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
const throttledAlert = throttle(function() {
|
||||
alert("Hi");
|
||||
});
|
||||
const TooComplex = function() {
|
||||
return hello;
|
||||
}(() => {});
|
||||
if (cond) {
|
||||
const Foo = thing(() => {});
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
// TODO: we might want to handle HOCs at usage site, however.
|
||||
// TODO: it would be nice if we could always avoid registering
|
||||
// a function that is known to return a function or other non-node.
|
||||
|
||||
let connect = () => {
|
||||
function Comp() {
|
||||
const handleClick = () => {};
|
||||
return <h1 onClick={handleClick}>Hi</h1>;
|
||||
}
|
||||
return Comp;
|
||||
};
|
||||
function withRouter() {
|
||||
return function Child() {
|
||||
const handleClick = () => {};
|
||||
return <h1 onClick={handleClick}>Hi</h1>;
|
||||
}
|
||||
};
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
import { jsx as _jsx } from "react/jsx-runtime";
|
||||
let connect = () => {
|
||||
function Comp() {
|
||||
const handleClick = () => {};
|
||||
return _jsx("h1", {
|
||||
onClick: handleClick,
|
||||
children: "Hi"
|
||||
});
|
||||
}
|
||||
return Comp;
|
||||
};
|
||||
function withRouter() {
|
||||
return function Child() {
|
||||
const handleClick = () => {};
|
||||
return _jsx("h1", {
|
||||
onClick: handleClick,
|
||||
children: "Hi"
|
||||
});
|
||||
};
|
||||
}
|
||||
;
|
||||
|
|
@ -0,0 +1 @@
|
|||
export default function() {}
|
||||
|
|
@ -0,0 +1 @@
|
|||
export default function() {}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
// this test is passing with Babel 6
|
||||
// but would fail for Babel 7 _without_ custom hook node being cloned for signature
|
||||
import {useFancyState} from './hooks';
|
||||
|
||||
export default function App() {
|
||||
const bar = useFancyState();
|
||||
return <h1>{bar}</h1>;
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"plugins": [
|
||||
[
|
||||
"transform-react-jsx",
|
||||
{
|
||||
"refresh": {}
|
||||
}
|
||||
],
|
||||
[
|
||||
"transform-modules-commonjs"
|
||||
]
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
"use strict";
|
||||
import { jsx as _jsx } from "react/jsx-runtime";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
(exports.default = App);
|
||||
var _hooks = require("./hooks");
|
||||
var _s = $RefreshSig$();
|
||||
function App() {
|
||||
_s();
|
||||
const bar = (0, _hooks.useFancyState)();
|
||||
return _jsx("h1", { children: bar });
|
||||
}
|
||||
_s(App, "useFancyState{bar}", false, function() {
|
||||
return [_hooks.useFancyState];
|
||||
});
|
||||
_c = App;
|
||||
var _c;
|
||||
$RefreshReg$(_c, "App");
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
function useFancyState() {
|
||||
const [foo, setFoo] = React.useState(0);
|
||||
useFancyEffect();
|
||||
return foo;
|
||||
}
|
||||
|
||||
const useFancyEffect = () => {
|
||||
React.useEffect(() => {});
|
||||
};
|
||||
|
||||
export default function App() {
|
||||
const bar = useFancyState();
|
||||
return <h1>{bar}</h1>;
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
import { jsx as _jsx } from "react/jsx-runtime";
|
||||
var _s = $RefreshSig$(), _s2 = $RefreshSig$(), _s3 = $RefreshSig$();
|
||||
function useFancyState() {
|
||||
_s();
|
||||
const [foo, setFoo] = React.useState(0);
|
||||
useFancyEffect();
|
||||
return foo;
|
||||
}
|
||||
_s(useFancyState, "useState{[foo, setFoo](0)}\\nuseFancyEffect{}", false, function() {
|
||||
return [useFancyEffect];
|
||||
});
|
||||
const useFancyEffect = () => {
|
||||
_s2();
|
||||
React.useEffect(() => {});
|
||||
};
|
||||
_s2(useFancyEffect, "useEffect{}");
|
||||
export default function App() {
|
||||
_s3();
|
||||
const bar = useFancyState();
|
||||
return _jsx("h1", { children: bar });
|
||||
}
|
||||
_s3(App, "useFancyState{bar}", false, function() {
|
||||
return [useFancyState];
|
||||
});
|
||||
_c = App;
|
||||
var _c;
|
||||
$RefreshReg$(_c, "App");
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
function hello() {
|
||||
return 2 * 2;
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
function hello() {
|
||||
return 2 * 2;
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"plugins": [["transform-react-jsx", {
|
||||
"refresh": {}
|
||||
}]]
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
function Foo() {
|
||||
return <h1>Hi</h1>;
|
||||
}
|
||||
|
||||
export default hoc(Foo);
|
||||
export const A = hoc(Foo);
|
||||
const B = hoc(Foo);
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
import { jsx as _jsx } from "react/jsx-runtime";
|
||||
function Foo() {
|
||||
return _jsx("h1", { children: "Hi" });
|
||||
}
|
||||
_c = Foo;
|
||||
export default _c2 = hoc(Foo);
|
||||
export const A = hoc(Foo);
|
||||
_c3 = A;
|
||||
const B = hoc(Foo);
|
||||
_c4 = B;
|
||||
var _c, _c2, _c3, _c4;
|
||||
$RefreshReg$(_c, "Foo");
|
||||
$RefreshReg$(_c2, "%default%");
|
||||
$RefreshReg$(_c3, "A");
|
||||
$RefreshReg$(_c4, "B");
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
// When in doubt, register variables that were used in JSX.
|
||||
// Foo, Header, and B get registered.
|
||||
// A doesn't get registered because it's not declared locally.
|
||||
// Alias doesn't get registered because its definition is just an identifier.
|
||||
|
||||
import A from './A';
|
||||
import Store from './Store';
|
||||
|
||||
Store.subscribe();
|
||||
|
||||
const Header = styled.div`color: red`
|
||||
const StyledFactory1 = styled('div')`color: hotpink`
|
||||
const StyledFactory2 = styled('div')({ color: 'hotpink' })
|
||||
const StyledFactory3 = styled(A)({ color: 'hotpink' })
|
||||
const FunnyFactory = funny.factory``;
|
||||
|
||||
let Alias1 = A;
|
||||
let Alias2 = A.Foo;
|
||||
const Dict = {};
|
||||
|
||||
function Foo() {
|
||||
return (
|
||||
<div><A /><B /><StyledFactory1 /><StyledFactory2 /><StyledFactory3 /><Alias1 /><Alias2 /><Header /><Dict.X /></div>
|
||||
);
|
||||
}
|
||||
|
||||
const B = hoc(A);
|
||||
// This is currently registered as a false positive:
|
||||
const NotAComponent = wow(A);
|
||||
// We could avoid it but it also doesn't hurt.
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
import A from "./A";
|
||||
import Store from "./Store";
|
||||
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
||||
Store.subscribe();
|
||||
const Header = styled.div`color: red`;
|
||||
_c = Header;
|
||||
const StyledFactory1 = styled("div")`color: hotpink`;
|
||||
_c2 = StyledFactory1;
|
||||
const StyledFactory2 = styled("div")({ color: "hotpink" });
|
||||
_c3 = StyledFactory2;
|
||||
const StyledFactory3 = styled(A)({ color: "hotpink" });
|
||||
_c4 = StyledFactory3;
|
||||
const FunnyFactory = funny.factory``;
|
||||
let Alias1 = A;
|
||||
let Alias2 = A.Foo;
|
||||
const Dict = {};
|
||||
function Foo() {
|
||||
return _jsxs("div", { children: [_jsx(A, {}), _jsx(B, {}), _jsx(StyledFactory1, {}), _jsx(StyledFactory2, {}), _jsx(StyledFactory3, {}), _jsx(Alias1, {}), _jsx(Alias2, {}), _jsx(Header, {}), _jsx(Dict.X, {})] });
|
||||
}
|
||||
_c5 = Foo;
|
||||
const B = hoc(A);
|
||||
_c6 = B;
|
||||
const NotAComponent = wow(A);
|
||||
_c7 = NotAComponent;
|
||||
var _c, _c2, _c3, _c4, _c5, _c6, _c7;
|
||||
$RefreshReg$(_c, "Header");
|
||||
$RefreshReg$(_c2, "StyledFactory1");
|
||||
$RefreshReg$(_c3, "StyledFactory2");
|
||||
$RefreshReg$(_c4, "StyledFactory3");
|
||||
$RefreshReg$(_c5, "Foo");
|
||||
$RefreshReg$(_c6, "B");
|
||||
$RefreshReg$(_c7, "NotAComponent");
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
// When in doubt, register variables that were used in JSX.
|
||||
// Foo, Header, and B get registered.
|
||||
// A doesn't get registered because it's not declared locally.
|
||||
// Alias doesn't get registered because its definition is just an identifier.
|
||||
|
||||
import A from './A';
|
||||
import Store from './Store';
|
||||
|
||||
Store.subscribe();
|
||||
|
||||
const Header = styled.div`color: red`
|
||||
const StyledFactory1 = styled('div')`color: hotpink`
|
||||
const StyledFactory2 = styled('div')({ color: 'hotpink' })
|
||||
const StyledFactory3 = styled(A)({ color: 'hotpink' })
|
||||
const FunnyFactory = funny.factory``;
|
||||
|
||||
let Alias1 = A;
|
||||
let Alias2 = A.Foo;
|
||||
const Dict = {};
|
||||
|
||||
function Foo() {
|
||||
return [
|
||||
React.createElement(A),
|
||||
React.createElement(B),
|
||||
React.createElement(StyledFactory1),
|
||||
React.createElement(StyledFactory2),
|
||||
React.createElement(StyledFactory3),
|
||||
React.createElement(Alias1),
|
||||
React.createElement(Alias2),
|
||||
jsx(Header),
|
||||
React.createElement(Dict.X),
|
||||
];
|
||||
}
|
||||
|
||||
React.createContext(Store);
|
||||
|
||||
const B = hoc(A);
|
||||
// This is currently registered as a false positive:
|
||||
const NotAComponent = wow(A);
|
||||
// We could avoid it but it also doesn't hurt.
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
import A from "./A";
|
||||
import Store from "./Store";
|
||||
Store.subscribe();
|
||||
const Header = styled.div`color: red`;
|
||||
_c = Header;
|
||||
const StyledFactory1 = styled("div")`color: hotpink`;
|
||||
_c2 = StyledFactory1;
|
||||
const StyledFactory2 = styled("div")({ color: "hotpink" });
|
||||
_c3 = StyledFactory2;
|
||||
const StyledFactory3 = styled(A)({ color: "hotpink" });
|
||||
_c4 = StyledFactory3;
|
||||
const FunnyFactory = funny.factory``;
|
||||
let Alias1 = A;
|
||||
let Alias2 = A.Foo;
|
||||
const Dict = {};
|
||||
function Foo() {
|
||||
return [React.createElement(A), React.createElement(B), React.createElement(StyledFactory1), React.createElement(StyledFactory2), React.createElement(StyledFactory3), React.createElement(Alias1), React.createElement(Alias2), jsx(Header), React.createElement(Dict.X)];
|
||||
}
|
||||
_c5 = Foo;
|
||||
React.createContext(Store);
|
||||
const B = hoc(A);
|
||||
_c6 = B;
|
||||
const NotAComponent = wow(A);
|
||||
_c7 = NotAComponent;
|
||||
var _c, _c2, _c3, _c4, _c5, _c6, _c7;
|
||||
$RefreshReg$(_c, "Header");
|
||||
$RefreshReg$(_c2, "StyledFactory1");
|
||||
$RefreshReg$(_c3, "StyledFactory2");
|
||||
$RefreshReg$(_c4, "StyledFactory3");
|
||||
$RefreshReg$(_c5, "Foo");
|
||||
$RefreshReg$(_c6, "B");
|
||||
$RefreshReg$(_c7, "NotAComponent");
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
const A = forwardRef(function() {
|
||||
return <h1>Foo</h1>;
|
||||
});
|
||||
const B = memo(React.forwardRef(() => {
|
||||
return <h1>Foo</h1>;
|
||||
}));
|
||||
export default React.memo(forwardRef((props, ref) => {
|
||||
return <h1>Foo</h1>;
|
||||
}));
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
import { jsx as _jsx } from "react/jsx-runtime";
|
||||
const A = forwardRef(_c = function() {
|
||||
return _jsx("h1", { children: "Foo" });
|
||||
});
|
||||
_c2 = A;
|
||||
const B = memo(_c4 = React.forwardRef(_c3 = () => {
|
||||
return _jsx("h1", { children: "Foo" });
|
||||
}));
|
||||
_c5 = B;
|
||||
export default _c8 = React.memo(_c7 = forwardRef(_c6 = (props, ref) => {
|
||||
return _jsx("h1", { children: "Foo" });
|
||||
}));
|
||||
var _c, _c2, _c3, _c4, _c5, _c6, _c7, _c8;
|
||||
$RefreshReg$(_c, "A$forwardRef");
|
||||
$RefreshReg$(_c2, "A");
|
||||
$RefreshReg$(_c3, "B$memo$React.forwardRef");
|
||||
$RefreshReg$(_c4, "B$memo");
|
||||
$RefreshReg$(_c5, "B");
|
||||
$RefreshReg$(_c6, "%default%$React.memo$forwardRef");
|
||||
$RefreshReg$(_c7, "%default%$React.memo");
|
||||
$RefreshReg$(_c8, "%default%");
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
export default React.memo(forwardRef(function (props, ref) {
|
||||
return <h1>Foo</h1>;
|
||||
}));
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
import { jsx as _jsx } from "react/jsx-runtime";
|
||||
export default _c3 = React.memo(_c2 = forwardRef(_c = function(props, ref) {
|
||||
return _jsx("h1", { children: "Foo" });
|
||||
}));
|
||||
var _c, _c2, _c3;
|
||||
$RefreshReg$(_c, "%default%$React.memo$forwardRef");
|
||||
$RefreshReg$(_c2, "%default%$React.memo");
|
||||
$RefreshReg$(_c3, "%default%");
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
export default React.memo(forwardRef(function Named(props, ref) {
|
||||
return <h1>Foo</h1>;
|
||||
}));
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
import { jsx as _jsx } from "react/jsx-runtime";
|
||||
export default _c3 = React.memo(_c2 = forwardRef(_c = function Named(props, ref) {
|
||||
return _jsx("h1", { children: "Foo" });
|
||||
}));
|
||||
var _c, _c2, _c3;
|
||||
$RefreshReg$(_c, "%default%$React.memo$forwardRef");
|
||||
$RefreshReg$(_c2, "%default%$React.memo");
|
||||
$RefreshReg$(_c3, "%default%");
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
export function Hello() {
|
||||
function handleClick() {}
|
||||
return <h1 onClick={handleClick}>Hi</h1>;
|
||||
}
|
||||
|
||||
export default function Bar() {
|
||||
return <Hello />;
|
||||
}
|
||||
|
||||
function Baz() {
|
||||
return <h1>OK</h1>;
|
||||
}
|
||||
|
||||
const NotAComp = 'hi';
|
||||
export { Baz, NotAComp };
|
||||
|
||||
export function sum() {}
|
||||
export const Bad = 42;
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
import { jsx as _jsx } from "react/jsx-runtime";
|
||||
export function Hello() {
|
||||
function handleClick() {}
|
||||
return _jsx("h1", {
|
||||
onClick: handleClick,
|
||||
children: "Hi"
|
||||
});
|
||||
}
|
||||
_c = Hello;
|
||||
export default function Bar() {
|
||||
return _jsx(Hello, {});
|
||||
}
|
||||
_c2 = Bar;
|
||||
function Baz() {
|
||||
return _jsx("h1", { children: "OK" });
|
||||
}
|
||||
_c3 = Baz;
|
||||
const NotAComp = 'hi';
|
||||
export { Baz, NotAComp };
|
||||
export function sum() {}
|
||||
export const Bad = 42;
|
||||
|
||||
var _c, _c2, _c3;
|
||||
|
||||
$RefreshReg$(_c, "Hello");
|
||||
$RefreshReg$(_c2, "Bar");
|
||||
$RefreshReg$(_c3, "Baz");
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
export const Hello = () => {
|
||||
function handleClick() {}
|
||||
return <h1 onClick={handleClick}>Hi</h1>;
|
||||
};
|
||||
|
||||
export let Bar = (props) => <Hello />;
|
||||
|
||||
export default () => {
|
||||
// This one should be ignored.
|
||||
// You should name your components.
|
||||
return <Hello />;
|
||||
};
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
import { jsx as _jsx } from "react/jsx-runtime";
|
||||
export const Hello = () => {
|
||||
function handleClick() {}
|
||||
return _jsx("h1", {
|
||||
onClick: handleClick,
|
||||
children: "Hi"
|
||||
});
|
||||
};
|
||||
_c = Hello;
|
||||
export let Bar = (props) => _jsx(Hello, {});
|
||||
_c2 = Bar;
|
||||
export default () => {
|
||||
return _jsx(Hello, {});
|
||||
};
|
||||
var _c, _c2;
|
||||
$RefreshReg$(_c, "Hello");
|
||||
$RefreshReg$(_c2, "Bar");
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
function Hello() {
|
||||
function handleClick() {}
|
||||
return <h1 onClick={handleClick}>Hi</h1>;
|
||||
}
|
||||
|
||||
function Bar() {
|
||||
return <Hello />;
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
import { jsx as _jsx } from "react/jsx-runtime";
|
||||
|
||||
function Hello() {
|
||||
function handleClick() {}
|
||||
|
||||
return _jsx("h1", {
|
||||
onClick: handleClick,
|
||||
children: "Hi"
|
||||
});
|
||||
}
|
||||
|
||||
_c = Hello;
|
||||
|
||||
function Bar() {
|
||||
return _jsx(Hello, {});
|
||||
}
|
||||
|
||||
_c2 = Bar;
|
||||
|
||||
var _c, _c2;
|
||||
|
||||
$RefreshReg$(_c, "Hello");
|
||||
$RefreshReg$(_c2, "Bar");
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
// Hello, Bar, and Baz should be registered; handleClick and sum shouldn't.
|
||||
let Hello = () => {
|
||||
const handleClick = () => {};
|
||||
return <h1 onClick={handleClick}>Hi</h1>;
|
||||
}
|
||||
const Bar = () => {
|
||||
return <Hello />;
|
||||
};
|
||||
var Baz = () => <div />;
|
||||
var sum = () => {};
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
import { jsx as _jsx } from "react/jsx-runtime";
|
||||
let Hello = () => {
|
||||
const handleClick = () => {};
|
||||
return _jsx("h1", {
|
||||
onClick: handleClick,
|
||||
children: "Hi"
|
||||
});
|
||||
};
|
||||
_c = Hello;
|
||||
const Bar = () => {
|
||||
return _jsx(Hello, {});
|
||||
};
|
||||
_c2 = Bar;
|
||||
var Baz = () => _jsx("div", {});
|
||||
_c3 = Baz;
|
||||
var sum = () => {};
|
||||
var _c, _c2, _c3;
|
||||
$RefreshReg$(_c, "Hello");
|
||||
$RefreshReg$(_c2, "Bar");
|
||||
$RefreshReg$(_c3, "Baz");
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
// Hello and Bar should be registered; handleClick, sum, Baz, and Qux shouldn't.
|
||||
|
||||
let Hello = function() {
|
||||
function handleClick() {}
|
||||
return <h1 onClick={handleClick}>Hi</h1>;
|
||||
};
|
||||
const Bar = function Baz() {
|
||||
return <Hello />;
|
||||
};
|
||||
function sum() {}
|
||||
let Baz = 10;
|
||||
var Qux;
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
import { jsx as _jsx } from "react/jsx-runtime";
|
||||
let Hello = function() {
|
||||
function handleClick() {}
|
||||
return _jsx("h1", {
|
||||
onClick: handleClick,
|
||||
children: "Hi"
|
||||
});
|
||||
};
|
||||
_c = Hello;
|
||||
const Bar = function Baz() {
|
||||
return _jsx(Hello, {});
|
||||
};
|
||||
_c2 = Bar;
|
||||
function sum() {}
|
||||
let Baz = 10;
|
||||
var Qux;
|
||||
var _c, _c2;
|
||||
$RefreshReg$(_c, "Hello");
|
||||
$RefreshReg$(_c2, "Bar");
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
namespace Foo {
|
||||
export namespace Bar {
|
||||
export const A = () => {};
|
||||
|
||||
function B() {};
|
||||
export const B1 = B;
|
||||
}
|
||||
|
||||
export const C = () => {};
|
||||
export function D() {};
|
||||
|
||||
namespace NotExported {
|
||||
export const E = () => {};
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
namespace Foo {
|
||||
export namespace Bar {
|
||||
export const A = () => {};
|
||||
_c = A;
|
||||
function B() {}
|
||||
_c2 = B;
|
||||
;
|
||||
export const B1 = B;
|
||||
}
|
||||
export const C = () => {};
|
||||
_c3 = C;
|
||||
export function D() {}
|
||||
_c4 = D;
|
||||
;
|
||||
namespace NotExported {
|
||||
export const E = () => {};
|
||||
}
|
||||
}
|
||||
|
||||
var _c, _c2, _c3, _c4;
|
||||
|
||||
$RefreshReg$(_c, "Foo$Bar$A");
|
||||
$RefreshReg$(_c2, "Foo$Bar$B");
|
||||
$RefreshReg$(_c3, "Foo$C");
|
||||
$RefreshReg$(_c4, "Foo$D");
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
export default function Bar () {
|
||||
useContext(X)
|
||||
return <Foo />
|
||||
};
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"plugins": [["transform-react-jsx", {
|
||||
"refresh": {
|
||||
"refreshReg": "import.meta.refreshReg",
|
||||
"refreshSig": "import.meta.refreshSig"
|
||||
}
|
||||
}]]
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
import { jsx as _jsx } from "react/jsx-runtime";
|
||||
var _s = import.meta.refreshSig();
|
||||
export default function Bar() {
|
||||
_s();
|
||||
useContext(X);
|
||||
return _jsx(Foo, {});
|
||||
}
|
||||
_s(Bar, "useContext{}");
|
||||
_c = Bar;
|
||||
;
|
||||
var _c;
|
||||
import.meta.refreshReg(_c, "Bar");
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
function Hello() {
|
||||
return <h1>Hi</h1>;
|
||||
}
|
||||
Hello = connect(Hello);
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
import { jsx as _jsx } from "react/jsx-runtime";
|
||||
function Hello() {
|
||||
return _jsx("h1", { children: "Hi" });
|
||||
}
|
||||
_c = Hello;
|
||||
Hello = connect(Hello);
|
||||
var _c;
|
||||
$RefreshReg$(_c, "Hello");
|
||||
Loading…
Reference in a new issue