mirror of
https://github.com/swc-project/swc.git
synced 2024-10-26 09:02:01 +03:00
feat(es/minifier): Support module: "unknown"
(#9026)
**Related issue:** - Closes #8571
This commit is contained in:
parent
2e22b5dc4f
commit
cada50b017
@ -190,7 +190,8 @@ describe("parse", () => {
|
|||||||
describe("minify", () => {
|
describe("minify", () => {
|
||||||
it("should work", () => {
|
it("should work", () => {
|
||||||
const output = swc.minifySync(
|
const output = swc.minifySync(
|
||||||
"const somename = 1; console.log(somename);"
|
"const somename = 1; console.log(somename);",
|
||||||
|
{ module: false }
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(output).toMatchInlineSnapshot(`
|
expect(output).toMatchInlineSnapshot(`
|
||||||
@ -202,7 +203,8 @@ describe("minify", () => {
|
|||||||
|
|
||||||
it("should work with async facade", async () => {
|
it("should work with async facade", async () => {
|
||||||
const output = await swc.minify(
|
const output = await swc.minify(
|
||||||
"const somename = 1; console.log(somename);"
|
"const somename = 1; console.log(somename);",
|
||||||
|
{ module: false }
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(output).toMatchInlineSnapshot(`
|
expect(output).toMatchInlineSnapshot(`
|
||||||
|
@ -804,7 +804,35 @@ impl Compiler {
|
|||||||
|
|
||||||
// https://github.com/swc-project/swc/issues/2254
|
// https://github.com/swc-project/swc/issues/2254
|
||||||
|
|
||||||
if opts.module {
|
if opts.keep_fnames {
|
||||||
|
if let Some(opts) = &mut min_opts.compress {
|
||||||
|
opts.keep_fnames = true;
|
||||||
|
}
|
||||||
|
if let Some(opts) = &mut min_opts.mangle {
|
||||||
|
opts.keep_fn_names = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let comments = SingleThreadedComments::default();
|
||||||
|
|
||||||
|
let program = self
|
||||||
|
.parse_js(
|
||||||
|
fm.clone(),
|
||||||
|
handler,
|
||||||
|
target,
|
||||||
|
Syntax::Es(EsConfig {
|
||||||
|
jsx: true,
|
||||||
|
decorators: true,
|
||||||
|
decorators_before_export: true,
|
||||||
|
import_attributes: true,
|
||||||
|
..Default::default()
|
||||||
|
}),
|
||||||
|
opts.module,
|
||||||
|
Some(&comments),
|
||||||
|
)
|
||||||
|
.context("failed to parse input file")?;
|
||||||
|
|
||||||
|
if program.is_module() {
|
||||||
if let Some(opts) = &mut min_opts.compress {
|
if let Some(opts) = &mut min_opts.compress {
|
||||||
if opts.top_level.is_none() {
|
if opts.top_level.is_none() {
|
||||||
opts.top_level = Some(TopLevelOptions { functions: true });
|
opts.top_level = Some(TopLevelOptions { functions: true });
|
||||||
@ -818,40 +846,12 @@ impl Compiler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if opts.keep_fnames {
|
|
||||||
if let Some(opts) = &mut min_opts.compress {
|
|
||||||
opts.keep_fnames = true;
|
|
||||||
}
|
|
||||||
if let Some(opts) = &mut min_opts.mangle {
|
|
||||||
opts.keep_fn_names = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let comments = SingleThreadedComments::default();
|
|
||||||
|
|
||||||
let module = self
|
|
||||||
.parse_js(
|
|
||||||
fm.clone(),
|
|
||||||
handler,
|
|
||||||
target,
|
|
||||||
Syntax::Es(EsConfig {
|
|
||||||
jsx: true,
|
|
||||||
decorators: true,
|
|
||||||
decorators_before_export: true,
|
|
||||||
import_attributes: true,
|
|
||||||
..Default::default()
|
|
||||||
}),
|
|
||||||
IsModule::Bool(opts.module),
|
|
||||||
Some(&comments),
|
|
||||||
)
|
|
||||||
.context("failed to parse input file")?;
|
|
||||||
|
|
||||||
let source_map_names = if source_map.enabled() {
|
let source_map_names = if source_map.enabled() {
|
||||||
let mut v = swc_compiler_base::IdentCollector {
|
let mut v = swc_compiler_base::IdentCollector {
|
||||||
names: Default::default(),
|
names: Default::default(),
|
||||||
};
|
};
|
||||||
|
|
||||||
module.visit_with(&mut v);
|
program.visit_with(&mut v);
|
||||||
|
|
||||||
v.names
|
v.names
|
||||||
} else {
|
} else {
|
||||||
@ -864,7 +864,7 @@ impl Compiler {
|
|||||||
let is_mangler_enabled = min_opts.mangle.is_some();
|
let is_mangler_enabled = min_opts.mangle.is_some();
|
||||||
|
|
||||||
let module = self.run_transform(handler, false, || {
|
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 =
|
let module =
|
||||||
module.fold_with(&mut resolver(unresolved_mark, top_level_mark, false));
|
module.fold_with(&mut resolver(unresolved_mark, top_level_mark, false));
|
||||||
|
@ -1107,7 +1107,7 @@ fn issue_7513_2() {
|
|||||||
fm,
|
fm,
|
||||||
handler,
|
handler,
|
||||||
&JsMinifyOptions {
|
&JsMinifyOptions {
|
||||||
module: true,
|
module: IsModule::Bool(true),
|
||||||
compress: BoolOrDataConfig::from_bool(true),
|
compress: BoolOrDataConfig::from_bool(true),
|
||||||
mangle: BoolOrDataConfig::from_obj(MangleOptions {
|
mangle: BoolOrDataConfig::from_obj(MangleOptions {
|
||||||
props: None,
|
props: None,
|
||||||
|
@ -1,15 +1,12 @@
|
|||||||
use std::{
|
use std::{
|
||||||
env, fmt,
|
env,
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
};
|
};
|
||||||
|
|
||||||
use anyhow::{Context, Error};
|
use anyhow::{Context, Error};
|
||||||
use base64::prelude::{Engine, BASE64_STANDARD};
|
use base64::prelude::{Engine, BASE64_STANDARD};
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
use serde::{
|
use serde::{Deserialize, Serialize};
|
||||||
de::{Unexpected, Visitor},
|
|
||||||
Deserialize, Deserializer, Serialize, Serializer,
|
|
||||||
};
|
|
||||||
use swc_atoms::JsWord;
|
use swc_atoms::JsWord;
|
||||||
use swc_common::{
|
use swc_common::{
|
||||||
collections::AHashMap,
|
collections::AHashMap,
|
||||||
@ -19,7 +16,8 @@ use swc_common::{
|
|||||||
sync::Lrc,
|
sync::Lrc,
|
||||||
BytePos, FileName, SourceFile, SourceMap,
|
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_ast::{EsVersion, Ident, Program};
|
||||||
use swc_ecma_codegen::{text_writer::WriteJs, Emitter, Node};
|
use swc_ecma_codegen::{text_writer::WriteJs, Emitter, Node};
|
||||||
use swc_ecma_minifier::js::JsMinifyCommentOption;
|
use swc_ecma_minifier::js::JsMinifyCommentOption;
|
||||||
@ -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 struct IdentCollector {
|
||||||
pub names: AHashMap<BytePos, JsWord>,
|
pub names: AHashMap<BytePos, JsWord>,
|
||||||
}
|
}
|
||||||
|
@ -2,10 +2,12 @@
|
|||||||
|
|
||||||
pub mod config_types;
|
pub mod config_types;
|
||||||
pub mod merge;
|
pub mod merge;
|
||||||
|
mod module;
|
||||||
#[cfg(feature = "sourcemap")]
|
#[cfg(feature = "sourcemap")]
|
||||||
mod source_map;
|
mod source_map;
|
||||||
|
|
||||||
pub use swc_cached::{regex::CachedRegex, Error};
|
pub use swc_cached::{regex::CachedRegex, Error};
|
||||||
|
|
||||||
|
pub use crate::module::IsModule;
|
||||||
#[cfg(feature = "sourcemap")]
|
#[cfg(feature = "sourcemap")]
|
||||||
pub use crate::source_map::*;
|
pub use crate::source_map::*;
|
||||||
|
76
crates/swc_config/src/module.rs
Normal file
76
crates/swc_config/src/module.rs
Normal file
@ -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)
|
||||||
|
}
|
||||||
|
}
|
@ -1,7 +1,7 @@
|
|||||||
//! NOT A PUBLIC API
|
//! NOT A PUBLIC API
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use swc_config::{config_types::BoolOrDataConfig, SourceMapContent};
|
use swc_config::{config_types::BoolOrDataConfig, IsModule, SourceMapContent};
|
||||||
|
|
||||||
use crate::option::{
|
use crate::option::{
|
||||||
terser::{TerserCompressorOptions, TerserEcmaVersion},
|
terser::{TerserCompressorOptions, TerserEcmaVersion},
|
||||||
@ -33,8 +33,8 @@ pub struct JsMinifyOptions {
|
|||||||
#[serde(default, alias = "keep_fnames")]
|
#[serde(default, alias = "keep_fnames")]
|
||||||
pub keep_fnames: bool,
|
pub keep_fnames: bool,
|
||||||
|
|
||||||
#[serde(default)]
|
#[serde(default = "default_module")]
|
||||||
pub module: bool,
|
pub module: IsModule,
|
||||||
|
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub safari10: bool,
|
pub safari10: bool,
|
||||||
@ -210,3 +210,7 @@ pub enum JsMinifyCommentOption {
|
|||||||
#[serde(rename = "all")]
|
#[serde(rename = "all")]
|
||||||
PreserveAllComments,
|
PreserveAllComments,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn default_module() -> IsModule {
|
||||||
|
IsModule::Bool(false)
|
||||||
|
}
|
||||||
|
@ -37,7 +37,8 @@ toFixed(1.2345, 2, Math.round, 1);
|
|||||||
async function minify() {
|
async function minify() {
|
||||||
const { code } = await swc.minify(origin, {
|
const { code } = await swc.minify(origin, {
|
||||||
compress: true,
|
compress: true,
|
||||||
mangle: false
|
mangle: false,
|
||||||
|
module: false
|
||||||
});
|
});
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
@ -260,7 +260,9 @@ it("should accept non-strict code", async () => {
|
|||||||
a = 1;
|
a = 1;
|
||||||
delete a;
|
delete a;
|
||||||
console.log(a);
|
console.log(a);
|
||||||
`);
|
`, {
|
||||||
|
module: false
|
||||||
|
});
|
||||||
|
|
||||||
expect(code).toMatchInlineSnapshot(`"a=1,delete a,console.log(a);"`);
|
expect(code).toMatchInlineSnapshot(`"a=1,delete a,console.log(a);"`);
|
||||||
});
|
});
|
||||||
|
@ -27,7 +27,7 @@ export interface JsMinifyOptions {
|
|||||||
|
|
||||||
keep_fnames?: boolean;
|
keep_fnames?: boolean;
|
||||||
|
|
||||||
module?: boolean;
|
module?: boolean | "unknown";
|
||||||
|
|
||||||
safari10?: boolean;
|
safari10?: boolean;
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@swc/types",
|
"name": "@swc/types",
|
||||||
"packageManager": "yarn@4.0.2",
|
"packageManager": "yarn@4.0.2",
|
||||||
"version": "0.1.7",
|
"version": "0.1.8",
|
||||||
"description": "Typings for the swc project.",
|
"description": "Typings for the swc project.",
|
||||||
"sideEffects": false,
|
"sideEffects": false,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
Loading…
Reference in New Issue
Block a user