fix(minifier): skip Object.defineProperty(exports, ...) for cjs-module-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`
This commit is contained in:
Boshen 2024-07-22 22:32:15 +10:00 committed by GitHub
parent 1b51511bb6
commit 267f7c4398
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 78 additions and 16 deletions

View file

@ -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
@ -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);

View file

@ -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,
@ -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
@ -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}");
}

View file

@ -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;
}
});",
);
}

View file

@ -1,5 +1,6 @@
mod code_removal;
mod folding;
// mod precedence;
mod booleans;
mod remove_dead_code;
mod replace_global_defines;

View file

@ -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;