Skip to content
This repository was archived by the owner on Jul 6, 2025. It is now read-only.

Commit fe24457

Browse files
committed
Revert client transfomer
1 parent 47eec87 commit fe24457

File tree

9 files changed

+121
-45
lines changed

9 files changed

+121
-45
lines changed

compiler/dist/wasm.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

compiler/src/lib.rs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ mod tests;
1515

1616
use resolver::{DependencyDescriptor, Resolver};
1717
use serde::{Deserialize, Serialize};
18+
use std::collections::HashMap;
1819
use std::str::FromStr;
1920
use std::{cell::RefCell, rc::Rc};
2021
use swc::{EmitOptions, SWC};
@@ -37,6 +38,12 @@ pub struct Options {
3738
#[serde(default)]
3839
pub import_map: Option<String>,
3940

41+
#[serde(default)]
42+
pub graph_versions: HashMap<String, String>,
43+
44+
#[serde(default)]
45+
pub initial_graph_version: Option<String>,
46+
4047
#[serde(default = "default_target")]
4148
pub target: String,
4249

@@ -96,7 +103,16 @@ pub fn parse_deps(specifier: &str, code: &str, options: JsValue) -> Result<JsVal
96103
.expect("could not pause the import map")
97104
.import_map;
98105
let resolver = Rc::new(RefCell::new(Resolver::new(
99-
specifier, "", None, None, None, importmap, false, false,
106+
specifier,
107+
"",
108+
None,
109+
None,
110+
None,
111+
importmap,
112+
HashMap::new(),
113+
None,
114+
false,
115+
false,
100116
)));
101117
let module = SWC::parse(specifier, code, EsVersion::Es2022, options.lang).expect("could not parse the module");
102118
let deps = module.parse_deps(resolver).expect("could not parse the module");
@@ -125,6 +141,8 @@ pub fn transform(specifier: &str, code: &str, options: JsValue) -> Result<JsValu
125141
options.jsx_runtime_version,
126142
options.jsx_runtime_cdn_version,
127143
importmap,
144+
options.graph_versions,
145+
options.initial_graph_version,
128146
options.is_dev,
129147
true,
130148
)));

compiler/src/resolve_fold.rs

Lines changed: 41 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,26 @@
11
use crate::resolver::Resolver;
22
use crate::swc_helpers::{is_call_expr_by_name, new_str};
33
use std::{cell::RefCell, rc::Rc};
4-
use swc_common::DUMMY_SP;
4+
use swc_common::{Span, DUMMY_SP};
55
use swc_ecmascript::ast::*;
66
use swc_ecmascript::visit::{noop_fold_type, Fold, FoldWith};
77

