rspack_plugin_library 0.101.3

rspack library plugin
Documentation
use rspack_core::{
  ChunkCodeTemplate, ChunkUkey, Compilation, CompilationAdditionalChunkRuntimeRequirements,
  CompilationParams, CompilerCompilation, Filename, LibraryName, LibraryNonUmdObject,
  LibraryOptions, LibraryType, PathData, Plugin, RuntimeGlobals, RuntimeModule, SourceType,
  rspack_sources::{ConcatSource, RawStringSource, SourceExt},
};
use rspack_error::{Result, error_bail};
use rspack_hash::{RspackHash, RspackHasher};
use rspack_hook::{plugin, plugin_hook};
use rspack_plugin_javascript::{
  JavascriptModulesChunkHash, JavascriptModulesRender, JsPlugin, RenderSource,
};

use crate::utils::{COMMON_LIBRARY_NAME_MESSAGE, get_options_for_chunk};

const PLUGIN_NAME: &str = "rspack.JsonpLibraryPlugin";

#[derive(Debug)]
struct JsonpLibraryPluginParsed<'a> {
  name: &'a str,
}

#[plugin]
#[derive(Debug)]
pub struct JsonpLibraryPlugin {
  library_type: LibraryType,
}

impl JsonpLibraryPlugin {
  pub fn new(library_type: LibraryType) -> Self {
    Self::new_inner(library_type)
  }

  fn parse_options<'a>(&self, library: &'a LibraryOptions) -> Result<JsonpLibraryPluginParsed<'a>> {
    match &library.name {
      Some(LibraryName::NonUmdObject(LibraryNonUmdObject::String(s))) => {
        Ok(JsonpLibraryPluginParsed { name: s.as_str() })
      }
      _ => {
        error_bail!("Jsonp library name must be a simple string. {COMMON_LIBRARY_NAME_MESSAGE}")
      }
    }
  }

  fn get_options_for_chunk<'a>(
    &self,
    compilation: &'a Compilation,
    chunk_ukey: &'a ChunkUkey,
  ) -> Result<Option<JsonpLibraryPluginParsed<'a>>> {
    get_options_for_chunk(compilation, chunk_ukey)
      .filter(|library| library.library_type == self.library_type)
      .map(|library| self.parse_options(library))
      .transpose()
  }
}

#[plugin_hook(CompilerCompilation for JsonpLibraryPlugin)]
async fn compilation(
  &self,
  compilation: &mut Compilation,
  _params: &mut CompilationParams,
) -> Result<()> {
  let hooks = JsPlugin::get_compilation_hooks_mut(compilation.id());
  let mut hooks = hooks.write().await;
  hooks.render.tap(render::new(self));
  hooks.chunk_hash.tap(js_chunk_hash::new(self));
  Ok(())
}

#[plugin_hook(JavascriptModulesRender for JsonpLibraryPlugin)]
async fn render(
  &self,
  compilation: &Compilation,
  chunk_ukey: &ChunkUkey,
  render_source: &mut RenderSource,
  _runtime_template: &ChunkCodeTemplate,
) -> Result<()> {
  let Some(options) = self.get_options_for_chunk(compilation, chunk_ukey)? else {
    return Ok(());
  };
  let chunk = compilation
    .build_chunk_graph_artifact
    .chunk_by_ukey
    .expect_get(chunk_ukey);
  let name = compilation
    .get_path(
      &Filename::from(options.name),
      PathData::default()
        .chunk(chunk.ukey(), compilation)
        .chunk_id_optional(chunk.id().map(|id| id.as_str()))
        .chunk_hash_optional(chunk.rendered_hash(
          &compilation.chunk_hashes_artifact,
          compilation.options.output.hash_digest_length,
        ))
        .chunk_name_optional(chunk.name_for_filename_template())
        .content_hash_optional(chunk.rendered_content_hash_by_source_type(
          &compilation.chunk_hashes_artifact,
          &SourceType::JavaScript,
          compilation.options.output.hash_digest_length,
        )),
    )
    .await?;
  let mut source = ConcatSource::default();
  source.add(RawStringSource::from(format!("{name}(")));
  source.add(render_source.source.clone());
  source.add(RawStringSource::from_static("\n)"));
  render_source.source = source.boxed();
  Ok(())
}

#[plugin_hook(JavascriptModulesChunkHash for JsonpLibraryPlugin)]
async fn js_chunk_hash(
  &self,
  compilation: &Compilation,
  chunk_ukey: &ChunkUkey,
  hasher: &mut RspackHasher,
) -> Result<()> {
  let Some(options) = self.get_options_for_chunk(compilation, chunk_ukey)? else {
    return Ok(());
  };
  PLUGIN_NAME.hash(hasher);
  options.name.hash(hasher);
  Ok(())
}

#[plugin_hook(CompilationAdditionalChunkRuntimeRequirements for JsonpLibraryPlugin)]
async fn additional_chunk_runtime_requirements(
  &self,
  compilation: &Compilation,
  chunk_ukey: &ChunkUkey,
  runtime_requirements: &mut RuntimeGlobals,
  _runtime_modules: &mut Vec<Box<dyn RuntimeModule>>,
) -> Result<()> {
  if self
    .get_options_for_chunk(compilation, chunk_ukey)?
    .is_none()
  {
    return Ok(());
  }
  runtime_requirements.insert(RuntimeGlobals::RETURN_EXPORTS_FROM_RUNTIME);
  Ok(())
}

impl Plugin for JsonpLibraryPlugin {
  fn name(&self) -> &'static str {
    PLUGIN_NAME
  }

  fn apply(&self, ctx: &mut rspack_core::ApplyContext<'_>) -> Result<()> {
    ctx.compiler_hooks.compilation.tap(compilation::new(self));
    ctx
      .compilation_hooks
      .additional_chunk_runtime_requirements
      .tap(additional_chunk_runtime_requirements::new(self));
    Ok(())
  }
}