diff --git a/bindings/binding_core_node/src/bundle.rs b/bindings/binding_core_node/src/bundle.rs index 6873adafde6a..c2378b16987b 100644 --- a/bindings/binding_core_node/src/bundle.rs +++ b/bindings/binding_core_node/src/bundle.rs @@ -138,6 +138,7 @@ impl Task for BundleTask { None, true, false, + Default::default(), )?; Ok((k, output)) diff --git a/bindings/binding_core_node/src/print.rs b/bindings/binding_core_node/src/print.rs index 3f129fcf3372..983cad30e133 100644 --- a/bindings/binding_core_node/src/print.rs +++ b/bindings/binding_core_node/src/print.rs @@ -51,6 +51,7 @@ impl Task for PrintTask { None, options.config.emit_source_map_columns.into_bool(), false, + Default::default(), ) .convert_err() }) @@ -112,6 +113,7 @@ pub fn print_sync(program: String, options: Buffer) -> napi::Result, + + #[serde(default)] + pub preamble: String, } #[derive(Debug, Clone, Serialize, Deserialize)] diff --git a/crates/swc/src/lib.rs b/crates/swc/src/lib.rs index 0629a2a3345a..64edb43cf0db 100644 --- a/crates/swc/src/lib.rs +++ b/crates/swc/src/lib.rs @@ -506,6 +506,7 @@ impl Compiler { comments: Option<&dyn Comments>, emit_source_map_columns: bool, ascii_only: bool, + preamble: &str, ) -> Result where T: Node + VisitWith, @@ -518,7 +519,7 @@ impl Compiler { let src = { let mut buf = vec![]; { - let mut wr = Box::new(swc_ecma_codegen::text_writer::JsWriter::new( + let mut w = swc_ecma_codegen::text_writer::JsWriter::new( self.cm.clone(), "\n", &mut buf, @@ -527,7 +528,9 @@ impl Compiler { } else { None }, - )) as Box; + ); + w.preamble(preamble).unwrap(); + let mut wr = Box::new(w) as Box; if minify { wr = Box::new(swc_ecma_codegen::text_writer::omit_trailing_semi(wr)); @@ -1158,6 +1161,7 @@ impl Compiler { Some(&comments), opts.emit_source_map_columns, opts.format.ascii_only, + &opts.format.preamble, ) }) } @@ -1236,6 +1240,7 @@ impl Compiler { .charset .map(|v| matches!(v, OutputCharset::Ascii)) .unwrap_or(false), + &config.output.preamble, ) }) } diff --git a/crates/swc/tests/minify/issue-7475/1-with-preamble/config.json b/crates/swc/tests/minify/issue-7475/1-with-preamble/config.json new file mode 100644 index 000000000000..7b5a35943ef5 --- /dev/null +++ b/crates/swc/tests/minify/issue-7475/1-with-preamble/config.json @@ -0,0 +1,5 @@ +{ + "format": { + "preamble": "/** @license */\n" + } +} diff --git a/crates/swc/tests/minify/issue-7475/1-with-preamble/input.js b/crates/swc/tests/minify/issue-7475/1-with-preamble/input.js new file mode 100644 index 000000000000..14f45bd101d9 --- /dev/null +++ b/crates/swc/tests/minify/issue-7475/1-with-preamble/input.js @@ -0,0 +1,5 @@ +function foo() { + console.log('Foo') +} + +foo() \ No newline at end of file diff --git a/crates/swc/tests/minify/issue-7475/1-with-preamble/output.js b/crates/swc/tests/minify/issue-7475/1-with-preamble/output.js new file mode 100644 index 000000000000..0cafb7709cbf --- /dev/null +++ b/crates/swc/tests/minify/issue-7475/1-with-preamble/output.js @@ -0,0 +1,2 @@ +/** @license */ +function foo(){console.log("Foo")}foo(); diff --git a/crates/swc/tests/minify/issue-7475/1-with-preamble/output.map b/crates/swc/tests/minify/issue-7475/1-with-preamble/output.map new file mode 100644 index 000000000000..c2db5abfaf91 --- /dev/null +++ b/crates/swc/tests/minify/issue-7475/1-with-preamble/output.map @@ -0,0 +1,15 @@ +{ + "mappings": ";AAAA,SAASA,MACLC,QAAQC,GAAG,CAAC,MAChB,CAEAF", + "names": [ + "foo", + "console", + "log" + ], + "sources": [ + "$DIR/tests/minify/issue-7475/1-with-preamble/input.js" + ], + "sourcesContent": [ + "function foo() {\n console.log('Foo')\n}\n\nfoo()" + ], + "version": 3 +} diff --git a/crates/swc/tests/minify/issue-7475/2-no-preamble/config.json b/crates/swc/tests/minify/issue-7475/2-no-preamble/config.json new file mode 100644 index 000000000000..8cb86d78d21b --- /dev/null +++ b/crates/swc/tests/minify/issue-7475/2-no-preamble/config.json @@ -0,0 +1,3 @@ +{ + "format": {} +} diff --git a/crates/swc/tests/minify/issue-7475/2-no-preamble/input.js b/crates/swc/tests/minify/issue-7475/2-no-preamble/input.js new file mode 100644 index 000000000000..14f45bd101d9 --- /dev/null +++ b/crates/swc/tests/minify/issue-7475/2-no-preamble/input.js @@ -0,0 +1,5 @@ +function foo() { + console.log('Foo') +} + +foo() \ No newline at end of file diff --git a/crates/swc/tests/minify/issue-7475/2-no-preamble/output.js b/crates/swc/tests/minify/issue-7475/2-no-preamble/output.js new file mode 100644 index 000000000000..a2e7bdceacd1 --- /dev/null +++ b/crates/swc/tests/minify/issue-7475/2-no-preamble/output.js @@ -0,0 +1 @@ +function foo(){console.log("Foo")}foo(); diff --git a/crates/swc/tests/minify/issue-7475/2-no-preamble/output.map b/crates/swc/tests/minify/issue-7475/2-no-preamble/output.map new file mode 100644 index 000000000000..db25a7dc8d2c --- /dev/null +++ b/crates/swc/tests/minify/issue-7475/2-no-preamble/output.map @@ -0,0 +1,15 @@ +{ + "mappings": "AAAA,SAASA,MACLC,QAAQC,GAAG,CAAC,MAChB,CAEAF", + "names": [ + "foo", + "console", + "log" + ], + "sources": [ + "$DIR/tests/minify/issue-7475/2-no-preamble/input.js" + ], + "sourcesContent": [ + "function foo() {\n console.log('Foo')\n}\n\nfoo()" + ], + "version": 3 +} diff --git a/crates/swc/tests/projects.rs b/crates/swc/tests/projects.rs index 94ef6f46eff4..d59d18343014 100644 --- a/crates/swc/tests/projects.rs +++ b/crates/swc/tests/projects.rs @@ -769,6 +769,7 @@ fn should_visit() { Some(&comments), config.emit_source_map_columns, false, + Default::default(), ) .unwrap() .code) @@ -1130,3 +1131,36 @@ fn issue_7513_2() { println!("{}", output.code); assert_eq!(output.code, "const a={ignoreBOM:!0,fatal:!0};"); } + +#[testing::fixture("tests/minify/**/input.js")] +fn minify(input_js: PathBuf) { + let input_dir = input_js.parent().unwrap(); + let config_json_path = input_dir.join("config.json"); + + testing::run_test2(false, |cm, handler| { + let c = Compiler::new(cm); + let fm = c.cm.load_file(&input_js).unwrap(); + + let mut config: JsMinifyOptions = + serde_json::from_str(&std::fs::read_to_string(&config_json_path).unwrap()).unwrap(); + + config.source_map = BoolOrDataConfig::from_bool(true); + let output = c.minify(fm, &handler, &config).unwrap(); + + NormalizedOutput::from(output.code) + .compare_to_file(input_dir.join("output.js")) + .unwrap(); + + let map = output.map.map(|json| { + let json: serde_json::Value = serde_json::from_str(&json).unwrap(); + serde_json::to_string_pretty(&json).unwrap() + }); + + NormalizedOutput::from(map.unwrap()) + .compare_to_file(input_dir.join("output.map")) + .unwrap(); + + Ok(()) + }) + .unwrap() +} diff --git a/crates/swc_ecma_codegen/src/text_writer/basic_impl.rs b/crates/swc_ecma_codegen/src/text_writer/basic_impl.rs index 34df0fa88827..ce27e83f8239 100644 --- a/crates/swc_ecma_codegen/src/text_writer/basic_impl.rs +++ b/crates/swc_ecma_codegen/src/text_writer/basic_impl.rs @@ -46,6 +46,13 @@ impl<'a, W: Write> JsWriter<'a, W> { } } + pub fn preamble(&mut self, s: &str) -> Result { + self.raw_write(s)?; + self.update_pos(s); + + Ok(()) + } + /// Sets the indentation string. Defaults to four spaces. pub fn set_indent_str(&mut self, indent_str: &'static str) { self.indent_str = indent_str; diff --git a/crates/swc_node_bundler/tests/fixture.rs b/crates/swc_node_bundler/tests/fixture.rs index 3be67a4822c1..9ecac943b378 100644 --- a/crates/swc_node_bundler/tests/fixture.rs +++ b/crates/swc_node_bundler/tests/fixture.rs @@ -99,6 +99,7 @@ fn pass(input_dir: PathBuf) { Some(&comments), false, false, + Default::default(), ) .expect("failed to print?") .code;