Skip to content

Commit

Permalink
Expand plugin traits and plugin config (#9744)
Browse files Browse the repository at this point in the history
* Expand plugin traits and plugin config

* Use trait objects

* Use Rc
  • Loading branch information
MonicaOlejniczak authored May 29, 2024
1 parent 0b58e51 commit 1180254
Show file tree
Hide file tree
Showing 18 changed files with 992 additions and 19 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions crates/parcel_core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ description = "Core logic for the parcel bundler"
default = []

[dependencies]
parcel_filesystem = { path = "../parcel_filesystem" }
parcel-resolver = { path = "../../packages/utils/node-resolver-rs" }

ahash = "0.8.11"
Expand Down
1 change: 1 addition & 0 deletions crates/parcel_core/src/bundle_graph.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub struct BundleGraph {}
1 change: 1 addition & 0 deletions crates/parcel_core/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#![deny(unused_crate_dependencies)]
//! Core re-implementation in Rust

pub mod bundle_graph;
pub mod hash;
pub mod plugin;
pub mod request_tracker;
Expand Down
7 changes: 7 additions & 0 deletions crates/parcel_core/src/plugin.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
mod bundler;

pub use bundler::*;

mod compressor;
Expand All @@ -13,6 +14,9 @@ pub use optimizer::*;
mod packager;
pub use packager::*;

mod plugin_config;
pub use plugin_config::*;

mod reporter;
pub use reporter::*;

Expand All @@ -28,11 +32,14 @@ pub use transformer::*;
mod validator;
pub use validator::*;

#[derive(Default)]
pub struct PluginContext {
pub options: PluginOptions,
pub logger: PluginLogger,
}

#[derive(Default)]
pub struct PluginLogger {}

#[derive(Default)]
pub struct PluginOptions {}
43 changes: 42 additions & 1 deletion crates/parcel_core/src/plugin/bundler.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,49 @@
use super::PluginConfig;
use crate::bundle_graph::BundleGraph;

/// Converts an asset graph into a BundleGraph
///
/// Bundlers accept the entire asset graph and modify it to add bundle nodes that group the assets
/// into output bundles.
///
/// Bundle and optimize run in series and are functionally identitical.
///
pub trait BundlerPlugin {}
pub trait BundlerPlugin {
/// A hook designed to load config necessary for the bundler to operate
///
/// This function will run once, shortly after the plugin is initialised.
///
fn load_config(&mut self, config: &PluginConfig) -> Result<(), anyhow::Error>;

// TODO: Should BundleGraph be AssetGraph or something that contains AssetGraph in the name?
fn bundle(&self, bundle_graph: &mut BundleGraph) -> Result<(), anyhow::Error>;

fn optimize(&self, bundle_graph: &mut BundleGraph) -> Result<(), anyhow::Error>;
}

#[cfg(test)]
mod tests {
use super::*;

#[derive(Debug)]
struct TestBundlerPlugin {}

impl BundlerPlugin for TestBundlerPlugin {
fn load_config(&mut self, _config: &PluginConfig) -> Result<(), anyhow::Error> {
todo!()
}

fn bundle(&self, _bundle_graph: &mut BundleGraph) -> Result<(), anyhow::Error> {
todo!()
}

fn optimize(&self, _bundle_graph: &mut BundleGraph) -> Result<(), anyhow::Error> {
todo!()
}
}

#[test]
fn can_be_dyn() {
let _bundler: Box<dyn BundlerPlugin> = Box::new(TestBundlerPlugin {});
}
}
44 changes: 43 additions & 1 deletion crates/parcel_core/src/plugin/compressor.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,44 @@
use std::fs::File;

pub struct CompressedFile {
/// An optional file extension appended to the output file
///
/// When no extension is returned, then the returned stream replaces the original file.
///
pub extension: Option<String>,

/// The compressed file
pub file: File,
}

/// Compresses the input file stream
pub trait CompressorPlugin {}
pub trait CompressorPlugin {
/// Compress the given file
///
/// The file contains the final contents of bundles and sourcemaps as they are being written.
/// A new stream can be returned, or None to forward compression onto the next plugin.
///
fn compress(&self, file: &File) -> Result<Option<CompressedFile>, String>;
}

#[cfg(test)]
mod tests {
use super::*;

struct TestCompressorPlugin {}

impl CompressorPlugin for TestCompressorPlugin {
fn compress(&self, _file: &File) -> Result<Option<CompressedFile>, String> {
todo!()
}
}

#[test]
fn can_be_defined_in_dyn_vec() {
let mut compressors = Vec::<Box<dyn CompressorPlugin>>::new();

compressors.push(Box::new(TestCompressorPlugin {}));

assert_eq!(compressors.len(), 1);
}
}
57 changes: 56 additions & 1 deletion crates/parcel_core/src/plugin/namer.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,60 @@
use std::path::PathBuf;

use super::PluginConfig;
use crate::bundle_graph::BundleGraph;
use crate::types::Bundle;

/// Determines the output filename for a bundle
///
/// Namers run in a pipeline until one returns a result.
///
pub trait NamerPlugin {}
pub trait NamerPlugin {
/// A hook designed to setup config needed for naming bundles
///
/// This function will run once, shortly after the plugin is initialised.
///
fn load_config(&mut self, config: &PluginConfig) -> Result<(), anyhow::Error>;

/// Names the given bundle
///
/// The returned file path should be relative to the target dist directory, and will be used to
/// name the bundle. Naming can be forwarded onto the next plugin by returning None.
///
fn name(
&mut self,
config: &PluginConfig,
bundle: &Bundle,
bundle_graph: &BundleGraph,
) -> Result<Option<PathBuf>, anyhow::Error>;
}

#[cfg(test)]
mod tests {
use super::*;

struct TestNamerPlugin {}

impl NamerPlugin for TestNamerPlugin {
fn load_config(&mut self, _config: &PluginConfig) -> Result<(), anyhow::Error> {
todo!()
}

fn name(
&mut self,
_config: &PluginConfig,
_bundle: &Bundle,
_bundle_graph: &BundleGraph,
) -> Result<Option<PathBuf>, anyhow::Error> {
todo!()
}
}

#[test]
fn can_be_defined_in_dyn_vec() {
let mut namers = Vec::<Box<dyn NamerPlugin>>::new();

namers.push(Box::new(TestNamerPlugin {}));

assert_eq!(namers.len(), 1);
}
}
65 changes: 64 additions & 1 deletion crates/parcel_core/src/plugin/optimizer.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,23 @@
use std::fs::File;

use super::PluginConfig;
use crate::bundle_graph::BundleGraph;
use crate::types::Bundle;
use crate::types::SourceMap;

pub struct OptimizeContext<'a> {
pub bundle: &'a Bundle,
pub bundle_graph: &'a BundleGraph,
pub contents: &'a File, // TODO We may want this to be a String or File later
pub map: Option<&'a SourceMap>,
// TODO getSourceMapReference?
}

