Skip to content

Commit 1ceac70

Browse files
authored
feat(parser): add commonjs options (#11744)
* feat(parser): add `suppressCommonjsExports` options * prefer common
1 parent e4d62c4 commit 1ceac70

File tree

28 files changed

+502
-216
lines changed

28 files changed

+502
-216
lines changed

crates/node_binding/napi-binding.d.ts

Lines changed: 30 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2285,6 +2285,14 @@ export interface RawIntegrityItem {
22852285
integrity: string
22862286
}
22872287

2288+
export declare enum RawJavascriptParserCommonjsExports {
2289+
SkipInEsm = 'skipInEsm'
2290+
}
2291+
2292+
export interface RawJavascriptParserCommonjsOptions {
2293+
exports?: boolean | 'skipInEsm'
2294+
}
2295+
22882296
export interface RawJavascriptParserOptions {
22892297
dynamicImportMode?: string
22902298
dynamicImportPreload?: string
@@ -2317,27 +2325,28 @@ export interface RawJavascriptParserOptions {
23172325
* @experimental
23182326
*/
23192327
requireResolve?: boolean
2320-
/**
2321-
* This option is experimental in Rspack only and subject to change or be removed anytime.
2322-
* @experimental
2323-
*/
2324-
importDynamic?: boolean
2325-
commonjsMagicComments?: boolean
2326-
/**
2327-
* This option is experimental in Rspack only and subject to change or be removed anytime.
2328-
* @experimental
2329-
*/
2330-
inlineConst?: boolean
2331-
/**
2332-
* This option is experimental in Rspack only and subject to change or be removed anytime.
2333-
* @experimental
2334-
*/
2335-
typeReexportsPresence?: string
2336-
/**
2337-
* This option is experimental in Rspack only and subject to change or be removed anytime.
2338-
* @experimental
2339-
*/
2340-
jsx?: boolean
2328+
commonjs?: boolean | { exports?: boolean | 'skipInEsm' }
2329+
/**
2330+
* This option is experimental in Rspack only and subject to change or be removed anytime.
2331+
* @experimental
2332+
*/
2333+
importDynamic?: boolean
2334+
commonjsMagicComments?: boolean
2335+
/**
2336+
* This option is experimental in Rspack only and subject to change or be removed anytime.
2337+
* @experimental
2338+
*/
2339+
inlineConst?: boolean
2340+
/**
2341+
* This option is experimental in Rspack only and subject to change or be removed anytime.
2342+
* @experimental
2343+
*/
2344+
typeReexportsPresence?: string
2345+
/**
2346+
* This option is experimental in Rspack only and subject to change or be removed anytime.
2347+
* @experimental
2348+
*/
2349+
jsx?: boolean
23412350
}
23422351

23432352
export interface RawJsonGeneratorOptions {

crates/node_binding/rspack.wasi-browser.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ export const JsRspackSeverity = __napiModule.exports.JsRspackSeverity
115115
export const loadBrowserslist = __napiModule.exports.loadBrowserslist
116116
export const minify = __napiModule.exports.minify
117117
export const minifySync = __napiModule.exports.minifySync
118+
export const RawJavascriptParserCommonjsExports = __napiModule.exports.RawJavascriptParserCommonjsExports
118119
export const RawRuleSetConditionType = __napiModule.exports.RawRuleSetConditionType
119120
export const registerGlobalTrace = __napiModule.exports.registerGlobalTrace
120121
export const RegisterJsTapKind = __napiModule.exports.RegisterJsTapKind

crates/node_binding/rspack.wasi.cjs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,7 @@ module.exports.JsRspackSeverity = __napiModule.exports.JsRspackSeverity
160160
module.exports.loadBrowserslist = __napiModule.exports.loadBrowserslist
161161
module.exports.minify = __napiModule.exports.minify
162162
module.exports.minifySync = __napiModule.exports.minifySync
163+
module.exports.RawJavascriptParserCommonjsExports = __napiModule.exports.RawJavascriptParserCommonjsExports
163164
module.exports.RawRuleSetConditionType = __napiModule.exports.RawRuleSetConditionType
164165
module.exports.registerGlobalTrace = __napiModule.exports.registerGlobalTrace
165166
module.exports.RegisterJsTapKind = __napiModule.exports.RegisterJsTapKind

crates/rspack/src/builder/mod.rs

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -42,13 +42,14 @@ use rspack_core::{
4242
CssGeneratorOptions, CssModuleGeneratorOptions, CssModuleParserOptions, CssParserOptions,
4343
DynamicImportMode, EntryDescription, EntryOptions, EntryRuntime, Environment,
4444
ExperimentCacheOptions, Experiments, ExternalItem, ExternalType, Filename, GeneratorOptions,
45-
GeneratorOptionsMap, JavascriptParserOptions, JavascriptParserOrder, JavascriptParserUrl,
46-
JsonGeneratorOptions, JsonParserOptions, LibraryName, LibraryNonUmdObject, LibraryOptions,
47-
LibraryType, MangleExportsOption, Mode, ModuleNoParseRules, ModuleOptions, ModuleRule,
48-
ModuleRuleEffect, ModuleType, NodeDirnameOption, NodeFilenameOption, NodeGlobalOption,
49-
NodeOption, Optimization, OutputOptions, ParseOption, ParserOptions, ParserOptionsMap, PathInfo,
50-
PublicPath, Resolve, RspackFuture, RuleSetCondition, RuleSetLogicalConditions, SideEffectOption,
51-
StatsOptions, TrustedTypes, UsedExportsOption, WasmLoading, WasmLoadingType,
45+
GeneratorOptionsMap, JavascriptParserCommonjsExportsOption, JavascriptParserCommonjsOptions,
46+
JavascriptParserOptions, JavascriptParserOrder, JavascriptParserUrl, JsonGeneratorOptions,
47+
JsonParserOptions, LibraryName, LibraryNonUmdObject, LibraryOptions, LibraryType,
48+
MangleExportsOption, Mode, ModuleNoParseRules, ModuleOptions, ModuleRule, ModuleRuleEffect,
49+
ModuleType, NodeDirnameOption, NodeFilenameOption, NodeGlobalOption, NodeOption, Optimization,
50+
OutputOptions, ParseOption, ParserOptions, ParserOptionsMap, PathInfo, PublicPath, Resolve,
51+
RspackFuture, RuleSetCondition, RuleSetLogicalConditions, SideEffectOption, StatsOptions,
52+
TrustedTypes, UsedExportsOption, WasmLoading, WasmLoadingType,
5253
incremental::{IncrementalOptions, IncrementalPasses},
5354
};
5455
use rspack_error::{Error, Result};
@@ -1713,6 +1714,9 @@ impl ModuleOptionsBuilder {
17131714
require_as_expression: Some(true),
17141715
require_dynamic: Some(true),
17151716
require_resolve: Some(true),
1717+
commonjs: Some(JavascriptParserCommonjsOptions {
1718+
exports: JavascriptParserCommonjsExportsOption::Enable,
1719+
}),
17161720
import_dynamic: Some(true),
17171721
commonjs_magic_comments: Some(false),
17181722
inline_const: Some(false),

crates/rspack/tests/snapshots/defaults__default_options.snap

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1435,6 +1435,11 @@ CompilerOptions {
14351435
require_resolve: Some(
14361436
true,
14371437
),
1438+
commonjs: Some(
1439+
JavascriptParserCommonjsOptions {
1440+
exports: Enable,
1441+
},
1442+
),
14381443
import_dynamic: Some(
14391444
true,
14401445
),

crates/rspack_binding_api/src/raw_options/raw_module/mod.rs

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,11 @@ use rspack_core::{
1313
CssAutoGeneratorOptions, CssAutoParserOptions, CssGeneratorOptions, CssModuleGeneratorOptions,
1414
CssModuleParserOptions, CssParserOptions, DescriptionData, DynamicImportFetchPriority,
1515
DynamicImportMode, ExportPresenceMode, FuncUseCtx, GeneratorOptions, GeneratorOptionsMap,
16-
JavascriptParserOptions, JavascriptParserOrder, JavascriptParserUrl, JsonGeneratorOptions,
17-
JsonParserOptions, ModuleNoParseRule, ModuleNoParseRules, ModuleNoParseTestFn, ModuleOptions,
18-
ModuleRule, ModuleRuleEffect, ModuleRuleEnforce, ModuleRuleUse, ModuleRuleUseLoader,
19-
OverrideStrict, ParseOption, ParserOptions, ParserOptionsMap, TypeReexportPresenceMode,
16+
JavascriptParserCommonjsExportsOption, JavascriptParserCommonjsOptions, JavascriptParserOptions,
17+
JavascriptParserOrder, JavascriptParserUrl, JsonGeneratorOptions, JsonParserOptions,
18+
ModuleNoParseRule, ModuleNoParseRules, ModuleNoParseTestFn, ModuleOptions, ModuleRule,
19+
ModuleRuleEffect, ModuleRuleEnforce, ModuleRuleUse, ModuleRuleUseLoader, OverrideStrict,
20+
ParseOption, ParserOptions, ParserOptionsMap, TypeReexportPresenceMode,
2021
};
2122
use rspack_error::error;
2223
use rspack_napi::threadsafe_function::ThreadsafeFunction;
@@ -288,6 +289,8 @@ pub struct RawJavascriptParserOptions {
288289
/// This option is experimental in Rspack only and subject to change or be removed anytime.
289290
/// @experimental
290291
pub require_resolve: Option<bool>,
292+
#[napi(ts_type = "boolean | { exports?: boolean | 'skipInEsm' }")]
293+
pub commonjs: Option<Either<bool, RawJavascriptParserCommonjsOptions>>,
291294
/// This option is experimental in Rspack only and subject to change or be removed anytime.
292295
/// @experimental
293296
pub import_dynamic: Option<bool>,
@@ -303,6 +306,20 @@ pub struct RawJavascriptParserOptions {
303306
pub jsx: Option<bool>,
304307
}
305308

309+
#[napi(object)]
310+
#[derive(Debug)]
311+
pub struct RawJavascriptParserCommonjsOptions {
312+
#[napi(ts_type = "boolean | 'skipInEsm'")]
313+
pub exports: Option<Either<bool, RawJavascriptParserCommonjsExports>>,
314+
}
315+
316+
#[napi(string_enum)]
317+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
318+
pub enum RawJavascriptParserCommonjsExports {
319+
#[napi(value = "skipInEsm")]
320+
SkipInEsm,
321+
}
322+
306323
impl From<RawJavascriptParserOptions> for JavascriptParserOptions {
307324
fn from(value: RawJavascriptParserOptions) -> Self {
308325
Self {
@@ -344,6 +361,23 @@ impl From<RawJavascriptParserOptions> for JavascriptParserOptions {
344361
require_as_expression: value.require_as_expression,
345362
require_dynamic: value.require_dynamic,
346363
require_resolve: value.require_resolve,
364+
commonjs: value.commonjs.map(|commonjs| match commonjs {
365+
Either::A(flag) => JavascriptParserCommonjsOptions {
366+
exports: JavascriptParserCommonjsExportsOption::from(flag),
367+
},
368+
Either::B(options) => {
369+
let exports = options
370+
.exports
371+
.map(|exports| match exports {
372+
Either::A(flag) => JavascriptParserCommonjsExportsOption::from(flag),
373+
Either::B(RawJavascriptParserCommonjsExports::SkipInEsm) => {
374+
JavascriptParserCommonjsExportsOption::SkipInEsm
375+
}
376+
})
377+
.unwrap_or(JavascriptParserCommonjsExportsOption::Enable);
378+
JavascriptParserCommonjsOptions { exports }
379+
}
380+
}),
347381
import_dynamic: value.import_dynamic,
348382
commonjs_magic_comments: value.commonjs_magic_comments,
349383
inline_const: value.inline_const,

crates/rspack_core/src/options/module.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,26 @@ impl From<&str> for JavascriptParserOrder {
191191
}
192192
}
193193

194+
#[cacheable]
195+
#[derive(Debug, Clone, Copy, MergeFrom, PartialEq, Eq)]
196+
pub enum JavascriptParserCommonjsExportsOption {
197+
Enable,
198+
Disable,
199+
SkipInEsm,
200+
}
201+
202+
impl From<bool> for JavascriptParserCommonjsExportsOption {
203+
fn from(value: bool) -> Self {
204+
if value { Self::Enable } else { Self::Disable }
205+
}
206+
}
207+
208+
#[cacheable]
209+
#[derive(Debug, Clone, MergeFrom)]
210+
pub struct JavascriptParserCommonjsOptions {
211+
pub exports: JavascriptParserCommonjsExportsOption,
212+
}
213+
194214
#[cacheable]
195215
#[derive(Debug, Clone, Copy, MergeFrom)]
196216
pub enum ExportPresenceMode {
@@ -281,6 +301,7 @@ pub struct JavascriptParserOptions {
281301
pub require_as_expression: Option<bool>,
282302
pub require_dynamic: Option<bool>,
283303
pub require_resolve: Option<bool>,
304+
pub commonjs: Option<JavascriptParserCommonjsOptions>,
284305
pub import_dynamic: Option<bool>,
285306
pub commonjs_magic_comments: Option<bool>,
286307
pub inline_const: Option<bool>,

crates/rspack_plugin_javascript/src/parser_plugin/common_js_exports_parse_plugin.rs

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,19 @@ fn handle_access_export(
256256
Some(true)
257257
}
258258

259-
pub struct CommonJsExportsParserPlugin;
259+
pub struct CommonJsExportsParserPlugin {
260+
skip_in_esm: bool,
261+
}
262+
263+
impl CommonJsExportsParserPlugin {
264+
pub fn new(skip_in_esm: bool) -> Self {
265+
Self { skip_in_esm }
266+
}
267+
268+
fn should_skip_handler(&self, parser: &JavascriptParser) -> bool {
269+
self.skip_in_esm && parser.is_esm
270+
}
271+
}
260272

261273
impl JavascriptParserPlugin for CommonJsExportsParserPlugin {
262274
fn assign_member_chain(
@@ -266,6 +278,10 @@ impl JavascriptParserPlugin for CommonJsExportsParserPlugin {
266278
remaining: &[Atom],
267279
for_name: &str,
268280
) -> Option<bool> {
281+
if self.should_skip_handler(parser) {
282+
return None;
283+
}
284+
269285
if for_name == "exports" {
270286
// exports.x = y;
271287
return handle_assign_export(parser, assign_expr, remaining, ExportsBase::Exports);
@@ -292,6 +308,10 @@ impl JavascriptParserPlugin for CommonJsExportsParserPlugin {
292308
call_expr: &CallExpr,
293309
for_name: &str,
294310
) -> Option<bool> {
311+
if self.should_skip_handler(parser) {
312+
return None;
313+
}
314+
295315
if parser.is_esm {
296316
return None;
297317
}
@@ -352,6 +372,10 @@ impl JavascriptParserPlugin for CommonJsExportsParserPlugin {
352372
ident: &Ident,
353373
for_name: &str,
354374
) -> Option<bool> {
375+
if self.should_skip_handler(parser) {
376+
return None;
377+
}
378+
355379
if for_name == "module" {
356380
let decorator = if parser.is_esm {
357381
RuntimeGlobals::ESM_MODULE_DECORATOR
@@ -379,6 +403,10 @@ impl JavascriptParserPlugin for CommonJsExportsParserPlugin {
379403
parser: &mut JavascriptParser,
380404
expr: &swc_core::ecma::ast::ThisExpr,
381405
) -> Option<bool> {
406+
if self.should_skip_handler(parser) {
407+
return None;
408+
}
409+
382410
if parser.is_top_level_this() {
383411
// this
384412
return handle_access_export(parser, expr.span(), &[], ExportsBase::This, None);
@@ -392,6 +420,10 @@ impl JavascriptParserPlugin for CommonJsExportsParserPlugin {
392420
expr: &MemberExpr,
393421
for_name: &str,
394422
) -> Option<bool> {
423+
if self.should_skip_handler(parser) {
424+
return None;
425+
}
426+
395427
if for_name == "module.exports" {
396428
// module.exports
397429
return handle_access_export(parser, expr.span(), &[], ExportsBase::ModuleExports, None);
@@ -408,6 +440,10 @@ impl JavascriptParserPlugin for CommonJsExportsParserPlugin {
408440
_members_optionals: &[bool],
409441
_member_ranges: &[Span],
410442
) -> Option<bool> {
443+
if self.should_skip_handler(parser) {
444+
return None;
445+
}
446+
411447
if for_name == "exports" {
412448
// exports.a.b.c
413449
return handle_access_export(parser, expr.span(), members, ExportsBase::Exports, None);
@@ -441,6 +477,10 @@ impl JavascriptParserPlugin for CommonJsExportsParserPlugin {
441477
_members_optionals: &[bool],
442478
_member_ranges: &[Span],
443479
) -> Option<bool> {
480+
if self.should_skip_handler(parser) {
481+
return None;
482+
}
483+
444484
if for_name == "exports" {
445485
// exports.a.b.c()
446486
return handle_access_export(
@@ -479,10 +519,14 @@ impl JavascriptParserPlugin for CommonJsExportsParserPlugin {
479519

480520
fn evaluate_typeof<'a>(
481521
&self,
482-
_parser: &mut JavascriptParser,
522+
parser: &mut JavascriptParser,
483523
expr: &'a UnaryExpr,
484524
for_name: &str,
485525
) -> Option<BasicEvaluatedExpression<'a>> {
526+
if self.should_skip_handler(parser) {
527+
return None;
528+
}
529+
486530
(for_name == "module" || for_name == "exports").then(|| {
487531
eval::evaluate_to_string(
488532
"object".to_string(),

crates/rspack_plugin_javascript/src/visitors/dependency/parser/mod.rs

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,9 @@ pub use call_hooks_name::CallHooksName;
1212
use rspack_cacheable::{cacheable, with::AsPreset};
1313
use rspack_core::{
1414
AsyncDependenciesBlock, BoxDependency, BoxDependencyTemplate, BuildInfo, BuildMeta,
15-
CompilerOptions, DependencyRange, FactoryMeta, JavascriptParserOptions, JavascriptParserUrl,
16-
ModuleIdentifier, ModuleLayer, ModuleType, ParseMeta, ResourceData, TypeReexportPresenceMode,
15+
CompilerOptions, DependencyRange, FactoryMeta, JavascriptParserCommonjsExportsOption,
16+
JavascriptParserOptions, JavascriptParserUrl, ModuleIdentifier, ModuleLayer, ModuleType,
17+
ParseMeta, ResourceData, TypeReexportPresenceMode,
1718
};
1819
use rspack_error::{Diagnostic, Result};
1920
use rspack_util::SpanExt;
@@ -346,7 +347,17 @@ impl<'parser> JavascriptParser<'parser> {
346347
if module_type.is_js_auto() || module_type.is_js_dynamic() {
347348
plugins.push(Box::new(parser_plugin::CommonJsImportsParserPlugin));
348349
plugins.push(Box::new(parser_plugin::CommonJsPlugin));
349-
plugins.push(Box::new(parser_plugin::CommonJsExportsParserPlugin));
350+
let commonjs_exports = javascript_options
351+
.commonjs
352+
.as_ref()
353+
.map_or(JavascriptParserCommonjsExportsOption::Enable, |commonjs| {
354+
commonjs.exports
355+
});
356+
if commonjs_exports != JavascriptParserCommonjsExportsOption::Disable {
357+
plugins.push(Box::new(parser_plugin::CommonJsExportsParserPlugin::new(
358+
commonjs_exports == JavascriptParserCommonjsExportsOption::SkipInEsm,
359+
)));
360+
}
350361
if compiler_options.node.is_some() {
351362
plugins.push(Box::new(parser_plugin::NodeStuffPlugin));
352363
}

0 commit comments

Comments
 (0)