Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Wasm version of JS Transformer #6360

Merged
merged 13 commits into from
Jun 3, 2021
41 changes: 35 additions & 6 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 6 additions & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
[workspace]
members = ["packages/transformers/js", "packages/utils/fs-search"]

[profile.release]
opt-level = 3
# lto = true
members = [
"packages/transformers/js/core",
"packages/transformers/js/napi",
"packages/transformers/js/wasm",
"packages/utils/fs-search",
]
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
[package]
authors = ["Devon Govett <devongovett@gmail.com>"]
name = "parcel-js-swc"
name = "parcel-js-swc-core"
version = "0.1.0"
edition = "2018"

[lib]
crate-type = ["cdylib"]
crate-type = ["rlib"]

[dependencies]
napi = { version = "1", features = ["serde-json"] }
napi-derive = "1"
swc_ecmascript = { version = "0.36.0", features = ["parser", "transforms", "module", "optimization", "react", "typescript", "utils", "visit", "codegen", "utils"] }
swc_ecma_preset_env = "0.20.1"
swc_common = { version = "0.10.19", features = ["tty-emitter", "sourcemap"] }
Expand All @@ -20,12 +19,3 @@ Inflector = "0.11.4"
data-encoding = "2.3.2"
sha-1 = "0.9.4"
dunce = "1.0.1"

[target.'cfg(target_os = "macos")'.dependencies]
jemallocator = { version = "0.3.2", features = ["disable_initial_exec_tls"] }

[target.'cfg(windows)'.dependencies]
mimalloc = { version = "0.1.25", default-features = false }

[build-dependencies]
napi-build = { version = "1" }
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use swc_common::{SourceMap, SyntaxContext, DUMMY_SP};
use swc_ecmascript::ast;
use swc_ecmascript::visit::{Fold, FoldWith};

use utils::*;
use crate::utils::*;