pub struct OptimizedBundle {
pub contents: File,
// TODO ast, map, type
}

/// Optimises a bundle
///
/// Optimizers are commonly used to implement minification, tree shaking, dead code elimination,
Expand All @@ -8,4 +28,47 @@
/// Multiple optimizer plugins may run in series, and the result of each optimizer is passed to
/// the next.
///
pub trait OptimizerPlugin: Send + Sync {}
pub trait OptimizerPlugin: Send + Sync {
/// A hook designed to setup config needed for optimizing bundles
///
/// This function will run once, shortly after the plugin is initialised.
///
fn load_config(&mut self, config: &PluginConfig) -> Result<(), anyhow::Error>;

/// Transforms the contents of a bundle and its source map
fn optimize(
&mut self,
config: &PluginConfig,
ctx: OptimizeContext,
) -> Result<OptimizedBundle, anyhow::Error>;
}

#[cfg(test)]
mod tests {
use super::*;

struct TestOptimizerPlugin {}

impl OptimizerPlugin for TestOptimizerPlugin {
fn load_config(&mut self, _config: &PluginConfig) -> Result<(), anyhow::Error> {
todo!()
}

fn optimize(
&mut self,
_config: &PluginConfig,
_ctx: OptimizeContext,
) -> Result<OptimizedBundle, anyhow::Error> {
todo!()
}
}

#[test]
fn can_be_defined_in_dyn_vec() {
let mut optimizers = Vec::<Box<dyn OptimizerPlugin>>::new();

optimizers.push(Box::new(TestOptimizerPlugin {}));

assert_eq!(optimizers.len(), 1);
}
}
61 changes: 60 additions & 1 deletion crates/parcel_core/src/plugin/packager.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,65 @@
use std::fs::File;

use super::PluginConfig;
use crate::bundle_graph::BundleGraph;
use crate::types::Bundle;
use crate::types::SourceMap;

pub struct PackageContext<'a> {
pub bundle: &'a Bundle,
pub bundle_graph: &'a BundleGraph,
pub contents: &'a File, // TODO We may want this to be a String or File later
pub map: Option<&'a SourceMap>,
// TODO getSourceMapReference?
}

pub struct PackagedBundle {
pub contents: File,
// TODO ast, map, type
}

/// Combines all the assets in a bundle together into an output file
///
/// Packagers are also responsible for resolving URL references, bundle inlining, and generating
/// source maps.
///
pub trait PackagerPlugin: Send + Sync {}
pub trait PackagerPlugin: Send + Sync {
/// A hook designed to setup config needed for packaging
///
/// This function will run once, shortly after the plugin is initialised.
///
fn load_config(&mut self, config: &PluginConfig) -> Result<(), anyhow::Error>;

/// Combines assets in a bundle
fn package(
&mut self,
config: &PluginConfig,
ctx: PackageContext,
) -> Result<PackagedBundle, anyhow::Error>;
}

#[cfg(test)]
mod tests {
use super::*;

struct TestPackagerPlugin {}

impl PackagerPlugin for TestPackagerPlugin {
fn load_config(&mut self, _config: &PluginConfig) -> Result<(), anyhow::Error> {
todo!()
}

fn package(
&mut self,
_config: &PluginConfig,
_ctx: PackageContext,
) -> Result<PackagedBundle, anyhow::Error> {
todo!()
}
}

#[test]
fn can_be_dyn() {
let _packager: Box<dyn PackagerPlugin> = Box::new(TestPackagerPlugin {});
}
}
Loading

0 comments on commit 1180254

Please sign in to comment.