8-
pub fn resolve_fold(resolver: Rc<RefCell<Resolver>>, strip_data_export: bool) -> impl Fold {
8+
pub fn resolve_fold(
9+
resolver: Rc<RefCell<Resolver>>,
10+
strip_data_export: bool,
11+
mark_import_src_location: bool,
12+
) -> impl Fold {
913
ResolveFold {
1014
resolver,
1115
strip_data_export,
16+
mark_import_src_location,
1217
}
1318
}
1419

1520
pub struct ResolveFold {
1621
resolver: Rc<RefCell<Resolver>>,
1722
strip_data_export: bool,
23+
mark_import_src_location: bool,
1824
}
1925

2026
impl Fold for ResolveFold {
@@ -35,7 +41,11 @@ impl Fold for ResolveFold {
3541
ModuleItem::ModuleDecl(ModuleDecl::Import(import_decl))
3642
} else {
3743
let mut resolver = self.resolver.borrow_mut();
38-
let resolved_url = resolver.resolve(import_decl.src.value.as_ref(), &import_decl.src.span, false);
44+
let resolved_url = resolver.resolve(
45+
import_decl.src.value.as_ref(),
46+
false,
47+
mark_span(&import_decl.src.span, self.mark_import_src_location),
48+
);
3949
ModuleItem::ModuleDecl(ModuleDecl::Import(ImportDecl {
4050
src: new_str(&resolved_url),
4151
..import_decl
@@ -62,7 +72,11 @@ impl Fold for ResolveFold {
6272
}))
6373
} else {
6474
let mut resolver = self.resolver.borrow_mut();
65-
let resolved_url = resolver.resolve(src.value.as_ref(), &src.span, false);
75+
let resolved_url = resolver.resolve(
76+
src.value.as_ref(),
77+
false,
78+
mark_span(&src.span, self.mark_import_src_location),
79+
);
6680
ModuleItem::ModuleDecl(ModuleDecl::ExportNamed(NamedExport {
6781
span,
6882
specifiers,
@@ -75,7 +89,11 @@ impl Fold for ResolveFold {
7589
// match: export * from "https://esm.sh/react"
7690
ModuleDecl::ExportAll(ExportAll { src, span, asserts }) => {
7791
let mut resolver = self.resolver.borrow_mut();
78-
let resolved_url = resolver.resolve(src.value.as_ref(), &src.span, false);
92+
let resolved_url = resolver.resolve(
93+
src.value.as_ref(),
94+
false,
95+
mark_span(&src.span, self.mark_import_src_location),
96+
);
7997
ModuleItem::ModuleDecl(ModuleDecl::ExportAll(ExportAll {
8098
span,
8199
src: new_str(&resolved_url),
@@ -167,7 +185,11 @@ impl Fold for ResolveFold {
167185
};
168186
if let Some(src) = src {
169187
let mut resolver = self.resolver.borrow_mut();
170-
let new_src = resolver.resolve(src.value.as_ref(), &src.span, true);
188+
let new_src = resolver.resolve(
189+
src.value.as_ref(),
190+
true,
191+
mark_span(&src.span, self.mark_import_src_location),
192+
);
171193

172194
args[0] = ExprOrSpread {
173195
spread: None,
@@ -195,7 +217,11 @@ impl Fold for ResolveFold {
195217
};
196218
if let Some(src) = src {
197219
let mut resolver = self.resolver.borrow_mut();
198-
let new_src = resolver.resolve(src.value.as_ref(), &src.span, true);
220+
let new_src = resolver.resolve(
221+
src.value.as_ref(),
222+
true,
223+
mark_span(&src.span, self.mark_import_src_location),
224+
);
199225

200226
call.args[0] = ExprOrSpread {
201227
spread: None,
@@ -207,3 +233,11 @@ impl Fold for ResolveFold {
207233
call.fold_children_with(self)
208234
}
209235
}
236+
237+
fn mark_span(span: &Span, ok: bool) -> Option<Span> {
238+
if ok {
239+
Some(span.clone())
240+
} else {
241+
None
242+
}
243+
}

compiler/src/resolver.rs

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use path_slash::PathBufExt;
44
use pathdiff::diff_paths;
55
use regex::Regex;
66
use serde::Serialize;
7+
use std::collections::HashMap;
78
use std::path::{Path, PathBuf};
89
use std::str::FromStr;
910
use swc_common::Span;
@@ -20,7 +21,8 @@ lazy_static! {
2021
pub struct DependencyDescriptor {
2122
pub specifier: String,
2223
pub import_url: String,
23-
pub loc: Span,
24+
#[serde(skip_serializing_if = "Option::is_none")]
25+
pub loc: Option<Span>,
2426
#[serde(skip_serializing_if = "is_false")]
2527
pub dynamic: bool,
2628
}
@@ -46,6 +48,8 @@ pub struct Resolver {
4648
resolve_remote_deps: bool,
4749
jsx_runtime_version: Option<String>,
4850
jsx_runtime_cdn_version: Option<String>,
51+
graph_versions: HashMap<String, String>,
52+
initial_graph_version: Option<String>,
4953
}
5054

5155
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
@@ -64,6 +68,8 @@ impl Resolver {
6468
jsx_runtime_version: Option<String>,
6569
jsx_runtime_cdn_version: Option<String>,
6670
import_map: ImportMap,
71+
graph_versions: HashMap<String, String>,
72+
initial_graph_version: Option<String>,
6773
is_dev: bool,
6874
resolve_remote_deps: bool,
6975
) -> Self {
@@ -77,6 +83,8 @@ impl Resolver {
7783
jsx_runtime_cdn_version,
7884
jsx_static_classes: IndexSet::new(),
7985
import_map,
86+
graph_versions,
87+
initial_graph_version,
8088
is_dev,
8189
resolve_remote_deps,
8290
}
@@ -120,7 +128,7 @@ impl Resolver {
120128
}
121129

122130
/// Resolve import/export URLs.
123-
pub fn resolve(&mut self, url: &str, span: &Span, dynamic: bool) -> String {
131+
pub fn resolve(&mut self, url: &str, dynamic: bool, loc: Option<Span>) -> String {
124132
let referrer = if self.specifier_is_remote {
125133
Url::from_str(self.specifier.as_str()).unwrap()
126134
} else {
@@ -208,16 +216,32 @@ impl Resolver {
208216
}
209217
}
210218

211-
// fix remote url to local path if allowed
212-
if is_remote && self.resolve_remote_deps {
213-
import_url = self.to_local_path(&import_url);
219+
if is_remote {
220+
// fix remote url to local path if allowed
221+
if self.resolve_remote_deps {
222+
import_url = self.to_local_path(&import_url);
223+
}
224+
} else {
225+
// apply graph version if exists
226+
let v = if self.graph_versions.contains_key(&fixed_url) {
227+
self.graph_versions.get(&fixed_url)
228+
} else {
229+
self.initial_graph_version.as_ref()
230+
};
231+
if let Some(version) = v {
232+
if import_url.contains("?") {
233+
import_url = format!("{}&v={}", import_url, version);
234+
} else {
235+
import_url = format!("{}?v={}", import_url, version);
236+
}
237+
}
214238
}
215239

216240
// update dep graph
217241
self.deps.push(DependencyDescriptor {
218242
specifier: fixed_url.clone(),
219-
loc: span.clone(),
220243
import_url: import_url.clone(),
244+
loc,
221245
dynamic,
222246
});
223247

compiler/src/swc.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use crate::resolver::{DependencyDescriptor, Resolver};
77
use std::{cell::RefCell, path::Path, rc::Rc};
88
use swc_common::comments::SingleThreadedComments;
99
use swc_common::errors::{Handler, HandlerFlags};
10-
use swc_common::{chain, FileName, Globals, Mark, SourceMap, DUMMY_SP};
10+
use swc_common::{chain, FileName, Globals, Mark, SourceMap};
1111
use swc_ecma_transforms::proposals::decorators;
1212
use swc_ecma_transforms::react;
1313
use swc_ecma_transforms::typescript::strip;
@@ -93,7 +93,7 @@ impl SWC {
9393
/// parse deps in the module.
9494
pub fn parse_deps(&self, resolver: Rc<RefCell<Resolver>>) -> Result<Vec<DependencyDescriptor>, anyhow::Error> {
9595
let program = Program::Module(self.module.clone());
96-
let mut resolve_fold = resolve_fold(resolver.clone(), false);
96+
let mut resolve_fold = resolve_fold(resolver.clone(), false, true);
9797
program.fold_with(&mut resolve_fold);
9898
let resolver = resolver.borrow();
9999
Ok(resolver.deps.clone())
@@ -114,7 +114,7 @@ impl SWC {
114114
let react_options = if let Some(jsx_import_source) = &options.jsx_import_source {
115115
let mut resolver = resolver.borrow_mut();
116116
let runtime = if is_dev { "/jsx-dev-runtime" } else { "/jsx-runtime" };
117-
let import_source = resolver.resolve(&(jsx_import_source.to_owned() + runtime), &DUMMY_SP, false);
117+
let import_source = resolver.resolve(&(jsx_import_source.to_owned() + runtime), false, None);
118118
let import_source = import_source
119119
.strip_suffix("?dev")
120120
.unwrap_or(&import_source)
@@ -148,7 +148,7 @@ impl SWC {
148148
let passes = chain!(
149149
resolver_with_mark(top_level_mark),
150150
Optional::new(react::jsx_src(is_dev, self.source_map.clone()), is_jsx),
151-
resolve_fold(resolver.clone(), options.strip_data_export),
151+
resolve_fold(resolver.clone(), options.strip_data_export, false),
152152
decorators::decorators(decorators::Config {
153153
legacy: true,
154154
emit_metadata: false

compiler/src/tests.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use super::*;
2+
use std::collections::HashMap;
23

34
fn transform(specifer: &str, source: &str, is_dev: bool, options: &EmitOptions) -> (String, Rc<RefCell<Resolver>>) {
45
let importmap = import_map::parse_from_json(
@@ -12,6 +13,8 @@ fn transform(specifer: &str, source: &str, is_dev: bool, options: &EmitOptions)
1213
)
1314
.expect("could not pause the import map")
1415
.import_map;
16+
let mut graph_versions: HashMap<String, String> = HashMap::new();
17+
graph_versions.insert("./foo.ts".into(), "100".into());
1518
let module =
1619
SWC::parse(specifer, source, swc_ecmascript::ast::EsVersion::Es2022, None).expect("could not parse module");
1720
let resolver = Rc::new(RefCell::new(Resolver::new(
@@ -21,6 +24,8 @@ fn transform(specifer: &str, source: &str, is_dev: bool, options: &EmitOptions)
2124
Some("17.0.2".into()),
2225
Some("64".into()),
2326
importmap,
27+
graph_versions,
28+
None,
2429
is_dev,
2530
true,
2631
)));
@@ -86,7 +91,7 @@ fn import_resolving() {
8691
let (code, _) = transform("./pages/blog/$id.tsx", source, false, &EmitOptions::default());
8792
assert!(code.contains("\"/-/esm.sh/[email protected]\""));
8893
assert!(code.contains("\"/-/cdn.esm.sh/v64/[email protected]\""));
89-
assert!(code.contains("\"../../foo.ts\""));
94+
assert!(code.contains("\"../../foo.ts?v=100\""));
9095
assert!(code.contains("\"./Layout.tsx\""));
9196
assert!(code.contains("\"/-/esm.sh/@fullcalendar/daygrid?css&dev&module\""));
9297
assert!(code.contains("\"../../style/app.css?module\""));

compiler/types.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
export type TransformOptions = {
22
alephPkgUri?: string;
33
importMap?: string;
4+
graphVersions?: Record<string, string>;
5+
initialGraphVersion?: string;
46
isDev?: boolean;
57
jsxImportSource?: string;
68
jsxRuntime?: "react" | "preact";
@@ -20,7 +22,7 @@ export type TransformResult = {
2022
export type DependencyDescriptor = {
2123
readonly specifier: string;
2224
readonly importUrl: string;
23-
readonly loc: { start: number; end: number; ctxt: number };
25+
readonly loc?: { start: number; end: number; ctxt: number };
2426
readonly dynamic?: boolean;
2527
};
2628

server/serve_modules.ts

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -67,14 +67,16 @@ const esModuleLoader = async (input: { pathname: string } & ModuleLoaderContent,
6767
const s = new MagicString(rawCode);
6868
locDeps.forEach((dep) => {
6969
const { specifier, importUrl, loc } = dep;
70-
const versionStr = serverDependencyGraph.get(specifier)?.version || serverDependencyGraph.initialVersion;
71-
let url = importUrl;
72-
if (url.includes("?")) {
73-
url = `"${url}&v=${versionStr}"`;
74-
} else {
75-
url = `"${url}?v=${versionStr}"`;
70+
if (loc) {
71+
const versionStr = serverDependencyGraph.get(specifier)?.version || serverDependencyGraph.initialVersion;
72+
let url = importUrl;
73+
if (url.includes("?")) {
74+
url = `"${url}&v=${versionStr}"`;
75+
} else {
76+
url = `"${url}?v=${versionStr}"`;
77+
}
78+
s.overwrite(loc.start, loc.end, url);
7679
}
77-
s.overwrite(loc.start, loc.end, url);
7880
});
7981
return { content: s.toString(), contentType };
8082
}

0 commit comments

Comments
 (0)