Skip to main content

rspack_plugin_remove_empty_chunks/
lib.rs

1// Port of https://github.com/webpack/webpack/blob/4b4ca3bb53f36a5b8fc6bc1bd976ed7af161bd80/lib/optimize/RemoveEmptyChunksPlugin.js
2
3use rspack_core::{
4  ChunkKind, Compilation, CompilationOptimizeChunks, Logger, Plugin, incremental::Mutation,
5};
6use rspack_error::Result;
7use rspack_hook::{plugin, plugin_hook};
8
9#[plugin]
10#[derive(Debug, Default)]
11pub struct RemoveEmptyChunksPlugin;
12
13impl RemoveEmptyChunksPlugin {
14  fn remove_empty_chunks(&self, compilation: &mut Compilation) {
15    let logger = compilation.get_logger(self.name());
16    let start = logger.time("remove empty chunks");
17
18    let chunk_graph = &mut compilation.build_chunk_graph_artifact.chunk_graph;
19    let empty_chunks = compilation
20      .build_chunk_graph_artifact
21      .chunk_by_ukey
22      .values()
23      .filter(|chunk| {
24        chunk.kind() != ChunkKind::Facade
25          && chunk_graph.get_number_of_chunk_modules(&chunk.ukey()) == 0
26          && !chunk.has_runtime(&compilation.build_chunk_graph_artifact.chunk_group_by_ukey)
27          && chunk_graph.get_number_of_entry_modules(&chunk.ukey()) == 0
28      })
29      .map(|chunk| chunk.ukey())
30      .collect::<Vec<_>>();
31
32    for chunk_ukey in empty_chunks.iter() {
33      if let Some(mut chunk) = compilation
34        .build_chunk_graph_artifact
35        .chunk_by_ukey
36        .remove(chunk_ukey)
37      {
38        chunk_graph.disconnect_chunk(
39          &mut chunk,
40          &mut compilation.build_chunk_graph_artifact.chunk_group_by_ukey,
41        );
42        if let Some(mut mutations) = compilation.incremental.mutations_write() {
43          mutations.add(Mutation::ChunkRemove { chunk: *chunk_ukey });
44        }
45      }
46    }
47
48    logger.time_end(start);
49  }
50}
51
52// Run after advanced chunk optimizers have established their final chunk
53// semantics. In particular, modern-module marks facade chunks at ADVANCED + 1.
54#[plugin_hook(CompilationOptimizeChunks for RemoveEmptyChunksPlugin, stage = Compilation::OPTIMIZE_CHUNKS_STAGE_ADVANCED + 2)]
55async fn optimize_chunks(&self, compilation: &mut Compilation) -> Result<Option<bool>> {
56  self.remove_empty_chunks(compilation);
57  Ok(None)
58}
59
60impl Plugin for RemoveEmptyChunksPlugin {
61  fn name(&self) -> &'static str {
62    "rspack.RemoveEmptyChunksPlugin"
63  }
64
65  fn apply(&self, ctx: &mut rspack_core::ApplyContext) -> Result<()> {
66    ctx
67      .compilation_hooks
68      .optimize_chunks
69      .tap(optimize_chunks::new(self));
70    Ok(())
71  }
72}