Repository: swc-project/swc (rust)

Issue:
const module imports not substituted in exported functions
### Describe the bug

When importing a value from a const module, references to it within an exported function aren't substituted

### Input code

```typescript
import foo from 'some-const-module';
console.log(foo);
export function _() {
  console.log(foo);
}
```


### Config

```json
{ jsc: { constModules: { globals: {
  'some-const-module': { default: '...' }
} } } }
```


### Playground link

_No response_

### Expected behavior

```javascript
console.log('...');
export function _() {
  console.log('...');
}
```

### Actual behavior

```javascript
console.log('...');
export function _() {
  console.log(foo);
}
```

### Version

1.3.71

### Additional context

_No response_

Pull request description:
fix(es/minifier): Handle `ModuleDecl` when transform const modules
**Related issue:**

 - Closes #7747 

Patch:
diff --git a/crates/swc_ecma_transforms_optimization/src/const_modules.rs b/crates/swc_ecma_transforms_optimization/src/const_modules.rs
index ed71111e62..c52199a334 100644
--- a/crates/swc_ecma_transforms_optimization/src/const_modules.rs
+++ b/crates/swc_ecma_transforms_optimization/src/const_modules.rs
@@ -151,11 +151,7 @@ impl VisitMut for ConstModules {
             return;
         }
 
-        n.iter_mut().for_each(|item| {
-            if let ModuleItem::Stmt(stmt) = item {
-                stmt.visit_mut_with(self);
-            }
-        });
+        n.visit_mut_children_with(self);
     }
 
     fn visit_mut_expr(&mut self, n: &mut Expr) {


Test patch:
diff --git a/crates/swc_ecma_transforms_optimization/tests/const-modules/issue-7747/globals.json b/crates/swc_ecma_transforms_optimization/tests/const-modules/issue-7747/globals.json
new file mode 100644
index 0000000000..a32ec59761
--- /dev/null
+++ b/crates/swc_ecma_transforms_optimization/tests/const-modules/issue-7747/globals.json
@@ -0,0 +1,5 @@
+{
+    "some-const-module": {
+        "default": "42"
+    }
+}
\ No newline at end of file
diff --git a/crates/swc_ecma_transforms_optimization/tests/const-modules/issue-7747/input.js b/crates/swc_ecma_transforms_optimization/tests/const-modules/issue-7747/input.js
new file mode 100644
index 0000000000..2db0d6742c
--- /dev/null
+++ b/crates/swc_ecma_transforms_optimization/tests/const-modules/issue-7747/input.js
@@ -0,0 +1,5 @@
+import foo from "some-const-module";
+console.log(foo);
+export function _() {
+    console.log(foo);
+}
diff --git a/crates/swc_ecma_transforms_optimization/tests/const-modules/issue-7747/output.js b/crates/swc_ecma_transforms_optimization/tests/const-modules/issue-7747/output.js
new file mode 100644
index 0000000000..0bf46e69c3
--- /dev/null
+++ b/crates/swc_ecma_transforms_optimization/tests/const-modules/issue-7747/output.js
@@ -0,0 +1,4 @@
+console.log(42);
+export function _() {
+    console.log(42);
+}
diff --git a/crates/swc_ecma_transforms_optimization/tests/const_modules.rs b/crates/swc_ecma_transforms_optimization/tests/const_modules.rs
index 52793e908c..37865f155e 100644
--- a/crates/swc_ecma_transforms_optimization/tests/const_modules.rs
+++ b/crates/swc_ecma_transforms_optimization/tests/const_modules.rs
@@ -1,7 +1,7 @@
-use std::collections::HashMap;
+use std::{collections::HashMap, fs::read_to_string, path::PathBuf};
 
 use swc_ecma_transforms_optimization::const_modules;
-use swc_ecma_transforms_testing::{test, Tester};
+use swc_ecma_transforms_testing::{test, test_fixture, Tester};
 use swc_ecma_visit::Fold;
 
 fn tr(t: &mut Tester<'_>, sources: &[(&str, &[(&str, &str)])]) -> impl Fold {
@@ -160,3 +160,24 @@ console.log(something);
 console.log(true);
 "#
 );
+
+#[testing::fixture("tests/const-modules/**/input.js")]
+fn const_modules_test(input: PathBuf) {
+    let globals = input.with_file_name("globals.json");
+    let output = input.with_file_name("output.js");
+
+    test_fixture(
+        ::swc_ecma_parser::Syntax::default(),
+        &|t| {
+            let globals = read_to_string(&globals)
+                .ok()
+                .and_then(|s| serde_json::from_str(&s).ok())
+                .unwrap_or_default();
+
+            const_modules(t.cm.clone(), globals)
+        },
+        &input,
+        &output,
+        Default::default(),
+    );
+}