Skip to content

Commit fd5d2e2

Browse files
authored
feat(es/minifeir): Inline lazily initialized literals (#10752)
**Related issue:** - Closes #10746
1 parent 4976b12 commit fd5d2e2

File tree

17 files changed

+104
-55
lines changed

17 files changed

+104
-55
lines changed

crates/swc_ecma_minifier/scripts/test.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ export SWC_RUN=0
88

99
touch tests/compress.rs
1010

11-
UPDATE=1 cargo test -p swc_ecma_minifier -p swc --test size
11+
RUST_LOG=off UPDATE=1 cargo test -p swc_ecma_minifier -p swc --test size
1212
cargo test -p swc_ecma_minifier -p swc --no-fail-fast --test projects --test tsc --test compress --test mangle --features concurrent $@
1313

1414
# find ../swc/tests/ -type f -empty -delete

crates/swc_ecma_minifier/src/compress/optimize/inline.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,14 @@ impl Optimizer<'_> {
259259

260260
Expr::Lit(lit) => match lit {
261261
Lit::Str(s) => {
262-
if ref_count == 1 || s.value.len() <= 3 {
262+
// If the string literal is declared without initializer and assigned
263+
// once, we can inline it.
264+
if (ref_count == 1
265+
|| (ref_count == 2
266+
&& usage.assign_count == 1
267+
&& usage.flags.intersects(VarUsageInfoFlags::LAZY_INIT)))
268+
|| s.value.len() <= 3
269+
{
263270
true
264271
} else {
265272
self.vars

crates/swc_ecma_minifier/src/program_data.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,8 @@ bitflags::bitflags! {
8888
/// `a` in `foo(<a />)`
8989
const USED_AS_JSX_CALLEE = 1 << 24;
9090

91+
/// The variable is declared without initializer.
92+
const LAZY_INIT = 1 << 25;
9193
}
9294

9395
#[derive(Debug, Default, Clone, Copy)]
@@ -581,6 +583,10 @@ impl VarDataLike for VarUsageInfo {
581583
self.flags.insert(VarUsageInfoFlags::DECLARED_AS_FN_PARAM);
582584
}
583585

586+
fn mark_as_lazy_init(&mut self) {
587+
self.flags.insert(VarUsageInfoFlags::LAZY_INIT);
588+
}
589+
584590
fn mark_declared_as_fn_decl(&mut self) {
585591
self.flags.insert(VarUsageInfoFlags::DECLARED_AS_FN_DECL);
586592
}

crates/swc_ecma_minifier/src/util/mod.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ pub trait ModuleItemExt:
2929
{
3030
fn as_module_decl(&self) -> Result<&ModuleDecl, &Stmt>;
3131

32+
fn as_module_decl_mut(&mut self) -> Result<&mut ModuleDecl, &mut Stmt>;
33+
3234
fn from_module_item(item: ModuleItem) -> Self;
3335

3436
fn into_module_item(self) -> ModuleItem {
@@ -46,6 +48,10 @@ impl ModuleItemExt for Stmt {
4648
Err(self)
4749
}
4850

51+
fn as_module_decl_mut(&mut self) -> Result<&mut ModuleDecl, &mut Stmt> {
52+
Err(self)
53+
}
54+
4955
fn from_module_item(item: ModuleItem) -> Self {
5056
item.expect_stmt()
5157
}
@@ -63,6 +69,13 @@ impl ModuleItemExt for ModuleItem {
6369
}
6470
}
6571

72+
fn as_module_decl_mut(&mut self) -> Result<&mut ModuleDecl, &mut Stmt> {
73+
match self {
74+
ModuleItem::ModuleDecl(v) => Ok(v),
75+
ModuleItem::Stmt(v) => Err(v),
76+
}
77+
}
78+
6679
fn from_module_item(item: ModuleItem) -> Self {
6780
item
6881
}

crates/swc_ecma_minifier/tests/benches-full/echarts.js

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
3535
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
3636
PERFORMANCE OF THIS SOFTWARE.
37-
***************************************************************************** */ /* global Reflect, Promise */ var ua, browser, firefox, ie, edge, weChat, style, mouseHandlerNames, pointerEventNameMap, pointerHandlerNames, classAttr, subTypeDefaulters, _super, mainType, creator, _ctx, _cachedFont, requestAnimationFrame, reCreateSeriesIndices, assertSeriesInitialized, initBase, _a, _b, _c, providerMethods, mountMethods, seriesType, nodeParsers, prepare, prepareView, updateDirectly, updateMethods, doConvertPixel, updateStreamModes, doDispatchAction, flushPendingActions, triggerUpdatedEvent, bindRenderedEvent, bindMouseEvent, clearColorPalette, render, renderComponents, renderSeries, performPostUpdateFuncs, createExtensionAPI, enableConnect, setTransitionOpt, markStatusToUpdate, applyChangedStates, defaultDimValueGetters, prepareInvertedIndex, getIndicesCtor, prepareStorage, getRawIndexWithoutIndices, getRawIndexWithIndices, getId, getIdNameFromStore, makeIdFromName, normalizeDimensions, validateDimensions, cloneListForMapAndSample, getInitialExtent, setItemDataAndSeriesIndex, transferProperties, checkNonStyleTansitionRefer, checkTransformPropRefer, extendStatics = function(d, b) {
37+
***************************************************************************** */ /* global Reflect, Promise */ var ua, browser, firefox, ie, edge, weChat, style, mouseHandlerNames, pointerEventNameMap, pointerHandlerNames, classAttr, subTypeDefaulters, _super, creator, _ctx, _cachedFont, requestAnimationFrame, reCreateSeriesIndices, assertSeriesInitialized, initBase, _a, _b, _c, providerMethods, mountMethods, seriesType, nodeParsers, prepare, prepareView, updateDirectly, updateMethods, doConvertPixel, updateStreamModes, doDispatchAction, flushPendingActions, triggerUpdatedEvent, bindRenderedEvent, bindMouseEvent, clearColorPalette, render, renderComponents, renderSeries, performPostUpdateFuncs, createExtensionAPI, enableConnect, setTransitionOpt, markStatusToUpdate, applyChangedStates, defaultDimValueGetters, prepareInvertedIndex, getIndicesCtor, prepareStorage, getRawIndexWithoutIndices, getRawIndexWithIndices, getId, getIdNameFromStore, makeIdFromName, normalizeDimensions, validateDimensions, cloneListForMapAndSample, getInitialExtent, setItemDataAndSeriesIndex, transferProperties, checkNonStyleTansitionRefer, checkTransformPropRefer, extendStatics = function(d, b) {
3838
return (extendStatics = Object.setPrototypeOf || ({
3939
__proto__: []
4040
}) instanceof Array && function(d, b) {
@@ -41507,7 +41507,7 @@
4150741507
}; // If both `xAxisIndex` `xAxisId` not set, it means 'all'.
4150841508
return null == setting.xAxisIndex && null == setting.xAxisId && (setting.xAxisIndex = 'all'), null == setting.yAxisIndex && null == setting.yAxisId && (setting.yAxisIndex = 'all'), setting;
4150941509
}
41510-
mainType = 'dataZoom', creator = function(ecModel) {
41510+
creator = function(ecModel) {
4151141511
var toolboxModel = ecModel.getComponent('toolbox', 0);
4151241512
if (toolboxModel) {
4151341513
var dzFeatureModel = toolboxModel.getModel([
@@ -41531,7 +41531,7 @@
4153141531
};
4153241532
newOpt[axisIndexPropName] = axisIndex, dzOptions.push(newOpt);
4153341533
}
41534-
}, assert(null == internalOptionCreatorMap.get(mainType) && creator), internalOptionCreatorMap.set(mainType, creator);
41534+
}, assert(null == internalOptionCreatorMap.get('dataZoom') && creator), internalOptionCreatorMap.set('dataZoom', creator);
4153541535
var TooltipModel = /** @class */ function(_super) {
4153641536
function TooltipModel() {
4153741537
var _this = null !== _super && _super.apply(this, arguments) || this;
@@ -41728,8 +41728,8 @@
4172841728
// this.hide();
4172941729
}, TooltipHTMLContent.prototype.show = function(tooltipModel, nearPointColor) {
4173041730
clearTimeout(this._hideTimeout), clearTimeout(this._longHideTimeout);
41731-
var enableTransition, onlyFade, cssText, transitionDuration, backgroundColor, shadowBlur, shadowColor, shadowOffsetX, shadowOffsetY, textStyleModel, padding, boxShadow, transitionCurve, transitionOption, transitionText, cssText1, fontSize, color, shadowColor1, shadowBlur1, shadowOffsetX1, shadowOffsetY1, el = this.el, style = el.style, styleCoord = this._styleCoord;
41732-
el.innerHTML ? style.cssText = gCssText + (enableTransition = !this._firstShow, onlyFade = this._longHide, cssText = [], transitionDuration = tooltipModel.get('transitionDuration'), backgroundColor = tooltipModel.get('backgroundColor'), shadowBlur = tooltipModel.get('shadowBlur'), shadowColor = tooltipModel.get('shadowColor'), shadowOffsetX = tooltipModel.get('shadowOffsetX'), shadowOffsetY = tooltipModel.get('shadowOffsetY'), textStyleModel = tooltipModel.getModel('textStyle'), padding = getPaddingFromTooltipModel(tooltipModel, 'html'), boxShadow = shadowOffsetX + "px " + shadowOffsetY + "px " + shadowBlur + "px " + shadowColor, cssText.push('box-shadow:' + boxShadow), enableTransition && transitionDuration && cssText.push((transitionText = "opacity" + (transitionOption = " " + transitionDuration / 2 + "s " + (transitionCurve = 'cubic-bezier(0.23,1,0.32,1)')) + ",visibility" + transitionOption, onlyFade || (transitionOption = " " + transitionDuration + "s " + transitionCurve, transitionText += env.transformSupported ? "," + TRANSFORM_VENDOR + transitionOption : ",left" + transitionOption + ",top" + transitionOption), CSS_TRANSITION_VENDOR + ':' + transitionText)), backgroundColor && (env.canvasSupported ? cssText.push('background-color:' + backgroundColor) : (// for ie
41731+
var enableTransition, onlyFade, cssText, transitionDuration, backgroundColor, shadowBlur, shadowColor, shadowOffsetX, shadowOffsetY, textStyleModel, padding, boxShadow, transitionOption, transitionText, cssText1, fontSize, color, shadowColor1, shadowBlur1, shadowOffsetX1, shadowOffsetY1, el = this.el, style = el.style, styleCoord = this._styleCoord;
41732+
el.innerHTML ? style.cssText = gCssText + (enableTransition = !this._firstShow, onlyFade = this._longHide, cssText = [], transitionDuration = tooltipModel.get('transitionDuration'), backgroundColor = tooltipModel.get('backgroundColor'), shadowBlur = tooltipModel.get('shadowBlur'), shadowColor = tooltipModel.get('shadowColor'), shadowOffsetX = tooltipModel.get('shadowOffsetX'), shadowOffsetY = tooltipModel.get('shadowOffsetY'), textStyleModel = tooltipModel.getModel('textStyle'), padding = getPaddingFromTooltipModel(tooltipModel, 'html'), boxShadow = shadowOffsetX + "px " + shadowOffsetY + "px " + shadowBlur + "px " + shadowColor, cssText.push('box-shadow:' + boxShadow), enableTransition && transitionDuration && cssText.push((transitionText = "opacity" + (transitionOption = " " + transitionDuration / 2 + "s cubic-bezier(0.23,1,0.32,1)") + ",visibility" + transitionOption, onlyFade || (transitionOption = " " + transitionDuration + "s cubic-bezier(0.23,1,0.32,1)", transitionText += env.transformSupported ? "," + TRANSFORM_VENDOR + transitionOption : ",left" + transitionOption + ",top" + transitionOption), CSS_TRANSITION_VENDOR + ':' + transitionText)), backgroundColor && (env.canvasSupported ? cssText.push('background-color:' + backgroundColor) : (// for ie
4173341733
cssText.push('background-color:#' + toHex(backgroundColor)), cssText.push('filter:alpha(opacity=70)'))), each([
4173441734
'width',
4173541735
'color',
@@ -45467,8 +45467,8 @@
4546745467
}, SliderZoomView.prototype.dispose = function() {
4546845468
this._clear(), _super.prototype.dispose.apply(this, arguments);
4546945469
}, SliderZoomView.prototype._clear = function() {
45470-
(fn = this[fnAttr = '_dispatchZoomAction']) && fn[ORIGIN_METHOD] && (this[fnAttr] = fn[ORIGIN_METHOD]);
45471-
var fnAttr, fn, zr = this.api.getZr();
45470+
(fn = this._dispatchZoomAction) && fn[ORIGIN_METHOD] && (this._dispatchZoomAction = fn[ORIGIN_METHOD]);
45471+
var fn, zr = this.api.getZr();
4547245472
zr.off('mousemove', this._onBrush), zr.off('mouseup', this._onBrushEnd);
4547345473
}, SliderZoomView.prototype._buildView = function() {
4547445474
var thisGroup = this.group;
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
const ErrorResponse = (statusCode, message) => {
2+
return Response.json({
3+
message
4+
}, {
5+
status: statusCode
6+
});
7+
}
8+
9+
export const unknownError = ErrorResponse(520, "Unknown error.");
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
export const unknownError = Response.json({
2+
message: "Unknown error."
3+
}, {
4+
status: 520
5+
});

crates/swc_ecma_minifier/tests/fixture/issues/2257/full/output.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17717,7 +17717,7 @@
1771717717
});
1771817718
// EXTERNAL MODULE: ./node_modules/_@[email protected]@@babel/runtime/helpers/esm/inheritsLoose.js + 1 modules
1771917719
var inheritsLoose = __webpack_require__(48861), _react_17_0_2_react = __webpack_require__(59301), _prop_types_15_7_2_prop_types = __webpack_require__(68712), _prop_types_15_7_2_prop_types_default = /*#__PURE__*/ __webpack_require__.n(_prop_types_15_7_2_prop_types), esm_history = __webpack_require__(91520), commonjsGlobal = "undefined" != typeof globalThis ? globalThis : "undefined" != typeof window ? window : void 0 !== __webpack_require__.g ? __webpack_require__.g : {}, index = _react_17_0_2_react.createContext || function(defaultValue, calculateChangedBits) {
17720-
var key, _Provider$childContex, _Consumer$contextType, contextProp = "__create-react-context-" + (commonjsGlobal[key = "__global_unique_id__"] = (commonjsGlobal[key] || 0) + 1) + "__", Provider = /*#__PURE__*/ function(_Component) {
17720+
var _Provider$childContex, _Consumer$contextType, contextProp = "__create-react-context-" + (commonjsGlobal.__global_unique_id__ = (commonjsGlobal.__global_unique_id__ || 0) + 1) + "__", Provider = /*#__PURE__*/ function(_Component) {
1772117721
function Provider() {
1772217722
var _this, value, handlers;
1772317723
return _this = _Component.apply(this, arguments) || this, value = _this.props.value, handlers = [], _this.emitter = {

crates/swc_ecma_minifier/tests/fixture/issues/emotion/react/1/output.js

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -344,7 +344,6 @@
344344
* @param {number} length
345345
* @return {string}
346346
*/ function prefix(value, length) {
347-
var search, search1;
348347
switch((((length << 2 ^ Utility_charat(value, 0)) << 2 ^ Utility_charat(value, 1)) << 2 ^ Utility_charat(value, 2)) << 2 ^ Utility_charat(value, 3)){
349348
// color-adjust
350349
case 5103:
@@ -454,7 +453,7 @@
454453
return replace(value, /(.+:)(.+)-([^]+)/, "$1" + WEBKIT + "$2-$3$1" + MOZ + (108 == Utility_charat(value, length + 3) ? "$3" : "$2-$3")) + value;
455454
// (s)tretch
456455
case 115:
457-
return ~(search = "stretch", value.indexOf(search)) ? prefix(replace(value, "stretch", "fill-available"), length) + value : value;
456+
return ~value.indexOf("stretch") ? prefix(replace(value, "stretch", "fill-available"), length) + value : value;
458457
}
459458
break;
460459
// position: sticky
@@ -463,7 +462,7 @@
463462
if (115 !== Utility_charat(value, length + 1)) break;
464463
// display: (flex|inline-flex)
465464
case 6444:
466-
switch(Utility_charat(value, Utility_strlen(value) - 3 - (~(search1 = "!important", value.indexOf(search1)) && 10))){
465+
switch(Utility_charat(value, Utility_strlen(value) - 3 - (~value.indexOf("!important") && 10))){
467466
// stic(k)y
468467
case 107:
469468
return replace(value, ":", ":" + WEBKIT) + value;

crates/swc_ecma_minifier/tests/fixture/next/syncfusion/933-e9f9a6bf671b96fc/output.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7112,10 +7112,10 @@
71127112
function Engine() {}
71137113
return(// eslint-disable-next-line
71147114
Engine.prototype.compile = function(templateString, helper, ignorePrefix) {
7115-
var helper1, argName, str, nameSpace, helper2, ignorePrefix1, varCOunt, localKeys, isClass, singleSpace;
7116-
return void 0 === helper && (helper = {}), str = templateString, nameSpace = argName = 'data', helper2 = helper1 = helper, ignorePrefix1 = void 0, varCOunt = 0, localKeys = [], isClass = str.match(/class="([^"]+|)\s{2}/g), singleSpace = '', isClass && isClass.forEach(function(value) {
7115+
var helper1, str, nameSpace, helper2, ignorePrefix1, varCOunt, localKeys, isClass, singleSpace;
7116+
return void 0 === helper && (helper = {}), str = templateString, nameSpace = 'data', helper2 = helper1 = helper, ignorePrefix1 = void 0, varCOunt = 0, localKeys = [], isClass = str.match(/class="([^"]+|)\s{2}/g), singleSpace = '', isClass && isClass.forEach(function(value) {
71177117
singleSpace = value.replace(/\s\s+/g, ' '), str = str.replace(value, singleSpace);
7118-
}), Function(argName, "var str=\"" + str.replace(LINES, '').replace(DBL_QUOTED_STR, '\'$1\'').replace(exp, // eslint-disable-next-line
7118+
}), Function('data', "var str=\"" + str.replace(LINES, '').replace(DBL_QUOTED_STR, '\'$1\'').replace(exp, // eslint-disable-next-line
71197119
function(match, cnt, offset, matchStr) {
71207120
var matches = cnt.match(CALL_FUNCTION);
71217121
// matches to detect any function calls

0 commit comments

Comments
 (0)