Skip to content

Commit c9025c3

Browse files
feat: add assetPath hook
1 parent d294680 commit c9025c3

File tree

15 files changed

+232
-38
lines changed

15 files changed

+232
-38
lines changed

crates/node_binding/binding.d.ts

+7
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,12 @@ export interface JsAssetInfoRelated {
155155
sourceMap?: string
156156
}
157157

158+
export interface JsAssetPathArgs {
159+
filename: string
160+
data: PathData
161+
assetInfo?: JsAssetInfo
162+
}
163+
158164
export interface JsChunk {
159165
files: Array<string>
160166
}
@@ -203,6 +209,7 @@ export interface JsHooks {
203209
contextModuleBeforeResolve: (...args: any[]) => any
204210
normalModuleFactoryResolveForScheme: (...args: any[]) => any
205211
chunkAsset: (...args: any[]) => any
212+
assetPath: (...args: any[]) => any
206213
succeedModule: (...args: any[]) => any
207214
stillValidModule: (...args: any[]) => any
208215
}

crates/node_binding/src/hook.rs

+2
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ pub enum Hook {
2828
NormalModuleFactoryResolveForScheme,
2929
AfterResolve,
3030
BeforeResolve,
31+
AssetPath,
3132
SucceedModule,
3233
StillValidModule,
3334
}
@@ -59,6 +60,7 @@ impl From<String> for Hook {
5960
"normalModuleFactoryResolveForScheme" => Hook::NormalModuleFactoryResolveForScheme,
6061
"afterResolve" => Hook::AfterResolve,
6162
"beforeResolve" => Hook::BeforeResolve,
63+
"assetPath" => Hook::AssetPath,
6264
"succeedModule" => Hook::SucceedModule,
6365
"stillValidModule" => Hook::StillValidModule,
6466
hook_name => panic!("{hook_name} is an invalid hook name"),

crates/node_binding/src/js_values/asset.rs

+30-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use super::JsCompatSource;
1+
use super::{JsCompatSource, PathData};
22

33
#[napi(object)]
44
pub struct JsAssetInfoRelated {
@@ -102,3 +102,32 @@ impl From<&rspack_core::AssetEmittedArgs<'_>> for JsAssetEmittedArgs {
102102
}
103103
}
104104
}
105+
106+
#[napi(object)]
107+
pub struct JsAssetPathArgs {
108+
pub filename: String,
109+
pub data: PathData,
110+
pub asset_info: Option<JsAssetInfo>,
111+
}
112+
113+
impl From<&rspack_core::AssetPathArgs<'_>> for JsAssetPathArgs {
114+
fn from(args: &rspack_core::AssetPathArgs) -> Self {
115+
let path_data = PathData {
116+
filename: args.data.filename.map(|s| s.to_string()),
117+
content_hash: args.data.content_hash.map(|s| s.to_string()),
118+
hash: args.data.hash.map(|s| s.to_string()),
119+
id: args.data.id.map(|s| s.to_string()),
120+
runtime: args.data.runtime.map(|s| s.to_string()),
121+
url: args.data.url.map(|s| s.to_string()),
122+
};
123+
let asset_info = args
124+
.asset_info
125+
.to_owned()
126+
.map(|info| JsAssetInfo::from(info.to_owned()));
127+
Self {
128+
filename: args.filename.to_string(),
129+
data: path_data,
130+
asset_info,
131+
}
132+
}
133+
}

crates/node_binding/src/js_values/hooks.rs

+1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ pub struct JsHooks {
2727
pub context_module_before_resolve: JsFunction,
2828
pub normal_module_factory_resolve_for_scheme: JsFunction,
2929
pub chunk_asset: JsFunction,
30+
pub asset_path: JsFunction,
3031
pub succeed_module: JsFunction,
3132
pub still_valid_module: JsFunction,
3233
}

crates/node_binding/src/plugins/mod.rs

