Skip to content

Commit 33f5ca1

Browse files
committed
feat: support module.generator.outputPath
1 parent 8646ecf commit 33f5ca1

File tree

10 files changed

+96
-17
lines changed

10 files changed

+96
-17
lines changed

crates/node_binding/binding.d.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1111,6 +1111,7 @@ export interface RawAssetGeneratorDataUrlOptions {
11111111
export interface RawAssetGeneratorOptions {
11121112
emit?: boolean
11131113
filename?: JsFilename
1114+
outputPath?: JsFilename
11141115
publicPath?: "auto" | JsFilename
11151116
dataUrl?: RawAssetGeneratorDataUrlOptions | ((arg: RawAssetGeneratorDataUrlFnArgs) => string)
11161117
}
@@ -1135,6 +1136,7 @@ export interface RawAssetParserOptions {
11351136
export interface RawAssetResourceGeneratorOptions {
11361137
emit?: boolean
11371138
filename?: JsFilename
1139+
outputPath?: JsFilename
11381140
publicPath?: "auto" | JsFilename
11391141
}
11401142

crates/rspack_binding_options/src/options/raw_module/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -497,6 +497,7 @@ impl From<RawGeneratorOptions> for GeneratorOptions {
497497
pub struct RawAssetGeneratorOptions {
498498
pub emit: Option<bool>,
499499
pub filename: Option<JsFilename>,
500+
pub output_path: Option<JsFilename>,
500501
#[napi(ts_type = "\"auto\" | JsFilename")]
501502
pub public_path: Option<JsFilename>,
502503
#[derivative(Debug = "ignore")]
@@ -511,6 +512,7 @@ impl From<RawAssetGeneratorOptions> for AssetGeneratorOptions {
511512
Self {
512513
emit: value.emit,
513514
filename: value.filename.map(|i| i.into()),
515+
output_path: value.output_path.map(|i| i.into()),
514516
public_path: value.public_path.map(|i| i.into()),
515517
data_url: value
516518
.data_url
@@ -545,6 +547,7 @@ impl From<RawAssetInlineGeneratorOptions> for AssetInlineGeneratorOptions {
545547
pub struct RawAssetResourceGeneratorOptions {
546548
pub emit: Option<bool>,
547549
pub filename: Option<JsFilename>,
550+
pub output_path: Option<JsFilename>,
548551
#[napi(ts_type = "\"auto\" | JsFilename")]
549552
pub public_path: Option<JsFilename>,
550553
}
@@ -554,6 +557,7 @@ impl From<RawAssetResourceGeneratorOptions> for AssetResourceGeneratorOptions {
554557
Self {
555558
emit: value.emit,
556559
filename: value.filename.map(|i| i.into()),
560+
output_path: value.output_path.map(|i| i.into()),
557561
public_path: value.public_path.map(|i| i.into()),
558562
}
559563
}

crates/rspack_core/src/options/module.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,17 @@ impl GeneratorOptions {
334334
.or_else(|| self.get_asset_resource().and_then(|x| x.filename.as_ref()))
335335
}
336336

337+
pub fn asset_output_path(&self) -> Option<&Filename> {
338+
self
339+
.get_asset()
340+
.and_then(|x| x.output_path.as_ref())
341+
.or_else(|| {
342+
self
343+
.get_asset_resource()
344+
.and_then(|x| x.output_path.as_ref())
345+
})
346+
}
347+
337348
pub fn asset_public_path(&self) -> Option<&PublicPath> {
338349
self
339350
.get_asset()
@@ -371,6 +382,7 @@ pub struct AssetInlineGeneratorOptions {
371382
pub struct AssetResourceGeneratorOptions {
372383
pub emit: Option<bool>,
373384
pub filename: Option<Filename>,
385+
pub output_path: Option<Filename>,
374386
pub public_path: Option<PublicPath>,
375387
}
376388

@@ -379,6 +391,7 @@ pub struct AssetResourceGeneratorOptions {
379391
pub struct AssetGeneratorOptions {
380392
pub emit: Option<bool>,
381393
pub filename: Option<Filename>,
394+
pub output_path: Option<Filename>,
382395
pub public_path: Option<PublicPath>,
383396
pub data_url: Option<AssetGeneratorDataUrl>,
384397
}

crates/rspack_plugin_asset/src/lib.rs

Lines changed: 38 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#![feature(let_chains)]
22

3-
use std::{borrow::Cow, hash::Hasher};
3+
use std::{borrow::Cow, hash::Hasher, path::PathBuf};
44

55
use async_trait::async_trait;
66
use rayon::prelude::*;
@@ -241,22 +241,38 @@ impl AssetParserAndGenerator {
241241
compilation: &Compilation,
242242
contenthash: Option<&str>,
243243
source_file_name: &str,
244-
) -> Result<(String, AssetInfo)> {
244+
use_output_path: bool,
245+
) -> Result<(String, String, AssetInfo)> {
245246
// Use [Rule.generator.filename] if it is set, otherwise use [output.assetModuleFilename].
246247
let asset_filename_template = module_generator_options
247248
.and_then(|x| x.asset_filename())
248249
.unwrap_or(&compilation.options.output.asset_module_filename);
250+
let path_data = PathData::default()
251+
.module_id_optional(
252+
ChunkGraph::get_module_id(&compilation.module_ids, module.id()).map(|s| s.as_str()),
253+
)
254+
.content_hash_optional(contenthash)
255+
.hash_optional(contenthash)
256+
.filename(source_file_name);
257+
258+
let (mut filename, mut asset_info) =
259+
compilation.get_asset_path_with_info(asset_filename_template, path_data)?;
260+
let original_filename = filename.clone();
261+
262+
if use_output_path {
263+
let output_path = module_generator_options.and_then(|x| x.asset_output_path());
264+
265+
if let Some(output_path) = output_path {
266+
let (output_path, another_asset_info) =
267+
compilation.get_asset_path_with_info(output_path, path_data)?;
268+
let output_path = PathBuf::from(output_path);
269+
let file_path = PathBuf::from(filename);
270+
filename = output_path.join(file_path).to_string_lossy().to_string();
271+
asset_info.merge_another_asset(another_asset_info);
272+
}
273+
}
249274

250-
compilation.get_asset_path_with_info(
251-
asset_filename_template,
252-
PathData::default()
253-
.module_id_optional(
254-
ChunkGraph::get_module_id(&compilation.module_ids, module.id()).map(|s| s.as_str()),
255-
)
256-
.content_hash_optional(contenthash)
257-
.hash_optional(contenthash)
258-
.filename(source_file_name),
259-
)
275+
Ok((original_filename, filename, asset_info))
260276
}
261277

262278
fn get_public_path<F: LocalFilenameFn>(
@@ -444,12 +460,13 @@ impl ParserAndGenerator for AssetParserAndGenerator {
444460
let contenthash = contenthash.rendered(compilation.options.output.hash_digest_length);
445461

446462
let source_file_name = self.get_source_file_name(normal_module, compilation);
447-
let (filename, mut asset_info) = self.get_asset_module_filename(
463+
let (original_filename, filename, mut asset_info) = self.get_asset_module_filename(
448464
normal_module,
449465
module_generator_options,
450466
compilation,
451467
Some(contenthash),
452468
&source_file_name,
469+
true,
453470
)?;
454471

455472
let asset_path = if let Some(public_path) =
@@ -469,13 +486,17 @@ impl ParserAndGenerator for AssetParserAndGenerator {
469486
}
470487
PublicPath::Auto => public_path.render(compilation, &filename),
471488
};
472-
serde_json::to_string(&format!("{public_path}{filename}"))
489+
serde_json::to_string(&format!("{public_path}{original_filename}"))
473490
.map_err(|e| error!(e.to_string()))?
474491
} else {
475492
generate_context
476493
.runtime_requirements
477494
.insert(RuntimeGlobals::PUBLIC_PATH);
478-
format!(r#"{} + "{}""#, RuntimeGlobals::PUBLIC_PATH, filename)
495+
format!(
496+
r#"{} + "{}""#,
497+
RuntimeGlobals::PUBLIC_PATH,
498+
original_filename
499+
)
479500
};
480501
asset_info.set_source_filename(source_file_name);
481502

@@ -562,12 +583,13 @@ impl ParserAndGenerator for AssetParserAndGenerator {
562583
data_url_options.dyn_hash(hasher);
563584
} else if parsed_asset_config.is_resource() {
564585
let source_file_name = self.get_source_file_name(module, compilation);
565-
let (filename, _) = self.get_asset_module_filename(
586+
let (filename, _, _) = self.get_asset_module_filename(
566587
module,
567588
module_generator_options,
568589
compilation,
569590
None,
570591
&source_file_name,
592+
false,
571593
)?;
572594
filename.dyn_hash(hasher);
573595
match module_generator_options.and_then(|x| x.asset_public_path()) {

packages/rspack/etc/core.api.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,9 @@ export type AssetInlineGeneratorOptions = {
179179
// @public
180180
export type AssetModuleFilename = Filename;
181181

182+
// @public
183+
export type AssetModuleOutputPath = Filename;
184+
182185
// @public
183186
export type AssetParserDataUrl = AssetParserDataUrlOptions;
184187

@@ -196,6 +199,7 @@ export type AssetParserOptions = {
196199
export type AssetResourceGeneratorOptions = {
197200
emit?: boolean;
198201
filename?: Filename;
202+
outputPath?: AssetModuleOutputPath;
199203
publicPath?: PublicPath;
200204
};
201205

@@ -5242,6 +5246,7 @@ declare namespace rspackExports {
52425246
AssetGeneratorDataUrlFunction,
52435247
AssetGeneratorDataUrl,
52445248
AssetInlineGeneratorOptions,
5249+
AssetModuleOutputPath,
52455250
AssetResourceGeneratorOptions,
52465251
AssetGeneratorOptions,
52475252
CssGeneratorExportsConvention,
@@ -10369,6 +10374,7 @@ declare namespace t {
1036910374
AssetGeneratorDataUrlFunction,
1037010375
AssetGeneratorDataUrl,
1037110376
AssetInlineGeneratorOptions,
10377+
AssetModuleOutputPath,
1037210378
AssetResourceGeneratorOptions,
1037310379
AssetGeneratorOptions,
1037410380
CssGeneratorExportsConvention,

packages/rspack/src/config/adapter.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -813,6 +813,7 @@ function getRawAssetResourceGeneratorOptions(
813813
return {
814814
emit: options.emit,
815815
filename: options.filename,
816+
outputPath: options.outputPath,
816817
publicPath: options.publicPath
817818
};
818819
}

packages/rspack/src/config/types.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1125,6 +1125,9 @@ export type AssetInlineGeneratorOptions = {
11251125
dataUrl?: AssetGeneratorDataUrl;
11261126
};
11271127

1128+
/** Emit the asset in the specified folder relative to 'output.path'. */
1129+
export type AssetModuleOutputPath = Filename;
1130+
11281131
/** Options for asset modules. */
11291132
export type AssetResourceGeneratorOptions = {
11301133
/**
@@ -1136,6 +1139,9 @@ export type AssetResourceGeneratorOptions = {
11361139
/** This option determines the name of each asset resource output bundle.*/
11371140
filename?: Filename;
11381141

1142+
/** Emit the asset in the specified folder relative to 'output.path' */
1143+
outputPath?: AssetModuleOutputPath;
1144+
11391145
/** This option determines the URL prefix of the referenced 'asset' or 'asset/resource'*/
11401146
publicPath?: PublicPath;
11411147
};

tests/webpack-test/configCases/asset-modules/rule-generator-outputPath/test.filter.js

Lines changed: 0 additions & 1 deletion
This file was deleted.

website/docs/en/config/module.mdx

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -506,6 +506,15 @@ module.exports = {
506506
};
507507
```
508508

509+
#### module.generator.asset.outputPath
510+
511+
- **Type:** `string | ((pathData: PathData, assetInfo?: AssetInfo) => string)`
512+
- **Default:** `undefined`
513+
514+
Emit the asset in the specified folder relative to [`output.path`](/config/output#outputpath).
515+
516+
Only for modules with module type `'asset'` or `'asset/resource'`.
517+
509518
#### module.generator.asset.publicPath
510519

511520
- **Type:** `string | ((pathData: PathData, assetInfo?: AssetInfo) => string)`
@@ -586,6 +595,10 @@ Generator options for `asset/resource` modules.
586595

587596
Same as [`module.generator["asset"].filename`](#modulegeneratorassetfilename).
588597

598+
#### module.generator["asset/resource"].outputPath
599+
600+
Same as [`module.generator["asset"].outputPath`](#modulegeneratorassetoutputpath).
601+
589602
#### module.generator["asset/resource"].publicPath
590603

591604
Same as [`module.generator["asset"].publicPath`](#modulegeneratorassetpublicpath).

website/docs/zh/config/module.mdx

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -506,6 +506,15 @@ module.exports = {
506506
};
507507
```
508508

509+
#### module.generator.asset.outputPath
510+
511+
- **类型:** `string | ((pathData: PathData, assetInfo?: AssetInfo) => string)`
512+
- **默认值:** `undefined`
513+
514+
将 asset 输出到指定文件夹,该文件夹相对于 [`output.path`](/config/output#outputpath)
515+
516+
仅对模块类型为 `'asset'``'asset/resource'` 的模块生效。
517+
509518
#### module.generator.asset.publicPath
510519

511520
- **类型:** `string | ((pathData: PathData, assetInfo?: AssetInfo) => string)`
@@ -586,6 +595,10 @@ module.exports = {
586595

587596
[`module.generator["asset"].filename`](#modulegeneratorassetfilename) 一样。
588597

598+
#### module.generator["asset/resource"].outputPath
599+
600+
[`module.generator["asset"].outputPath`](#modulegeneratorassetoutputpath) 一样。
601+
589602
#### module.generator["asset/resource"].publicPath
590603

591604
[`module.generator["asset"].publicPath`](#modulegeneratorassetpublicpath) 一样。

0 commit comments

Comments
 (0)