From 636d37dc2056bd4eddd0b5c52845419a1421fe73 Mon Sep 17 00:00:00 2001 From: Ramon Villain Date: Mon, 14 Oct 2024 09:18:47 +0100 Subject: [PATCH] feat(rspack_plugin_copy): Set source_filename and copied flag when copying an asset (#8077) --- crates/node_binding/binding.d.ts | 3 +++ crates/rspack_binding_values/src/asset.rs | 4 ++++ crates/rspack_binding_values/src/stats.rs | 2 ++ crates/rspack_core/src/compiler/compilation.rs | 2 ++ crates/rspack_core/src/stats/mod.rs | 1 + crates/rspack_core/src/stats/struct.rs | 1 + crates/rspack_plugin_copy/src/lib.rs | 10 ++++++++-- packages/rspack/etc/api.md | 1 + .../src/stats/DefaultStatsPrinterPlugin.ts | 3 +++ packages/rspack/src/stats/statsFactoryUtils.ts | 1 + packages/rspack/src/util/AssetInfo.ts | 8 ++++++-- tests/plugin-test/copy-plugin/CopyPlugin.test.js | 16 +++++++++++----- 12 files changed, 43 insertions(+), 9 deletions(-) diff --git a/crates/node_binding/binding.d.ts b/crates/node_binding/binding.d.ts index b40897b1e85..8d2531e0231 100644 --- a/crates/node_binding/binding.d.ts +++ b/crates/node_binding/binding.d.ts @@ -397,6 +397,8 @@ export interface JsAssetInfo { */ contenthash: Array sourceFilename?: string + /** when asset was created from a source file (potentially transformed), it should be flagged as copied */ + copied?: boolean /** * size in bytes, only set after asset has been emitted * when asset is only used for development and doesn't count towards user-facing assets @@ -802,6 +804,7 @@ export interface JsStatsAssetInfo { development?: boolean hotModuleReplacement?: boolean sourceFilename?: string + copied?: boolean immutable?: boolean javascriptModule?: boolean chunkhash: Array diff --git a/crates/rspack_binding_values/src/asset.rs b/crates/rspack_binding_values/src/asset.rs index 45ce3ba94fc..615e1f1485a 100644 --- a/crates/rspack_binding_values/src/asset.rs +++ b/crates/rspack_binding_values/src/asset.rs @@ -29,6 +29,8 @@ pub struct JsAssetInfo { pub contenthash: Vec, // when asset was created from a source file (potentially transformed), the original filename relative to compilation context pub source_filename: Option, + /// when asset was created from a source file (potentially transformed), it should be flagged as copied + pub copied: Option, /// size in bytes, only set after asset has been emitted // pub size: f64, /// when asset is only used for development and doesn't count towards user-facing assets @@ -63,6 +65,7 @@ impl From for rspack_core::AssetInfo { content_hash: i.contenthash.into_iter().collect(), version: String::from(""), source_filename: i.source_filename, + copied: i.copied, javascript_module: i.javascript_module, css_unused_idents: i.css_unused_idents.map(|i| i.into_iter().collect()), extras: i.extras, @@ -97,6 +100,7 @@ impl From for JsAssetInfo { fullhash: info.full_hash.into_iter().collect(), contenthash: info.content_hash.into_iter().collect(), source_filename: info.source_filename, + copied: info.copied, javascript_module: info.javascript_module, css_unused_idents: info.css_unused_idents.map(|i| i.into_iter().collect()), extras: info.extras, diff --git a/crates/rspack_binding_values/src/stats.rs b/crates/rspack_binding_values/src/stats.rs index 5dc26a6630b..51bd6dec6a8 100644 --- a/crates/rspack_binding_values/src/stats.rs +++ b/crates/rspack_binding_values/src/stats.rs @@ -413,6 +413,7 @@ pub struct JsStatsAssetInfo { pub development: Option, pub hot_module_replacement: Option, pub source_filename: Option, + pub copied: Option, pub immutable: Option, pub javascript_module: Option, pub chunkhash: Vec, @@ -438,6 +439,7 @@ impl From for JsStatsAssetInfo { development: stats.development, hot_module_replacement: stats.hot_module_replacement, source_filename: stats.source_filename, + copied: stats.copied, immutable: stats.immutable, javascript_module: stats.javascript_module, chunkhash: stats.chunk_hash, diff --git a/crates/rspack_core/src/compiler/compilation.rs b/crates/rspack_core/src/compiler/compilation.rs index f39849721bc..cdf44e62f32 100644 --- a/crates/rspack_core/src/compiler/compilation.rs +++ b/crates/rspack_core/src/compiler/compilation.rs @@ -1895,6 +1895,8 @@ pub struct AssetInfo { pub content_hash: HashSet, /// when asset was created from a source file (potentially transformed), the original filename relative to compilation context pub source_filename: Option, + /// when asset was created from a source file (potentially transformed), it should be flagged as copied + pub copied: Option, /// size in bytes, only set after asset has been emitted // pub size: f64, /// when asset is only used for development and doesn't count towards user-facing assets diff --git a/crates/rspack_core/src/stats/mod.rs b/crates/rspack_core/src/stats/mod.rs index 11be76a4767..22b9cac4613 100644 --- a/crates/rspack_core/src/stats/mod.rs +++ b/crates/rspack_core/src/stats/mod.rs @@ -101,6 +101,7 @@ impl Stats<'_> { development: asset.info.development, hot_module_replacement: asset.info.hot_module_replacement, source_filename: asset.info.source_filename.clone(), + copied: asset.info.copied, is_over_size_limit: asset.info.is_over_size_limit, }, emitted: self.compilation.emitted_assets.contains(name), diff --git a/crates/rspack_core/src/stats/struct.rs b/crates/rspack_core/src/stats/struct.rs index 6e163ff42e7..17ec9b53558 100644 --- a/crates/rspack_core/src/stats/struct.rs +++ b/crates/rspack_core/src/stats/struct.rs @@ -114,6 +114,7 @@ pub struct StatsAssetInfo { pub development: Option, pub hot_module_replacement: Option, pub source_filename: Option, + pub copied: Option, pub immutable: Option, pub javascript_module: Option, pub chunk_hash: Vec, diff --git a/crates/rspack_plugin_copy/src/lib.rs b/crates/rspack_plugin_copy/src/lib.rs index a07446dcb53..45a08dffe3f 100644 --- a/crates/rspack_plugin_copy/src/lib.rs +++ b/crates/rspack_plugin_copy/src/lib.rs @@ -631,9 +631,15 @@ async fn process_assets(&self, compilation: &mut Compilation) -> Result<()> { if let Some(info) = result.info { set_info(&mut exist_asset.info, info); } - // TODO set info { copied: true, sourceFilename } + exist_asset.info.source_filename = Some(result.source_filename.to_string()); + exist_asset.info.copied = Some(true); } else { - let mut asset_info = Default::default(); + let mut asset_info = AssetInfo { + source_filename: Some(result.source_filename.to_string()), + copied: Some(true), + ..Default::default() + }; + if let Some(info) = result.info { set_info(&mut asset_info, info); } diff --git a/packages/rspack/etc/api.md b/packages/rspack/etc/api.md index 04d54459a1f..be4522bf1c3 100644 --- a/packages/rspack/etc/api.md +++ b/packages/rspack/etc/api.md @@ -3494,6 +3494,7 @@ type KnownAssetInfo = { chunkhash?: string | string[]; contenthash?: string | string[]; sourceFilename?: string; + copied?: boolean; size?: number; development?: boolean; hotModuleReplacement?: boolean; diff --git a/packages/rspack/src/stats/DefaultStatsPrinterPlugin.ts b/packages/rspack/src/stats/DefaultStatsPrinterPlugin.ts index ca7ab9f88a6..c0890e67245 100644 --- a/packages/rspack/src/stats/DefaultStatsPrinterPlugin.ts +++ b/packages/rspack/src/stats/DefaultStatsPrinterPlugin.ts @@ -312,6 +312,8 @@ const SIMPLE_PRINTERS: Record< : `from: ${sourceFilename}` ) : undefined, + "asset.info.copied": (copied, { green, formatFlag }) => + copied ? green(formatFlag("copied")) : undefined, "asset.info.development": (development, { green, formatFlag }) => development ? green(formatFlag("dev")) : undefined, "asset.info.hotModuleReplacement": ( @@ -779,6 +781,7 @@ const PREFERRED_ORDERS: Record = { "asset.info": [ "immutable", "sourceFilename", + "copied", "javascriptModule", "development", "hotModuleReplacement" diff --git a/packages/rspack/src/stats/statsFactoryUtils.ts b/packages/rspack/src/stats/statsFactoryUtils.ts index d094597e866..cb0254844c1 100644 --- a/packages/rspack/src/stats/statsFactoryUtils.ts +++ b/packages/rspack/src/stats/statsFactoryUtils.ts @@ -63,6 +63,7 @@ export type KnownAssetInfo = { // modulehash?: string | string[]; contenthash?: string | string[]; sourceFilename?: string; + copied?: boolean; size?: number; development?: boolean; hotModuleReplacement?: boolean; diff --git a/packages/rspack/src/util/AssetInfo.ts b/packages/rspack/src/util/AssetInfo.ts index 94448a8b141..f577b75c865 100644 --- a/packages/rspack/src/util/AssetInfo.ts +++ b/packages/rspack/src/util/AssetInfo.ts @@ -16,6 +16,7 @@ class JsAssetInfo { contenthash, javascriptModule, sourceFilename, + copied, extras } = jsAssetInfo; return { @@ -29,7 +30,8 @@ class JsAssetInfo { chunkhash, contenthash, javascriptModule, - sourceFilename + sourceFilename, + copied }; } @@ -45,6 +47,7 @@ class JsAssetInfo { contenthash = [], javascriptModule, sourceFilename, + copied, ...extras } = assetInfo; extras = extras ?? {}; @@ -59,7 +62,8 @@ class JsAssetInfo { contenthash, extras, javascriptModule, - sourceFilename + sourceFilename, + copied }; } } diff --git a/tests/plugin-test/copy-plugin/CopyPlugin.test.js b/tests/plugin-test/copy-plugin/CopyPlugin.test.js index 18f10dba70f..ebd4aedfe1e 100644 --- a/tests/plugin-test/copy-plugin/CopyPlugin.test.js +++ b/tests/plugin-test/copy-plugin/CopyPlugin.test.js @@ -146,7 +146,7 @@ describe("CopyPlugin", () => { }); it("should copy a file to a new file", done => { - runEmit({ + run({ expectedAssetKeys: ["newfile.txt"], patterns: [ { @@ -155,6 +155,12 @@ describe("CopyPlugin", () => { } ] }) + .then(({ stats, compilation }) => { + const assetInfo = stats.compilation.getAsset("newfile.txt"); + expect(assetInfo.info.sourceFilename).toBe("file.txt"); + expect(assetInfo.name).toBe("newfile.txt"); + expect(compilation.assets["newfile.txt"]).toBeDefined(); + }) .then(done) .catch(done); }); @@ -306,7 +312,7 @@ describe("CopyPlugin", () => { }) .then(({ stats }) => { for (const name of expectedAssetKeys) { - const info = stats.compilation.assetsInfo.get(name); + const { info } = stats.compilation.getAsset(name); expect(info.copied).toBe(true); @@ -350,7 +356,7 @@ describe("CopyPlugin", () => { }) .then(({ stats }) => { for (const name of expectedAssetKeys) { - const info = stats.compilation.assetsInfo.get(name); + const { info } = stats.compilation.getAsset(name); expect(info.immutable).toBe(true); @@ -363,7 +369,7 @@ describe("CopyPlugin", () => { .catch(done); }); - it.skip('should copy files and print "copied" in the string representation ', done => { + it('should copy files and print "copied" in the string representation ', done => { expect.assertions(1); const expectedAssetKeys = [ @@ -524,7 +530,7 @@ describe("CopyPlugin", () => { { from: path.resolve(__dirname, "./fixtures/directory"), to: () => { - return 'directory'; + return "directory"; } } ]