当使用继承缩小/ uglification ES6代码时,Webpack会删除类名

时间:2018-04-01 12:54:14

标签: javascript node.js webpack uglifyjs uglifyjs2

当使用继承缩小/丑化ES6代码时,Webpack会删除类名

我们尝试缩小/ uglify的MVCE代码:

班级儿童

const ParentClass = require('parent');

class Child extends ParentClass{
    constructor(){
        super();
    }
}

module.exports = Child;

index.js 调用Child类:

const Child = require('./classes_so/child');

let child = new Child();

console.log(child.constructor.name);
node_modules内的

模块父级

class Parent {
    constructor() {
        if (this.constructor.name === 'Parent'){
            throw new TypeError("Parent class is abstract - cant be instance");
        }
    }

}

module.exports = Parent;

整个输出我将发布到问题的结尾,这里我只想发布我认为导致错误行为的相关行(原始输出的第33-37行):

n.exports = class extends r {
        constructor() {
            super();
        }
    };

为什么此处缺少 classname class extends r?我希望这个价值会被破坏但是会存在,我可以把它看成是一个错误吗?我尝试使用keep_classnames标志,但它保留了原始的类名,这是不可接受的。

我们正在使用

  • Webpack:3.11.0(尝试4,相同的行为)
  • uglifyjs-webpack-plugin:1.2.4(尝试使用不同的插件)
  • NodeJS:v6.9.1和v8.9.1(相同输出)
  • 展示问题的完整项目:webpack-uglify-inheritence

更新1

我们的webpack.config.js

const webpack = require('webpack');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
const path = require('path');
const fs = require('fs');

const nodeModules = {};
const localDependencies = ['.bin'];
fs.readdirSync('node_modules')
    .filter(function (x) {
        return localDependencies.indexOf(x) === -1;
    })
    .forEach(function (mod) {
        nodeModules[mod] = 'commonjs ' + mod;
    });

try {


    module.exports = {
        target: 'node',
        node: {
            console: false,
            global: false,
            process: false,
            Buffer: false,
            __filename: true,
            __dirname: true
        },

        entry: './index_so.js',

        output: {
            path: path.join(__dirname, 'build'),
            filename: 'index.js'
        },

        externals: nodeModules,
        plugins: [
            new webpack.IgnorePlugin(/\.(css|less)$/),
            new webpack.BannerPlugin({
                banner: 'require("source-map-support").install();',
                raw: true,
                entryOnly: false
            })
        ],
        devtool: 'sourcemap',

        module: {
            loaders: [
                {test: /\.json$/, loader: "json-loader"}
            ]
        },

        plugins: [
            new UglifyJsPlugin({
                uglifyOptions: {
                    compress: {
                        warnings: false
                    },
                    keep_classnames: false,
                    mangle: true,
                    output: {
                        beautify: true
                    }
                }
            })
        ]
    };
}
catch (e) {
    console.error(e);
}

上述示例中的整个缩小/未经授权的代码:

!function(n) {
    var t = {};
    function e(r) {
        if (t[r]) return t[r].exports;
        var o = t[r] = {
            i: r,
            l: !1,
            exports: {}
        };
        return n[r].call(o.exports, o, o.exports, e), o.l = !0, o.exports;
    }
    e.m = n, e.c = t, e.d = function(n, t, r) {
        e.o(n, t) || Object.defineProperty(n, t, {
            configurable: !1,
            enumerable: !0,
            get: r
        });
    }, e.n = function(n) {
        var t = n && n.__esModule ? function() {
            return n.default;
        } : function() {
            return n;
        };
        return e.d(t, "a", t), t;
    }, e.o = function(n, t) {
        return Object.prototype.hasOwnProperty.call(n, t);
    }, e.p = "", e(e.s = 0);
}([ function(n, t, e) {
    let r = new (e(1))();
    console.log(r.constructor.name);
}, function(n, t, e) {
    const r = e(2);
    n.exports = class extends r {
        constructor() {
            super();
        }
    };
}, function(n, t) {
    n.exports = require("parent");
} ]);

2 个答案:

答案 0 :(得分:3)

给定设置中的问题不在webpack或uglify的代码中,而是在这部分代码中:

class Parent {
  constructor() {
    if (this.constructor.name === 'Parent') {
      throw new TypeError("Parent class is abstract - cant be instance");
    }
  }

}

module.exports = Parent;

this.constructor.name === 'Parent' / class名称上的function个中继,用于测试Parent是否直接实例化。

不是将一个名称转发给可能导致各种问题的名称,而是测试构造函数是否等于该类更好。

class Parent {
  constructor() {
    if (this.constructor === Parent) {
      throw new TypeError("Parent class is abstract - cant be instance");
    }
  }

}

module.exports = Parent;

答案 1 :(得分:0)

尝试我的lib typescript-class-helpers

import { CLASS } from 'typescript-class-helpers/browser';

@CLASS.NAME('Parent')
class Parent {
    constructor() {
        if (CLASS.getNameFromObject(child) === 'Parent'){
            throw new TypeError("Parent class is abstract - cant be instance");
        }
    }

}

@CLASS.NAME('Child')
class Child extends ParentClass{
    constructor(){
        super();
    }
}

let child = new Child();

console.log(CLASS.getNameFromObject(child)); // Child

使用此方法,您可以缩小班级名称,一切都会好起来的。