Repository: swc-project/swc (rust)

Issue:
"/* @refresh reset */" for fast refresh does not work
### Describe the bug

`/* @refresh reset */` comment should disable hot "refreshing" when editing this file, but for some reason, it doesn't work.

A related issue in `Next.js` using `swc` - https://github.com/vercel/next.js/issues/34880

### Input code

```typescript
/* @refresh reset */

import { useState } from 'react';

function Counter() {
  const [count, setCount] = useState(0);

  return (
    <button type="button" onClick={() => setCount(c => c + 1)}>
      {count}
    </button>
  );
}
```


### Config

_No response_

### Playground link

_No response_

### Expected behavior

According to https://github.com/pmmmwh/react-refresh-webpack-plugin/blob/main/docs/API.md#reset, this directive instructs Fast Refresh to remount components defined in that file on every edit.

### Actual behavior

_No response_

### Version

1.3.4

### Additional context

_No response_

Pull request:
fix(es/transform_react): should force refresh if code contains `@refresh reset`
<!-- Note: CI script will automatically rebase your PR so please do not rebase unless required -->

<!-- Thanks for submitting a pull request! Please provide enough information so that others can review your pull request. -->

**Description:**

<!-- Explain the **motivation** for making this change. What existing problem does the pull request solve? -->

**BREAKING CHANGE:**

<!--
If this PR introduces a breaking change, it must contain a notice for it to be included in the CHANGELOG. Add description or remove entirely if not breaking.

You may need to update `MIGRATION.md` for the breaking changes.
-->

**Related issue (if exists):**
Fix #6022.

Patch:
diff --git a/crates/swc_ecma_transforms_react/src/refresh/mod.rs b/crates/swc_ecma_transforms_react/src/refresh/mod.rs
index 5194bb274b..58b423c2bd 100644
--- a/crates/swc_ecma_transforms_react/src/refresh/mod.rs
+++ b/crates/swc_ecma_transforms_react/src/refresh/mod.rs
@@ -249,6 +249,12 @@ where
                 });
             }
 
+            comments.with_leading(n.lo, |comments| {
+                if comments.iter().any(|c| c.text.contains("@refresh reset")) {
+                    should_refresh = true
+                }
+            });
+
             comments.with_trailing(n.lo, |comments| {
                 if comments.iter().any(|c| c.text.contains("@refresh reset")) {
                     should_refresh = true
@@ -265,14 +271,18 @@ impl<C: Comments> VisitMut for Refresh<C> {
     // Does anyone write react without esmodule?
     // fn visit_mut_script(&mut self, _: &mut Script) {}
 
-    fn visit_mut_module_items(&mut self, module_items: &mut Vec<ModuleItem>) {
+    fn visit_mut_module(&mut self, n: &mut Module) {
         if !self.enable {
             return;
         }
 
         // to collect comments
-        self.visit_module_items(module_items);
+        self.visit_module(n);
+
+        self.visit_mut_module_items(&mut n.body);
+    }
 
+    fn visit_mut_module_items(&mut self, module_items: &mut Vec<ModuleItem>) {
         let used_in_jsx = collect_ident_in_jsx(module_items);
 
         let mut items = Vec::with_capacity(module_items.len());


Test patch:
diff --git a/crates/swc_ecma_transforms_react/src/refresh/tests.rs b/crates/swc_ecma_transforms_react/src/refresh/tests.rs
index b537aeb004..128037f21c 100644
--- a/crates/swc_ecma_transforms_react/src/refresh/tests.rs
+++ b/crates/swc_ecma_transforms_react/src/refresh/tests.rs
@@ -1535,3 +1535,35 @@ const a = (a)=>{
 }
 "#
 );
+
+test!(
+    ::swc_ecma_parser::Syntax::Es(::swc_ecma_parser::EsConfig {
+        jsx: true,
+        ..Default::default()
+    }),
+    tr,
+    issue_6022,
+    r#"/* @refresh reset */
+    import { useState } from 'react';
+
+    function Counter() {
+      const [count, setCount] = useState(0);
+
+      return (
+        <button type="button" onClick={() => setCount(c => c + 1)}>{count}</button>
+      );
+    }
+"#,
+    r#"var _s = $RefreshSig$();
+import { useState } from 'react';
+function Counter() {
+    _s();
+    const [count, setCount] = useState(0);
+    return <button type="button" onClick={()=>setCount((c)=>c + 1)}>{count}</button>;
+}
+_s(Counter, "useState{[count, setCount](0)}", true);
+_c = Counter;
+var _c;
+$RefreshReg$(_c, "Counter");
+"#
+);