Repository: swc-project/swc (rust)

Issue:
esm-style exports and imports still don't get lazy loaded
### Describe the bug

When transpiling with lazy: true, dependencies that are declared with export are not being lazyfied.
The same is done with imports. They should also be lazy but instead are handled like below the export is done with the direct require.
Fixing https://github.com/swc-project/swc/issues/4799 didnt help unfortunately.
So I upload here to whole code.

### Input code

```typescript
import { SI } from './path/to/SS';

import {
    S_E_T as SSET
} from './path/to/ST';

export const SETs = {
    [SSET]: SSET as typeof SSET
};

export const SI = {
    [SETs[SSET]]: SI
};

export { S_E_R_T as SSERT } from './path/to/ST';

export {
    ILIAN,
    IWI,
    SM,
    VP,
} from './path/to/ST';

export {
    SC
} from './path/to/SC';

export {
    cSEP,
    iCSEPFT,
    SASC
} from './path/to/S';

import {
    cSP,
} from './path/to/S';

const iCSP = async () => {
    return Promise.resolve(cSP);
};

p.eE({
    i: 's',
    eP: 's.o.sEP',
    d: 0,
    f:iCSP
});

import {
    gTFNDP,
    gTFPP,
    C as pC,
    vT
} from './path/to/PTUs';

import {
    cDC,
    cIRTI,
    CPC,
    D_C_E,
    rCW,
    SDC,
    TS,
    WL
} from './path/to/SDUs';

export const us = {
    e: {
        p: {
            gTFNDP,
            gTFPP,
            vT,
        }
    },
    ds: {
        D_C_E,
        cDC,
        cIRTI,
        CPC,
        rCW,
        SDC,
        WL,
        TS
    }
};

export const C = {
    ...pC
};
```


### Config

```json
{
                    test: /\.ts(x?)$/,
                    use: 
                        {
                            loader: "swc-loader",
                            options: {
                                sync: true,
                                jsc: {
                                    parser: {
                                        syntax: "typescript",
                                        tsx: true,
                                        dynamicImport: true
                                    },
                                    loose: false,
                                    externalHelpers: true,
                                    // Requires v1.2.50 or upper and requires target to be es2016 or upper.
                                    keepClassNames: false,

                                },
                                module: {
                                    type: "commonjs",
                                    strictMode: false,
                                    lazy: true
                                }
                            }
                        }
                }
```


### Playground link

_No response_

### Expected behavior

```
Object.defineProperty(exports, "__esModule", ({
    value: true
}));
exports.C = void 0;
Object.defineProperty(exports, "ILIAN", ({
    enumerable: true,
    get: function get() {
        return _ST().ILIAN;
    }
}));
Object.defineProperty(exports, "IWI", ({
    enumerable: true,
    get: function get() {
        return _ST().IWI;
    }
}));
exports.SETs = exports.SI = void 0;
Object.defineProperty(exports, "SASC", ({
    enumerable: true,
    get: function get() {
        return _S().SASC;
    }
}));
Object.defineProperty(exports, "SC", ({
    enumerable: true,
    get: function get() {
        return _SC().SC;
    }
}));
Object.defineProperty(exports, "SM", ({
    enumerable: true,
    get: function get() {
        return _ST().SM;
    }
}));
Object.defineProperty(exports, "SSERT", ({
    enumerable: true,
    get: function get() {
        return _ST().S_E_R_T;
    }
}));
Object.defineProperty(exports, "VP", ({
    enumerable: true,
    get: function get() {
        return _ST().VP;
    }
}));
Object.defineProperty(exports, "cSEP", ({
    enumerable: true,
    get: function get() {
        return _S().cSEP;
    }
}));
Object.defineProperty(exports, "iCSEPFT", ({
    enumerable: true,
    get: function get() {
        return _S().iCSEPFT;
    }
}));
exports.us = void 0;

function _tslib() {
    var data = __webpack_require__("./node_modules/tslib/tslib.es6.js");

    _tslib = function _tslib() {
        return data;
    };

    return data;
}

function _SS() {
    var data = __webpack_require__("./path/to/SS.ts");

    _SS = function _SS() {
        return data;
    };

    return data;
}

function _ST() {
    var data = __webpack_require__("./path/to/ST.ts");

    _ST = function _ST() {
        return data;
    };

    return data;
}

function _SC() {
    var data = __webpack_require__("./path/to/SC.ts");

    _SC = function _SC() {
        return data;
    };

    return data;
}

function _S() {
    var data = __webpack_require__("./path/to/S.ts");

    _S = function _S() {
        return data;
    };

    return data;
}

function _PTUs() {
    var data = __webpack_require__("./path/to/PTUs.ts");

    _PTUs = function _PTUs() {
        return data;
    };

    return data;
}

function _SDUs() {
    var data = __webpack_require__("./path/to/SDUs.ts");

    _SDUs = function _SDUs() {
        return data;
    };

    return data;
}

var _a, _b;

var SETs = (_a = {}, _a[_ST().S_E_T] = _ST().S_E_T, _a);
exports.SETs = SETs;
var SI = (_b = {}, _b[SETs[_ST().S_E_T]] = _SS().SI, _b);
exports.SI = SI;

var iCSP = function iCSP() {
    return (0, _tslib().__awaiter)(void 0, void 0, void 0, function () {
        return (0, _tslib().__generator)(this, function (_a) {
            return [2
                /*return*/
                , Promise.resolve(_S().cSP)];
        });
    });
};

__webpack_require__.p.eE({
    i: 's',
    eP: 's.o.sEP',
    d: 0,
    f:iCSP
});
var us = {
    e: {
        p: {
            gTFNDP: _PTUs().gTFNDP,
            gTFPP: _PTUs().gTFPP,
            vT: _PTUs().vT
        }
    },
    ds: {
        D_C_E: _SDUs().D_C_E,
        cDC: _SDUs().cDC,
        cIRTI: _SDUs().cIRTI,
        CPC: _SDUs().CPC,
        rCW: _SDUs().rCW,
        SDC: _SDUs().SDC,
        WL: _SDUs().WL,
        TS: _SDUs().TS
    }
};
exports.us = us;
var C = (0, _tslib().__assign)({}, _PTUs().C);
exports.C = C;

```

