mirror of
https://github.com/swc-project/swc.git
synced 2024-11-24 02:06:08 +03:00
Fix bundler (#1234)
swc_bundler: - Handle dependencies of circular modules in wrapped modules. (#1214) - Handle `export * from './file.ts'` properly. (denoland/deno#8481) - Fix deglobbing. (denoland/deno#8486)
This commit is contained in:
parent
f8a1fb878d
commit
8ca3d1160d
@ -8,7 +8,7 @@ edition = "2018"
|
||||
license = "Apache-2.0/MIT"
|
||||
name = "swc_bundler"
|
||||
repository = "https://github.com/swc-project/swc.git"
|
||||
version = "0.17.1"
|
||||
version = "0.17.2"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
[features]
|
||||
|
@ -1,9 +1,6 @@
|
||||
use super::plan::CircularPlan;
|
||||
use crate::{
|
||||
bundler::{
|
||||
chunk::{merge::Ctx, sort::sort},
|
||||
load::TransformedModule,
|
||||
},
|
||||
bundler::chunk::{merge::Ctx, sort::sort},
|
||||
id::Id,
|
||||
Bundler, Load, ModuleId, Resolve,
|
||||
};
|
||||
@ -34,16 +31,6 @@ where
|
||||
"# of circular modules should be 2 or greater than 2 including entry. Got {:?}",
|
||||
plan
|
||||
);
|
||||
let entry_module = self.scope.get_module(entry_id).unwrap();
|
||||
|
||||
let modules = plan
|
||||
.chunks
|
||||
.iter()
|
||||
.map(|&id| self.scope.get_module(id).unwrap())
|
||||
.collect::<Vec<_>>();
|
||||
let mut entry = self
|
||||
.merge_modules(ctx, entry_id, false, false)
|
||||
.context("failed to merge dependency of a cyclic module")?;
|
||||
|
||||
if !ctx.merged.insert(entry_id) {
|
||||
log::debug!("[circular] skip: {:?}", entry_id);
|
||||
@ -54,6 +41,14 @@ where
|
||||
});
|
||||
}
|
||||
|
||||
log::debug!("[circular] Stsrting with: {:?}", entry_id);
|
||||
|
||||
let entry_module = self.scope.get_module(entry_id).unwrap();
|
||||
|
||||
let mut entry = self
|
||||
.merge_modules(ctx, entry_id, false, false)
|
||||
.context("failed to merge dependency of a cyclic module")?;
|
||||
|
||||
let mut exports = vec![];
|
||||
for item in entry.body.iter_mut() {
|
||||
match item {
|
||||
@ -124,24 +119,8 @@ where
|
||||
// imports: &entry_module.imports,
|
||||
// });
|
||||
// print_hygiene("entry:drop_imports", &self.cm, &entry);
|
||||
let mut deps = plan.chunks.clone();
|
||||
deps.retain(|&dep| {
|
||||
if dep == entry_id {
|
||||
return false;
|
||||
}
|
||||
|
||||
if !ctx.merged.insert(dep) {
|
||||
log::debug!("[circular] skip: {:?}", dep);
|
||||
return false;
|
||||
}
|
||||
|
||||
log::debug!("Circular merge: {:?}", dep);
|
||||
|
||||
true
|
||||
});
|
||||
deps.sort();
|
||||
|
||||
let new_module = self.merge_circular_modules(ctx, &modules, entry, deps)?;
|
||||
let new_module = self.merge_circular_modules(ctx, entry, entry_id, plan.chunks.clone())?;
|
||||
|
||||
entry = new_module;
|
||||
|
||||
@ -164,13 +143,29 @@ where
|
||||
}
|
||||
|
||||
/// Merges `a` and `b` into one module.
|
||||
fn merge_circular_modules(
|
||||
pub(super) fn merge_circular_modules(
|
||||
&self,
|
||||
ctx: &Ctx,
|
||||
_circular_modules: &[TransformedModule],
|
||||
mut entry: Module,
|
||||
deps: Vec<ModuleId>,
|
||||
entry_id: ModuleId,
|
||||
mut deps: Vec<ModuleId>,
|
||||
) -> Result<Module, Error> {
|
||||
deps.retain(|&dep| {
|
||||
if dep == entry_id {
|
||||
return false;
|
||||
}
|
||||
|
||||
if !ctx.merged.insert(dep) {
|
||||
log::debug!("[circular] skip: {:?}", dep);
|
||||
return false;
|
||||
}
|
||||
|
||||
log::debug!("Circular merge: {:?}", dep);
|
||||
|
||||
true
|
||||
});
|
||||
deps.sort();
|
||||
|
||||
self.run(|| {
|
||||
let mut dep_body = vec![];
|
||||
|
||||
|
@ -238,12 +238,15 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) struct ExportInjector {
|
||||
pub(super) struct ExportInjector<'a> {
|
||||
pub ctx: &'a Ctx,
|
||||
pub export_ctxt: SyntaxContext,
|
||||
pub wrapped: bool,
|
||||
pub imported: Vec<ModuleItem>,
|
||||
pub source: Source,
|
||||
}
|
||||
|
||||
impl VisitMut for ExportInjector {
|
||||
impl VisitMut for ExportInjector<'_> {
|
||||
noop_visit_mut_type!();
|
||||
|
||||
fn visit_mut_module_items(&mut self, orig: &mut Vec<ModuleItem>) {
|
||||
@ -298,6 +301,13 @@ impl VisitMut for ExportInjector {
|
||||
ModuleItem::ModuleDecl(ModuleDecl::ExportAll(ref export))
|
||||
if export.src.value == self.source.src.value =>
|
||||
{
|
||||
if !self.wrapped {
|
||||
let export_ctxt = export.span.ctxt;
|
||||
self.ctx
|
||||
.transitive_remap
|
||||
.insert(self.export_ctxt, export_ctxt);
|
||||
}
|
||||
|
||||
buf.extend(take(&mut self.imported));
|
||||
}
|
||||
|
||||
|
@ -80,7 +80,7 @@ where
|
||||
// &module,
|
||||
// );
|
||||
|
||||
module = self.merge_deps(ctx, is_entry, module, plan, &info)?;
|
||||
module = self.merge_deps(ctx, is_entry, module, plan, &info, !allow_circular)?;
|
||||
|
||||
// print_hygiene(
|
||||
// &format!("after merging deps: {}", info.fm.name),
|
||||
@ -150,18 +150,16 @@ where
|
||||
|
||||
if let Some(plan) = ctx.plan.circular.get(&dep_id) {
|
||||
module = self
|
||||
.merge_circular(ctx, plan, dep_id)
|
||||
.merge_circular_modules(ctx, module, dep_id, plan.chunks.clone())
|
||||
.with_context(|| format!("failed to merge {:?} (circular import)", dep_id))?;
|
||||
}
|
||||
|
||||
module = self
|
||||
.merge_deps(ctx, false, module, plan, &dep_info)
|
||||
.merge_deps(ctx, false, module, plan, &dep_info, false)
|
||||
.context("failed to merge dependencies")?;
|
||||
|
||||
self.handle_import_deps(ctx, &dep_info, &mut module, false);
|
||||
|
||||
// print_hygiene("wrapped: after deps", &self.cm, &module);
|
||||
|
||||
module
|
||||
} else {
|
||||
let mut module = self.merge_modules(ctx, dep_id, false, true)?;
|
||||
@ -278,6 +276,7 @@ where
|
||||
mut module: Module,
|
||||
plan: &NormalPlan,
|
||||
info: &TransformedModule,
|
||||
from_circular: bool,
|
||||
) -> Result<Module, Error> {
|
||||
self.run(|| -> Result<_, Error> {
|
||||
log::debug!(
|
||||
@ -287,15 +286,18 @@ where
|
||||
plan
|
||||
);
|
||||
|
||||
let deps = info
|
||||
.exports
|
||||
.reexports
|
||||
.iter()
|
||||
.map(|v| &v.0)
|
||||
.cloned()
|
||||
.filter(|source| plan.chunks.iter().all(|chunk| chunk.id != source.module_id))
|
||||
.collect();
|
||||
self.transform_indirect_reexports(ctx, &mut module, deps)?;
|
||||
if !from_circular {
|
||||
let deps = info
|
||||
.exports
|
||||
.reexports
|
||||
.iter()
|
||||
.map(|v| &v.0)
|
||||
.cloned()
|
||||
.filter(|source| plan.chunks.iter().all(|chunk| chunk.id != source.module_id))
|
||||
.collect();
|
||||
self.transform_indirect_reexports(ctx, &mut module, deps)?;
|
||||
}
|
||||
|
||||
if plan.chunks.is_empty() {
|
||||
return Ok(module);
|
||||
}
|
||||
@ -373,6 +375,10 @@ where
|
||||
let mut injector = ExportInjector {
|
||||
imported: take(&mut dep_module.body),
|
||||
source: source.unwrap().clone(),
|
||||
ctx,
|
||||
export_ctxt: info.export_ctxt(),
|
||||
// We use id of the entry
|
||||
wrapped: self.scope.should_be_wrapped_with_a_fn(info.id),
|
||||
};
|
||||
module.body.visit_mut_with(&mut injector);
|
||||
|
||||
@ -503,7 +509,7 @@ where
|
||||
/// This should only be called after everything is merged.
|
||||
///
|
||||
/// This method does not care about orders of statement, and it's expected
|
||||
/// to be collaed before `sort`.
|
||||
/// to be called before `sort`.
|
||||
fn handle_export_stars(&self, ctx: &Ctx, entry: &mut Module) {
|
||||
{
|
||||
// Handle `export *` for non-wrapped modules.
|
||||
@ -525,6 +531,7 @@ where
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
@ -448,6 +448,17 @@ where
|
||||
}
|
||||
|
||||
// Handle circular imports
|
||||
for (root_entry, _) in builder.kinds.iter() {
|
||||
if let Some(members) = builder.circular.get(*root_entry) {
|
||||
plans
|
||||
.normal
|
||||
.entry(*root_entry)
|
||||
.or_default()
|
||||
.chunks
|
||||
.retain(|dep| !members.contains(&dep.id));
|
||||
}
|
||||
}
|
||||
|
||||
for (root_entry, _) in builder.kinds.iter() {
|
||||
let mut bfs = Bfs::new(&builder.direct_deps, *root_entry);
|
||||
|
||||
|
@ -364,11 +364,7 @@ where
|
||||
}
|
||||
|
||||
Expr::Member(mut e) => {
|
||||
e.obj = e.obj.fold_with(self);
|
||||
|
||||
if e.computed {
|
||||
e.prop = e.prop.fold_with(self);
|
||||
}
|
||||
e = e.fold_with(self);
|
||||
|
||||
match &e.obj {
|
||||
ExprOrSuper::Expr(obj) => {
|
||||
@ -377,11 +373,11 @@ where
|
||||
// Deglob identifier usages.
|
||||
if self.deglob_phase && self.idents_to_deglob.contains(&i.to_id()) {
|
||||
match *e.prop {
|
||||
Expr::Ident(prop) => {
|
||||
Expr::Ident(prop) if prop.sym == i.sym => {
|
||||
return Expr::Ident(Ident::new(
|
||||
prop.sym,
|
||||
prop.span.with_ctxt(i.span.ctxt),
|
||||
))
|
||||
));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
@ -299,6 +299,75 @@ fn deno_8399_2() {
|
||||
run("tests/deno/issue-8399-2/input.ts", &[]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn deno_8486_1() {
|
||||
run("tests/deno/issue-8486-1/input.ts", &["myCLI"]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn deno_7288_1() {
|
||||
run("tests/deno/deno-7288-1/input.ts", &[]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn deno_8481_1() {
|
||||
run(
|
||||
"https://raw.githubusercontent.com/nats-io/nats.ws/master/src/mod.ts",
|
||||
&[
|
||||
"Bench",
|
||||
"Connect",
|
||||
"DataBuffer",
|
||||
"DebugEvents",
|
||||
"DenoBuffer",
|
||||
"Empty",
|
||||
"ErrorCode",
|
||||
"Events",
|
||||
"Heartbeat",
|
||||
"INFO",
|
||||
"JSONCodec",
|
||||
"Kind",
|
||||
"MAX_SIZE",
|
||||
"Metric",
|
||||
"MsgHdrsImpl",
|
||||
"MsgImpl",
|
||||
"MuxSubscription",
|
||||
"NatsConnectionImpl",
|
||||
"NatsError",
|
||||
"Nuid",
|
||||
"Parser",
|
||||
"ProtocolHandler",
|
||||
"QueuedIterator",
|
||||
"Request",
|
||||
"State",
|
||||
"StringCodec",
|
||||
"SubscriptionImpl",
|
||||
"Subscriptions",
|
||||
"TD",
|
||||
"TE",
|
||||
"checkOptions",
|
||||
"connect",
|
||||
"createInbox",
|
||||
"credsAuthenticator",
|
||||
"deferred",
|
||||
"delay",
|
||||
"extractProtocolMessage",
|
||||
"headers",
|
||||
"isIP",
|
||||
"jwtAuthenticator",
|
||||
"nkeyAuthenticator",
|
||||
"nkeys",
|
||||
"nuid",
|
||||
"parseIP",
|
||||
"readAll",
|
||||
"render",
|
||||
"setTransportFactory",
|
||||
"setUrlParseFn",
|
||||
"timeout",
|
||||
"writeAll",
|
||||
],
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn merging_order_01() {
|
||||
run(
|
||||
|
2
bundler/tests/deno/deno-7288-1/input.ts
Normal file
2
bundler/tests/deno/deno-7288-1/input.ts
Normal file
@ -0,0 +1,2 @@
|
||||
import * as path from "https://deno.land/std@0.67.0/path/mod.ts";
|
||||
console.log(path);
|
24
bundler/tests/deno/issue-8486-1/input.ts
Normal file
24
bundler/tests/deno/issue-8486-1/input.ts
Normal file
@ -0,0 +1,24 @@
|
||||
import * as log from "https://deno.land/std/log/mod.ts";
|
||||
|
||||
export async function myCLI(): Promise<void> {
|
||||
await log.setup({
|
||||
handlers: {
|
||||
file: new log.handlers.FileHandler("DEBUG", {
|
||||
filename: 'my.log'
|
||||
}),
|
||||
console: new log.handlers.ConsoleHandler("INFO")
|
||||
},
|
||||
loggers: {
|
||||
default: {
|
||||
level: "DEBUG",
|
||||
handlers: ["console", "file"]
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
log.info("Ok!");
|
||||
}
|
||||
|
||||
if (import.meta.main) {
|
||||
myCLI();
|
||||
}
|
Loading…
Reference in New Issue
Block a user