+27-5
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,18 @@ pub use loader::JsLoaderResolver;
77
use napi::{Env, Result};
88
use rspack_binding_macros::js_fn_into_theadsafe_fn;
99
use rspack_core::{
10-
ChunkAssetArgs, NormalModuleAfterResolveArgs, NormalModuleBeforeResolveArgs,
11-
PluginNormalModuleFactoryAfterResolveOutput, PluginNormalModuleFactoryBeforeResolveOutput,
12-
PluginNormalModuleFactoryResolveForSchemeOutput, ResourceData,
10+
AssetPathArgs, ChunkAssetArgs, NormalModuleAfterResolveArgs, NormalModuleBeforeResolveArgs,
11+
PluginJsAssetPathOutput, PluginNormalModuleFactoryAfterResolveOutput,
12+
PluginNormalModuleFactoryBeforeResolveOutput, PluginNormalModuleFactoryResolveForSchemeOutput,
13+
ResourceData,
1314
};
1415
use rspack_error::internal_error;
1516
use rspack_napi_shared::threadsafe_function::{ThreadsafeFunction, ThreadsafeFunctionCallMode};
1617
use rspack_napi_shared::NapiResultExt;
1718

1819
use crate::js_values::{
19-
AfterResolveData, BeforeResolveData, JsAssetEmittedArgs, JsChunkAssetArgs, JsModule,
20-
JsResolveForSchemeInput, JsResolveForSchemeResult, ToJsModule,
20+
AfterResolveData, BeforeResolveData, JsAssetEmittedArgs, JsAssetPathArgs, JsChunkAssetArgs,
21+
JsModule, JsResolveForSchemeInput, JsResolveForSchemeResult, ToJsModule,
2122
};
2223
use crate::{DisabledHooks, Hook, JsCompilation, JsHooks};
2324

