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

perf: improve performance of eval-source-map #7630

Merged
merged 1 commit into from
Aug 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
134 changes: 133 additions & 1 deletion Cargo.lock

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

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ rustc-hash = { version = "1.1.0" }
schemars = { version = "0.8.16" }
serde = { version = "1.0.197" }
serde_json = { version = "1.0.115" }
simd-json = { version = "0.13.10" }
stacker = { version = "0.1.15" }
sugar_path = { version = "1.2.0", features = ["cached_current_dir"] }
syn = { version = "2.0.58" }
Expand Down
3 changes: 2 additions & 1 deletion crates/rspack_plugin_devtool/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,15 @@ pathdiff = { workspace = true }
rayon = { workspace = true }
regex = { workspace = true }
rspack_base64 = { version = "0.1.0", path = "../rspack_base64" }
rspack_collections = { version = "0.1.0", path = "../rspack_collections" }
rspack_core = { version = "0.1.0", path = "../rspack_core" }
rspack_error = { version = "0.1.0", path = "../rspack_error" }
rspack_hash = { version = "0.1.0", path = "../rspack_hash" }
rspack_hook = { version = "0.1.0", path = "../rspack_hook" }
rspack_plugin_javascript = { version = "0.1.0", path = "../rspack_plugin_javascript" }
rspack_util = { version = "0.1.0", path = "../rspack_util" }
rustc-hash = { workspace = true }
serde_json = { workspace = true }
simd-json = { workspace = true }
tracing = { workspace = true }

[package.metadata.cargo-shear]
Expand Down
69 changes: 43 additions & 26 deletions crates/rspack_plugin_devtool/src/eval_dev_tool_module_plugin.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
use std::hash::Hash;
use std::sync::LazyLock;
use std::{borrow::Cow, hash::Hash};

use dashmap::DashMap;
use derivative::Derivative;
use rspack_collections::UkeySet;
use rspack_core::{
rspack_sources::{BoxSource, RawSource, Source, SourceExt},
ApplyContext, BoxModule, ChunkInitFragments, ChunkUkey, Compilation, CompilationParams,
Expand All @@ -15,8 +16,6 @@ use rspack_plugin_javascript::{
JavascriptModulesChunkHash, JavascriptModulesInlineInRuntimeBailout,
JavascriptModulesRenderModuleContent, JsPlugin, RenderSource,
};
use rustc_hash::FxHashSet as HashSet;
use serde_json::json;

use crate::{
module_filename_helpers::ModuleFilenameHelpers, ModuleFilenameTemplate, ModuleOrSource,
Expand Down Expand Up @@ -138,7 +137,11 @@ fn eval_devtool_plugin_render_module_content(
);
// TODO: Implement support for the trustedTypes option.
// This will depend on the additionalModuleRuntimeRequirements hook.
RawSource::from(format!("eval({});", json!(format!("{source}{footer}")))).boxed()
RawSource::from(format!(
"eval({});",
simd_json::to_string(&format!("{source}{footer}")).expect("failed to parse string")
))
.boxed()
};

self.cache.insert(origin_source, source.clone());
Expand Down Expand Up @@ -184,36 +187,50 @@ impl Plugin for EvalDevToolModulePlugin {
}
}

// https://tc39.es/ecma262/#sec-encodeuri-uri
fn encode_uri(uri: &str) -> String {
encode(uri, ";/?:@&=+$,#")
}

static ALWAYS_UNESCAPED: LazyLock<HashSet<char>> = LazyLock::new(|| {
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~!*'()"
// https://tc39.es/ecma262/#sec-encode
// UNESCAPED is combined by ALWAYS_UNESCAPED and ";/?:@&=+$,#"
static UNESCAPED: LazyLock<UkeySet<u32>> = LazyLock::new(|| {
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~!*'();/?:@&=+$,#"
.chars()
.map(|c| c as u32)
.collect()
});

// https://tc39.es/ecma262/#sec-encode
fn encode(string: &str, extra_unescaped: &str) -> String {
fn encode_uri(string: &str) -> Cow<str> {
// Let R be the empty String.
let mut r = String::new();
let mut r = Cow::Borrowed(string);
// Let alwaysUnescaped be the string-concatenation of the ASCII word characters and "-.!~*'()".
let always_unescaped = ALWAYS_UNESCAPED.clone();
// Let unescapedSet be the string-concatenation of alwaysUnescaped and extraUnescaped.
let unescaped_set: HashSet<char> = always_unescaped
.union(&extra_unescaped.chars().collect::<HashSet<_>>())
.cloned()
.collect();
for c in string.chars() {
if unescaped_set.contains(&c) {
r.push(c);
for (byte_idx, c) in string.char_indices() {
if UNESCAPED.contains(&(c as u32)) {
match r {
Cow::Borrowed(_) => {
continue;
}
Cow::Owned(mut inner) => {
inner.push(c);
r = Cow::Owned(inner);
}
}
} else {
let mut b = [0u8; 4];
let octets = c.encode_utf8(&mut b).as_bytes().to_vec();
for octet in octets {
r.push_str(&format!("%{:02X}", octet));
match r {
Cow::Borrowed(_) => {
let mut s = string[0..byte_idx].to_string();
let mut b = [0u8; 4];
let octets = c.encode_utf8(&mut b).as_bytes().to_vec();
for octet in octets {
s.push_str(&format!("%{:02X}", octet));
}
r = Cow::Owned(s);
}
Cow::Owned(mut inner) => {
let mut b = [0u8; 4];
let octets = c.encode_utf8(&mut b).as_bytes().to_vec();
for octet in octets {
inner.push_str(&format!("%{:02X}", octet));
}
r = Cow::Owned(inner);
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ use rspack_plugin_javascript::{
JavascriptModulesRenderModuleContent, JsPlugin, RenderSource,
};
use rspack_util::identifier::make_paths_absolute;
use serde_json::json;

use crate::{
module_filename_helpers::ModuleFilenameHelpers, ModuleFilenameTemplate, ModuleOrSource,
Expand Down Expand Up @@ -174,7 +173,11 @@ fn eval_source_map_devtool_plugin_render_module_content(
let base64 = rspack_base64::encode_to_string(&map_buffer);
let footer =
format!("\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,{base64}");
RawSource::from(format!("eval({});", json!(format!("{source}{footer}")))).boxed()
RawSource::from(format!(
"eval({});",
simd_json::to_string(&format!("{source}{footer}")).expect("should convert to string")
))
.boxed()
};
self.cache.insert(origin_source, source.clone());
render_source.source = source;
Expand Down
Loading