Skip to content

Commit fc0ba2a

Browse files
authored
fix(es/module): Rewrite import specifier in type declaration (#9577)
**Description:** Use `Arc<dyn ImportResolver>` to reduce cost **Related issue:** - Closes #9548
1 parent cf74382 commit fc0ba2a

File tree

25 files changed

+194
-259
lines changed

25 files changed

+194
-259
lines changed

.changeset/serious-ducks-suffer.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
swc_ecma_transforms_module: minor
3+
---
4+
5+
fix(typescript): rewrite import specifier in type declaration

crates/swc/src/builder.rs

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::{path::PathBuf, sync::Arc};
1+
use std::sync::Arc;
22

33
use compat::es2015::regenerator;
44
use either::Either;
@@ -15,16 +15,16 @@ use swc_ecma_transforms::{
1515
compat,
1616
feature::{enable_available_feature_from_es_version, FeatureFlag},
1717
fixer::{fixer, paren_remover},
18-
helpers, hygiene,
19-
hygiene::hygiene_with_config,
20-
modules,
18+
helpers,
19+
hygiene::{self, hygiene_with_config},
20+
modules::{self, path::ImportResolver},
2121
optimization::const_modules,
2222
pass::Optional,
2323
resolver, Assumptions,
2424
};
2525
use swc_ecma_visit::{as_folder, noop_visit_mut_type, VisitMut, VisitMutWith};
2626

27-
use crate::config::{CompiledPaths, GlobalPassOption, JsMinifyOptions, ModuleConfig};
27+
use crate::config::{GlobalPassOption, JsMinifyOptions, ModuleConfig};
2828

2929
/// Builder is used to create a high performance `Compiler`.
3030
pub struct PassBuilder<'a, 'b, P: swc_ecma_visit::Fold> {
@@ -168,12 +168,10 @@ impl<'a, 'b, P: swc_ecma_visit::Fold> PassBuilder<'a, 'b, P> {
168168
/// - fixer if enabled
169169
pub fn finalize<'cmt>(
170170
self,
171-
base_url: PathBuf,
172-
paths: CompiledPaths,
173-
base: &FileName,
174171
syntax: Syntax,
175172
module: Option<ModuleConfig>,
176173
comments: Option<&'cmt dyn Comments>,
174+
resolver: Option<(FileName, Arc<dyn ImportResolver>)>,
177175
) -> impl 'cmt + swc_ecma_visit::Fold
178176
where
179177
P: 'cmt,
@@ -347,12 +345,10 @@ impl<'a, 'b, P: swc_ecma_visit::Fold> PassBuilder<'a, 'b, P> {
347345
ModuleConfig::build(
348346
self.cm.clone(),
349347
comments,
350-
base_url,
351-
paths,
352-
base,
353-
self.unresolved_mark,
354348
module,
355-
feature_flag
349+
self.unresolved_mark,
350+
feature_flag,
351+
resolver,
356352
),
357353
as_folder(MinifierPass {
358354
options: self.minify,

crates/swc/src/config/mod.rs

Lines changed: 80 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,13 @@ use swc_ecma_parser::{parse_file_as_expr, Syntax, TsSyntax};
4545
pub use swc_ecma_transforms::proposals::DecoratorVersion;
4646
use swc_ecma_transforms::{
4747
feature::FeatureFlag,
48-
hygiene, modules,
49-
modules::{path::NodeImportResolver, rewriter::import_rewriter, EsModuleConfig},
48+
hygiene,
49+
modules::{
50+
self,
51+
path::{ImportResolver, NodeImportResolver, Resolver},
52+
rewriter::import_rewriter,
53+
EsModuleConfig,
54+
},
5055
optimization::{const_modules, json_parse, simplifier},
5156
pass::{noop, Optional},
5257
proposals::{
@@ -540,6 +545,9 @@ impl Options {
540545
.unwrap_or_default()
541546
};
542547

548+
let paths = paths.into_iter().collect();
549+
let resolver = ModuleConfig::get_resolver(&base_url, paths, base, cfg.module.as_ref());
550+
543551
let pass = PassBuilder::new(
544552
cm,
545553
handler,
@@ -564,12 +572,10 @@ impl Options {
564572
.preset_env(cfg.env)
565573
.regenerator(regenerator)
566574
.finalize(
567-
base_url,
568-
paths.into_iter().collect(),
569-
base,
570575
syntax,
571576
cfg.module,
572577
comments.map(|v| v as _),
578+
resolver.clone(),
573579
);
574580

575581
let keep_import_attributes = experimental.keep_import_attributes.into_bool();
@@ -782,6 +788,7 @@ impl Options {
782788
.emit_assert_for_import_attributes
783789
.into_bool(),
784790
emit_isolated_dts: experimental.emit_isolated_dts.into_bool(),
791+
resolver,
785792
})
786793
}
787794
}
@@ -1090,6 +1097,7 @@ pub struct BuiltInput<P: swc_ecma_visit::Fold> {
10901097
pub emit_assert_for_import_attributes: bool,
10911098

10921099
pub emit_isolated_dts: bool,
1100+
pub resolver: Option<(FileName, Arc<dyn ImportResolver>)>,
10931101
}
10941102

10951103
impl<P> BuiltInput<P>
@@ -1120,6 +1128,7 @@ where
11201128
output: self.output,
11211129
emit_assert_for_import_attributes: self.emit_assert_for_import_attributes,
11221130
emit_isolated_dts: self.emit_isolated_dts,
1131+
resolver: self.resolver,
11231132
}
11241133
}
11251134
}
@@ -1288,116 +1297,91 @@ impl ModuleConfig {
12881297
pub fn build<'cmt>(
12891298
cm: Arc<SourceMap>,
12901299
comments: Option<&'cmt dyn Comments>,
1291-
base_url: PathBuf,
1292-
paths: CompiledPaths,
1293-
base: &FileName,
1294-
unresolved_mark: Mark,
12951300
config: Option<ModuleConfig>,
1301+
unresolved_mark: Mark,
12961302
available_features: FeatureFlag,
1303+
resolver: Option<(FileName, Arc<dyn ImportResolver>)>,
12971304
) -> Box<dyn swc_ecma_visit::Fold + 'cmt> {
1305+
let resolver = if let Some((base, resolver)) = resolver {
1306+
Resolver::Real { base, resolver }
1307+
} else {
1308+
Resolver::Default
1309+
};
1310+
1311+
match config {
1312+
None | Some(ModuleConfig::Es6(..)) | Some(ModuleConfig::NodeNext(..)) => match resolver
1313+
{
1314+
Resolver::Default => Box::new(noop()),
1315+
Resolver::Real { base, resolver } => Box::new(import_rewriter(base, resolver)),
1316+
},
1317+
Some(ModuleConfig::CommonJs(config)) => Box::new(modules::common_js::common_js(
1318+
resolver,
1319+
unresolved_mark,
1320+
config,
1321+
available_features,
1322+
)),
1323+
Some(ModuleConfig::Umd(config)) => Box::new(modules::umd::umd(
1324+
cm,
1325+
resolver,
1326+
unresolved_mark,
1327+
config,
1328+
available_features,
1329+
)),
1330+
Some(ModuleConfig::Amd(config)) => Box::new(modules::amd::amd(
1331+
resolver,
1332+
unresolved_mark,
1333+
config,
1334+
available_features,
1335+
comments,
1336+
)),
1337+
Some(ModuleConfig::SystemJs(config)) => Box::new(modules::system_js::system_js(
1338+
resolver,
1339+
unresolved_mark,
1340+
config,
1341+
)),
1342+
}
1343+
}
1344+
1345+
pub fn get_resolver(
1346+
base_url: &Path,
1347+
paths: CompiledPaths,
1348+
base: &FileName,
1349+
config: Option<&ModuleConfig>,
1350+
) -> Option<(FileName, Arc<dyn ImportResolver>)> {
12981351
let skip_resolver = base_url.as_os_str().is_empty() && paths.is_empty();
12991352

1353+
if skip_resolver {
1354+
return None;
1355+
}
1356+
13001357
let base = match base {
13011358
FileName::Real(v) if !skip_resolver => {
13021359
FileName::Real(v.canonicalize().unwrap_or_else(|_| v.to_path_buf()))
13031360
}
13041361
_ => base.clone(),
13051362
};
13061363

1307-
match config {
1308-
None => {
1309-
if skip_resolver {
1310-
Box::new(noop())
1311-
} else {
1312-
let resolver = build_resolver(base_url, paths, false);
1313-
1314-
Box::new(import_rewriter(base, resolver))
1315-
}
1316-
}
1364+
let base_url = base_url.to_path_buf();
1365+
let resolver = match config {
1366+
None => build_resolver(base_url, paths, false),
13171367
Some(ModuleConfig::Es6(config)) | Some(ModuleConfig::NodeNext(config)) => {
1318-
if skip_resolver {
1319-
Box::new(noop())
1320-
} else {
1321-
let resolver = build_resolver(base_url, paths, config.resolve_fully);
1322-
1323-
Box::new(import_rewriter(base, resolver))
1324-
}
1368+
build_resolver(base_url, paths, config.resolve_fully)
13251369
}
13261370
Some(ModuleConfig::CommonJs(config)) => {
1327-
if skip_resolver {
1328-
Box::new(modules::common_js::common_js(
1329-
unresolved_mark,
1330-
config,
1331-
available_features,
1332-
))
1333-
} else {
1334-
let resolver = build_resolver(base_url, paths, config.resolve_fully);
1335-
Box::new(modules::common_js::common_js_with_resolver(
1336-
resolver,
1337-
base,
1338-
unresolved_mark,
1339-
config,
1340-
available_features,
1341-
))
1342-
}
1371+
build_resolver(base_url, paths, config.resolve_fully)
13431372
}
13441373
Some(ModuleConfig::Umd(config)) => {
1345-
if skip_resolver {
1346-
Box::new(modules::umd::umd(
1347-
cm,
1348-
unresolved_mark,
1349-
config,
1350-
available_features,
1351-
))
1352-
} else {
1353-
let resolver = build_resolver(base_url, paths, config.config.resolve_fully);
1354-
1355-
Box::new(modules::umd::umd_with_resolver(
1356-
cm,
1357-
resolver,
1358-
base,
1359-
unresolved_mark,
1360-
config,
1361-
available_features,
1362-
))
1363-
}
1374+
build_resolver(base_url, paths, config.config.resolve_fully)
13641375
}
13651376
Some(ModuleConfig::Amd(config)) => {
1366-
if skip_resolver {
1367-
Box::new(modules::amd::amd(
1368-
unresolved_mark,
1369-
config,
1370-
available_features,
1371-
comments,
1372-
))
1373-
} else {
1374-
let resolver = build_resolver(base_url, paths, config.config.resolve_fully);
1375-
1376-
Box::new(modules::amd::amd_with_resolver(
1377-
resolver,
1378-
base,
1379-
unresolved_mark,
1380-
config,
1381-
available_features,
1382-
comments,
1383-
))
1384-
}
1377+
build_resolver(base_url, paths, config.config.resolve_fully)
13851378
}
13861379
Some(ModuleConfig::SystemJs(config)) => {
1387-
if skip_resolver {
1388-
Box::new(modules::system_js::system_js(unresolved_mark, config))
1389-
} else {
1390-
let resolver = build_resolver(base_url, paths, config.resolve_fully);
1391-
1392-
Box::new(modules::system_js::system_js_with_resolver(
1393-
resolver,
1394-
base,
1395-
unresolved_mark,
1396-
config,
1397-
))
1398-
}
1380+
build_resolver(base_url, paths, config.resolve_fully)
13991381
}
1400-
}
1382+
};
1383+
1384+
Some((base, resolver))
14011385
}
14021386
}
14031387

@@ -1712,7 +1696,7 @@ fn build_resolver(
17121696
mut base_url: PathBuf,
17131697
paths: CompiledPaths,
17141698
resolve_fully: bool,
1715-
) -> Box<SwcImportResolver> {
1699+
) -> SwcImportResolver {
17161700
static CACHE: Lazy<DashMap<(PathBuf, CompiledPaths, bool), SwcImportResolver, ARandomState>> =
17171701
Lazy::new(Default::default);
17181702

@@ -1731,7 +1715,7 @@ fn build_resolver(
17311715
}
17321716

17331717
if let Some(cached) = CACHE.get(&(base_url.clone(), paths.clone(), resolve_fully)) {
1734-
return Box::new((*cached).clone());
1718+
return cached.clone();
17351719
}
17361720

17371721
let r = {
@@ -1758,5 +1742,5 @@ fn build_resolver(
17581742

17591743
CACHE.insert((base_url, paths, resolve_fully), r.clone());
17601744

1761-
Box::new(r)
1745+
r
17621746
}

crates/swc/src/lib.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ use swc_ecma_transforms::{
147147
fixer,
148148
helpers::{self, Helpers},
149149
hygiene,
150-
modules::path::NodeImportResolver,
150+
modules::{path::NodeImportResolver, rewriter::import_rewriter},
151151
pass::noop,
152152
resolver,
153153
};
@@ -982,6 +982,10 @@ impl Compiler {
982982
let mut checker = FastDts::new(fm.name.clone());
983983
let mut module = program.clone().expect_module();
984984

985+
if let Some((base, resolver)) = config.resolver {
986+
module = module.fold_with(&mut import_rewriter(base, resolver));
987+
}
988+
985989
let issues = checker.transform(&mut module);
986990

987991
for issue in issues {
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"jsc": {
3+
"parser": {
4+
"syntax": "typescript"
5+
},
6+
"experimental": {
7+
"emitIsolatedDts": true
8+
},
9+
"baseUrl": "./",
10+
"paths": {
11+
"@lib/*": ["src/*"]
12+
}
13+
}
14+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from "@lib/example";
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
const a = 1;
2+
export { a };
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from "./src/example";
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from "./src/example";
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
declare const a: number;
2+
export { a };
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
var a = 1;
2+
export { a };

0 commit comments

Comments
 (0)