### Actual behavior

```
Object.defineProperty(exports, "__esModule", ({
    value: true
}));
Object.defineProperty(exports, "SSERT", ({
    enumerable: true,
    get: function() {
        return _sT.S_E_R_T;
    }
}));
Object.defineProperty(exports, "ILIAN", ({
    enumerable: true,
    get: function() {
        return _sT.ILIAN;
    }
}));
Object.defineProperty(exports, "IWI", ({
    enumerable: true,
    get: function() {
        return _sT.IWI;
    }
}));
Object.defineProperty(exports, "SM", ({
    enumerable: true,
    get: function() {
        return _sT.SM;
    }
}));
Object.defineProperty(exports, "VP", ({
    enumerable: true,
    get: function() {
        return _sT.VP;
    }
}));
Object.defineProperty(exports, "SC", ({
    enumerable: true,
    get: function() {
        return _sC.SC;
    }
}));
Object.defineProperty(exports, "cSEP", ({
    enumerable: true,
    get: function() {
        return _s.cSEP;
    }
}));
Object.defineProperty(exports, "iCSEPFT", ({
    enumerable: true,
    get: function() {
        return _s.iCSEPFT;
    }
}));
Object.defineProperty(exports, "SASC", ({
    enumerable: true,
    get: function() {
        return _s.SASC;
    }
}));
exports.C = exports.us = exports.SEIs = exports.SETs = void 0;
function _regeneratorRuntime() {
    const data = _interopRequireDefault(__webpack_require__("./node_modules/regenerator-runtime/runtime.js"));
    _regeneratorRuntime = function() {
        return data;
    };
    return data;
}
var _sS = __webpack_require__("./path/to/SS.ts");
var _sT = __webpack_require__("./path/to/ST.ts");
var _s = __webpack_require__("./path/to/S.ts");
var _pTUs = __webpack_require__("./path/to/PTUs.ts");
var _sDUs = __webpack_require__("./path/to/SDUs.ts");
var _sC = __webpack_require__("./path/to/SC.ts");
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) {
    try {
        var info = gen[key](arg);
        var value = info.value;
    } catch (error) {
        reject(error);
        return;
    }
    if (info.done) {
        resolve(value);
    } else {
        Promise.resolve(value).then(_next, _throw);
    }
}
function _asyncToGenerator(fn) {
    return function() {
        var self = this, args = arguments;
        return new Promise(function(resolve, reject) {
            var gen = fn.apply(self, args);
            function _next(value) {
                asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value);
            }
            function _throw(err) {
                asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err);
            }
            _next(undefined);
        });
    };
}
function _defineProperty(obj, key, value) {
    if (key in obj) {
        Object.defineProperty(obj, key, {
            value: value,
            enumerable: true,
            configurable: true,
            writable: true
        });
    } else {
        obj[key] = value;
    }
    return obj;
}
function _interopRequireDefault(obj) {
    return obj && obj.__esModule ? obj : {
        default: obj
    };
}
function _objectSpread(target) {
    for(var i = 1; i < arguments.length; i++){
        var source = arguments[i] != null ? arguments[i] : {};
        var ownKeys = Object.keys(source);
        if (typeof Object.getOwnPropertySymbols === "function") {
            ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function(sym) {
                return Object.getOwnPropertyDescriptor(source, sym).enumerable;
            }));
        }
        ownKeys.forEach(function(key) {
            _defineProperty(target, key, source[key]);
        });
    }
    return target;
}
var SETs = _defineProperty({}, _sT.S_E_T, _sT.S_E_T);
exports.SETs = SETs;
var SEIs = _defineProperty({}, SETs[_sT.S_E_T], _sS.SI);
exports.SEIs = SEIs;
var iCSP = function() {
    var _ref = _asyncToGenerator(_regeneratorRuntime().default.mark(function _callee() {
        return _regeneratorRuntime().default.wrap(function _callee$(_ctx) {
            while(1)switch(_ctx.prev = _ctx.next){
                case 0:
                    return _ctx.abrupt("return", Promise.resolve(_s.cSP));
                case 1:
                case "end":
                    return _ctx.stop();
            }
        }, _callee);
    }));
    return function iCSP() {
        return _ref.apply(this, arguments);
    };
}();
__webpack_require__.p.eE({
    i: "s",
    eP: "s.o.sEP",
    d: 0,
    f:iCSP
});
var us = {
    e: {
        p: {
            gTFNDP: _pTUs.gTFNDP,
            gTFPP: _pTUs.gTFPP,
            vT: _pTUs.vT
        }
    },
    ds: {
        D_C_E: _sDUs.D_C_E,
        cDC: _sDUs.cDC,
        cIRTI: _sDUs.cIRTI,
        CPC: _sDUs.CPC,
        rCW: _sDUs.rCW,
        SDC: _sDUs.SDC,
        WL: _sDUs.WL,
        TS: _sDUs.TS
    }
};
exports.us = us;
var C = _objectSpread({}, _pTUs.C);
exports.C = C;

```

### Version

1.2.196

### Additional context

_No response_

Pull request:
fix(es/module): Handle lazy require for `export from`
<!-- 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:**

- handle lazy require for `export from`
- handle type only import/export
- small refactor

**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 #4864


Patch:
diff --git a/crates/swc_ecma_transforms_module/src/amd.rs b/crates/swc_ecma_transforms_module/src/amd.rs
index 24a0ece070..5da6858c1f 100644
--- a/crates/swc_ecma_transforms_module/src/amd.rs
+++ b/crates/swc_ecma_transforms_module/src/amd.rs
@@ -338,10 +338,7 @@ where
 
         let mut stmts = Vec::with_capacity(link.len());
 
