Skip to content

Commit 16ec430

Browse files
authored
perf: get resolve in external plugin (#11111)
1 parent 46c867e commit 16ec430

3 files changed

Lines changed: 115 additions & 42 deletions

File tree

crates/node_binding/napi-binding.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -463,7 +463,7 @@ export declare class NativeWatchResult {
463463

464464
export declare class RawExternalItemFnCtx {
465465
data(): RawExternalItemFnCtxData
466-
getResolver(): JsResolver
466+
getResolve(options?: RawResolveOptionsWithDependencyType | undefined | null): (context: string, path: string, callback: (error?: Error, text?: string) => void) => void
467467
}
468468

469469
export declare class ReadonlyResourceData {

crates/rspack_binding_api/src/raw_options/raw_external.rs

Lines changed: 77 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
1-
use std::{fmt::Debug, sync::Arc};
1+
use std::{fmt::Debug, path::Path, sync::Arc};
22

3-
use napi::bindgen_prelude::{Either4, Promise};
3+
use napi::{
4+
bindgen_prelude::{Either4, Function, FunctionCallContext, Promise},
5+
Either, Env,
6+
};
47
use napi_derive::napi;
58
use rspack_core::{
69
ExternalItem, ExternalItemFnCtx, ExternalItemFnResult, ExternalItemValue,
@@ -10,7 +13,10 @@ use rspack_napi::threadsafe_function::ThreadsafeFunction;
1013
use rspack_regex::RspackRegex;
1114
use rustc_hash::FxHashMap as HashMap;
1215

13-
use crate::JsResolver;
16+
use crate::{
17+
callbackify, normalize_raw_resolve_options_with_dependency_type, ErrorCode,
18+
RawResolveOptionsWithDependencyType, ResolveRequest,
19+
};
1420

1521
#[napi(object)]
1622
pub struct RawHttpExternalsRspackPluginOptions {
@@ -105,12 +111,74 @@ impl RawExternalItemFnCtx {
105111
}
106112
}
107113

108-
#[napi]
109-
pub fn get_resolver(&self) -> JsResolver {
110-
JsResolver::new(
111-
self.resolver_factory.clone(),
112-
self.resolve_options_with_dependency_type.clone(),
113-
)
114+
#[napi(
115+
ts_return_type = "(context: string, path: string, callback: (error?: Error, text?: string) => void) => void"
116+
)]
117+
pub fn get_resolve<'a>(
118+
&self,
119+
env: &'a Env,
120+
options: Option<RawResolveOptionsWithDependencyType>,
121+
) -> napi::Result<Function<'a, (String, String, Function<'static>), ()>> {
122+
let first = Arc::new(self.resolve_options_with_dependency_type.clone());
123+
let second = Arc::new(
124+
normalize_raw_resolve_options_with_dependency_type(options, first.resolve_to_context)
125+
.map_err(|e| napi::Error::from_reason(e.to_string()))?,
126+
);
127+
let resolver_factory = self.resolver_factory.clone();
128+
129+
let f: Function<(String, String, Function<'static>), ()> =
130+
env.create_function_from_closure("resolve", move |ctx: FunctionCallContext| {
131+
let context = ctx.get::<String>(0)?;
132+
let request = ctx.get::<String>(1)?;
133+
let callback = ctx.get::<Function<'static>>(2)?;
134+
135+
let first_clone = first.clone();
136+
let second_clone = second.clone();
137+
let resolver_factory = resolver_factory.clone();
138+
139+
callbackify(
140+
callback,
141+
async move {
142+
let merged_resolve_options = match second_clone.resolve_options.as_ref() {
143+
Some(second_resolve_options) => match first_clone.resolve_options.as_ref() {
144+
Some(resolve_options) => Some(Box::new(
145+
resolve_options
146+
.clone()
147+
.merge(*second_resolve_options.clone()),
148+
)),
149+
None => Some(second_resolve_options.clone()),
150+
},
151+
None => first_clone.resolve_options.clone(),
152+
};
153+
154+
let merged_options = ResolveOptionsWithDependencyType {
155+
resolve_options: merged_resolve_options,
156+
resolve_to_context: second_clone.resolve_to_context,
157+
dependency_category: second_clone.dependency_category,
158+
};
159+
let resolver = resolver_factory.get(merged_options);
160+
161+
match resolver.resolve(Path::new(&context), &request).await {
162+
Ok(rspack_core::ResolveResult::Resource(resource)) => {
163+
let resolve_request = ResolveRequest::from(resource);
164+
Ok(match serde_json::to_string(&resolve_request) {
165+
Ok(json) => Either::<String, ()>::A(json),
166+
Err(_) => Either::B(()),
167+
})
168+
}
169+
Ok(rspack_core::ResolveResult::Ignored) => Ok(Either::B(())),
170+
Err(err) => Err(napi::Error::new(
171+
ErrorCode::Napi(napi::Status::GenericFailure),
172+
format!("{err:?}"),
173+
)),
174+
}
175+
},
176+
None::<fn()>,
177+
)
178+
.map_err(|e| napi::Error::from_reason(e.reason.to_string()))
179+
})?;
180+
181+
Ok(f)
114182
}
115183
}
116184

packages/rspack/src/builtin-plugin/ExternalsPlugin.ts

Lines changed: 37 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@ import {
66
} from "@rspack/binding";
77

88
import type { Compiler, ExternalItem, ExternalItemValue, Externals } from "..";
9-
import { Resolver } from "../Resolver";
9+
import { getRawResolve } from "../config/adapter";
10+
import type { ResolveCallback } from "../config/adapterRuleUse";
11+
import type { ResolveRequest } from "../Resolver";
1012
import { createBuiltinPlugin, RspackBuiltinPlugin } from "./base";
1113

1214
export class ExternalsPlugin extends RspackBuiltinPlugin {
@@ -57,38 +59,41 @@ function getRawExternalItem(
5759
issuer: data.contextInfo.issuer,
5860
issuerLayer: data.contextInfo.issuerLayer ?? null
5961
},
60-
getResolve: options => (context, request, callback) => {
61-
const resolver = new Resolver(ctx.getResolver());
62-
const child = options ? resolver.withOptions(options) : resolver;
63-
const getResolveContext = () => ({
64-
fileDependencies: compiler._lastCompilation!.fileDependencies,
65-
missingDependencies:
66-
compiler._lastCompilation!.missingDependencies,
67-
contextDependencies:
68-
compiler._lastCompilation!.contextDependencies
69-
});
70-
if (callback) {
71-
child.resolve(
72-
{},
73-
context,
74-
request,
75-
getResolveContext(),
76-
callback
77-
);
78-
} else {
79-
return new Promise((resolve, reject) => {
80-
child.resolve(
81-
{},
82-
context,
83-
request,
84-
getResolveContext(),
85-
(err, result) => {
86-
if (err) reject(err);
87-
else resolve(result);
62+
getResolve(options) {
63+
const rawResolve = options ? getRawResolve(options) : undefined;
64+
const resolve = ctx.getResolve(rawResolve);
65+
66+
return (
67+
context: string,
68+
request: string,
69+
callback?: ResolveCallback
70+
) => {
71+
if (callback) {
72+
resolve(context, request, (error, text) => {
73+
if (error) {
74+
callback(error);
75+
} else {
76+
const req = text
77+
? (JSON.parse(text) as ResolveRequest)
78+
: undefined;
79+
callback(null, req?.path ?? false, req);
8880
}
89-
);
90-
});
91-
}
81+
});
82+
} else {
83+
return new Promise((res, rej) => {
84+
resolve(context, request, (error, text) => {
85+
if (error) {
86+
rej(error);
87+
} else {
88+
const req = text
89+
? (JSON.parse(text) as ResolveRequest)
90+
: undefined;
91+
res(req?.path);
92+
}
93+
});
94+
});
95+
}
96+
};
9297
}
9398
},
9499
(err, result, type) => {

0 commit comments

Comments
 (0)