#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)]
pub enum DependencyKind {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use swc_common::{SyntaxContext, DUMMY_SP};
use swc_ecmascript::ast;
use swc_ecmascript::visit::Fold;

use utils::*;
use crate::utils::*;

pub struct EnvReplacer<'a> {
pub replace_env: bool,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::dependency_collector::{DependencyDescriptor, DependencyKind};
use crate::hoist::{Collect, Import};
use crate::utils::SourceLocation;
use data_encoding::{BASE64, HEXLOWER};
use dependency_collector::{DependencyDescriptor, DependencyKind};
use std::collections::HashSet;
use std::path::{Path, PathBuf};
use swc_atoms::JsWord;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ use swc_common::{SourceMap, SyntaxContext, DUMMY_SP};
use swc_ecmascript::ast;
use swc_ecmascript::visit::{Fold, FoldWith};

use dependency_collector::{DependencyDescriptor, DependencyKind};
use utils::{create_require, SourceLocation};
use crate::dependency_collector::{DependencyDescriptor, DependencyKind};
use crate::utils::{create_require, SourceLocation};

pub struct GlobalReplacer<'a> {
pub source_map: &'a SourceMap,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
extern crate napi;
#[macro_use]
extern crate napi_derive;
extern crate swc_common;
extern crate swc_ecma_preset_env;
extern crate swc_ecmascript;
Expand All @@ -13,14 +10,6 @@ extern crate serde;
extern crate serde_bytes;
extern crate sha1;

#[cfg(target_os = "macos")]
#[global_allocator]
static GLOBAL: jemallocator::Jemalloc = jemallocator::Jemalloc;

#[cfg(windows)]
#[global_allocator]
static ALLOC: mimalloc::MiMalloc = mimalloc::MiMalloc;

mod decl_collector;
mod dependency_collector;
mod env_replacer;
Expand All @@ -30,7 +19,6 @@ mod hoist;
mod modules;
mod utils;

use napi::{CallContext, JsObject, JsUnknown, Result};
use std::collections::{HashMap, HashSet};
use std::str::FromStr;

Expand All @@ -39,7 +27,6 @@ use swc_common::comments::SingleThreadedComments;
use swc_common::errors::{DiagnosticBuilder, Emitter, Handler};
use swc_common::{chain, sync::Lrc, FileName, Globals, Mark, SourceMap};
use swc_ecma_preset_env::{preset_env, Mode::Entry, Targets, Version, Versions};
use swc_ecmascript::ast;
use swc_ecmascript::ast::Module;
use swc_ecmascript::codegen::text_writer::JsWriter;
use swc_ecmascript::parser::lexer::Lexer;
Expand All @@ -62,7 +49,7 @@ use modules::esm2cjs;
use utils::{CodeHighlight, Diagnostic, SourceLocation};

#[derive(Serialize, Debug, Deserialize)]
struct Config {
pub struct Config {
filename: String,
#[serde(with = "serde_bytes")]
code: Vec<u8>,
Expand All @@ -85,9 +72,9 @@ struct Config {
}

#[derive(Serialize, Debug, Deserialize, Default)]
struct TransformResult<'a> {
pub struct TransformResult {
#[serde(with = "serde_bytes")]
code: &'a [u8],
code: Vec<u8>,
Copy link
Member Author

@mischnic mischnic May 29, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure whether this being a Vec has worse performance, and if yes, how to still use a slice

AFAICT, before Vec was a local variable, so it shouldn't really change anything

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@devongovett What did you see while profiling that motivated the change from string to &'a [u8]?

map: Option<String>,
shebang: Option<String>,
dependencies: Vec<DependencyDescriptor>,
Expand Down Expand Up @@ -136,12 +123,8 @@ impl Emitter for ErrorBuffer {
}
}

#[js_function(1)]
fn transform(ctx: CallContext) -> Result<JsUnknown> {
let opts = ctx.get::<JsObject>(0)?;
let config: Config = ctx.env.from_js_value(opts)?;
pub fn transform(config: Config) -> Result<TransformResult, std::io::Error> {
let mut result = TransformResult::default();
let mut code_buf = vec![];
let mut map_buf = vec![];

let code = unsafe { std::str::from_utf8_unchecked(&config.code) };
Expand Down Expand Up @@ -197,7 +180,7 @@ fn transform(ctx: CallContext) -> Result<JsUnknown> {
.collect();

result.diagnostics = Some(diagnostics);
ctx.env.to_js_value(&result)
Ok(result)
}
Ok((module, comments)) => {
let mut module = module;
Expand Down Expand Up @@ -333,7 +316,7 @@ fn transform(ctx: CallContext) -> Result<JsUnknown> {
}
Err(diagnostics) => {
result.diagnostics = Some(diagnostics);
return ctx.env.to_js_value(&result);
return Ok(result);
}
}
} else {
Expand All @@ -360,9 +343,8 @@ fn transform(ctx: CallContext) -> Result<JsUnknown> {
result.map = Some(String::from_utf8(map_buf).unwrap());
}
}
code_buf = buf;
result.code = &code_buf;
ctx.env.to_js_value(&result)
result.code = buf;
Ok(result)
},
)
})
Expand Down Expand Up @@ -413,7 +395,7 @@ fn emit(
comments: SingleThreadedComments,
program: &Module,
source_maps: bool,
) -> Result<(Vec<u8>, Vec<(swc_common::BytePos, swc_common::LineCol)>)> {
) -> Result<(Vec<u8>, Vec<(swc_common::BytePos, swc_common::LineCol)>), std::io::Error> {
let mut src_map_buf = vec![];
let mut buf = vec![];
{
Expand All @@ -440,10 +422,3 @@ fn emit(

return Ok((buf, src_map_buf));
}

#[module_exports]
fn init(mut exports: JsObject) -> Result<()> {
exports.create_named_method("transform", transform)?;

Ok(())
}
22 changes: 22 additions & 0 deletions packages/transformers/js/napi/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
[package]
authors = ["Devon Govett <devongovett@gmail.com>"]
name = "parcel-js-swc-napi"
version = "0.1.0"
edition = "2018"

[lib]
crate-type = ["cdylib"]

[dependencies]
napi = { version = "1", features = ["serde-json"] }
napi-derive = "1"
parcel-js-swc-core = { path = "../core" }

[target.'cfg(target_os = "macos")'.dependencies]
jemallocator = { version = "0.3.2", features = ["disable_initial_exec_tls"] }

[target.'cfg(windows)'.dependencies]
mimalloc = { version = "0.1.25", default-features = false }

[build-dependencies]
napi-build = { version = "1" }
30 changes: 30 additions & 0 deletions packages/transformers/js/napi/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
extern crate napi;
#[macro_use]
extern crate napi_derive;
extern crate parcel_js_swc_core;

use napi::{CallContext, JsObject, JsUnknown, Result};

#[cfg(target_os = "macos")]
#[global_allocator]
static GLOBAL: jemallocator::Jemalloc = jemallocator::Jemalloc;

#[cfg(windows)]
#[global_allocator]
static ALLOC: mimalloc::MiMalloc = mimalloc::MiMalloc;

#[js_function(1)]
fn transform(ctx: CallContext) -> Result<JsUnknown> {
let opts = ctx.get::<JsObject>(0)?;
let config: parcel_js_swc_core::Config = ctx.env.from_js_value(opts)?;

let result = parcel_js_swc_core::transform(config)?;
ctx.env.to_js_value(&result)
}

#[module_exports]
fn init(mut exports: JsObject) -> Result<()> {
exports.create_named_method("transform", transform)?;

Ok(())
}
37 changes: 37 additions & 0 deletions packages/transformers/js/native-browser.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import initFn, {transform} from './wasm/dist-web/parcel_js_swc_wasm.js';

export const init = initFn();

function transformWrapper(config) {
let result = transform(config);
return {
...result,
// Hydrate Uint8Array into Buffer
code: Buffer.from(result.code.buffer),
// https://github.com/cloudflare/serde-wasm-bindgen/issues/10
dependencies: result.dependencies?.map(d => ({
...d,
attributes:
d.attributes != null
? Object.fromEntries([...d.attributes])
: undefined,
})),
hoist_result:
result.hoist_result != null
? {
...result.hoist_result,
imported_symbols: Object.fromEntries([

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just noticed this while looking at the link from other PR and wanted to note here too that you can use Object.fromEntries(result.hoist_result.imported_symbols) directly without converting to an intermediate array.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right. But even better, I can remove this altogether now: #6413

...result.hoist_result.imported_symbols,
]),
exported_symbols: Object.fromEntries([
...result.hoist_result.exported_symbols,
]),
dynamic_imports: Object.fromEntries([
...result.hoist_result.dynamic_imports,
]),
}
: undefined,
};
Comment on lines +11 to +34
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(We can remove this again once RReverser/serde-wasm-bindgen#12 is merged)

}

export {transformWrapper as transform};