Skip to content

Commit 81c1a2e

Browse files
committed
perf: js source map
1 parent 0496ac8 commit 81c1a2e

File tree

4 files changed

+131
-49
lines changed

4 files changed

+131
-49
lines changed

crates/node_binding/binding.d.ts

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -733,15 +733,13 @@ export interface JsLibraryOptions {
733733

734734
export interface JsLoaderContext {
735735
resourceData: Readonly<JsResourceData>
736-
/** Will be deprecated. Use module.module_identifier instead */
737-
_moduleIdentifier: Readonly<string>
738736
_module: JsModule
739737
hot: Readonly<boolean>
740738
/** Content maybe empty in pitching stage */
741-
content: null | Buffer
739+
content: null | Buffer | string
742740
additionalData?: any
743741
__internal__parseMeta: Record<string, string>
744-
sourceMap?: Buffer
742+
sourceMap?: JsSourceMap
745743
cacheable: boolean
746744
fileDependencies: Array<string>
747745
contextDependencies: Array<string>
@@ -870,6 +868,16 @@ export interface JsRuntimeRequirementInTreeResult {
870868
runtimeRequirements: JsRuntimeGlobals
871869
}
872870

871+
export interface JsSourceMap {
872+
version: number
873+
file?: string
874+
sources: Array<string>
875+
sourcesContent?: Array<string>
876+
names: Array<string>
877+
mappings: string
878+
sourceRoot?: string
879+
}
880+
873881
export interface JsStatsAsset {
874882
type: string
875883
name: string

crates/rspack_binding_values/src/plugins/js_loader/context.rs

Lines changed: 108 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,109 @@ use std::collections::HashMap;
22

33
use napi::bindgen_prelude::*;
44
use napi_derive::napi;
5-
use rspack_core::{LoaderContext, RunnerContext};
6-
use rspack_error::error;
5+
use rspack_core::{rspack_sources::SourceMap, LoaderContext, RunnerContext};
76
use rspack_loader_runner::{LoaderItem, State as LoaderState};
8-
use rspack_napi::threadsafe_js_value_ref::ThreadsafeJsValueRef;
7+
use rspack_napi::{
8+
napi::JsString, string::JsStringExt, threadsafe_js_value_ref::ThreadsafeJsValueRef,
9+
};
910

1011
use crate::{JsModuleWrapper, JsResourceData, JsRspackError};
1112

13+
#[napi(object)]
14+
pub struct JsSourceMap {
15+
pub version: u8,
16+
pub file: Option<JsString>,
17+
pub sources: Vec<JsString>,
18+
pub sources_content: Option<Vec<JsString>>,
19+
pub names: Vec<JsString>,
20+
pub mappings: JsString,
21+
pub source_root: Option<JsString>,
22+
}
23+
24+
pub struct JsSourceMapWrapper(SourceMap);
25+
26+
impl JsSourceMapWrapper {
27+
pub fn new(source_map: SourceMap) -> Self {
28+
Self(source_map)
29+
}
30+
31+
pub fn take(self) -> SourceMap {
32+
self.0
33+
}
34+
}
35+
36+
impl ToNapiValue for JsSourceMapWrapper {
37+
unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> Result<sys::napi_value> {
38+
let env_wrapper = Env::from_raw(env);
39+
40+
let file = match val.0.file() {
41+
Some(s) => Some(env_wrapper.create_string(s)?),
42+
None => None,
43+
};
44+
let mut sources = Vec::with_capacity(val.0.sources().len());
45+
for source in val.0.sources() {
46+
sources.push(env_wrapper.create_string(source)?);
47+
}
48+
let mut sources_content = Vec::with_capacity(val.0.sources_content().len());
49+
for source_content in val.0.sources_content() {
50+
sources_content.push(env_wrapper.create_string(source_content)?);
51+
}
52+
let mut names = Vec::with_capacity(val.0.sources_content().len());
53+
for name in val.0.names() {
54+
names.push(env_wrapper.create_string(name)?);
55+
}
56+
let mappings = env_wrapper.create_string(val.0.mappings())?;
57+
let source_root = match val.0.source_root() {
58+
Some(s) => Some(env_wrapper.create_string(s)?),
59+
None => None,
60+
};
61+
62+
let js_source_map = JsSourceMap {
63+
version: 3,
64+
file,
65+
sources,
66+
sources_content: if sources_content.is_empty() {
67+
None
68+
} else {
69+
Some(sources_content)
70+
},
71+
names,
72+
mappings,
73+
source_root,
74+
};
75+
ToNapiValue::to_napi_value(env, js_source_map)
76+
}
77+
}
78+
79+
impl FromNapiValue for JsSourceMapWrapper {
80+
unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> {
81+
let js_source_map: JsSourceMap = FromNapiValue::from_napi_value(env, napi_val)?;
82+
83+
let sources_content = match js_source_map.sources_content {
84+
Some(sources_content) => sources_content
85+
.into_iter()
86+
.map(|source| source.into_string())
87+
.collect::<Vec<_>>(),
88+
None => vec![],
89+
};
90+
91+
Ok(JsSourceMapWrapper(SourceMap::new(
92+
js_source_map.mappings.into_string(),
93+
js_source_map
94+
.sources
95+
.into_iter()
96+
.map(|source| source.into_string())
97+
.collect::<Vec<_>>(),
98+
sources_content,
99+
js_source_map
100+
.names
101+
.into_iter()
102+
.map(|source| source.into_string())
103+
.collect::<Vec<_>>(),
104+
)))
105+
}
106+
}
107+
12108
#[napi(object)]
13109
pub struct JsLoaderItem {
14110
pub request: String,
@@ -57,21 +153,19 @@ impl From<LoaderState> for JsLoaderState {
57153
pub struct JsLoaderContext {
58154
#[napi(ts_type = "Readonly<JsResourceData>")]
59155
pub resource_data: JsResourceData,
60-
/// Will be deprecated. Use module.module_identifier instead
61-
#[napi(js_name = "_moduleIdentifier", ts_type = "Readonly<string>")]
62-
pub module_identifier: String,
63156
#[napi(js_name = "_module", ts_type = "JsModule")]
64157
pub module: JsModuleWrapper,
65158
#[napi(ts_type = "Readonly<boolean>")]
66159
pub hot: bool,
67160

68161
/// Content maybe empty in pitching stage
69-
pub content: Either<Null, Buffer>,
162+
pub content: Either3<Null, Buffer, String>,
70163
#[napi(ts_type = "any")]
71164
pub additional_data: Option<ThreadsafeJsValueRef<Unknown>>,
72165
#[napi(js_name = "__internal__parseMeta")]
73166
pub parse_meta: HashMap<String, String>,
74-
pub source_map: Option<Buffer>,
167+
#[napi(ts_type = "JsSourceMap")]
168+
pub source_map: Option<JsSourceMapWrapper>,
75169
pub cacheable: bool,
76170
pub file_dependencies: Vec<String>,
77171
pub context_dependencies: Vec<String>,
@@ -96,25 +190,21 @@ impl TryFrom<&mut LoaderContext<RunnerContext>> for JsLoaderContext {
96190

97191
Ok(JsLoaderContext {
98192
resource_data: cx.resource_data.as_ref().into(),
99-
module_identifier: module.identifier().to_string(),
100193
module: JsModuleWrapper::new(module, cx.context.compilation_id, None),
101194
hot: cx.hot,
102195
content: match cx.content() {
103-
Some(c) => Either::B(c.to_owned().into_bytes().into()),
104-
None => Either::A(Null),
196+
Some(c) => match c {
197+
rspack_core::Content::String(s) => Either3::C(s.to_string()),
198+
rspack_core::Content::Buffer(vec) => Either3::B(vec.clone().into()),
199+
},
200+
None => Either3::A(Null),
105201
},
106202
parse_meta: cx.parse_meta.clone().into_iter().collect(),
107203
additional_data: cx
108204
.additional_data()
109205
.and_then(|data| data.get::<ThreadsafeJsValueRef<Unknown>>())
110206
.cloned(),
111-
source_map: cx
112-
.source_map()
113-
.cloned()
114-
.map(|v| v.to_json())
115-
.transpose()
116-
.map_err(|e| error!(e.to_string()))?
117-
.map(|v| v.into_bytes().into()),
207+
source_map: cx.source_map().cloned().map(JsSourceMapWrapper::new),
118208
cacheable: cx.cacheable,
119209
file_dependencies: cx
120210
.file_dependencies

crates/rspack_binding_values/src/plugins/js_loader/scheduler.rs

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
use napi::Either;
1+
use napi::bindgen_prelude::Either3;
22
use rspack_core::{
33
diagnostics::CapturedLoaderError, AdditionalData, LoaderContext, NormalModuleLoaderShouldYield,
44
NormalModuleLoaderStartYielding, RunnerContext, BUILTIN_LOADER_PREFIX,
55
};
6-
use rspack_error::{error, Result};
6+
use rspack_error::Result;
77
use rspack_hook::plugin_hook;
88
use rspack_loader_runner::State as LoaderState;
99

@@ -78,15 +78,11 @@ pub(crate) fn merge_loader_context(
7878
.collect();
7979

8080
let content = match from.content {
81-
Either::A(_) => None,
82-
Either::B(c) => Some(rspack_core::Content::from(Into::<Vec<u8>>::into(c))),
81+
Either3::A(_) => None,
82+
Either3::B(c) => Some(rspack_core::Content::from(Into::<Vec<u8>>::into(c))),
83+
Either3::C(s) => Some(rspack_core::Content::from(s)),
8384
};
84-
let source_map = from
85-
.source_map
86-
.as_ref()
87-
.map(|s| rspack_core::rspack_sources::SourceMap::from_slice(s))
88-
.transpose()
89-
.map_err(|e| error!(e.to_string()))?;
85+
let source_map = from.source_map.map(|s| s.take());
9086
let additional_data = from.additional_data.take().map(|data| {
9187
let mut additional = AdditionalData::default();
9288
additional.insert(data);

packages/rspack/src/loader-runner/index.ts

Lines changed: 5 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,8 @@ import {
4242
import {
4343
concatErrorMsgAndStack,
4444
isNil,
45-
serializeObject,
4645
stringifyLoaderObject,
47-
toBuffer,
48-
toObject
46+
toBuffer
4947
} from "../util";
5048
import { createHash } from "../util/createHash";
5149
import {
@@ -222,16 +220,6 @@ export class LoaderObject {
222220
}
223221
}
224222

225-
class JsSourceMap {
226-
static __from_binding(map?: Buffer) {
227-
return isNil(map) ? undefined : toObject(map);
228-
}
229-
230-
static __to_binding(map?: object) {
231-
return serializeObject(map);
232-
}
233-
}
234-
235223
const loadLoaderAsync: (loaderObject: LoaderObject) => Promise<void> =
236224
promisify(loadLoader);
237225

@@ -679,7 +667,7 @@ export async function runLoaders(
679667
name,
680668
source!,
681669
assetInfo!,
682-
context._moduleIdentifier
670+
context._module.moduleIdentifier
683671
);
684672
};
685673
loaderContext.fs = compiler.inputFileSystem;
@@ -823,7 +811,7 @@ export async function runLoaders(
823811
if (hasArg) {
824812
const [content, sourceMap, additionalData] = args;
825813
context.content = isNil(content) ? null : toBuffer(content);
826-
context.sourceMap = serializeObject(sourceMap);
814+
context.sourceMap = sourceMap;
827815
context.additionalData = additionalData;
828816
break;
829817
}
@@ -833,7 +821,7 @@ export async function runLoaders(
833821
}
834822
case JsLoaderState.Normal: {
835823
let content = context.content;
836-
let sourceMap = JsSourceMap.__from_binding(context.sourceMap);
824+
let sourceMap = context.sourceMap;
837825
let additionalData = context.additionalData;
838826

839827
while (loaderContext.loaderIndex >= 0) {
@@ -857,7 +845,7 @@ export async function runLoaders(
857845
}
858846

859847
context.content = isNil(content) ? null : toBuffer(content);
860-
context.sourceMap = JsSourceMap.__to_binding(sourceMap);
848+
context.sourceMap = sourceMap;
861849
context.additionalData = additionalData;
862850

863851
break;

0 commit comments

Comments
 (0)