Skip to content

Commit

Permalink
fix(minifier): skip Object.defineProperty(exports, ...) for `cjs-mo…
Browse files Browse the repository at this point in the history
…dule-lexer` (#4409)

```
> monitor-oxc@ test /home/runner/work/monitor-oxc/monitor-oxc
> node src/main.test.mjs

file:///home/runner/work/monitor-oxc/monitor-oxc/node_modules/.pnpm/inquirer@[10](https://github.com/oxc-project/monitor-oxc/actions/runs/10038139357/job/27739464680#step:8:11).0.1/node_modules/inquirer/dist/esm/ui/prompt.mjs:2
import { defer, EMPTY, from, of, concatMap, filter, reduce, isObservable, lastValueFrom } from "rxjs";
                ^^^^^
SyntaxError: Named export 'EMPTY' not found. The requested module 'rxjs' is a CommonJS module, which may not support all module.exports as named exports.
CommonJS modules can always be imported via the default export, for example using:

import pkg from 'rxjs';
const { defer, EMPTY, from, of, concatMap, filter, reduce, isObservable, lastValueFrom } = pkg;

    at ModuleJob._instantiate (node:internal/modules/esm/module_job:134:21)
    at async ModuleJob.run (node:internal/modules/esm/module_job:217:5)
    at async ModuleLoader.import (node:internal/modules/esm/loader:316:24)
    at async asyncRunEntryPointWithESMLoader (node:internal/modules/run_main:[12](https://github.com/oxc-project/monitor-oxc/actions/runs/10038139357/job/27739464680#step:8:13)3:5)

Node.js v20.15.1
```

Export is undefined when `enumerable` is "!0".
See `https://github.com/nodejs/cjs-module-lexer/issues/64`
  • Loading branch information
Boshen authored Jul 22, 2024
1 parent 1b51511 commit 267f7c4
Show file tree
Hide file tree
Showing 5 changed files with 78 additions and 16 deletions.
14 changes: 14 additions & 0 deletions crates/oxc_minifier/src/compressor/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,16 @@ impl<'a> Compressor<'a> {
self.ast.expression_binary(SPAN, left, BinaryOperator::Division, right)
}

/// Test `Object.defineProperty(exports, ...)`
fn is_object_define_property_exports(expr: &Expression<'a>) -> bool {
let Expression::CallExpression(call_expr) = expr else { return false };
let Some(Argument::Identifier(ident)) = call_expr.arguments.first() else { return false };
if ident.name != "exports" {
return false;
}
call_expr.callee.is_specific_member_access("Object", "defineProperty")
}

/* Statements */

/// Remove block from single line blocks
Expand Down Expand Up @@ -345,6 +355,10 @@ impl<'a> VisitMut<'a> for Compressor<'a> {
}

fn visit_expression(&mut self, expr: &mut Expression<'a>) {
// Bail cjs `Object.defineProperty(exports, ...)`
if Self::is_object_define_property_exports(expr) {
return;
}
walk_mut::walk_expression(self, expr);
self.compress_console(expr);
self.folder.fold_expression(expr);
Expand Down
14 changes: 12 additions & 2 deletions crates/oxc_minifier/tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,20 @@ mod oxc;
// mod terser;

use oxc_allocator::Allocator;
use oxc_codegen::{CodegenOptions, WhitespaceRemover};
use oxc_codegen::{CodeGenerator, CodegenOptions};
use oxc_minifier::{CompressOptions, Minifier, MinifierOptions};
use oxc_parser::Parser;
use oxc_span::SourceType;

fn codegen(source_text: &str, source_type: SourceType) -> String {
let allocator = Allocator::default();
let ret = Parser::new(&allocator, source_text, source_type).parse();
CodeGenerator::new()
.with_options(CodegenOptions { single_quote: true })
.build(&ret.program)
.source_text
}

pub(crate) fn minify(
source_text: &str,
source_type: SourceType,
Expand All @@ -20,7 +29,7 @@ pub(crate) fn minify(
let ret = Parser::new(&allocator, source_text, source_type).parse();
let program = allocator.alloc(ret.program);
Minifier::new(options).build(&allocator, program);
WhitespaceRemover::new()
CodeGenerator::new()
.with_options(CodegenOptions { single_quote: true })
.build(program)
.source_text
Expand All @@ -34,6 +43,7 @@ pub(crate) fn test(source_text: &str, expected: &str) {
pub(crate) fn test_with_options(source_text: &str, expected: &str, options: MinifierOptions) {
let source_type = SourceType::default();
let minified = minify(source_text, source_type, options);
let expected = codegen(expected, source_type);
assert_eq!(expected, minified, "for source {source_text}");
}

Expand Down
15 changes: 15 additions & 0 deletions crates/oxc_minifier/tests/oxc/booleans.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
use crate::test_same;

#[test]
fn cjs() {
// Export is undefined when `enumerable` is "!0".
// https://github.com/nodejs/cjs-module-lexer/issues/64
test_same(
"Object.defineProperty(exports, 'ConnectableObservable', {
enumerable: true,
get: function() {
return ConnectableObservable_1.ConnectableObservable;
}
});",
);
}
1 change: 1 addition & 0 deletions crates/oxc_minifier/tests/oxc/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
mod code_removal;
mod folding;
// mod precedence;
mod booleans;
mod remove_dead_code;
mod replace_global_defines;
50 changes: 36 additions & 14 deletions crates/oxc_minifier/tests/snapshots/addition_folding.snap
Original file line number Diff line number Diff line change
Expand Up @@ -6,82 +6,104 @@ expression: snapshot
let x = 1 + 1

=================================== MINIFIED ===================================
let x=2
let x = 2;


==================================== SOURCE ====================================
function foo() { return 1 + 1; }

=================================== MINIFIED ===================================
function foo(){return 2}
function foo() {
return 2;
}


==================================== SOURCE ====================================
'' + true

=================================== MINIFIED ===================================
;'true'
;
'true';


==================================== SOURCE ====================================
'' + false

=================================== MINIFIED ===================================
;'false'
;
'false';


==================================== SOURCE ====================================
'' + null

=================================== MINIFIED ===================================
;'null'
;
'null';


==================================== SOURCE ====================================
false + null

=================================== MINIFIED ===================================
!1+null
!1 + null;


==================================== SOURCE ====================================
'1' + '1'

=================================== MINIFIED ===================================
;'11'
;
'11';


==================================== SOURCE ====================================
NaN + NaN

=================================== MINIFIED ===================================
NaN+NaN
NaN + NaN;


==================================== SOURCE ====================================
'' + NaN

=================================== MINIFIED ===================================
;'NaN'
;
'NaN';


==================================== SOURCE ====================================
let x = 1; let y = x + 1

=================================== MINIFIED ===================================
let x=1,y=x+1
let x = 1, y = x + 1;


==================================== SOURCE ====================================
var x = 1; x + 1 === 2

=================================== MINIFIED ===================================
var x=1;x+1===2
var x = 1;
x + 1 === 2;


==================================== SOURCE ====================================
var y = 1; 1 + y === 2

=================================== MINIFIED ===================================
var y=1;1+y===2
var y = 1;
1 + y === 2;


==================================== SOURCE ====================================
null - Number(1)

=================================== MINIFIED ===================================
null-Number(1)
null - Number(1);


==================================== SOURCE ====================================
1 + 1.0000001

=================================== MINIFIED ===================================
2.0000001000000003
2.0000001000000003;

0 comments on commit 267f7c4

Please sign in to comment.