Skip to content

Commit

Permalink
feat(es/minifier): Support module: "unknown" (#9026)
Browse files Browse the repository at this point in the history
**Related issue:**

 - Closes #8571
  • Loading branch information
kdy1 committed Jun 7, 2024
1 parent 2e22b5d commit cada50b
Show file tree
Hide file tree
Showing 11 changed files with 119 additions and 102 deletions.
6 changes: 4 additions & 2 deletions bindings/binding_core_wasm/__tests__/simple.js
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,8 @@ describe("parse", () => {
describe("minify", () => {
it("should work", () => {
const output = swc.minifySync(
"const somename = 1; console.log(somename);"
"const somename = 1; console.log(somename);",
{ module: false }
);

expect(output).toMatchInlineSnapshot(`
Expand All @@ -202,7 +203,8 @@ describe("minify", () => {

it("should work with async facade", async () => {
const output = await swc.minify(
"const somename = 1; console.log(somename);"
"const somename = 1; console.log(somename);",
{ module: false }
);

expect(output).toMatchInlineSnapshot(`
Expand Down
36 changes: 18 additions & 18 deletions crates/swc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -804,20 +804,6 @@ impl Compiler {

// https://github.com/swc-project/swc/issues/2254

if opts.module {
if let Some(opts) = &mut min_opts.compress {
if opts.top_level.is_none() {
opts.top_level = Some(TopLevelOptions { functions: true });
}
}

if let Some(opts) = &mut min_opts.mangle {
if opts.top_level.is_none() {
opts.top_level = Some(true);
}
}
}

if opts.keep_fnames {
if let Some(opts) = &mut min_opts.compress {
opts.keep_fnames = true;
Expand All @@ -829,7 +815,7 @@ impl Compiler {

let comments = SingleThreadedComments::default();

let module = self
let program = self
.parse_js(
fm.clone(),
handler,
Expand All @@ -841,17 +827,31 @@ impl Compiler {
import_attributes: true,
..Default::default()
}),
IsModule::Bool(opts.module),
opts.module,
Some(&comments),
)
.context("failed to parse input file")?;

if program.is_module() {
if let Some(opts) = &mut min_opts.compress {
if opts.top_level.is_none() {
opts.top_level = Some(TopLevelOptions { functions: true });
}
}

if let Some(opts) = &mut min_opts.mangle {
if opts.top_level.is_none() {
opts.top_level = Some(true);
}
}
}

let source_map_names = if source_map.enabled() {
let mut v = swc_compiler_base::IdentCollector {
names: Default::default(),
};

module.visit_with(&mut v);
program.visit_with(&mut v);

v.names
} else {
Expand All @@ -864,7 +864,7 @@ impl Compiler {
let is_mangler_enabled = min_opts.mangle.is_some();

let module = self.run_transform(handler, false, || {
let module = module.fold_with(&mut paren_remover(Some(&comments)));
let module = program.fold_with(&mut paren_remover(Some(&comments)));

let module =
module.fold_with(&mut resolver(unresolved_mark, top_level_mark, false));
Expand Down
2 changes: 1 addition & 1 deletion crates/swc/tests/projects.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1107,7 +1107,7 @@ fn issue_7513_2() {
fm,
handler,
&JsMinifyOptions {
module: true,
module: IsModule::Bool(true),
compress: BoolOrDataConfig::from_bool(true),
mangle: BoolOrDataConfig::from_obj(MangleOptions {
props: None,
Expand Down
78 changes: 4 additions & 74 deletions crates/swc_compiler_base/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
use std::{
env, fmt,
env,
path::{Path, PathBuf},
};

use anyhow::{Context, Error};
use base64::prelude::{Engine, BASE64_STANDARD};
use once_cell::sync::Lazy;
use serde::{
de::{Unexpected, Visitor},
Deserialize, Deserializer, Serialize, Serializer,
};
use serde::{Deserialize, Serialize};
use swc_atoms::JsWord;
use swc_common::{
collections::AHashMap,
Expand All @@ -19,7 +16,8 @@ use swc_common::{
sync::Lrc,
BytePos, FileName, SourceFile, SourceMap,
};
use swc_config::{config_types::BoolOr, merge::Merge};
use swc_config::config_types::BoolOr;
pub use swc_config::IsModule;
use swc_ecma_ast::{EsVersion, Ident, Program};
use swc_ecma_codegen::{text_writer::WriteJs, Emitter, Node};
use swc_ecma_minifier::js::JsMinifyCommentOption;
Expand Down Expand Up @@ -384,74 +382,6 @@ impl Default for SourceMapsConfig {
}
}

#[derive(Clone, Debug, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum IsModule {
Bool(bool),
Unknown,
}

impl Default for IsModule {
fn default() -> Self {
IsModule::Bool(true)
}
}

impl Merge for IsModule {
fn merge(&mut self, other: Self) {
if *self == Default::default() {
*self = other;
}
}
}

impl Serialize for IsModule {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match *self {
IsModule::Bool(ref b) => b.serialize(serializer),
IsModule::Unknown => "unknown".serialize(serializer),
}
}
}

impl<'de> Deserialize<'de> for IsModule {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct IsModuleVisitor;

impl<'de> Visitor<'de> for IsModuleVisitor {
type Value = IsModule;

fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a boolean or the string 'unknown'")
}

fn visit_bool<E>(self, b: bool) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
Ok(IsModule::Bool(b))
}

fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
match s {
"unknown" => Ok(IsModule::Unknown),
_ => Err(serde::de::Error::invalid_value(Unexpected::Str(s), &self)),
}
}
}

deserializer.deserialize_any(IsModuleVisitor)
}
}

pub struct IdentCollector {
pub names: AHashMap<BytePos, JsWord>,
}
Expand Down
2 changes: 2 additions & 0 deletions crates/swc_config/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@

pub mod config_types;
pub mod merge;
mod module;
#[cfg(feature = "sourcemap")]
mod source_map;

pub use swc_cached::{regex::CachedRegex, Error};

pub use crate::module::IsModule;
#[cfg(feature = "sourcemap")]
pub use crate::source_map::*;
76 changes: 76 additions & 0 deletions crates/swc_config/src/module.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
use std::fmt;

use serde::{
de::{Unexpected, Visitor},
Deserialize, Deserializer, Serialize, Serializer,
};

use crate::merge::Merge;

#[derive(Clone, Debug, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum IsModule {
Bool(bool),
Unknown,
}

impl Default for IsModule {
fn default() -> Self {
IsModule::Bool(true)
}
}

impl Merge for IsModule {
fn merge(&mut self, other: Self) {
if *self == Default::default() {
*self = other;
}
}
}

impl Serialize for IsModule {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match *self {
IsModule::Bool(ref b) => b.serialize(serializer),
IsModule::Unknown => "unknown".serialize(serializer),
}
}
}

struct IsModuleVisitor;

impl<'de> Visitor<'de> for IsModuleVisitor {
type Value = IsModule;

fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a boolean or the string 'unknown'")
}

fn visit_bool<E>(self, b: bool) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
Ok(IsModule::Bool(b))
}

fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
match s {
"unknown" => Ok(IsModule::Unknown),
_ => Err(serde::de::Error::invalid_value(Unexpected::Str(s), &self)),
}
}
}

impl<'de> Deserialize<'de> for IsModule {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
deserializer.deserialize_any(IsModuleVisitor)
}
}
10 changes: 7 additions & 3 deletions crates/swc_ecma_minifier/src/js.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! NOT A PUBLIC API

use serde::{Deserialize, Serialize};
use swc_config::{config_types::BoolOrDataConfig, SourceMapContent};
use swc_config::{config_types::BoolOrDataConfig, IsModule, SourceMapContent};

use crate::option::{
terser::{TerserCompressorOptions, TerserEcmaVersion},
Expand Down Expand Up @@ -33,8 +33,8 @@ pub struct JsMinifyOptions {
#[serde(default, alias = "keep_fnames")]
pub keep_fnames: bool,

#[serde(default)]
pub module: bool,
#[serde(default = "default_module")]
pub module: IsModule,

#[serde(default)]
pub safari10: bool,
Expand Down Expand Up @@ -210,3 +210,7 @@ pub enum JsMinifyCommentOption {
#[serde(rename = "all")]
PreserveAllComments,
}

fn default_module() -> IsModule {
IsModule::Bool(false)
}
3 changes: 2 additions & 1 deletion packages/core/__tests__/minify/issue_8437_test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@ toFixed(1.2345, 2, Math.round, 1);
async function minify() {
const { code } = await swc.minify(origin, {
compress: true,
mangle: false
mangle: false,
module: false
});
return code;
}
Expand Down
4 changes: 3 additions & 1 deletion packages/core/__tests__/minify_test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,9 @@ it("should accept non-strict code", async () => {
a = 1;
delete a;
console.log(a);
`);
`, {
module: false
});

expect(code).toMatchInlineSnapshot(`"a=1,delete a,console.log(a);"`);
});
2 changes: 1 addition & 1 deletion packages/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export interface JsMinifyOptions {

keep_fnames?: boolean;

module?: boolean;
module?: boolean | "unknown";

safari10?: boolean;

Expand Down
2 changes: 1 addition & 1 deletion packages/types/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@swc/types",
"packageManager": "yarn@4.0.2",
"version": "0.1.7",
"version": "0.1.8",
"description": "Typings for the swc project.",
"sideEffects": false,
"scripts": {
Expand Down

0 comments on commit cada50b

Please sign in to comment.