Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(es/minifier): Fix block unwrapping issue #2570

Merged
merged 7 commits into from
Oct 28, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion ecmascript/minifier/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ include = ["Cargo.toml", "src/**/*.rs", "src/lists/*.json"]
license = "Apache-2.0/MIT"
name = "swc_ecma_minifier"
repository = "https://github.com/swc-project/swc.git"
version = "0.46.6"
version = "0.46.7"

[features]
debug = ["backtrace"]
Expand Down
5 changes: 4 additions & 1 deletion ecmascript/minifier/src/compress/optimize/mod.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#![allow(dead_code)]

use self::util::MultiReplacer;
use super::util::is_fine_for_if_cons;
use crate::{
analyzer::{ProgramData, UsageAnalyzer},
compress::util::is_pure_undefined,
Expand Down Expand Up @@ -1457,7 +1458,9 @@ where
Stmt::Block(block) if block.stmts.is_empty() => {
*s = Stmt::Empty(EmptyStmt { span: block.span });
}
Stmt::Block(block) if block.stmts.len() == 1 => {
Stmt::Block(block)
if block.stmts.len() == 1 && is_fine_for_if_cons(&block.stmts[0]) =>
{
*s = block.stmts.take().into_iter().next().unwrap();
}
_ => {}
Expand Down
33 changes: 8 additions & 25 deletions ecmascript/minifier/src/compress/pure/dead_code.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use super::Pure;
use crate::{compress::util::always_terminates, mode::Mode};
use swc_atoms::js_word;
use crate::{
compress::util::{always_terminates, is_fine_for_if_cons},
mode::Mode,
};
use swc_common::{util::take::Take, DUMMY_SP};
use swc_ecma_ast::*;
use swc_ecma_utils::{ExprExt, StmtLike, Value};
Expand All @@ -14,31 +16,12 @@ where
where
T: StmtLike,
{
fn is_inliable(b: &BlockStmt) -> bool {
b.stmts.iter().all(|s| match s {
Stmt::Decl(Decl::Fn(FnDecl {
ident:
Ident {
sym: js_word!("undefined"),
..
},
..
})) => false,

Stmt::Decl(
Decl::Var(VarDecl {
kind: VarDeclKind::Var,
..
})
| Decl::Fn(..),
) => true,
Stmt::Decl(..) => false,
_ => true,
})
fn is_ok(b: &BlockStmt) -> bool {
b.stmts.iter().all(|s| is_fine_for_if_cons(s))
}

if stmts.iter().all(|stmt| match stmt.as_stmt() {
Some(Stmt::Block(b)) if is_inliable(b) => false,
Some(Stmt::Block(b)) if is_ok(b) => false,
_ => true,
}) {
return;
Expand All @@ -51,7 +34,7 @@ where
for stmt in stmts.take() {
match stmt.try_into_stmt() {
Ok(v) => match v {
Stmt::Block(v) if is_inliable(&v) => {
Stmt::Block(v) if is_ok(&v) => {
new.extend(v.stmts.into_iter().map(T::from_stmt));
}
_ => new.push(T::from_stmt(v)),
Expand Down
5 changes: 2 additions & 3 deletions ecmascript/minifier/src/compress/pure/if_return.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use crate::compress::util::negate;

use super::Pure;
use crate::compress::util::{is_fine_for_if_cons, negate};
use swc_common::{util::take::Take, DUMMY_SP};
use swc_ecma_ast::*;

Expand Down Expand Up @@ -96,7 +95,7 @@ impl<M> Pure<'_, M> {
self.changed = true;
negate(&mut s.test, false);

s.cons = if cons.len() == 1 {
s.cons = if cons.len() == 1 && is_fine_for_if_cons(&cons[0]) {
Box::new(cons.into_iter().next().unwrap())
} else {
Box::new(Stmt::Block(BlockStmt {
Expand Down
16 changes: 8 additions & 8 deletions ecmascript/minifier/src/compress/pure/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ pub(crate) fn pure_optimizer<'a, M>(
options: &'a CompressOptions,
marks: Marks,
mode: &'a M,
debug_inifinite_loop: bool,
debug_infinite_loop: bool,
) -> impl 'a + VisitMut + Repeated
where
M: Mode,
Expand All @@ -44,7 +44,7 @@ where
ctx: Default::default(),
changed: Default::default(),
mode,
debug_inifinite_loop,
debug_infinite_loop,
}
}

Expand All @@ -55,7 +55,7 @@ struct Pure<'a, M> {
changed: bool,
mode: &'a M,

debug_inifinite_loop: bool,
debug_infinite_loop: bool,
}

impl<M> Repeated for Pure<'_, M> {
Expand Down Expand Up @@ -117,7 +117,7 @@ where
ctx: self.ctx,
changed: false,
mode: self.mode,
debug_inifinite_loop: self.debug_inifinite_loop,
debug_infinite_loop: self.debug_infinite_loop,
};
node.visit_mut_with(&mut v);

Expand All @@ -136,7 +136,7 @@ where
},
changed: false,
mode: self.mode,
debug_inifinite_loop: self.debug_inifinite_loop,
debug_infinite_loop: self.debug_infinite_loop,
};
node.visit_mut_with(&mut v);

Expand Down Expand Up @@ -447,7 +447,7 @@ where
}

fn visit_mut_stmt(&mut self, s: &mut Stmt) {
let _tracing = if cfg!(feature = "debug") && self.debug_inifinite_loop {
let _tracing = if cfg!(feature = "debug") && self.debug_infinite_loop {
let text = dump(&*s);

if text.lines().count() < 10 {
Expand All @@ -470,7 +470,7 @@ where
s.visit_mut_children_with(&mut *self.with_ctx(ctx));
}

if cfg!(feature = "debug") && self.debug_inifinite_loop {
if cfg!(feature = "debug") && self.debug_infinite_loop {
let text = dump(&*s);

if text.lines().count() < 10 {
Expand Down Expand Up @@ -501,7 +501,7 @@ where
_ => {}
}

if cfg!(feature = "debug") && self.debug_inifinite_loop {
if cfg!(feature = "debug") && self.debug_infinite_loop {
let text = dump(&*s);

if text.lines().count() < 10 {
Expand Down
23 changes: 23 additions & 0 deletions ecmascript/minifier/src/compress/util/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -593,3 +593,26 @@ where
{
node.visit_mut_with(&mut ExprReplacer { op })
}

pub(super) fn is_fine_for_if_cons(s: &Stmt) -> bool {
match s {
Stmt::Decl(Decl::Fn(FnDecl {
ident:
Ident {
sym: js_word!("undefined"),
..
},
..
})) => false,

Stmt::Decl(
Decl::Var(VarDecl {
kind: VarDeclKind::Var,
..
})
| Decl::Fn(..),
) => true,
Stmt::Decl(..) => false,
_ => true,
}
}
162 changes: 162 additions & 0 deletions ecmascript/minifier/tests/compress/fixture/issues/vercel/006/input.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
import * as React from "react";
import invariant from "invariant";
import { injectScript } from "./utils/injectscript";
import { preventGoogleFonts } from "./utils/prevent-google-fonts";
import { isBrowser } from "./utils/isbrowser";
import { makeLoadScriptUrl } from "./utils/make-load-script-url";
let cleaningUp = false;
export function DefaultLoadingElement() {
return (/*#__PURE__*/ _jsx("div", {
children: `Loading...`
}));
}
export const defaultLoadScriptProps = {
id: "script-loader",
version: "weekly"
};
class LoadScript extends React.PureComponent {
componentDidMount() {
if (isBrowser) {
if (window.google && window.google.maps && !cleaningUp) {
console.error("google api is already presented");
return;
}
this.isCleaningUp().then(this.injectScript).catch(function error(err) {
console.error("Error at injecting script after cleaning up: ", err);
});
}
}
componentDidUpdate(prevProps) {
if (this.props.libraries !== prevProps.libraries) {
console.warn("Performance warning! LoadScript has been reloaded unintentionally! You should not pass `libraries` prop as new array. Please keep an array of libraries as static class property for Components and PureComponents, or just a const variable outside of component, or somewhere in config files or ENV variables");
}
if (isBrowser && prevProps.language !== this.props.language) {
this.cleanup();
// TODO: refactor to use gDSFP maybe... wait for hooks refactoring.
// eslint-disable-next-line react/no-did-update-set-state
this.setState(function setLoaded() {
return {
loaded: false
};
}, this.cleanupCallback);
}
}
componentWillUnmount() {
if (isBrowser) {
this.cleanup();
const timeoutCallback = () => {
if (!this.check.current) {
// @ts-ignore
delete window.google;
cleaningUp = false;
}
};
window.setTimeout(timeoutCallback, 1);
if (this.props.onUnmount) {
this.props.onUnmount();
}
}
}
render() {
return (/*#__PURE__*/ _jsxs(_Fragment, {
children: [
/*#__PURE__*/ _jsx("div", {
ref: this.check
}),
this.state.loaded ? this.props.children : this.props.loadingElement || /*#__PURE__*/ _jsx(DefaultLoadingElement, {
})
]
}));
}
constructor(...args) {
super(...args);
this.check = /*#__PURE__*/ React.createRef();
this.state = {
loaded: false
};
this.cleanupCallback = () => {
// @ts-ignore
delete window.google.maps;
this.injectScript();
};
this.isCleaningUp = async () => {
function promiseCallback(resolve) {
if (!cleaningUp) {
resolve();
} else {
if (isBrowser) {
const timer = window.setInterval(function interval() {
if (!cleaningUp) {
window.clearInterval(timer);
resolve();
}
}, 1);
}
}
return;
}
return new Promise(promiseCallback);
};
this.cleanup = () => {
cleaningUp = true;
const script1 = document.getElementById(this.props.id);
if (script1 && script1.parentNode) {
script1.parentNode.removeChild(script1);
}
Array.prototype.slice.call(document.getElementsByTagName("script")).filter(function filter(script) {
return typeof script.src === "string" && script.src.includes("maps.googleapis");
}).forEach(function forEach(script) {
if (script.parentNode) {
script.parentNode.removeChild(script);
}
});
Array.prototype.slice.call(document.getElementsByTagName("link")).filter(function filter(link) {
return link.href === "https://fonts.googleapis.com/css?family=Roboto:300,400,500,700|Google+Sans";
}).forEach(function forEach(link) {
if (link.parentNode) {
link.parentNode.removeChild(link);
}
});
Array.prototype.slice.call(document.getElementsByTagName("style")).filter(function filter(style) {
return style.innerText !== undefined && style.innerText.length > 0 && style.innerText.includes(".gm-");
}).forEach(function forEach(style) {
if (style.parentNode) {
style.parentNode.removeChild(style);
}
});
};
this.injectScript = () => {
if (this.props.preventGoogleFontsLoading) {
preventGoogleFonts();
}
invariant(!!this.props.id, 'LoadScript requires "id" prop to be a string: %s', this.props.id);
const injectScriptOptions = {
id: this.props.id,
nonce: this.props.nonce,
url: makeLoadScriptUrl(this.props)
};
injectScript(injectScriptOptions).then(() => {
if (this.props.onLoad) {
this.props.onLoad();
}
this.setState(function setLoaded() {
return {
loaded: true
};
});
return;
}).catch((err) => {
if (this.props.onError) {
this.props.onError(err);
}
console.error(`
There has been an Error with loading Google Maps API script, please check that you provided correct google API key (${this.props.googleMapsApiKey || "-"}) or Client ID (${this.props.googleMapsClientId || "-"}) to <LoadScript />
Otherwise it is a Network issue.
`);
});
};
}
}
LoadScript.defaultProps = defaultLoadScriptProps;
export default LoadScript;
Loading