Skip to content

Commit

Permalink
feat: support externals in compiler builder options (#8959)
Browse files Browse the repository at this point in the history
feat: init
  • Loading branch information
h-a-n-a authored Jan 8, 2025
1 parent 0dbc9ac commit 9da4fc8
Show file tree
Hide file tree
Showing 5 changed files with 207 additions and 10 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.

3 changes: 2 additions & 1 deletion crates/rspack/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ rspack_regex = { workspace = true }
rustc-hash = { workspace = true }
serde_json = { workspace = true }

rspack_plugin_devtool = { workspace = true }
rspack_plugin_devtool = { workspace = true }
rspack_plugin_externals = { workspace = true }

[lints]
workspace = true
152 changes: 143 additions & 9 deletions crates/rspack/src/options/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,20 @@ use rspack_core::{
ChunkLoading, ChunkLoadingType, CleanOptions, CompilerOptions, Context, CrossOriginLoading,
CssAutoGeneratorOptions, CssAutoParserOptions, CssExportsConvention, CssGeneratorOptions,
CssModuleGeneratorOptions, CssModuleParserOptions, CssParserOptions, DynamicImportMode,
EntryDescription, Environment, ExperimentCacheOptions, Experiments, Filename, FilenameTemplate,
GeneratorOptions, GeneratorOptionsMap, JavascriptParserOptions, JavascriptParserOrder,
JavascriptParserUrl, JsonParserOptions, LibraryName, LibraryNonUmdObject, LibraryOptions,
LibraryType, Mode, ModuleNoParseRules, ModuleOptions, ModuleRule, ModuleRuleEffect,
OutputOptions, ParserOptions, ParserOptionsMap, PathInfo, PublicPath, Resolve, RspackFuture,
RuleSetCondition, RuleSetLogicalConditions, TrustedTypes, WasmLoading, WasmLoadingType,
EntryDescription, Environment, ExperimentCacheOptions, Experiments, ExternalItem, ExternalType,
Filename, FilenameTemplate, GeneratorOptions, GeneratorOptionsMap, JavascriptParserOptions,
JavascriptParserOrder, JavascriptParserUrl, JsonParserOptions, LibraryName, LibraryNonUmdObject,
LibraryOptions, LibraryType, Mode, ModuleNoParseRules, ModuleOptions, ModuleRule,
ModuleRuleEffect, OutputOptions, ParserOptions, ParserOptionsMap, PathInfo, PublicPath, Resolve,
RspackFuture, RuleSetCondition, RuleSetLogicalConditions, TrustedTypes, WasmLoading,
WasmLoadingType,
};
use rspack_hash::{HashDigest, HashFunction, HashSalt};
use rspack_paths::{AssertUtf8, Utf8PathBuf};
use rspack_regex::RspackRegex;
use rustc_hash::FxHashMap as HashMap;

use super::externals::ExternalsPresets;
use super::target::{get_targets_properties, TargetProperties};
use super::{Devtool, DevtoolFlags, Target};
macro_rules! d {
Expand Down Expand Up @@ -83,9 +85,9 @@ pub(crate) enum BuiltinPluginOptions {
ProgressPlugin,
EntryPlugin,
DynamicEntryPlugin,
ExternalsPlugin,
ExternalsPlugin((ExternalType, Vec<ExternalItem>)),
NodeTargetPlugin,
ElectronTargetPlugin,
ElectronTargetPlugin(rspack_plugin_externals::ElectronTargetContext),
EnableChunkLoadingPlugin(ChunkLoadingType),
EnableLibraryPlugin(LibraryType),
EnableWasmLoadingPlugin(WasmLoadingType),
Expand Down Expand Up @@ -149,7 +151,7 @@ pub(crate) enum BuiltinPluginOptions {

// rspack specific plugins
// naming format follow XxxRspackPlugin
HttpExternalsRspackPlugin,
HttpExternalsRspackPlugin((bool /* css */, bool /* web_async */)),
CopyRspackPlugin,
HtmlRspackPlugin,
SwcJsMinimizerRspackPlugin,
Expand All @@ -168,6 +170,9 @@ pub struct CompilerOptionsBuilder {
name: Option<String>,
target: Option<Target>,
entry: IndexMap<String, EntryDescription>,
externals: Option<Vec<ExternalItem>>,
externals_type: Option<ExternalType>,
externals_presets: Option<ExternalsPresets>,
context: Option<Context>,
cache: Option<CacheOptions>,
mode: Option<Mode>,
Expand Down Expand Up @@ -195,6 +200,24 @@ impl CompilerOptionsBuilder {
self
}

pub fn externals(&mut self, externals: ExternalItem) -> &mut Self {
match &mut self.externals {
Some(e) => e.push(externals),
None => self.externals = Some(vec![externals]),
}
self
}

pub fn externals_type(&mut self, externals_type: ExternalType) -> &mut Self {
self.externals_type = Some(externals_type);
self
}

pub fn externals_presets(&mut self, externals_presets: ExternalsPresets) -> &mut Self {
self.externals_presets = Some(externals_presets);
self
}

pub fn context<V>(&mut self, context: V) -> &mut Self
where
V: Into<Context>,
Expand Down Expand Up @@ -288,6 +311,7 @@ impl CompilerOptionsBuilder {
}
});

// apply experiments defaults
let mut experiments_builder = f!(self.experiments.take(), Experiments::builder);
let mut experiments = experiments_builder.build(builder_context, development, production);
// Disable experiments cache if global cache is set to `Disabled`
Expand Down Expand Up @@ -317,6 +341,7 @@ impl CompilerOptionsBuilder {
.output_module
.expect("should apply default value");

// apply module defaults
let module = f!(self.module.take(), ModuleOptions::builder).build(
builder_context,
async_web_assembly,
Expand All @@ -325,6 +350,7 @@ impl CompilerOptionsBuilder {
&mode,
);

// apply output defaults
let is_affected_by_browserslist = target.iter().any(|t| t.starts_with("browserslist"));
let mut output_builder = f!(self.output.take(), OutputOptions::builder);
let output = output_builder.build(
Expand All @@ -337,6 +363,8 @@ impl CompilerOptionsBuilder {
&self.entry,
future_defaults,
);

// apply devtool plugin
let devtool_flags = DevtoolFlags::from(devtool);
if devtool_flags.source_map() {
let hidden = devtool_flags.hidden();
Expand Down Expand Up @@ -392,6 +420,112 @@ impl CompilerOptionsBuilder {
.push(BuiltinPluginOptions::EvalDevToolModulePlugin(options));
}

// TODO: bundler info

// applyExternalsPresetsDefaults
let externals_presets = self.externals_presets.get_or_insert_default();
let tp = &target_properties;
w!(externals_presets.node, tp.node());
w!(externals_presets.electron, tp.electron());
w!(
externals_presets.electron_main,
tp.electron() && tp.electron_main()
);
w!(
externals_presets.electron_preload,
tp.electron() && tp.electron_preload()
);
w!(
externals_presets.electron_renderer,
tp.electron() && tp.electron_renderer()
);
w!(externals_presets.nwjs, tp.nwjs());

w!(self.externals_type, {
if let Some(library) = &output.library {
library.library_type.clone()
} else if output.module {
"module-import".to_string()
} else {
"var".to_string()
}
});

// apply externals plugin
if let Some(externals) = &mut self.externals {
let externals = std::mem::take(externals);
builder_context
.plugins
.push(BuiltinPluginOptions::ExternalsPlugin((
self
.externals_type
.clone()
.expect("should available after apply"),
externals,
)));
}

// apply externals presets plugin
if externals_presets.node() {
builder_context
.plugins
.push(BuiltinPluginOptions::NodeTargetPlugin);
}

use rspack_plugin_externals::ElectronTargetContext;

if externals_presets.electron_main() {
builder_context
.plugins
.push(BuiltinPluginOptions::ElectronTargetPlugin(
ElectronTargetContext::Main,
));
}
if externals_presets.electron_preload() {
builder_context
.plugins
.push(BuiltinPluginOptions::ElectronTargetPlugin(
ElectronTargetContext::Preload,
));
}
if externals_presets.electron_renderer() {
builder_context
.plugins
.push(BuiltinPluginOptions::ElectronTargetPlugin(
ElectronTargetContext::Renderer,
));
}
if externals_presets.electron()
&& !externals_presets.electron_main()
&& !externals_presets.electron_preload()
&& !externals_presets.electron_renderer()
{
builder_context
.plugins
.push(BuiltinPluginOptions::ElectronTargetPlugin(
ElectronTargetContext::None,
));
}

if externals_presets.nwjs() {
builder_context
.plugins
.push(BuiltinPluginOptions::ExternalsPlugin((
"node-commonjs".to_string(),
vec!["nw.gui".to_string().into()],
)));
}

if externals_presets.web() || externals_presets.web_async() || (externals_presets.node() && css)
{
builder_context
.plugins
.push(BuiltinPluginOptions::HttpExternalsRspackPlugin((
css,
externals_presets.web_async(),
)));
}

CompilerOptions {
name,
context,
Expand Down
60 changes: 60 additions & 0 deletions crates/rspack/src/options/externals.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
#[derive(Debug, Default)]
pub struct ExternalsPresets {
/// Treat node.js built-in modules like `fs`, `path` or `vm` as external and load them via `require()` when used.
pub(crate) node: Option<bool>,

/// Treat references to `http(s)://...` and `std:...` as external and load them via import when used.
pub(crate) web: Option<bool>,

/// Treat references to `http(s)://...` and `std:...` as external and load them via async import() when used
pub(crate) web_async: Option<bool>,

/// Treat common electron built-in modules in main and preload context like `electron`, `ipc` or `shell` as external and load them via `require()` when used.
pub(crate) electron: Option<bool>,

/// Treat electron built-in modules in the main context like `app`, `ipc-main` or `shell` as external and load them via `require()` when used.
pub(crate) electron_main: Option<bool>,

/// Treat electron built-in modules in the preload context like `web-frame`, `ipc-renderer` or `shell` as external and load them via require() when used.
pub(crate) electron_preload: Option<bool>,

/// Treat electron built-in modules in the preload context like `web-frame`, `ipc-renderer` or `shell` as external and load them via require() when used.
pub(crate) electron_renderer: Option<bool>,

/// Treat `NW.js` legacy `nw.gui` module as external and load it via `require()` when used.
pub(crate) nwjs: Option<bool>,
}

impl ExternalsPresets {
pub fn node(&self) -> bool {
self.node.unwrap_or(false)
}

pub fn web(&self) -> bool {
self.web.unwrap_or(false)
}

pub fn web_async(&self) -> bool {
self.web_async.unwrap_or(false)
}

pub fn electron(&self) -> bool {
self.electron.unwrap_or(false)
}

pub fn electron_main(&self) -> bool {
self.electron_main.unwrap_or(false)
}

pub fn electron_preload(&self) -> bool {
self.electron_preload.unwrap_or(false)
}

pub fn electron_renderer(&self) -> bool {
self.electron_renderer.unwrap_or(false)
}

pub fn nwjs(&self) -> bool {
self.nwjs.unwrap_or(false)
}
}
1 change: 1 addition & 0 deletions crates/rspack/src/options/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
mod builder;
mod devtool;
mod externals;
mod target;

pub use builder::{
Expand Down

2 comments on commit 9da4fc8

@github-actions
Copy link
Contributor

@github-actions github-actions bot commented on 9da4fc8 Jan 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 Ecosystem CI detail: Open

suite result
modernjs ❌ failure
rspress ✅ success
rslib ✅ success
rsbuild ✅ success
rsdoctor ✅ success
examples ✅ success
devserver ✅ success
nuxt ✅ success

@github-actions
Copy link
Contributor

@github-actions github-actions bot commented on 9da4fc8 Jan 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 Benchmark detail: Open

Name Base (2025-01-08 0dbc9ac) Current Change
10000_big_production-mode_disable-minimize + exec 37.8 s ± 463 ms 38.5 s ± 424 ms +1.90 %
10000_development-mode + exec 1.86 s ± 18 ms 1.86 s ± 35 ms -0.01 %
10000_development-mode_hmr + exec 675 ms ± 5.4 ms 675 ms ± 7 ms +0.03 %
10000_production-mode + exec 2.5 s ± 38 ms 2.43 s ± 36 ms -2.97 %
arco-pro_development-mode + exec 1.78 s ± 148 ms 1.74 s ± 100 ms -2.20 %
arco-pro_development-mode_hmr + exec 376 ms ± 0.77 ms 377 ms ± 2.9 ms +0.26 %
arco-pro_production-mode + exec 3.63 s ± 72 ms 3.51 s ± 85 ms -3.37 %
arco-pro_production-mode_generate-package-json-webpack-plugin + exec 3.65 s ± 113 ms 3.56 s ± 85 ms -2.33 %
arco-pro_production-mode_traverse-chunk-modules + exec 3.6 s ± 53 ms 3.56 s ± 91 ms -1.12 %
large-dyn-imports_development-mode + exec 2.08 s ± 16 ms 2.08 s ± 28 ms -0.03 %
large-dyn-imports_production-mode + exec 2.11 s ± 41 ms 2.08 s ± 27 ms -1.53 %
threejs_development-mode_10x + exec 1.5 s ± 20 ms 1.51 s ± 38 ms +1.00 %
threejs_development-mode_10x_hmr + exec 779 ms ± 27 ms 788 ms ± 18 ms +1.19 %
threejs_production-mode_10x + exec 5.32 s ± 29 ms 5.38 s ± 135 ms +1.11 %
10000_big_production-mode_disable-minimize + rss memory 9502 MiB ± 255 MiB 9551 MiB ± 121 MiB +0.51 %
10000_development-mode + rss memory 642 MiB ± 7.83 MiB 711 MiB ± 30.2 MiB +10.62 %
10000_development-mode_hmr + rss memory 1398 MiB ± 340 MiB 1501 MiB ± 302 MiB +7.35 %
10000_production-mode + rss memory 626 MiB ± 26.9 MiB 701 MiB ± 44.1 MiB +11.99 %
arco-pro_development-mode + rss memory 586 MiB ± 36.2 MiB 615 MiB ± 28.7 MiB +5.04 %
arco-pro_development-mode_hmr + rss memory 617 MiB ± 18.3 MiB 665 MiB ± 22.3 MiB +7.75 %
arco-pro_production-mode + rss memory 735 MiB ± 36.7 MiB 761 MiB ± 39.5 MiB +3.56 %
arco-pro_production-mode_generate-package-json-webpack-plugin + rss memory 751 MiB ± 86.5 MiB 782 MiB ± 27.7 MiB +4.06 %
arco-pro_production-mode_traverse-chunk-modules + rss memory 738 MiB ± 41.8 MiB 789 MiB ± 49.4 MiB +6.99 %
large-dyn-imports_development-mode + rss memory 666 MiB ± 12.4 MiB 679 MiB ± 4.55 MiB +1.86 %
large-dyn-imports_production-mode + rss memory 559 MiB ± 9 MiB 579 MiB ± 5.14 MiB +3.69 %
threejs_development-mode_10x + rss memory 637 MiB ± 33.9 MiB 679 MiB ± 51.2 MiB +6.51 %
threejs_development-mode_10x_hmr + rss memory 1103 MiB ± 187 MiB 1119 MiB ± 192 MiB +1.44 %
threejs_production-mode_10x + rss memory 918 MiB ± 47 MiB 928 MiB ± 70 MiB +1.15 %

Please sign in to comment.