@@ -45,6 +46,7 @@ pub struct JsHooksAdapter {
4546
pub finish_make_tsfn: ThreadsafeFunction<JsCompilation, ()>,
4647
pub chunk_asset_tsfn: ThreadsafeFunction<JsChunkAssetArgs, ()>,
4748
pub before_resolve: ThreadsafeFunction<BeforeResolveData, (Option<bool>, BeforeResolveData)>,
49+
pub asset_path_tsfn: ThreadsafeFunction<JsAssetPathArgs, Option<String>>,
4850
pub after_resolve: ThreadsafeFunction<AfterResolveData, Option<bool>>,
4951
pub context_module_before_resolve: ThreadsafeFunction<BeforeResolveData, Option<bool>>,
5052
pub normal_module_factory_resolve_for_scheme:
@@ -125,6 +127,22 @@ impl rspack_core::Plugin for JsHooksAdapter {
125127
.map_err(|err| internal_error!("Failed to chunk asset: {err}"))?
126128
}
127129

130+
async fn asset_path(&self, args: &AssetPathArgs) -> PluginJsAssetPathOutput {
131+
if self.is_hook_disabled(&Hook::AssetPath) {
132+
return Ok(Some(args.filename.to_owned()));
133+
}
134+
135+
self
136+
.asset_path_tsfn
137+
.call(
138+
JsAssetPathArgs::from(args),
139+
ThreadsafeFunctionCallMode::Blocking,
140+
)
141+
.into_rspack_result()?
142+
.await
143+
.map_err(|err| internal_error!("Failed to call this_asset_path: {err}"))?
144+
}
145+
128146
#[tracing::instrument(name = "js_hooks_adapter::make", skip_all)]
129147
async fn make(
130148
&self,
@@ -587,6 +605,7 @@ impl JsHooksAdapter {
587605
finish_modules,
588606
finish_make,
589607
chunk_asset,
608+
asset_path,
590609
succeed_module,
591610
still_valid_module,
592611
} = js_hooks;
@@ -640,6 +659,8 @@ impl JsHooksAdapter {
640659
> = js_fn_into_theadsafe_fn!(normal_module_factory_resolve_for_scheme, env);
641660
let chunk_asset_tsfn: ThreadsafeFunction<JsChunkAssetArgs, ()> =
642661
js_fn_into_theadsafe_fn!(chunk_asset, env);
662+
let asset_path_tsfn: ThreadsafeFunction<JsAssetPathArgs, Option<String>> =
663+
js_fn_into_theadsafe_fn!(asset_path, env);
643664
let succeed_module_tsfn: ThreadsafeFunction<JsModule, ()> =
644665
js_fn_into_theadsafe_fn!(succeed_module, env);
645666
let still_valid_module_tsfn: ThreadsafeFunction<JsModule, ()> =
@@ -672,6 +693,7 @@ impl JsHooksAdapter {
672693
finish_make_tsfn,
673694
chunk_asset_tsfn,
674695
after_resolve,
696+
asset_path_tsfn,
675697
succeed_module_tsfn,
676698
still_valid_module_tsfn,
677699
})

crates/rspack_core/src/compiler/compilation.rs

+34-9
Original file line numberDiff line numberDiff line change
@@ -1334,34 +1334,59 @@ impl Compilation {
13341334
if data.hash.is_none() {
13351335
data.hash = self.get_hash();
13361336
}
1337-
filename.render(data, None)
1337+
self.get_asset_path(filename, data)
13381338
}
13391339

13401340
pub fn get_path_with_info<'b, 'a: 'b>(
13411341
&'a self,
13421342
filename: &Filename,
13431343
mut data: PathData<'b>,
13441344
) -> (String, AssetInfo) {
1345-
let mut info = AssetInfo::default();
13461345
if data.hash.is_none() {
13471346
data.hash = self.get_hash();
13481347
}
1349-
let path = filename.render(data, Some(&mut info));
1350-
(path, info)
1348+
self.get_asset_path_with_info(filename, data)
13511349
}
13521350

1353-
pub fn get_asset_path(&self, filename: &Filename, data: PathData) -> String {
1354-
filename.render(data, None)
1351+
pub fn get_asset_path(&self, filename: &Filename, data: PathData<'_>) -> String {
1352+
tokio::task::block_in_place(move || {
1353+
tokio::runtime::Handle::current().block_on(async move {
1354+
let result = &self
1355+
.plugin_driver
1356+
.asset_path(filename.template().to_owned().to_string(), &data, None)
1357+
.await
1358+
.unwrap();
1359+
let new_file_name = Filename::from(result.to_owned());
1360+
1361+
new_file_name.render(data, None)
1362+
})
1363+
})
13551364
}
13561365

13571366
pub fn get_asset_path_with_info(
13581367
&self,
13591368
filename: &Filename,
13601369
data: PathData,
13611370
) -> (String, AssetInfo) {
1362-
let mut info = AssetInfo::default();
1363-
let path = filename.render(data, Some(&mut info));
1364-
(path, info)
1371+
tokio::task::block_in_place(move || {
1372+
tokio::runtime::Handle::current().block_on(async move {
1373+
let mut info = AssetInfo::default();
1374+
1375+
let result = &self
1376+
.plugin_driver
1377+
.asset_path(
1378+
filename.template().to_owned().to_string(),
1379+
&data,
1380+
Some(&mut info),
1381+
)
1382+
.await
1383+
.unwrap();
1384+
let new_file_name = Filename::from(result.to_owned());
1385+
1386+
let path = new_file_name.render(data, Some(&mut info));
1387+
(path, info)
1388+
})
1389+
})
13651390
}
13661391
}
13671392

crates/rspack_core/src/plugin/api.rs

+14-7
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,14 @@ use rspack_loader_runner::{Content, ResourceData};
77
use rspack_sources::BoxSource;
88

99
use crate::{
10-
AdditionalChunkRuntimeRequirementsArgs, AssetEmittedArgs, AssetInfo, BoxLoader, BoxModule,
11-
ChunkAssetArgs, ChunkHashArgs, Compilation, CompilationArgs, CompilerOptions, ContentHashArgs,
12-
DoneArgs, FactorizeArgs, JsChunkHashArgs, Module, ModuleArgs, ModuleFactoryResult, ModuleType,
13-
NormalModule, NormalModuleAfterResolveArgs, NormalModuleBeforeResolveArgs,
14-
NormalModuleFactoryContext, OptimizeChunksArgs, ParserAndGenerator, PluginContext,
15-
ProcessAssetsArgs, RenderArgs, RenderChunkArgs, RenderManifestArgs, RenderModuleContentArgs,
16-
RenderStartupArgs, Resolver, SourceType, ThisCompilationArgs,
10+
AdditionalChunkRuntimeRequirementsArgs, AssetEmittedArgs, AssetInfo, AssetPathArgs, BoxLoader,
11+
BoxModule, ChunkAssetArgs, ChunkHashArgs, Compilation, CompilationArgs, CompilerOptions,
12+
ContentHashArgs, DoneArgs, FactorizeArgs, JsChunkHashArgs, Module, ModuleArgs,
13+
ModuleFactoryResult, ModuleType, NormalModule, NormalModuleAfterResolveArgs,
14+
NormalModuleBeforeResolveArgs, NormalModuleFactoryContext, OptimizeChunksArgs,
15+
ParserAndGenerator, PluginContext, ProcessAssetsArgs, RenderArgs, RenderChunkArgs,
16+
RenderManifestArgs, RenderModuleContentArgs, RenderStartupArgs, Resolver, SourceType,
17+
ThisCompilationArgs,
1718
};
1819

1920
// use anyhow::{Context, Result};
@@ -39,6 +40,7 @@ pub type PluginRenderModuleContentOutput = Result<Option<BoxSource>>;
3940
pub type PluginRenderStartupHookOutput = Result<Option<BoxSource>>;
4041
pub type PluginRenderHookOutput = Result<Option<BoxSource>>;
4142
pub type PluginJsChunkHashHookOutput = Result<()>;
43+
pub type PluginJsAssetPathOutput = Result<Option<String>>;
4244

4345
#[async_trait::async_trait]
4446
pub trait Plugin: Debug + Send + Sync {
@@ -165,6 +167,11 @@ pub trait Plugin: Debug + Send + Sync {
165167
Ok(())
166168
}
167169

170+
/// webpack `compilation.hooks.assetPath`
171+
async fn asset_path(&self, _args: &AssetPathArgs) -> PluginJsAssetPathOutput {
172+
Ok(Some(_args.filename.to_owned()))
173+
}
174+
168175
// JavascriptModulesPlugin hook
169176
fn render(&self, _ctx: PluginContext, _args: &RenderArgs) -> PluginRenderStartupHookOutput {
170177
Ok(None)

crates/rspack_core/src/plugin/args.rs

+9-2
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ use rustc_hash::FxHashSet as HashSet;
99
use crate::ast::css::Ast as CssAst;
1010
use crate::ast::javascript::Ast as JsAst;
1111
use crate::{
12-
Chunk, ChunkUkey, Compilation, Context, DependencyCategory, DependencyType, ErrorSpan,
13-
ModuleDependency, ModuleIdentifier, Resolve, RuntimeGlobals, SharedPluginDriver, Stats,
12+
AssetInfo, Chunk, ChunkUkey, Compilation, Context, DependencyCategory, DependencyType, ErrorSpan,
13+
ModuleDependency, ModuleIdentifier, PathData, Resolve, RuntimeGlobals, SharedPluginDriver, Stats,
1414
};
1515
// #[derive(Debug)]
1616
// pub struct ParseModuleArgs<'a> {
@@ -212,6 +212,13 @@ pub struct ChunkAssetArgs<'a> {
212212
pub filename: &'a str,
213213
}
214214

215+
#[derive(Debug)]
216+
pub struct AssetPathArgs<'a> {
217+
pub filename: &'a str,
218+
pub data: &'a PathData<'a>,
219+
pub asset_info: Option<&'a AssetInfo>,
220+
}
221+
215222
impl<'me> RenderChunkArgs<'me> {
216223
pub fn chunk(&self) -> &Chunk {
217224
self

crates/rspack_core/src/plugin/plugin_driver.rs

+39-14
Original file line numberDiff line numberDiff line change
@@ -10,20 +10,20 @@ use rustc_hash::FxHashMap as HashMap;
1010
use tracing::instrument;
1111

1212
use crate::{
13-
AdditionalChunkRuntimeRequirementsArgs, ApplyContext, AssetEmittedArgs, BoxLoader,
14-
BoxedParserAndGeneratorBuilder, Chunk, ChunkAssetArgs, ChunkContentHash, ChunkHashArgs,
15-
Compilation, CompilationArgs, CompilerOptions, Content, ContentHashArgs, DoneArgs, FactorizeArgs,
16-
JsChunkHashArgs, Module, ModuleArgs, ModuleType, NormalModule, NormalModuleAfterResolveArgs,
17-
NormalModuleBeforeResolveArgs, NormalModuleFactoryContext, OptimizeChunksArgs, Plugin,
18-
PluginAdditionalChunkRuntimeRequirementsOutput, PluginBuildEndHookOutput,
19-
PluginChunkHashHookOutput, PluginCompilationHookOutput, PluginContext, PluginFactorizeHookOutput,
20-
PluginJsChunkHashHookOutput, PluginMakeHookOutput, PluginModuleHookOutput,
21-
PluginNormalModuleFactoryAfterResolveOutput, PluginNormalModuleFactoryBeforeResolveOutput,
22-
PluginProcessAssetsOutput, PluginRenderChunkHookOutput, PluginRenderHookOutput,
23-
PluginRenderManifestHookOutput, PluginRenderModuleContentOutput, PluginRenderStartupHookOutput,
24-
PluginThisCompilationHookOutput, ProcessAssetsArgs, RenderArgs, RenderChunkArgs,
25-
RenderManifestArgs, RenderModuleContentArgs, RenderStartupArgs, Resolver, ResolverFactory, Stats,
26-
ThisCompilationArgs,
13+
AdditionalChunkRuntimeRequirementsArgs, ApplyContext, AssetEmittedArgs, AssetInfo, AssetPathArgs,
14+
BoxLoader, BoxedParserAndGeneratorBuilder, Chunk, ChunkAssetArgs, ChunkContentHash,
15+
ChunkHashArgs, Compilation, CompilationArgs, CompilerOptions, Content, ContentHashArgs, DoneArgs,
16+
FactorizeArgs, JsChunkHashArgs, Module, ModuleArgs, ModuleType, NormalModule,
17+
NormalModuleAfterResolveArgs, NormalModuleBeforeResolveArgs, NormalModuleFactoryContext,
18+
OptimizeChunksArgs, PathData, Plugin, PluginAdditionalChunkRuntimeRequirementsOutput,
19+
PluginBuildEndHookOutput, PluginChunkHashHookOutput, PluginCompilationHookOutput, PluginContext,
20+
PluginFactorizeHookOutput, PluginJsChunkHashHookOutput, PluginMakeHookOutput,
21+
PluginModuleHookOutput, PluginNormalModuleFactoryAfterResolveOutput,
22+
PluginNormalModuleFactoryBeforeResolveOutput, PluginProcessAssetsOutput,
23+
PluginRenderChunkHookOutput, PluginRenderHookOutput, PluginRenderManifestHookOutput,
24+
PluginRenderModuleContentOutput, PluginRenderStartupHookOutput, PluginThisCompilationHookOutput,
25+
ProcessAssetsArgs, RenderArgs, RenderChunkArgs, RenderManifestArgs, RenderModuleContentArgs,
26+
RenderStartupArgs, Resolver, ResolverFactory, Stats, ThisCompilationArgs,
2727
};
2828

2929
pub struct PluginDriver {
@@ -160,6 +160,31 @@ impl PluginDriver {
160160
Ok(())
161161
}
162162

163+
#[instrument(name = "plugin:asset_path", skip_all)]
164+
pub async fn asset_path(
165+
&self,
166+
filename: String,
167+
data: &PathData<'_>,
168+
asset_info: Option<&AssetInfo>,
169+
) -> Result<String> {
170+
let mut updated_name = filename;
171+
for plugin in &self.plugins {
172+
let temp = &plugin
173+
.asset_path(&AssetPathArgs {
174+
filename: &updated_name,
175+
data: &data,
176+
asset_info: asset_info,
177+
})
178+
.await?;
179+
180+
if let Some(value) = temp.to_owned() {
181+
updated_name = value;
182+
}
183+
}
184+
185+
Ok(updated_name)
186+
}
187+
163188
pub async fn before_compile(
164189
&self,
165190
// compilationParams: &mut CompilationParams<'_>,

packages/rspack/src/compilation.ts

+8
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,9 @@ export class Compilation {
8888
finishModules: tapable.AsyncSeriesHook<[Iterable<JsModule>], undefined>;
8989
chunkAsset: tapable.SyncHook<[JsChunk, string], undefined>;
9090
processWarnings: tapable.SyncWaterfallHook<[Error[]]>;
91+
assetPath: tapable.SyncWaterfallHook<
92+
[path: string, options: PathData, assetInfo: AssetInfo | undefined]
93+
>;
9194
succeedModule: tapable.SyncHook<[JsModule], undefined>;
9295
stillValidModule: tapable.SyncHook<[JsModule], undefined>;
9396
};
@@ -124,6 +127,11 @@ export class Compilation {
124127
finishModules: new tapable.AsyncSeriesHook(["modules"]),
125128
chunkAsset: new tapable.SyncHook(["chunk", "filename"]),
126129
processWarnings: new tapable.SyncWaterfallHook(["warnings"]),
130+
assetPath: new tapable.SyncWaterfallHook([
131+
"path",
132+
"options",
133+
"assetInfo"
134+
]),
127135
succeedModule: new tapable.SyncHook(["module"]),
128136
stillValidModule: new tapable.SyncHook(["module"])
129137
};

0 commit comments

Comments
 (0)