Skip to content

Commit 58b920d

Browse files
kwonojijjk
andauthored
feat(next-swc/wasm): export async interfaces (#39231)
* build(cargo): update dependencies * feat(next-swc/wasm): export async interfaces * feat(next/swc): use async wasm binding interface * refactor(next/swc): allow to fallback for non-async published pkg * Apply suggestions from code review Co-authored-by: JJ Kasper <jj@jjsweb.site>
1 parent de41597 commit 58b920d

File tree

4 files changed

+86
-46
lines changed

4 files changed

+86
-46
lines changed

packages/next-swc/Cargo.lock

Lines changed: 14 additions & 13 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/next-swc/crates/wasm/Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,9 @@ swc_common = { version = "0.26.0", features = ["concurrent", "sourcemap"] }
3030
swc_ecmascript = { version = "0.186.0", features = ["codegen", "minifier", "optimization", "parser", "react", "transforms", "typescript", "utils", "visit"] }
3131
swc_plugin_runner = { version = "0.70.0", default-features = false, optional = true }
3232
tracing = { version = "0.1.32", features = ["release_max_level_off"] }
33-
wasm-bindgen = {version = "0.2", features = ["serde-serialize"]}
33+
wasm-bindgen = {version = "0.2", features = ["serde-serialize", "enable-interning"]}
3434
wasm-bindgen-futures = "0.4.8"
3535
wasmer = { version = "2.3.0", optional = true, default-features = false }
3636
wasmer-wasi = { version = "2.3.0", optional = true, default-features = false }
3737
getrandom = { version = "0.2.5", optional = true, default-features = false }
38+
js-sys = "0.3.59"

packages/next-swc/crates/wasm/src/lib.rs

Lines changed: 60 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,20 @@
11
use anyhow::{Context, Error};
2+
use js_sys::JsString;
23
use next_swc::{custom_before_pass, TransformOptions};
34
use once_cell::sync::Lazy;
45
use std::sync::Arc;
56
use swc::{config::JsMinifyOptions, config::ParseOptions, try_with_handler, Compiler};
67
use swc_common::{comments::Comments, errors::ColorConfig, FileName, FilePathMapping, SourceMap};
78
use swc_ecmascript::transforms::pass::noop;
8-
use wasm_bindgen::prelude::*;
9+
use wasm_bindgen::{prelude::*, JsCast};
10+
use wasm_bindgen_futures::future_to_promise;
911

1012
fn convert_err(err: Error) -> JsValue {
1113
format!("{:?}", err).into()
1214
}
1315

1416
#[wasm_bindgen(js_name = "minifySync")]
15-
pub fn minify_sync(s: &str, opts: JsValue) -> Result<JsValue, JsValue> {
17+
pub fn minify_sync(s: JsString, opts: JsValue) -> Result<JsValue, JsValue> {
1618
console_error_panic_hook::set_once();
1719

1820
let c = compiler();
@@ -37,8 +39,15 @@ pub fn minify_sync(s: &str, opts: JsValue) -> Result<JsValue, JsValue> {
3739
.map_err(convert_err)
3840
}
3941

42+
#[wasm_bindgen(js_name = "minify")]
43+
pub fn minify(s: JsString, opts: JsValue) -> js_sys::Promise {
44+
// TODO: This'll be properly scheduled once wasm have standard backed thread
45+
// support.
46+
future_to_promise(async { minify_sync(s, opts) })
47+
}
48+
4049
#[wasm_bindgen(js_name = "transformSync")]
41-
pub fn transform_sync(s: &str, opts: JsValue) -> Result<JsValue, JsValue> {
50+
pub fn transform_sync(s: JsValue, opts: JsValue) -> Result<JsValue, JsValue> {
4251
console_error_panic_hook::set_once();
4352

4453
let c = compiler();
@@ -52,37 +61,55 @@ pub fn transform_sync(s: &str, opts: JsValue) -> Result<JsValue, JsValue> {
5261
|handler| {
5362
let opts: TransformOptions = opts.into_serde().context("failed to parse options")?;
5463

55-
let fm = c.cm.new_source_file(
56-
if opts.swc.filename.is_empty() {
57-
FileName::Anon
58-
} else {
59-
FileName::Real(opts.swc.filename.clone().into())
60-
},
61-
s.into(),
62-
);
63-
let cm = c.cm.clone();
64-
let file = fm.clone();
65-
let out = c
66-
.process_js_with_custom_pass(
67-
fm,
68-
None,
69-
handler,
70-
&opts.swc,
71-
|_, comments| {
72-
custom_before_pass(cm, file, &opts, comments.clone(), Default::default())
73-
},
74-
|_, _| noop(),
75-
)
76-
.context("failed to process js file")?;
64+
let s = s.dyn_into::<js_sys::JsString>();
65+
let out = match s {
66+
Ok(s) => {
67+
let fm = c.cm.new_source_file(
68+
if opts.swc.filename.is_empty() {
69+
FileName::Anon
70+
} else {
71+
FileName::Real(opts.swc.filename.clone().into())
72+
},
73+
s.into(),
74+
);
75+
let cm = c.cm.clone();
76+
let file = fm.clone();
77+
c.process_js_with_custom_pass(
78+
fm,
79+
None,
80+
handler,
81+
&opts.swc,
82+
|_, comments| {
83+
custom_before_pass(
84+
cm,
85+
file,
86+
&opts,
87+
comments.clone(),
88+
Default::default(),
89+
)
90+
},
91+
|_, _| noop(),
92+
)
93+
.context("failed to process js file")?
94+
}
95+
Err(v) => c.process_js(handler, v.into_serde().expect(""), &opts.swc)?,
96+
};
7797

7898
JsValue::from_serde(&out).context("failed to serialize json")
7999
},
80100
)
81101
.map_err(convert_err)
82102
}
83103

104+
#[wasm_bindgen(js_name = "transform")]
105+
pub fn transform(s: JsValue, opts: JsValue) -> js_sys::Promise {
106+
// TODO: This'll be properly scheduled once wasm have standard backed thread
107+
// support.
108+
future_to_promise(async { transform_sync(s, opts) })
109+
}
110+
84111
#[wasm_bindgen(js_name = "parseSync")]
85-
pub fn parse_sync(s: &str, opts: JsValue) -> Result<JsValue, JsValue> {
112+
pub fn parse_sync(s: JsString, opts: JsValue) -> Result<JsValue, JsValue> {
86113
console_error_panic_hook::set_once();
87114

88115
let c = swc::Compiler::new(Arc::new(SourceMap::new(FilePathMapping::empty())));
@@ -124,6 +151,13 @@ pub fn parse_sync(s: &str, opts: JsValue) -> Result<JsValue, JsValue> {
124151
.map_err(convert_err)
125152
}
126153

154+
#[wasm_bindgen(js_name = "parse")]
155+
pub fn parse(s: JsString, opts: JsValue) -> js_sys::Promise {
156+
// TODO: This'll be properly scheduled once wasm have standard backed thread
157+
// support.
158+
future_to_promise(async { parse_sync(s, opts) })
159+
}
160+
127161
/// Get global sourcemap
128162
fn compiler() -> Arc<Compiler> {
129163
static C: Lazy<Arc<Compiler>> = Lazy::new(|| {

packages/next/build/swc/index.js

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -143,22 +143,26 @@ async function loadWasm(importPath = '') {
143143
wasmBindings = {
144144
isWasm: true,
145145
transform(src, options) {
146-
return Promise.resolve(
147-
bindings.transformSync(src.toString(), options)
148-
)
146+
// TODO: we can remove fallback to sync interface once new stable version of next-swc gets published (current v12.2)
147+
return bindings?.transform
148+
? bindings.transform(src.toString(), options)
149+
: Promise.resolve(bindings.transformSync(src.toString(), options))
149150
},
150151
transformSync(src, options) {
151152
return bindings.transformSync(src.toString(), options)
152153
},
153154
minify(src, options) {
154-
return Promise.resolve(bindings.minifySync(src.toString(), options))
155+
return bindings?.minify
156+
? bindings.minify(src.toString(), options)
157+
: Promise.resolve(bindings.minifySync(src.toString(), options))
155158
},
156159
minifySync(src, options) {
157160
return bindings.minifySync(src.toString(), options)
158161
},
159162
parse(src, options) {
160-
const astStr = bindings.parseSync(src.toString(), options)
161-
return Promise.resolve(astStr)
163+
return bindings?.parse
164+
? bindings.parse(src.toString(), options)
165+
: Promise.resolve(bindings.parseSync(src.toString(), options))
162166
},
163167
parseSync(src, options) {
164168
const astStr = bindings.parseSync(src.toString(), options)

0 commit comments

Comments
 (0)