Skip to content

Commit

Permalink
perf: js source map
Browse files Browse the repository at this point in the history
  • Loading branch information
SyMind committed Jan 8, 2025
1 parent 0496ac8 commit 81c1a2e
Show file tree
Hide file tree
Showing 4 changed files with 131 additions and 49 deletions.
16 changes: 12 additions & 4 deletions crates/node_binding/binding.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -733,15 +733,13 @@ export interface JsLibraryOptions {

export interface JsLoaderContext {
resourceData: Readonly<JsResourceData>
/** Will be deprecated. Use module.module_identifier instead */
_moduleIdentifier: Readonly<string>
_module: JsModule
hot: Readonly<boolean>
/** Content maybe empty in pitching stage */
content: null | Buffer
content: null | Buffer | string
additionalData?: any
__internal__parseMeta: Record<string, string>
sourceMap?: Buffer
sourceMap?: JsSourceMap
cacheable: boolean
fileDependencies: Array<string>
contextDependencies: Array<string>
Expand Down Expand Up @@ -870,6 +868,16 @@ export interface JsRuntimeRequirementInTreeResult {
runtimeRequirements: JsRuntimeGlobals
}

export interface JsSourceMap {
version: number
file?: string
sources: Array<string>
sourcesContent?: Array<string>
names: Array<string>
mappings: string
sourceRoot?: string
}

export interface JsStatsAsset {
type: string
name: string
Expand Down
126 changes: 108 additions & 18 deletions crates/rspack_binding_values/src/plugins/js_loader/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,109 @@ use std::collections::HashMap;

use napi::bindgen_prelude::*;
use napi_derive::napi;
use rspack_core::{LoaderContext, RunnerContext};
use rspack_error::error;
use rspack_core::{rspack_sources::SourceMap, LoaderContext, RunnerContext};
use rspack_loader_runner::{LoaderItem, State as LoaderState};
use rspack_napi::threadsafe_js_value_ref::ThreadsafeJsValueRef;
use rspack_napi::{
napi::JsString, string::JsStringExt, threadsafe_js_value_ref::ThreadsafeJsValueRef,
};

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

#[napi(object)]
pub struct JsSourceMap {
pub version: u8,
pub file: Option<JsString>,
pub sources: Vec<JsString>,
pub sources_content: Option<Vec<JsString>>,
pub names: Vec<JsString>,
pub mappings: JsString,
pub source_root: Option<JsString>,
}

pub struct JsSourceMapWrapper(SourceMap);

impl JsSourceMapWrapper {
pub fn new(source_map: SourceMap) -> Self {
Self(source_map)
}

pub fn take(self) -> SourceMap {
self.0
}
}

impl ToNapiValue for JsSourceMapWrapper {
unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> Result<sys::napi_value> {
let env_wrapper = Env::from_raw(env);

let file = match val.0.file() {
Some(s) => Some(env_wrapper.create_string(s)?),
None => None,
};
let mut sources = Vec::with_capacity(val.0.sources().len());
for source in val.0.sources() {
sources.push(env_wrapper.create_string(source)?);
}
let mut sources_content = Vec::with_capacity(val.0.sources_content().len());
for source_content in val.0.sources_content() {
sources_content.push(env_wrapper.create_string(source_content)?);
}
let mut names = Vec::with_capacity(val.0.sources_content().len());
for name in val.0.names() {
names.push(env_wrapper.create_string(name)?);
}
let mappings = env_wrapper.create_string(val.0.mappings())?;
let source_root = match val.0.source_root() {
Some(s) => Some(env_wrapper.create_string(s)?),
None => None,
};

let js_source_map = JsSourceMap {
version: 3,
file,
sources,
sources_content: if sources_content.is_empty() {
None
} else {
Some(sources_content)
},
names,
mappings,
source_root,
};
ToNapiValue::to_napi_value(env, js_source_map)
}
}

impl FromNapiValue for JsSourceMapWrapper {
unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> {
let js_source_map: JsSourceMap = FromNapiValue::from_napi_value(env, napi_val)?;

let sources_content = match js_source_map.sources_content {
Some(sources_content) => sources_content
.into_iter()
.map(|source| source.into_string())
.collect::<Vec<_>>(),
None => vec![],
};

Ok(JsSourceMapWrapper(SourceMap::new(
js_source_map.mappings.into_string(),
js_source_map
.sources
.into_iter()
.map(|source| source.into_string())
.collect::<Vec<_>>(),
sources_content,
js_source_map
.names
.into_iter()
.map(|source| source.into_string())
.collect::<Vec<_>>(),
)))
}
}

#[napi(object)]
pub struct JsLoaderItem {
pub request: String,
Expand Down Expand Up @@ -57,21 +153,19 @@ impl From<LoaderState> for JsLoaderState {
pub struct JsLoaderContext {
#[napi(ts_type = "Readonly<JsResourceData>")]
pub resource_data: JsResourceData,
/// Will be deprecated. Use module.module_identifier instead
#[napi(js_name = "_moduleIdentifier", ts_type = "Readonly<string>")]
pub module_identifier: String,
#[napi(js_name = "_module", ts_type = "JsModule")]
pub module: JsModuleWrapper,
#[napi(ts_type = "Readonly<boolean>")]
pub hot: bool,

/// Content maybe empty in pitching stage
pub content: Either<Null, Buffer>,
pub content: Either3<Null, Buffer, String>,
#[napi(ts_type = "any")]
pub additional_data: Option<ThreadsafeJsValueRef<Unknown>>,
#[napi(js_name = "__internal__parseMeta")]
pub parse_meta: HashMap<String, String>,
pub source_map: Option<Buffer>,
#[napi(ts_type = "JsSourceMap")]
pub source_map: Option<JsSourceMapWrapper>,
pub cacheable: bool,
pub file_dependencies: Vec<String>,
pub context_dependencies: Vec<String>,
Expand All @@ -96,25 +190,21 @@ impl TryFrom<&mut LoaderContext<RunnerContext>> for JsLoaderContext {

Ok(JsLoaderContext {
resource_data: cx.resource_data.as_ref().into(),
module_identifier: module.identifier().to_string(),
module: JsModuleWrapper::new(module, cx.context.compilation_id, None),
hot: cx.hot,
content: match cx.content() {
Some(c) => Either::B(c.to_owned().into_bytes().into()),
None => Either::A(Null),
Some(c) => match c {
rspack_core::Content::String(s) => Either3::C(s.to_string()),
rspack_core::Content::Buffer(vec) => Either3::B(vec.clone().into()),
},
None => Either3::A(Null),
},
parse_meta: cx.parse_meta.clone().into_iter().collect(),
additional_data: cx
.additional_data()
.and_then(|data| data.get::<ThreadsafeJsValueRef<Unknown>>())
.cloned(),
source_map: cx
.source_map()
.cloned()
.map(|v| v.to_json())
.transpose()
.map_err(|e| error!(e.to_string()))?
.map(|v| v.into_bytes().into()),
source_map: cx.source_map().cloned().map(JsSourceMapWrapper::new),
cacheable: cx.cacheable,
file_dependencies: cx
.file_dependencies
Expand Down
16 changes: 6 additions & 10 deletions crates/rspack_binding_values/src/plugins/js_loader/scheduler.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use napi::Either;
use napi::bindgen_prelude::Either3;
use rspack_core::{
diagnostics::CapturedLoaderError, AdditionalData, LoaderContext, NormalModuleLoaderShouldYield,
NormalModuleLoaderStartYielding, RunnerContext, BUILTIN_LOADER_PREFIX,
};
use rspack_error::{error, Result};
use rspack_error::Result;
use rspack_hook::plugin_hook;
use rspack_loader_runner::State as LoaderState;

Expand Down Expand Up @@ -78,15 +78,11 @@ pub(crate) fn merge_loader_context(
.collect();

let content = match from.content {
Either::A(_) => None,
Either::B(c) => Some(rspack_core::Content::from(Into::<Vec<u8>>::into(c))),
Either3::A(_) => None,
Either3::B(c) => Some(rspack_core::Content::from(Into::<Vec<u8>>::into(c))),
Either3::C(s) => Some(rspack_core::Content::from(s)),
};
let source_map = from
.source_map
.as_ref()
.map(|s| rspack_core::rspack_sources::SourceMap::from_slice(s))
.transpose()
.map_err(|e| error!(e.to_string()))?;
let source_map = from.source_map.map(|s| s.take());
let additional_data = from.additional_data.take().map(|data| {
let mut additional = AdditionalData::default();
additional.insert(data);
Expand Down
22 changes: 5 additions & 17 deletions packages/rspack/src/loader-runner/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,8 @@ import {
import {
concatErrorMsgAndStack,
isNil,
serializeObject,
stringifyLoaderObject,
toBuffer,
toObject
toBuffer
} from "../util";
import { createHash } from "../util/createHash";
import {
Expand Down Expand Up @@ -222,16 +220,6 @@ export class LoaderObject {
}
}

class JsSourceMap {
static __from_binding(map?: Buffer) {
return isNil(map) ? undefined : toObject(map);
}

static __to_binding(map?: object) {
return serializeObject(map);
}
}

const loadLoaderAsync: (loaderObject: LoaderObject) => Promise<void> =
promisify(loadLoader);

Expand Down Expand Up @@ -679,7 +667,7 @@ export async function runLoaders(
name,
source!,
assetInfo!,
context._moduleIdentifier
context._module.moduleIdentifier
);
};
loaderContext.fs = compiler.inputFileSystem;
Expand Down Expand Up @@ -823,7 +811,7 @@ export async function runLoaders(
if (hasArg) {
const [content, sourceMap, additionalData] = args;
context.content = isNil(content) ? null : toBuffer(content);
context.sourceMap = serializeObject(sourceMap);
context.sourceMap = sourceMap;
context.additionalData = additionalData;
break;
}
Expand All @@ -833,7 +821,7 @@ export async function runLoaders(
}
case JsLoaderState.Normal: {
let content = context.content;
let sourceMap = JsSourceMap.__from_binding(context.sourceMap);
let sourceMap = context.sourceMap;
let additionalData = context.additionalData;

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

context.content = isNil(content) ? null : toBuffer(content);
context.sourceMap = JsSourceMap.__to_binding(sourceMap);
context.sourceMap = sourceMap;
context.additionalData = additionalData;

break;
Expand Down

0 comments on commit 81c1a2e

Please sign in to comment.