mirror of
https://github.com/swc-project/swc.git
synced 2024-09-11 08:45:34 +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", () => {
|
||||
it("should work", () => {
|
||||
const output = swc.minifySync(
|
||||
"const somename = 1; console.log(somename);"
|
||||
"const somename = 1; console.log(somename);",
|
||||
{ module: false }
|
||||
);
|
||||
|
||||
expect(output).toMatchInlineSnapshot(`
|
||||
@ -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(`
|
||||
|
@ -804,7 +804,35 @@ impl Compiler {
|
||||
|
||||
// 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 opts.top_level.is_none() {
|
||||
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 mut v = swc_compiler_base::IdentCollector {
|
||||
names: Default::default(),
|
||||
};
|
||||
|
||||
module.visit_with(&mut v);
|
||||
program.visit_with(&mut v);
|
||||
|
||||
v.names
|
||||
} else {
|
||||
@ -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));
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
@ -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;
|
||||
@ -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>,
|
||||
}
|
||||
|
@ -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
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
|
||||
|
||||
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},
|
||||
@ -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,
|
||||
@ -210,3 +210,7 @@ pub enum JsMinifyCommentOption {
|
||||
#[serde(rename = "all")]
|
||||
PreserveAllComments,
|
||||
}
|
||||
|
||||
fn default_module() -> IsModule {
|
||||
IsModule::Bool(false)
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);"`);
|
||||
});
|
||||
|
@ -27,7 +27,7 @@ export interface JsMinifyOptions {
|
||||
|
||||
keep_fnames?: boolean;
|
||||
|
||||
module?: boolean;
|
||||
module?: boolean | "unknown";
|
||||
|
||||
safari10?: boolean;
|
||||
|
||||
|
@ -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": {
|
||||
|
Loading…
Reference in New Issue
Block a user