-        let mut export_obj_prop_list = export
-            .into_iter()
-            .map(|((key, span), ident)| (key, span, ident.into()))
-            .collect();
+        let mut export_obj_prop_list = export.into_iter().map(Into::into).collect();
 
         link.into_iter().for_each(
             |(src, LinkItem(src_span, link_specifier_set, mut link_flag))| {
@@ -438,7 +435,7 @@ where
         let mut export_stmts = Default::default();
 
         if !export_obj_prop_list.is_empty() && !is_export_assign {
-            export_obj_prop_list.sort_by(|a, b| a.1.cmp(&b.1));
+            export_obj_prop_list.sort_by_key(|prop| prop.span());
 
             let features = self.available_features;
             let exports = self.exports();
diff --git a/crates/swc_ecma_transforms_module/src/common_js.rs b/crates/swc_ecma_transforms_module/src/common_js.rs
index 8bf5c64da0..deb479709d 100644
--- a/crates/swc_ecma_transforms_module/src/common_js.rs
+++ b/crates/swc_ecma_transforms_module/src/common_js.rs
@@ -1,6 +1,7 @@
-use swc_atoms::{js_word, JsWord};
+use swc_atoms::js_word;
 use swc_common::{
-    collections::AHashSet, comments::Comments, util::take::Take, FileName, Mark, Span, DUMMY_SP,
+    collections::AHashSet, comments::Comments, util::take::Take, FileName, Mark, Span, Spanned,
+    DUMMY_SP,
 };
 use swc_ecma_ast::*;
 use swc_ecma_transforms_base::{feature::FeatureFlag, helper_expr};
@@ -16,7 +17,7 @@ use crate::{
     path::{ImportResolver, Resolver},
     util::{
         clone_first_use_strict, define_es_module, emit_export_stmts, local_name_for_src, prop_name,
-        use_strict, ImportInterop,
+        use_strict, ImportInterop, ObjPropKeyIdent,
     },
 };
 
@@ -240,10 +241,7 @@ where
 
         let mut stmts = Vec::with_capacity(link.len());
 
-        let mut export_obj_prop_list = export
-            .into_iter()
-            .map(|((key, span), ident)| (key, span, ident.into()))
-            .collect();
+        let mut export_obj_prop_list = export.into_iter().map(Into::into).collect();
 
         link.into_iter().for_each(
             |(src, LinkItem(src_span, link_specifier_set, mut link_flag))| {
@@ -380,15 +378,10 @@ where
         let mut export_stmts: Vec<Stmt> = Default::default();
 
         if !export_obj_prop_list.is_empty() && !is_export_assign {
-            export_obj_prop_list.sort_by(|a, b| a.1.cmp(&b.1));
+            export_obj_prop_list.sort_by_key(|prop| prop.span());
 
             if import_interop.is_node() {
-                let export_id_list: Vec<(JsWord, Span)> = export_obj_prop_list
-                    .iter()
-                    .map(|(name, span, _)| (name.clone(), *span))
-                    .collect();
-
-                export_stmts = self.emit_lexer_exports_init(export_id_list);
+                export_stmts = self.emit_lexer_exports_init(&export_obj_prop_list);
             }
 
             let features = self.available_features;
@@ -408,18 +401,18 @@ where
     /// ```javascript
     /// exports.foo = exports.bar = void 0;
     /// ```
-    fn emit_lexer_exports_init(&mut self, export_id_list: Vec<(JsWord, Span)>) -> Vec<Stmt> {
+    fn emit_lexer_exports_init(&mut self, export_id_list: &[ObjPropKeyIdent]) -> Vec<Stmt> {
         export_id_list
             .chunks(100)
             .map(|group| {
                 let mut expr = *undefined(DUMMY_SP);
 
-                for (export_name, span) in group {
-                    let prop = prop_name(export_name, DUMMY_SP).into();
+                for key_value in group {
+                    let prop = prop_name(key_value.key(), DUMMY_SP).into();
 
                     let export_binding = MemberExpr {
                         obj: Box::new(self.exports().into()),
-                        span: *span,
+                        span: key_value.span(),
                         prop,
                     };
 
diff --git a/crates/swc_ecma_transforms_module/src/module_decl_strip.rs b/crates/swc_ecma_transforms_module/src/module_decl_strip.rs
index 1297ec9bf7..639d179223 100644
--- a/crates/swc_ecma_transforms_module/src/module_decl_strip.rs
+++ b/crates/swc_ecma_transforms_module/src/module_decl_strip.rs
@@ -2,10 +2,10 @@ use indexmap::IndexMap;
 use swc_atoms::{js_word, JsWord};
 use swc_common::{collections::AHashSet, util::take::Take, Span, DUMMY_SP};
 use swc_ecma_ast::*;
-use swc_ecma_utils::{find_pat_ids, is_valid_prop_ident, private_ident, quote_ident, ExprFactory};
+use swc_ecma_utils::{find_pat_ids, ident::IdentLike, private_ident, quote_ident, ExprFactory};
 use swc_ecma_visit::{noop_visit_mut_type, VisitMut, VisitMutWith};
 
-use crate::module_ref_rewriter::ImportMap;
+use crate::{module_ref_rewriter::ImportMap, util::ObjPropKeyIdent};
 
 pub type Link = IndexMap<JsWord, LinkItem>;
 pub type Export = IndexMap<(JsWord, Span), Ident>;
@@ -85,6 +85,10 @@ impl VisitMut for ModuleDeclStrip {
 
     // collect all static import
     fn visit_mut_import_decl(&mut self, n: &mut ImportDecl) {
+        if n.type_only {
+            return;
+        }
+
         let ImportDecl {
             specifiers, src, ..
         } = n.take();
@@ -135,6 +139,10 @@ impl VisitMut for ModuleDeclStrip {
     /// export * as "bar" from "mod";
     /// ```
     fn visit_mut_named_export(&mut self, n: &mut NamedExport) {
+        if n.type_only {
+            return;
+        }
+
         let NamedExport {
             specifiers, src, ..
         } = n.take();
@@ -257,18 +265,17 @@ impl VisitMut for ModuleDeclStrip {
     /// export import foo = require("mod");
     /// ```
     fn visit_mut_ts_import_equals_decl(&mut self, n: &mut TsImportEqualsDecl) {
+        if n.is_type_only || n.declare {
+            return;
+        }
+
         let TsImportEqualsDecl {
             id,
             module_ref,
             is_export,
-            declare,
-            is_type_only,
             ..
         } = n;
 
-        debug_assert!(!*declare);
-        debug_assert!(!*is_type_only);
-
         if let TsModuleRef::TsExternalModuleRef(TsExternalModuleRef {
             expr:
                 Str {
@@ -301,6 +308,15 @@ impl VisitMut for ModuleDeclStrip {
 
 #[derive(Debug, PartialEq, Eq, Hash)]
 pub enum LinkSpecifier {
+    ///```javascript
+    /// import "mod";
+    /// import {} from "mod",
+    /// import { type foo } from "mod";
+    /// export {} from "mod";
+    /// export { type foo } from "mod";
+    /// ```
+    Empty,
+
     /// ```javascript
     /// import { imported as local, local } from "mod";
     /// import { "imported" as local } from "mod";
@@ -362,6 +378,7 @@ impl From<ImportSpecifier> for LinkSpecifier {
 
             ImportSpecifier::Default(ImportDefaultSpecifier { local, .. })
             | ImportSpecifier::Named(ImportNamedSpecifier {
+                is_type_only: false,
                 local,
                 imported:
                     Some(ModuleExportName::Ident(Ident {
@@ -376,7 +393,10 @@ impl From<ImportSpecifier> for LinkSpecifier {
             }) => Self::ImportDefault(local.to_id()),
 
             ImportSpecifier::Named(ImportNamedSpecifier {
-                local, imported, ..
+                is_type_only: false,
+                local,
+                imported,
+                ..
             }) => {
                 let imported = imported.map(|e| match e {
                     ModuleExportName::Ident(Ident { sym, .. }) => sym,
@@ -388,6 +408,7 @@ impl From<ImportSpecifier> for LinkSpecifier {
                     imported,
                 }
             }
+            _ => Self::Empty,
         }
     }
 }
@@ -409,7 +430,12 @@ impl From<ExportSpecifier> for LinkSpecifier {
                 Self::ExportDefaultAs(exported.span, exported.sym, exported.span)
             }
 
-            ExportSpecifier::Named(ExportNamedSpecifier { orig, exported, .. }) => {
+            ExportSpecifier::Named(ExportNamedSpecifier {
+                is_type_only: false,
+                orig,
+                exported,
+                ..
+            }) => {
                 let orig = match orig {
                     ModuleExportName::Ident(Ident { span, sym, .. })
                     | ModuleExportName::Str(Str {
@@ -433,6 +459,7 @@ impl From<ExportSpecifier> for LinkSpecifier {
                     _ => Self::ExportNamed { orig, exported },
                 }
             }
+            _ => Self::Empty,
         }
     }
 }
@@ -478,6 +505,7 @@ impl LinkFlag {
 impl From<&LinkSpecifier> for LinkFlag {
     fn from(s: &LinkSpecifier) -> Self {
         match s {
+            LinkSpecifier::Empty => Self::empty(),
             LinkSpecifier::ImportStarAs(..) => Self::NAMESPACE,
             LinkSpecifier::ImportDefault(..) => Self::DEFAULT,
             LinkSpecifier::ImportNamed { .. } => Self::NAMED,
@@ -511,7 +539,12 @@ impl From<&ImportSpecifier> for LinkFlag {
                 ..
             }) => Self::DEFAULT,
 
-            ImportSpecifier::Named(..) => Self::NAMED,
+            ImportSpecifier::Named(ImportNamedSpecifier {
+                is_type_only: false,
+                ..
+            }) => Self::NAMED,
+
+            _ => Self::empty(),
         }
     }
 }
@@ -536,7 +569,12 @@ impl From<&ExportSpecifier> for LinkFlag {
                 ..
             }) => Self::DEFAULT,
 
-            ExportSpecifier::Named(..) => Self::NAMED,
+            ExportSpecifier::Named(ExportNamedSpecifier {
+                is_type_only: false,
+                ..
+            }) => Self::NAMED,
+
+            _ => Self::empty(),
         }
     }
 }
@@ -564,11 +602,10 @@ impl LinkItem {
     }
 }
 
-/// (exported_name, exported_span, expr)
-pub type ExportObjPropList = Vec<(JsWord, Span, Expr)>;
+pub(crate) type ExportObjPropList = Vec<ObjPropKeyIdent>;
 
 /// Reduce self to generate ImportMap and ExportObjPropList
-pub trait LinkSpecifierReducer {
+pub(crate) trait LinkSpecifierReducer {
     fn reduce(
         self,
         import_map: &mut ImportMap,
@@ -619,35 +656,45 @@ impl LinkSpecifierReducer for AHashSet<LinkSpecifier> {
             LinkSpecifier::ExportNamed { orig, exported } => {
                 *ref_to_mod_ident = true;
 
-                let (key, span) = exported.unwrap_or_else(|| orig.clone());
+                // ```javascript
+                // export { foo as bar } from "mod";
+                //
+                // import { foo } from "mod";
+                // export { foo as bar };
+                // ```
 
-                let expr = {
-                    let (name, span) = orig;
-                    if is_valid_prop_ident(&name) {
-                        mod_ident.clone().make_member(quote_ident!(span, name))
-                    } else {
-                        mod_ident.clone().computed_member(Str {
-                            span,
-                            value: name,
-                            raw: None,
-                        })
-                    }
-                };
-                export_obj_prop_list.push((key, span, expr))
+                // foo -> mod.foo
+                import_map.insert(orig.to_id(), (mod_ident.clone(), Some(orig.0.clone())));
+
+                let exported = exported.unwrap_or_else(|| orig.clone());
+
+                // bar -> foo
+                export_obj_prop_list.push((exported, quote_ident!(orig.1, orig.0)).into())
             }
-            LinkSpecifier::ExportDefaultAs(default_span, key, span) => {
+            LinkSpecifier::ExportDefaultAs(_, key, span) => {
                 *ref_to_mod_ident = true;
 
-                let expr = mod_ident
-                    .clone()
-                    .make_member(quote_ident!(default_span, "default"));
-                export_obj_prop_list.push((key, span, expr))
+                // ```javascript
+                // export { default as foo } from "mod";
+                //
+                // import { default as foo } from "mod";
+                // export { foo };
+                // ```
+
+                let exported = (key.clone(), span);
+
+                // foo -> mod.default
+                import_map.insert(
+                    exported.to_id(),
+                    (mod_ident.clone(), Some("default".into())),
+                );
+
+                export_obj_prop_list.push((exported, quote_ident!(span, key)).into())
             }
             LinkSpecifier::ExportStarAs(key, span) => {
                 *ref_to_mod_ident = true;
 
-                let expr = mod_ident.clone().into();
-                export_obj_prop_list.push((key, span, expr))
+                export_obj_prop_list.push((key, span, mod_ident.clone()).into())
             }
             LinkSpecifier::ExportStar => {}
             LinkSpecifier::ImportEqual(id) => {
@@ -661,6 +708,7 @@ impl LinkSpecifierReducer for AHashSet<LinkSpecifier> {
                     ),
                 );
             }
+            LinkSpecifier::Empty => {}
         })
     }
 }
diff --git a/crates/swc_ecma_transforms_module/src/umd.rs b/crates/swc_ecma_transforms_module/src/umd.rs
index c71c4033ce..2b8c96d185 100644
--- a/crates/swc_ecma_transforms_module/src/umd.rs
+++ b/crates/swc_ecma_transforms_module/src/umd.rs
@@ -1,7 +1,8 @@
 use anyhow::Context;
 use swc_atoms::JsWord;
 use swc_common::{
-    comments::Comments, sync::Lrc, util::take::Take, FileName, Mark, SourceMap, Span, DUMMY_SP,
+    comments::Comments, sync::Lrc, util::take::Take, FileName, Mark, SourceMap, Span, Spanned,
+    DUMMY_SP,
 };
 use swc_ecma_ast::*;
 use swc_ecma_transforms_base::{feature::FeatureFlag, helper_expr};
@@ -220,10 +221,7 @@ where
 
         let mut stmts = Vec::with_capacity(link.len());
 
-        let mut export_obj_prop_list = export
-            .into_iter()
-            .map(|((key, span), ident)| (key, span, ident.into()))
-            .collect();
+        let mut export_obj_prop_list = export.into_iter().map(Into::into).collect();
 
         link.into_iter().for_each(
             |(src, LinkItem(src_span, link_specifier_set, mut link_flag))| {
@@ -320,7 +318,7 @@ where
         let mut export_stmts = Default::default();
 
         if !export_obj_prop_list.is_empty() && !is_export_assign {
-            export_obj_prop_list.sort_by(|a, b| a.1.cmp(&b.1));
+            export_obj_prop_list.sort_by_key(|prop| prop.span());
 
             let features = self.available_features;
             let exports = self.exports();
diff --git a/crates/swc_ecma_transforms_module/src/util.rs b/crates/swc_ecma_transforms_module/src/util.rs
index 5f46f53c20..a24294551e 100644
--- a/crates/swc_ecma_transforms_module/src/util.rs
+++ b/crates/swc_ecma_transforms_module/src/util.rs
@@ -3,7 +3,7 @@ use is_macro::Is;
 use serde::{Deserialize, Serialize};
 use swc_atoms::{js_word, JsWord};
 use swc_cached::regex::CachedRegex;
-use swc_common::{Span, DUMMY_SP};
+use swc_common::{Span, Spanned, DUMMY_SP};
 use swc_ecma_ast::*;
 use swc_ecma_transforms_base::feature::FeatureFlag;
 use swc_ecma_utils::{
@@ -291,7 +291,7 @@ pub(crate) fn esm_export() -> Function {
 pub(crate) fn emit_export_stmts(
     features: FeatureFlag,
     exports: Ident,
-    mut prop_list: crate::module_decl_strip::ExportObjPropList,
+    mut prop_list: Vec<ObjPropKeyIdent>,
 ) -> Vec<Stmt> {
     let features = &features;
     let support_arrow = caniuse!(features.ArrowFunctions);
@@ -308,11 +308,11 @@ pub(crate) fn emit_export_stmts(
     match prop_list.len() {
         0 | 1 => prop_list
             .pop()
-            .map(|(prop_name, span, expr)| {
+            .map(|obj_prop| {
                 object_define_enumerable(
                     exports.as_arg(),
-                    quote_str!(span, prop_name).as_arg(),
-                    prop_auto((js_word!("get"), DUMMY_SP, expr)).into(),
+                    quote_str!(obj_prop.span(), obj_prop.key()).as_arg(),
+                    prop_auto((js_word!("get"), DUMMY_SP, obj_prop.2.clone()).into()).into(),
                 )
                 .into_stmt()
             })
@@ -377,17 +377,50 @@ impl From<IdentOrStr> for MemberProp {
     }
 }
 
+/// {
+///     "key": ident,
+/// }
+pub(crate) struct ObjPropKeyIdent(JsWord, Span, Ident);
+
+impl From<((JsWord, Span), Ident)> for ObjPropKeyIdent {
+    fn from(((key, span), ident): ((JsWord, Span), Ident)) -> Self {
+        Self(key, span, ident)
+    }
+}
+
+impl From<(JsWord, Span, Ident)> for ObjPropKeyIdent {
+    fn from((key, span, ident): (JsWord, Span, Ident)) -> Self {
+        Self(key, span, ident)
+    }
+}
+
+impl Spanned for ObjPropKeyIdent {
+    fn span(&self) -> Span {
+        self.1
+    }
+}
+
+impl ObjPropKeyIdent {
+    pub fn key(&self) -> &JsWord {
+        &self.0
+    }
+
+    pub fn into_expr(self) -> Expr {
+        self.2.into()
+    }
+}
+
 /// ```javascript
 /// {
 ///     key: () => expr,
 /// }
 /// ```
-pub(crate) fn prop_arrow((key, span, expr): (JsWord, Span, Expr)) -> Prop {
-    let key = prop_name(&key, span).into();
+pub(crate) fn prop_arrow(prop: ObjPropKeyIdent) -> Prop {
+    let key = prop_name(prop.key(), prop.span()).into();
 
     KeyValueProp {
         key,
-        value: Box::new(expr.into_lazy_arrow(Default::default()).into()),
+        value: Box::new(prop.into_expr().into_lazy_arrow(Default::default()).into()),
     }
     .into()
 }
@@ -399,10 +432,11 @@ pub(crate) fn prop_arrow((key, span, expr): (JsWord, Span, Expr)) -> Prop {
 ///     },
 /// }
 /// ```
-pub(crate) fn prop_method((key, span, expr): (JsWord, Span, Expr)) -> Prop {
-    let key = prop_name(&key, span).into();
+pub(crate) fn prop_method(prop: ObjPropKeyIdent) -> Prop {
+    let key = prop_name(prop.key(), prop.span()).into();
 
-    expr.into_lazy_fn(Default::default())
+    prop.into_expr()
+        .into_lazy_fn(Default::default())
         .into_method_prop(key)
         .into()
 }
@@ -414,13 +448,14 @@ pub(crate) fn prop_method((key, span, expr): (JsWord, Span, Expr)) -> Prop {
 ///     },
 /// }
 /// ```
-pub(crate) fn prop_function((key, span, expr): (JsWord, Span, Expr)) -> Prop {
-    let key = prop_name(&key, span).into();
+pub(crate) fn prop_function(prop: ObjPropKeyIdent) -> Prop {
+    let key = prop_name(prop.key(), prop.span()).into();
 
     KeyValueProp {
         key,
         value: Box::new(
-            expr.into_lazy_fn(Default::default())
+            prop.into_expr()
+                .into_lazy_fn(Default::default())
                 .into_fn_expr(None)
                 .into(),
         ),


Test patch:
diff --git a/crates/swc_ecma_transforms_module/tests/fixture/common/issue-4864/input.ts b/crates/swc_ecma_transforms_module/tests/fixture/common/issue-4864/input.ts
new file mode 100644
index 0000000000..493cdef529
--- /dev/null
+++ b/crates/swc_ecma_transforms_module/tests/fixture/common/issue-4864/input.ts
@@ -0,0 +1,60 @@
+import { SI as SI_IMPORTED } from "./path/to/SS";
+
+import { S_E_T as SSET } from "./path/to/ST";
+
+export const SETs = {
+    [SSET]: SSET as typeof SSET,
+};
+
+export const SI = {
+    [SETs[SSET]]: SI_IMPORTED,
+};
+
+export { S_E_R_T as SSERT } from "./path/to/ST";
+
+export { ILIAN, IWI, SM, VP } from "./path/to/ST";
+
+export { SC } from "./path/to/SC";
+
+export { cSEP, iCSEPFT, SASC } from "./path/to/S";
+
+import { cSP } from "./path/to/S";
+
+const iCSP = async () => {
+    return Promise.resolve(cSP);
+};
+
+p.eE({
+    i: "s",
+    eP: "s.o.sEP",
+    d: 0,
+    f: iCSP,
+});
+
+import { gTFNDP, gTFPP, C as pC, vT } from "./path/to/PTUs";
+
+import { cDC, cIRTI, CPC, D_C_E, rCW, SDC, TS, WL } from "./path/to/SDUs";
+
+export const us = {
+    e: {
+        p: {
+            gTFNDP,
+            gTFPP,
+            vT,
+        },
+    },
+    ds: {
+        D_C_E,
+        cDC,
+        cIRTI,
+        CPC,
+        rCW,
+        SDC,
+        WL,
+        TS,
+    },
+};
+
+export const C = {
+    ...pC,
+};
diff --git a/crates/swc_ecma_transforms_module/tests/fixture/common/issue-4864/module.json b/crates/swc_ecma_transforms_module/tests/fixture/common/issue-4864/module.json
new file mode 100644
index 0000000000..906af28839
--- /dev/null
+++ b/crates/swc_ecma_transforms_module/tests/fixture/common/issue-4864/module.json
@@ -0,0 +1,10 @@
+{
+    "lazy": [
+        "./path/to/SS",
+        "./path/to/ST",
+        "./path/to/SC",
+        "./path/to/S",
+        "./path/to/PTUs",
+        "./path/to/SDUs"
+    ]
+}
\ No newline at end of file
diff --git a/crates/swc_ecma_transforms_module/tests/fixture/common/issue-4864/output.amd.ts b/crates/swc_ecma_transforms_module/tests/fixture/common/issue-4864/output.amd.ts
new file mode 100644
index 0000000000..2352cf49b1
--- /dev/null
+++ b/crates/swc_ecma_transforms_module/tests/fixture/common/issue-4864/output.amd.ts
@@ -0,0 +1,73 @@
+define([
+    "require",
+    "exports",
+    "./path/to/SS",
+    "./path/to/ST",
+    "./path/to/SC",
+    "./path/to/S",
+    "./path/to/PTUs",
+    "./path/to/SDUs"
+], function(require, exports, _ss, _st, _sc, _s, _ptus, _sdus) {
+    "use strict";
+    Object.defineProperty(exports, "__esModule", {
+        value: true
+    });
+    function _export(target, all) {
+        for(var name in all)Object.defineProperty(target, name, {
+            enumerable: true,
+            get: all[name]
+        });
+    }
+    _export(exports, {
+        SETs: ()=>SETs,
+        SI: ()=>SI,
+        SSERT: ()=>_st.S_E_R_T,
+        ILIAN: ()=>_st.ILIAN,
+        IWI: ()=>_st.IWI,
+        SM: ()=>_st.SM,
+        VP: ()=>_st.VP,
+        SC: ()=>_sc.SC,
+        cSEP: ()=>_s.cSEP,
+        iCSEPFT: ()=>_s.iCSEPFT,
+        SASC: ()=>_s.SASC,
+        us: ()=>us,
+        C: ()=>C
+    });
+    const SETs = {
+        [_st.S_E_T]: _st.S_E_T as typeof SSET
+    };
+    const SI = {
+        [SETs[_st.S_E_T]]: _ss.SI
+    };
+    const iCSP = async ()=>{
+        return Promise.resolve(_s.cSP);
+    };
+    p.eE({
+        i: "s",
+        eP: "s.o.sEP",
+        d: 0,
+        f: iCSP
+    });
+    const us = {
+        e: {
+            p: {
+                gTFNDP: _ptus.gTFNDP,
+                gTFPP: _ptus.gTFPP,
+                vT: _ptus.vT
+            }
+        },
+        ds: {
+            D_C_E: _sdus.D_C_E,
+            cDC: _sdus.cDC,
+            cIRTI: _sdus.cIRTI,
+            CPC: _sdus.CPC,
+            rCW: _sdus.rCW,
+            SDC: _sdus.SDC,
+            WL: _sdus.WL,
+            TS: _sdus.TS
+        }
+    };
+    const C = {
+        ..._ptus.C
+    };
+});
diff --git a/crates/swc_ecma_transforms_module/tests/fixture/common/issue-4864/output.cts b/crates/swc_ecma_transforms_module/tests/fixture/common/issue-4864/output.cts
new file mode 100644
index 0000000000..92d3d5715e
--- /dev/null
+++ b/crates/swc_ecma_transforms_module/tests/fixture/common/issue-4864/output.cts
@@ -0,0 +1,104 @@
+"use strict";
+Object.defineProperty(exports, "__esModule", {
+    value: true
+});
+function _export(target, all) {
+    for(var name in all)Object.defineProperty(target, name, {
+        enumerable: true,
+        get: all[name]
+    });
+}
+_export(exports, {
+    SETs: ()=>SETs,
+    SI: ()=>SI,
+    SSERT: ()=>_st().S_E_R_T,
+    ILIAN: ()=>_st().ILIAN,
+    IWI: ()=>_st().IWI,
+    SM: ()=>_st().SM,
+    VP: ()=>_st().VP,
+    SC: ()=>_sc().SC,
+    cSEP: ()=>_s().cSEP,
+    iCSEPFT: ()=>_s().iCSEPFT,
+    SASC: ()=>_s().SASC,
+    us: ()=>us,
+    C: ()=>C
+});
+function _ss() {
+    const data = require("./path/to/SS");
+    _ss = function() {
+        return data;
+    };
+    return data;
+}
+function _st() {
+    const data = require("./path/to/ST");
+    _st = function() {
+        return data;
+    };
+    return data;
+}
+function _sc() {
+    const data = require("./path/to/SC");
+    _sc = function() {
+        return data;
+    };
+    return data;
+}
+function _s() {
+    const data = require("./path/to/S");
+    _s = function() {
+        return data;
+    };
+    return data;
+}
+function _ptus() {
+    const data = require("./path/to/PTUs");
+    _ptus = function() {
+        return data;
+    };
+    return data;
+}
+function _sdus() {
+    const data = require("./path/to/SDUs");
+    _sdus = function() {
+        return data;
+    };
+    return data;
+}
+const SETs = {
+    [_st().S_E_T]: _st().S_E_T as typeof SSET
+};
+const SI = {
+    [SETs[_st().S_E_T]]: _ss().SI
+};
+const iCSP = async ()=>{
+    return Promise.resolve(_s().cSP);
+};
+p.eE({
+    i: "s",
+    eP: "s.o.sEP",
+    d: 0,
+    f: iCSP
+});
+const us = {
+    e: {
+        p: {
+            gTFNDP: _ptus().gTFNDP,
+            gTFPP: _ptus().gTFPP,
+            vT: _ptus().vT
+        }
+    },
+    ds: {
+        D_C_E: _sdus().D_C_E,
+        cDC: _sdus().cDC,
+        cIRTI: _sdus().cIRTI,
+        CPC: _sdus().CPC,
+        rCW: _sdus().rCW,
+        SDC: _sdus().SDC,
+        WL: _sdus().WL,
+        TS: _sdus().TS
+    }
+};
+const C = {
+    ..._ptus().C
+};
diff --git a/crates/swc_ecma_transforms_module/tests/fixture/common/issue-4864/output.umd.ts b/crates/swc_ecma_transforms_module/tests/fixture/common/issue-4864/output.umd.ts
new file mode 100644
index 0000000000..caac1eacaf
--- /dev/null
+++ b/crates/swc_ecma_transforms_module/tests/fixture/common/issue-4864/output.umd.ts
@@ -0,0 +1,76 @@
+(function(global, factory) {
+    if (typeof module === "object" && typeof module.exports === "object") factory(exports, require("./path/to/SS"), require("./path/to/ST"), require("./path/to/SC"), require("./path/to/S"), require("./path/to/PTUs"), require("./path/to/SDUs"));
+    else if (typeof define === "function" && define.amd) define([
+        "exports",
+        "./path/to/SS",
+        "./path/to/ST",
+        "./path/to/SC",
+        "./path/to/S",
+        "./path/to/PTUs",
+        "./path/to/SDUs"
+    ], factory);
+    else if (global = typeof globalThis !== "undefined" ? globalThis : global || self) factory(global.input = {}, global.ss, global.st, global.sc, global.s, global.ptus, global.sdus);
+})(this, function(exports, _ss, _st, _sc, _s, _ptus, _sdus) {
+    "use strict";
+    Object.defineProperty(exports, "__esModule", {
+        value: true
+    });
+    function _export(target, all) {
+        for(var name in all)Object.defineProperty(target, name, {
+            enumerable: true,
+            get: all[name]
+        });
+    }
+    _export(exports, {
+        SETs: ()=>SETs,
+        SI: ()=>SI,
+        SSERT: ()=>_st.S_E_R_T,
+        ILIAN: ()=>_st.ILIAN,
+        IWI: ()=>_st.IWI,
+        SM: ()=>_st.SM,
+        VP: ()=>_st.VP,
+        SC: ()=>_sc.SC,
+        cSEP: ()=>_s.cSEP,
+        iCSEPFT: ()=>_s.iCSEPFT,
+        SASC: ()=>_s.SASC,
+        us: ()=>us,
+        C: ()=>C
+    });
+    const SETs = {
+        [_st.S_E_T]: _st.S_E_T as typeof SSET
+    };
+    const SI = {
+        [SETs[_st.S_E_T]]: _ss.SI
+    };
+    const iCSP = async ()=>{
+        return Promise.resolve(_s.cSP);
+    };
+    p.eE({
+        i: "s",
+        eP: "s.o.sEP",
+        d: 0,
+        f: iCSP
+    });
+    const us = {
+        e: {
+            p: {
+                gTFNDP: _ptus.gTFNDP,
+                gTFPP: _ptus.gTFPP,
+                vT: _ptus.vT
+            }
+        },
+        ds: {
+            D_C_E: _sdus.D_C_E,
+            cDC: _sdus.cDC,
+            cIRTI: _sdus.cIRTI,
+            CPC: _sdus.CPC,
+            rCW: _sdus.rCW,
+            SDC: _sdus.SDC,
+            WL: _sdus.WL,
+            TS: _sdus.TS
+        }
+    };
+    const C = {
+        ..._ptus.C
+    };
+});
diff --git a/crates/swc_ecma_transforms_module/tests/fixture/common/lazy/export-default/input.js b/crates/swc_ecma_transforms_module/tests/fixture/common/lazy/export-default/input.js
new file mode 100644
index 0000000000..b7ae4a8222
--- /dev/null
+++ b/crates/swc_ecma_transforms_module/tests/fixture/common/lazy/export-default/input.js
@@ -0,0 +1,6 @@
+export { default } from "foo";
+export { default as foo } from "foo";
+
+export { default as bar } from "bar";
+
+import bar from "bar";
diff --git a/crates/swc_ecma_transforms_module/tests/fixture/common/lazy/export-default/module.json b/crates/swc_ecma_transforms_module/tests/fixture/common/lazy/export-default/module.json
new file mode 100644
index 0000000000..e94b79a2ac
--- /dev/null
+++ b/crates/swc_ecma_transforms_module/tests/fixture/common/lazy/export-default/module.json
@@ -0,0 +1,3 @@
+{
+    "lazy": true
+}
\ No newline at end of file
diff --git a/crates/swc_ecma_transforms_module/tests/fixture/common/lazy/export-default/output.amd.js b/crates/swc_ecma_transforms_module/tests/fixture/common/lazy/export-default/output.amd.js
new file mode 100644
index 0000000000..7ca9edfb42
--- /dev/null
+++ b/crates/swc_ecma_transforms_module/tests/fixture/common/lazy/export-default/output.amd.js
@@ -0,0 +1,24 @@
+define([
+    "require",
+    "exports",
+    "foo",
+    "bar"
+], function(require, exports, _foo, _bar) {
+    "use strict";
+    Object.defineProperty(exports, "__esModule", {
+        value: true
+    });
+    function _export(target, all) {
+        for(var name in all)Object.defineProperty(target, name, {
+            enumerable: true,
+            get: all[name]
+        });
+    }
+    _export(exports, {
+        default: ()=>_foo.default,
+        foo: ()=>_foo.default,
+        bar: ()=>_bar.default
+    });
+    _foo = /*#__PURE__*/ _interopRequireDefault(_foo);
+    _bar = /*#__PURE__*/ _interopRequireDefault(_bar);
+});
diff --git a/crates/swc_ecma_transforms_module/tests/fixture/common/lazy/export-default/output.cjs b/crates/swc_ecma_transforms_module/tests/fixture/common/lazy/export-default/output.cjs
new file mode 100644
index 0000000000..c20f0527c2
--- /dev/null
+++ b/crates/swc_ecma_transforms_module/tests/fixture/common/lazy/export-default/output.cjs
@@ -0,0 +1,29 @@
+"use strict";
+Object.defineProperty(exports, "__esModule", {
+    value: true
+});
+function _export(target, all) {
+    for(var name in all)Object.defineProperty(target, name, {
+        enumerable: true,
+        get: all[name]
+    });
+}
+_export(exports, {
+    default: ()=>_foo().default,
+    foo: ()=>_foo().default,
+    bar: ()=>_bar().default
+});
+function _foo() {
+    const data = /*#__PURE__*/ _interopRequireDefault(require("foo"));
+    _foo = function() {
+        return data;
+    };
+    return data;
+}
+function _bar() {
+    const data = /*#__PURE__*/ _interopRequireDefault(require("bar"));
+    _bar = function() {
+        return data;
+    };
+    return data;
+}
diff --git a/crates/swc_ecma_transforms_module/tests/fixture/common/lazy/export-default/output.umd.js b/crates/swc_ecma_transforms_module/tests/fixture/common/lazy/export-default/output.umd.js
new file mode 100644
index 0000000000..519a0613b2
--- /dev/null
+++ b/crates/swc_ecma_transforms_module/tests/fixture/common/lazy/export-default/output.umd.js
@@ -0,0 +1,27 @@
+(function(global, factory) {
+    if (typeof module === "object" && typeof module.exports === "object") factory(exports, require("foo"), require("bar"));
+    else if (typeof define === "function" && define.amd) define([
+        "exports",
+        "foo",
+        "bar"
+    ], factory);
+    else if (global = typeof globalThis !== "undefined" ? globalThis : global || self) factory(global.input = {}, global.foo, global.bar);
+})(this, function(exports, _foo, _bar) {
+    "use strict";
+    Object.defineProperty(exports, "__esModule", {
+        value: true
+    });
+    function _export(target, all) {
+        for(var name in all)Object.defineProperty(target, name, {
+            enumerable: true,
+            get: all[name]
+        });
+    }
+    _export(exports, {
+        default: ()=>_foo.default,
+        foo: ()=>_foo.default,
+        bar: ()=>_bar.default
+    });
+    _foo = /*#__PURE__*/ _interopRequireDefault(_foo);
+    _bar = /*#__PURE__*/ _interopRequireDefault(_bar);
+});
diff --git a/crates/swc_ecma_transforms_module/tests/fixture/common/lazy/export-named/output.cjs b/crates/swc_ecma_transforms_module/tests/fixture/common/lazy/export-named/output.cjs
index 6aa96137d4..5f97e71c28 100644
--- a/crates/swc_ecma_transforms_module/tests/fixture/common/lazy/export-named/output.cjs
+++ b/crates/swc_ecma_transforms_module/tests/fixture/common/lazy/export-named/output.cjs
@@ -4,7 +4,7 @@ Object.defineProperty(exports, "__esModule", {
 });
 Object.defineProperty(exports, "named1", {
     enumerable: true,
-    get: ()=>_external.named1
+    get: ()=>_external().named1
 });
 function _external() {
     const data = require("external");