use std::{any::Any, collections::HashMap, hash::Hash, sync::Arc};
use farmfe_macro_cache_item::cache_item;
use serde::{Deserialize, Serialize};
use crate::{
config::Config,
context::CompilationContext,
error::Result,
module::{
module_graph::ModuleGraph, module_group::ModuleGroupGraph, Module, ModuleId, ModuleMetaData,
ModuleType,
},
resource::{
resource_pot::{ResourcePot, ResourcePotInfo, ResourcePotMetaData},
Resource, ResourceType,
},
stats::Stats,
};
pub mod constants;
pub mod plugin_driver;
pub const DEFAULT_PRIORITY: i32 = 100;
pub trait Plugin: Any + Send + Sync {
fn name(&self) -> &str;
fn priority(&self) -> i32 {
DEFAULT_PRIORITY
}
fn config(&self, _config: &mut Config) -> Result<Option<()>> {
Ok(None)
}
fn plugin_cache_loaded(
&self,
_cache: &Vec<u8>,
_context: &Arc<CompilationContext>,
) -> Result<Option<()>> {
Ok(None)
}
fn build_start(&self, _context: &Arc<CompilationContext>) -> Result<Option<()>> {
Ok(None)
}
fn resolve(
&self,
_param: &PluginResolveHookParam,
_context: &Arc<CompilationContext>,
_hook_context: &PluginHookContext,
) -> Result<Option<PluginResolveHookResult>> {
Ok(None)
}
fn load(
&self,
_param: &PluginLoadHookParam,
_context: &Arc<CompilationContext>,
_hook_context: &PluginHookContext,
) -> Result<Option<PluginLoadHookResult>> {
Ok(None)
}
fn transform(
&self,
_param: &PluginTransformHookParam,
_context: &Arc<CompilationContext>,
) -> Result<Option<PluginTransformHookResult>> {
Ok(None)
}
fn parse(
&self,
_param: &PluginParseHookParam,
_context: &Arc<CompilationContext>,
_hook_context: &PluginHookContext,
) -> Result<Option<ModuleMetaData>> {
Ok(None)
}
fn process_module(
&self,
_param: &mut PluginProcessModuleHookParam,
_context: &Arc<CompilationContext>,
) -> Result<Option<()>> {
Ok(None)
}
fn analyze_deps(
&self,
_param: &mut PluginAnalyzeDepsHookParam,
_context: &Arc<CompilationContext>,
) -> Result<Option<()>> {
Ok(None)
}
fn finalize_module(
&self,
_param: &mut PluginFinalizeModuleHookParam,
_context: &Arc<CompilationContext>,
) -> Result<Option<()>> {
Ok(None)
}
fn build_end(&self, _context: &Arc<CompilationContext>) -> Result<Option<()>> {
Ok(None)
}
fn generate_start(&self, _context: &Arc<CompilationContext>) -> Result<Option<()>> {
Ok(None)
}
fn optimize_module_graph(
&self,
_module_graph: &mut ModuleGraph,
_context: &Arc<CompilationContext>,
) -> Result<Option<()>> {
Ok(None)
}
fn analyze_module_graph(
&self,
_module_graph: &mut ModuleGraph,
_context: &Arc<CompilationContext>,
_hook_context: &PluginHookContext,
) -> Result<Option<ModuleGroupGraph>> {
Ok(None)
}
fn partial_bundling(
&self,
_modules: &Vec<ModuleId>,
_context: &Arc<CompilationContext>,
_hook_context: &PluginHookContext,
) -> Result<Option<Vec<ResourcePot>>> {
Ok(None)
}
fn process_resource_pots(
&self,
_resource_pots: &mut Vec<&mut ResourcePot>,
_context: &Arc<CompilationContext>,
) -> Result<Option<()>> {
Ok(None)
}
fn render_start(
&self,
_config: &Config,
_context: &Arc<CompilationContext>,
) -> Result<Option<()>> {
Ok(None)
}
fn render_resource_pot_modules(
&self,
_resource_pot: &ResourcePot,
_context: &Arc<CompilationContext>,
_hook_context: &PluginHookContext,
) -> Result<Option<ResourcePotMetaData>> {
Ok(None)
}
fn render_resource_pot(
&self,
_resource_pot: &PluginRenderResourcePotHookParam,
_context: &Arc<CompilationContext>,
) -> Result<Option<PluginRenderResourcePotHookResult>> {
Ok(None)
}
fn augment_resource_hash(
&self,
_render_pot_info: &ResourcePotInfo,
_context: &Arc<CompilationContext>,
) -> Result<Option<String>> {
Ok(None)
}
fn optimize_resource_pot(
&self,
_resource: &mut ResourcePot,
_context: &Arc<CompilationContext>,
) -> Result<Option<()>> {
Ok(None)
}
fn generate_resources(
&self,
_resource_pot: &mut ResourcePot,
_context: &Arc<CompilationContext>,
_hook_context: &PluginHookContext,
) -> Result<Option<PluginGenerateResourcesHookResult>> {
Ok(None)
}
fn process_generated_resources(
&self,
_resources: &mut PluginGenerateResourcesHookResult,
_context: &Arc<CompilationContext>,
) -> Result<Option<()>> {
Ok(None)
}
fn handle_entry_resource(
&self,
_resource: &mut PluginHandleEntryResourceHookParams,
_context: &Arc<CompilationContext>,
) -> Result<Option<()>> {
Ok(None)
}
fn finalize_resources(
&self,
_param: &mut PluginFinalizeResourcesHookParams,
_context: &Arc<CompilationContext>,
) -> Result<Option<()>> {
Ok(None)
}
fn generate_end(&self, _context: &Arc<CompilationContext>) -> Result<Option<()>> {
Ok(None)
}
fn finish(&self, _stat: &Stats, _context: &Arc<CompilationContext>) -> Result<Option<()>> {
Ok(None)
}
fn update_modules(
&self,
_params: &mut PluginUpdateModulesHookParams,
_context: &Arc<CompilationContext>,
) -> Result<Option<()>> {
Ok(None)
}
fn module_graph_updated(
&self,
_param: &PluginModuleGraphUpdatedHookParams,
_context: &Arc<CompilationContext>,
) -> Result<Option<()>> {
Ok(None)
}
fn update_finished(&self, _context: &Arc<CompilationContext>) -> Result<Option<()>> {
Ok(None)
}
fn handle_persistent_cached_module(
&self,
_module: &Module,
_context: &Arc<CompilationContext>,
) -> Result<Option<bool>> {
Ok(None)
}
fn write_plugin_cache(&self, _context: &Arc<CompilationContext>) -> Result<Option<Vec<u8>>> {
Ok(None)
}
}
#[derive(Debug, Clone, Hash, PartialEq, Eq, serde::Serialize, serde::Deserialize, Default)]
#[serde(rename_all = "camelCase")]
#[cache_item]
pub enum ResolveKind {
Entry(String),
#[default]
Import,
ExportFrom,
DynamicImport,
Require,
CssAtImport,
CssUrl,
ScriptSrc,
LinkHref,
HmrUpdate,
Custom(String),
}
impl ResolveKind {
pub fn is_dynamic(&self) -> bool {
matches!(self, ResolveKind::DynamicImport)
|| matches!(self, ResolveKind::Custom(c) if c.starts_with("dynamic:"))
}
pub fn is_export_from(&self) -> bool {
matches!(self, ResolveKind::ExportFrom)
}
pub fn is_require(&self) -> bool {
matches!(self, ResolveKind::Require)
}
}
impl From<&str> for ResolveKind {
fn from(value: &str) -> Self {
serde_json::from_str(value).unwrap()
}
}
impl From<ResolveKind> for String {
fn from(value: ResolveKind) -> Self {
serde_json::to_string(&value).unwrap()
}
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct PluginHookContext {
pub caller: Option<String>,
pub meta: HashMap<String, String>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Hash, PartialEq, Eq)]
#[serde(rename_all = "camelCase")]
pub struct PluginResolveHookParam {
pub source: String,
pub importer: Option<ModuleId>,
pub kind: ResolveKind,
}
#[derive(Debug, Serialize, Deserialize, Clone)]
#[serde(rename_all = "camelCase", default)]
pub struct PluginResolveHookResult {
pub resolved_path: String,
pub external: bool,
pub side_effects: bool,
pub query: Vec<(String, String)>,
pub meta: HashMap<String, String>,
}
impl Default for PluginResolveHookResult {
fn default() -> Self {
Self {
side_effects: true,
resolved_path: "unknown".to_string(),
external: false,
query: vec![],
meta: Default::default(),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct PluginLoadHookParam<'a> {
pub module_id: String,
pub resolved_path: &'a str,
pub query: Vec<(String, String)>,
pub meta: HashMap<String, String>,
}
#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct PluginLoadHookResult {
pub content: String,
pub module_type: ModuleType,
pub source_map: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct PluginTransformHookParam<'a> {
pub module_id: String,
pub content: String,
pub module_type: ModuleType,
pub resolved_path: &'a str,
pub query: Vec<(String, String)>,
pub meta: HashMap<String, String>,
pub source_map_chain: Vec<Arc<String>>,
}
#[derive(Debug, Default, Serialize, Deserialize)]
#[serde(rename_all = "camelCase", default)]
pub struct PluginTransformHookResult {
pub content: String,
pub module_type: Option<ModuleType>,
pub source_map: Option<String>,
pub ignore_previous_source_map: bool,
}
#[derive(Debug)]
pub struct PluginParseHookParam {
pub module_id: ModuleId,
pub resolved_path: String,
pub query: Vec<(String, String)>,
pub module_type: ModuleType,
pub content: Arc<String>,
}
pub struct PluginProcessModuleHookParam<'a> {
pub module_id: &'a ModuleId,
pub module_type: &'a ModuleType,
pub content: Arc<String>,
pub meta: &'a mut ModuleMetaData,
}
pub struct PluginAnalyzeDepsHookParam<'a> {
pub module: &'a Module,
pub deps: Vec<PluginAnalyzeDepsHookResultEntry>,
}
#[derive(Debug, PartialEq, Eq, Clone)]
#[cache_item]
pub struct PluginAnalyzeDepsHookResultEntry {
pub source: String,
pub kind: ResolveKind,
}
pub struct PluginFinalizeModuleHookParam<'a> {
pub module: &'a mut Module,
pub deps: &'a Vec<PluginAnalyzeDepsHookResultEntry>,
}
#[derive(Default, Debug, serde::Serialize, serde::Deserialize, Clone)]
pub struct WatchDiffResult {
pub add: Vec<String>,
pub remove: Vec<String>,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
#[serde(rename_all = "camelCase", default)]
pub struct UpdateResult {
pub added_module_ids: Vec<ModuleId>,
pub updated_module_ids: Vec<ModuleId>,
pub removed_module_ids: Vec<ModuleId>,
pub immutable_resources: String,
pub mutable_resources: String,
pub boundaries: HashMap<String, Vec<Vec<String>>>,
pub dynamic_resources_map: Option<HashMap<ModuleId, Vec<(String, ResourceType)>>>,
pub extra_watch_result: WatchDiffResult,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum UpdateType {
Added,
Updated,
Removed,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase", default)]
pub struct PluginUpdateModulesHookParams {
pub paths: Vec<(String, UpdateType)>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase", default)]
pub struct PluginModuleGraphUpdatedHookParams {
pub added_modules_ids: Vec<ModuleId>,
pub removed_modules_ids: Vec<ModuleId>,
pub updated_modules_ids: Vec<ModuleId>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct EmptyPluginHookParam {}
#[derive(Debug, Serialize, Deserialize)]
pub struct EmptyPluginHookResult {}
#[cache_item]
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct PluginGenerateResourcesHookResult {
pub resource: Resource,
pub source_map: Option<Resource>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct PluginRenderResourcePotHookParam {
pub content: Arc<String>,
pub source_map_chain: Vec<Arc<String>>,
pub resource_pot_info: ResourcePotInfo,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct PluginRenderResourcePotHookResult {
pub content: String,
pub source_map: Option<String>,
}
pub struct PluginDriverRenderResourcePotHookResult {
pub content: Arc<String>,
pub source_map_chain: Vec<Arc<String>>,
}
pub struct PluginFinalizeResourcesHookParams<'a> {
pub resources_map: &'a mut HashMap<String, Resource>,
pub config: &'a Config,
}
pub struct PluginHandleEntryResourceHookParams<'a> {
pub resource: &'a mut Resource,
pub module_graph: &'a ModuleGraph,
pub module_group_graph: &'a ModuleGroupGraph,
pub entry_module_id: &'a ModuleId,
}