Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support function type for splitChunks.{cacheGroup}.{test, name} #4722

Merged
merged 1 commit into from
Nov 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ node_modules/
!webpack-examples/*/node_modules
!webpack-test/*/**/node_modules
!packages/rspack-cli/tests/**/node_modules
!packages/rspack/tests/**/node_modules
jspm_packages/

# Snowpack dependency directory (https://snowpack.dev/)
Expand Down
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.

15 changes: 12 additions & 3 deletions crates/node_binding/binding.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,7 @@ export interface JsModule {
originalSource?: JsCompatSource
resource?: string
moduleIdentifier: string
nameForCondition?: string
}

export interface JsResolveForSchemeInput {
Expand Down Expand Up @@ -554,7 +555,7 @@ export interface RawBuiltins {
export interface RawCacheGroupOptions {
key: string
priority?: number
test?: RegExp | string
test?: RegExp | string | Function
idHint?: string
/** What kind of chunks should be selected. */
chunks?: RegExp | 'async' | 'initial' | 'all'
Expand All @@ -564,11 +565,15 @@ export interface RawCacheGroupOptions {
maxSize?: number
maxAsyncSize?: number
maxInitialSize?: number
name?: string
name?: string | false | Function
reuseExistingChunk?: boolean
enforce?: boolean
}

export interface RawCacheGroupTestCtx {
module: JsModule
}

export interface RawCacheOptions {
type: string
maxGenerations: number
Expand All @@ -581,6 +586,10 @@ export interface RawCacheOptions {
version: string
}

export interface RawChunkOptionNameCtx {
module: JsModule
}

export interface RawCopyGlobOptions {
caseSensitiveMatch?: boolean
dot?: boolean
Expand Down Expand Up @@ -1030,7 +1039,7 @@ export interface RawSnapshotStrategy {

export interface RawSplitChunksOptions {
fallbackCacheGroup?: RawFallbackCacheGroupOptions
name?: string
name?: string | false | Function
cacheGroups?: Array<RawCacheGroupOptions>
/** What kind of chunks should be selected. */
chunks?: RegExp | 'async' | 'initial' | 'all'
Expand Down
15 changes: 5 additions & 10 deletions crates/rspack_binding_options/src/options/raw_external.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,15 @@
use std::collections::HashMap;
use std::fmt::Debug;
use std::sync::Arc;

use napi::bindgen_prelude::Either4;
use napi::JsFunction;
use napi::{Env, JsFunction};
use napi_derive::napi;
use rspack_core::ExternalItemFnCtx;
use rspack_core::{ExternalItem, ExternalItemFnResult, ExternalItemValue};
use rspack_napi_shared::{JsRegExp, JsRegExpExt};
use {
napi::Env,
rspack_error::internal_error,
rspack_napi_shared::threadsafe_function::{ThreadsafeFunction, ThreadsafeFunctionCallMode},
rspack_napi_shared::NapiResultExt,
rspack_napi_shared::NAPI_ENV,
std::sync::Arc,
};
use rspack_error::internal_error;
use rspack_napi_shared::threadsafe_function::{ThreadsafeFunction, ThreadsafeFunctionCallMode};
use rspack_napi_shared::{JsRegExp, JsRegExpExt, NapiResultExt, NAPI_ENV};

#[napi(object)]
pub struct RawHttpExternalsRspackPluginOptions {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,23 @@
mod raw_split_chunk_cache_group_test;
mod raw_split_chunk_name;

use std::sync::Arc;

use derivative::Derivative;
use napi::{Either, JsString};
use napi_derive::napi;
use new_split_chunks_plugin::ModuleTypeFilter;
use raw_split_chunk_name::normalize_raw_chunk_name;
use raw_split_chunk_name::RawChunkOptionName;
use rspack_core::SourceType;
use rspack_napi_shared::{JsRegExp, JsRegExpExt, JsStringExt};
use rspack_plugin_split_chunks::{CacheGroupOptions, ChunkType, SplitChunksOptions, TestFn};
use rspack_plugin_split_chunks_new::ChunkNameGetter;
use serde::Deserialize;

use self::raw_split_chunk_cache_group_test::default_cache_group_test;
use self::raw_split_chunk_cache_group_test::normalize_raw_cache_group_test;
use self::raw_split_chunk_cache_group_test::RawCacheGroupTest;
use self::raw_split_chunk_name::default_chunk_option_name;

type Chunks = Either<JsRegExp, JsString>;

#[derive(Derivative, Deserialize)]
Expand All @@ -17,7 +26,10 @@ type Chunks = Either<JsRegExp, JsString>;
#[derivative(Debug)]
pub struct RawSplitChunksOptions {
pub fallback_cache_group: Option<RawFallbackCacheGroupOptions>,
pub name: Option<String>,
#[serde(skip_deserializing)]
#[napi(ts_type = "string | false | Function")]
#[derivative(Debug = "ignore")]
pub name: Option<RawChunkOptionName>,
pub cache_groups: Option<Vec<RawCacheGroupOptions>>,
/// What kind of chunks should be selected.
#[serde(skip_deserializing)]
Expand All @@ -40,8 +52,10 @@ pub struct RawSplitChunksOptions {
pub max_initial_size: Option<f64>,
}

impl From<RawSplitChunksOptions> for SplitChunksOptions {
impl From<RawSplitChunksOptions> for rspack_plugin_split_chunks::SplitChunksOptions {
fn from(value: RawSplitChunksOptions) -> Self {
use rspack_plugin_split_chunks::{CacheGroupOptions, ChunkType, SplitChunksOptions, TestFn};

let mut defaults = SplitChunksOptions {
max_async_requests: value.max_async_requests,
max_initial_requests: value.max_initial_requests,
Expand Down Expand Up @@ -70,22 +84,13 @@ impl From<RawSplitChunksOptions> for SplitChunksOptions {
(
v.key,
CacheGroupOptions {
name: v.name,
// FIXME: since old split chunk will not used so I use `None` here
name: None,
priority: v.priority,
reuse_existing_chunk: Some(false),
test: v.test.map(|test| {
let test = match test {
Either::A(s) => s.into_string(),
Either::B(_reg) => unimplemented!(),
};
let f: TestFn = Arc::new(move |module| {
let re = rspack_regex::RspackRegex::new(&test)
.unwrap_or_else(|_| panic!("Invalid regex: {}", &test));
module
.name_for_condition()
.map_or(false, |name| re.test(&name))
});
f
test: v.test.map(|_| {
let f: TestFn = Arc::new(move |_| false);
f // FIXME: since old split chunk will not used so I use `|| -> false` here
}),
chunks: v.chunks.map(|chunks| {
let Either::B(chunks) = chunks else {
Expand Down Expand Up @@ -118,9 +123,9 @@ pub struct RawCacheGroupOptions {
// pub reuse_existing_chunk: Option<bool>,
// pub r#type: SizeType,
#[serde(skip_deserializing)]
#[napi(ts_type = "RegExp | string")]
#[napi(ts_type = "RegExp | string | Function")]
#[derivative(Debug = "ignore")]
pub test: Option<Either<JsString, JsRegExp>>,
pub test: Option<RawCacheGroupTest>,
// pub filename: String,
// pub enforce: bool,
pub id_hint: Option<String>,
Expand All @@ -146,14 +151,15 @@ pub struct RawCacheGroupOptions {
pub max_size: Option<f64>,
pub max_async_size: Option<f64>,
pub max_initial_size: Option<f64>,
pub name: Option<String>,
#[serde(skip_deserializing)]
#[napi(ts_type = "string | false | Function")]
#[derivative(Debug = "ignore")]
pub name: Option<RawChunkOptionName>,
// used_exports: bool,
pub reuse_existing_chunk: Option<bool>,
pub enforce: Option<bool>,
}

use rspack_plugin_split_chunks_new as new_split_chunks_plugin;

fn create_chunks_filter(raw: Chunks) -> rspack_plugin_split_chunks_new::ChunkFilter {
match raw {
Either::A(reg) => {
Expand All @@ -166,20 +172,19 @@ fn create_chunks_filter(raw: Chunks) -> rspack_plugin_split_chunks_new::ChunkFil
}
}

impl From<RawSplitChunksOptions> for new_split_chunks_plugin::PluginOptions {
impl From<RawSplitChunksOptions> for rspack_plugin_split_chunks_new::PluginOptions {
fn from(raw_opts: RawSplitChunksOptions) -> Self {
use new_split_chunks_plugin::SplitChunkSizes;
use rspack_plugin_split_chunks_new::SplitChunkSizes;

let mut cache_groups = vec![];

let overall_chunk_filter = raw_opts.chunks.map(create_chunks_filter);

let overall_min_chunks = raw_opts.min_chunks.unwrap_or(1);

let overall_name_getter = raw_opts
.name
.map(new_split_chunks_plugin::create_chunk_name_getter_by_const_name)
.unwrap_or_else(new_split_chunks_plugin::create_empty_chunk_name_getter);
let overall_name_getter = raw_opts.name.map_or(default_chunk_option_name(), |name| {
normalize_raw_chunk_name(name)
});

let default_size_types = [SourceType::JavaScript, SourceType::Unknown];

Expand Down Expand Up @@ -240,15 +245,20 @@ impl From<RawSplitChunksOptions> for new_split_chunks_plugin::PluginOptions {
.map(create_module_type_filter)
.unwrap_or_else(rspack_plugin_split_chunks_new::create_default_module_type_filter);

new_split_chunks_plugin::CacheGroup {
let mut name = v.name.map_or(default_chunk_option_name(), |name| {
normalize_raw_chunk_name(name)
});
if matches!(name, ChunkNameGetter::Disabled) {
name = overall_name_getter.clone();
}
rspack_plugin_split_chunks_new::CacheGroup {
id_hint: v.id_hint.unwrap_or_else(|| v.key.clone()),
key: v.key,
name: v
.name
.map(new_split_chunks_plugin::create_chunk_name_getter_by_const_name)
.unwrap_or_else(|| overall_name_getter.clone()),
name,
priority: v.priority.unwrap_or(0) as f64,
test: create_module_filter(v.test),
test: v.test.map_or(default_cache_group_test(), |test| {
normalize_raw_cache_group_test(test)
}),
chunk_filter: v.chunks.map(create_chunks_filter).unwrap_or_else(|| {
overall_chunk_filter
.clone()
Expand Down Expand Up @@ -287,7 +297,7 @@ impl From<RawSplitChunksOptions> for new_split_chunks_plugin::PluginOptions {
.merge(&overall_max_initial_size)
.merge(&overall_max_size);

new_split_chunks_plugin::PluginOptions {
rspack_plugin_split_chunks_new::PluginOptions {
cache_groups,
fallback_cache_group: rspack_plugin_split_chunks_new::FallbackCacheGroup {
chunks_filter: fallback_chunks_filter.unwrap_or_else(|| {
Expand Down Expand Up @@ -318,7 +328,9 @@ pub struct RawFallbackCacheGroupOptions {
pub max_initial_size: Option<f64>,
}

fn create_module_type_filter(raw: Either<JsRegExp, JsString>) -> ModuleTypeFilter {
fn create_module_type_filter(
raw: Either<JsRegExp, JsString>,
) -> rspack_plugin_split_chunks_new::ModuleTypeFilter {
match raw {
Either::A(js_reg) => {
let regex = js_reg.to_rspack_regex();
Expand All @@ -330,19 +342,3 @@ fn create_module_type_filter(raw: Either<JsRegExp, JsString>) -> ModuleTypeFilte
}
}
}

pub fn create_module_filter(
re: Option<Either<JsString, JsRegExp>>,
) -> new_split_chunks_plugin::ModuleFilter {
re.map(|test| match test {
Either::A(data) => {
let data = data.into_string();
rspack_plugin_split_chunks_new::create_module_filter_from_rspack_str(data)
}
Either::B(data) => {
let re = data.to_rspack_regex();
rspack_plugin_split_chunks_new::create_module_filter_from_rspack_regex(re)
}
})
.unwrap_or_else(rspack_plugin_split_chunks_new::create_default_module_filter)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
use std::sync::Arc;

use napi::bindgen_prelude::Either3;
use napi::{Env, JsFunction};
use napi_derive::napi;
use rspack_binding_values::{JsModule, ToJsModule};
use rspack_error::internal_error;
use rspack_napi_shared::threadsafe_function::{ThreadsafeFunction, ThreadsafeFunctionCallMode};
use rspack_napi_shared::{JsRegExp, JsRegExpExt, NapiResultExt, NAPI_ENV};
use rspack_plugin_split_chunks_new::{CacheGroupTest, CacheGroupTestFnCtx};

pub(super) type RawCacheGroupTest = Either3<String, JsRegExp, JsFunction>;

#[napi(object)]
struct RawCacheGroupTestCtx {
pub module: JsModule,
}

impl<'a> From<CacheGroupTestFnCtx<'a>> for RawCacheGroupTestCtx {
fn from(value: CacheGroupTestFnCtx<'a>) -> Self {
RawCacheGroupTestCtx {
module: value
.module
.to_js_module()
.expect("should convert js module success"),
}
}
}

pub(super) fn normalize_raw_cache_group_test(raw: RawCacheGroupTest) -> CacheGroupTest {
match raw {
Either3::A(str) => CacheGroupTest::String(str),
Either3::B(regexp) => CacheGroupTest::RegExp(regexp.to_rspack_regex()),
Either3::C(v) => {
let fn_payload: ThreadsafeFunction<RawCacheGroupTestCtx, Option<bool>> = NAPI_ENV
.with(|env| -> anyhow::Result<_> {
let env = env.borrow().expect("Failed to get env with external");
let fn_payload = rspack_binding_macros::js_fn_into_threadsafe_fn!(v, &Env::from(env));
Ok(fn_payload)
})
.expect("should generate fn_payload success");
let fn_payload = Arc::new(fn_payload);
CacheGroupTest::Fn(Arc::new(move |ctx| {
let fn_payload = fn_payload.clone();
Box::pin(async move {
fn_payload
.call(ctx.into(), ThreadsafeFunctionCallMode::NonBlocking)
.into_rspack_result()
.expect("into rspack result failed")
.await
.unwrap_or_else(|err| {
panic!(
"{}",
internal_error!("Failed to call external function: {err}")
)
})
.expect("failed")
})
}))
}
}
}

#[inline]
pub(super) fn default_cache_group_test() -> CacheGroupTest {
CacheGroupTest::Enabled
}
Loading
Loading