Skip to main content

rspack_plugin_runtime_chunk/
lib.rs

1use std::fmt;
2
3use futures::future::BoxFuture;
4use rspack_core::{CompilationAddEntry, EntryOptions};
5use rspack_error::Result;
6use rspack_hook::{plugin, plugin_hook};
7
8#[plugin]
9#[derive(Debug)]
10pub struct RuntimeChunkPlugin {
11  name: RuntimeChunkName,
12}
13
14impl RuntimeChunkPlugin {
15  pub fn new(options: RuntimeChunkOptions) -> Self {
16    Self::new_inner(options.name)
17  }
18}
19
20#[derive(Debug)]
21pub struct RuntimeChunkOptions {
22  pub name: RuntimeChunkName,
23}
24
25pub enum RuntimeChunkName {
26  Single,
27  Multiple,
28  String(String),
29  Fn(RuntimeChunkNameFn),
30}
31
32impl fmt::Debug for RuntimeChunkName {
33  fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
34    match self {
35      Self::Single => write!(f, "Single"),
36      Self::Multiple => write!(f, "Multiple"),
37      Self::String(arg0) => f.debug_tuple("String").field(arg0).finish(),
38      Self::Fn(_) => f.debug_tuple("Fn").finish(),
39    }
40  }
41}
42
43pub type RuntimeChunkNameFn =
44  Box<dyn for<'a> Fn(&'a str) -> BoxFuture<'a, Result<String>> + Sync + Send>;
45
46#[plugin_hook(CompilationAddEntry for RuntimeChunkPlugin)]
47async fn add_entry(&self, entry_name: Option<&str>, options: &mut EntryOptions) -> Result<()> {
48  if let Some(entry_name) = entry_name
49    && options.runtime.is_none()
50    && options.depend_on.is_none()
51  {
52    let name = match &self.name {
53      RuntimeChunkName::Single => "runtime".to_string(),
54      RuntimeChunkName::Multiple => {
55        format!("runtime~{entry_name}")
56      }
57      RuntimeChunkName::String(name) => name.clone(),
58      RuntimeChunkName::Fn(f) => f(entry_name).await?,
59    };
60    options.runtime = Some(name.into());
61  }
62  Ok(())
63}
64
65impl rspack_core::Plugin for RuntimeChunkPlugin {
66  fn apply(&self, ctx: &mut rspack_core::ApplyContext<'_>) -> Result<()> {
67    ctx.compilation_hooks.add_entry.tap(add_entry::new(self));
68    Ok(())
69  }
70}