在生产分发文件中删除一些代码行?

21

我正在使用BabelWebpackES6代码生成ES5代码。这里有一些验证可以帮助我减少编码时的错误。

class Logger {
    /**
     * @param {LogModel} info
     *  {LogTypes} type
     *  {String} message
     *  {Date} date
     */
    static log(info) {
        if(info instanceof LogModel)
            throw new Error("not a instance of LogModel");

        notify(info);
    }
}

log函数中,我会验证参数是否为LogModel类的实例,这只是为了防止错误。我不想在生产环境中有那么多的if判断语句,因为这会导致应用程序变慢。是否可以通过BabelWebpack生成具有验证功能的开发版本以及没有这些验证的生产版本?

6个回答

36

看起来其他答案已经过时了。在Webpack 4中,您可以在Webpack配置中设置mode: 'production'

在您的代码中,像这样检查开发模式:

if (process.env.NODE_ENV === 'development') {
    if(info instanceof LogModel)
        throw new Error("not a instance of LogModel");
}
当webpack使用mode: 'production'创建捆绑包时,所有这些if语句内部的代码和if语句本身将自动从捆绑包中删除。无需显式地使用define插件(它在webpack“底层”中使用),也不需要使用像其他答案中提到的webpack-unassert-loaderwebpack-strip-block之类的东西。请查看我制作的这个小演示库:https://github.com/pahund/webpack-devprod-experiment

4
Webpack不会从编译后的代码中移除if代码块。 - s1n7ax
1
我的错。由于某种原因,Webpack无法覆盖env.NODE_ENV。 - s1n7ax
2
如果您不想剥离该块中的所有代码,那该怎么办呢?webpack-strip-block 似乎可以给您更多的控制。 - Tamb
1
@Tamb 所有在那个代码块中的代码都被 webpack 剥离了。 - Patrick Hund
1
我相信在webpack内部,使用ConstPluginif...语句解析为简单的true/false。您可以使用DefinePlugin这个内部webpack插件来实现这种行为。该页面还包含一个非常简单的示例,说明如何使用。 - Alexander Kucheryuk
显示剩余6条评论

10

webpack-strip-block是一个不错的解决方案,它可以在编译时从你的生产代码中移除一段代码块。

/* develblock:start */
/* develblock:end */

不仅限于assert,且生产环境中没有多余的代码。


使用webpack 4,这不再是必需的,它通过 mode 配置和 process.env.NODE_ENV 内置支持。 - Patrick Hund
4
即使使用了 mode = production,Webpack 仍然不会移除开发时的代码。 - Andrey Izman

9
更清晰的选择是使用webpack中的define-plugin
在配置文件中: new webpack.DefinePlugin({ __DEV: JSON.stringify(true) })

app.js:

如果是开发环境,那么只会在控制台输出"logged only in dev env",__DEV的值将由webpack在编译时提供。

1
在你的例子中,__DEV 似乎总是为 true。难道不应该是 JSON.stringify(process.env.NODE_ENV === 'development') 吗? - Devin Rhode
如果使用 eslint,您可能还需要在您的 .eslintrc 文件中添加 "globals": { "__DEV": true }。否则,eslint 可能会抱怨:error '__DEV' is not defined no-undef - Martin_W

6
你可以使用assert包来强制执行代码,然后使用webpack-unassert-loaderwebpack-strip-assert来删除生产代码中的断言。
var assert = require('assert').ok;

class Logger {
    /**
     * @param {LogModel} info
     *  {LogTypes} type
     *  {String} message
     *  {Date} date
     */
    static log(info) {
        assert(info instanceof LogModel, "Param must be an instance of LogModel");
        notify(info);
    }
}

1
我采用了这种方法,因为我希望在生产中从源代码中完全删除断言。然而,在Webpack 4中,webpack-strip-assert会抛出一个错误。我改用了string-replace-webpack-plugin插件,并使用替换模式/\n[ \t]*assert\([^\);]+[\)\s]+[ \t]*[;\n]/g - Alex Walker

2
这里有一些不错的选择,但我认为我们可以做得更好。如果您想完全删除Logger.log()函数以及调用它的语句,例如:
Logger.log('Remove me');

如果我们需要做到这一点,那么string-replace-loader可以满足我们的需求!

安装 string-replace-loader

npm install --save-dev string-replace-loader

然后,在你的Webpack配置文件中:
...
    module: {
        rules: [
            //Replace strings
            {
                test: /\.js$/,
                loader: 'string-replace-loader',
                options: {
                    multiple: [
                        //Remove calls to Logger.log()
                        {
                            search: /Logger\.log\s*\(.*?\);?\s*?\n/g,
                            replace: '\n'
                        },
                        //Remove the actual Logger.log() function. This regex may need tweaking depending on your actual code for `log()`.
                        {
                            search: /static\s*log\s*\([^}]*}/gs,
                            replace: ''
                        }
                    ]
                }
            }
        ]
    },
...

不需要在实际源代码中添加额外的无意义代码。尽情享受吧!

感谢这个答案指引我朝着正确的方向前进(尽管是一个过时的插件)。 - rinogo
1
我尝试了几个选项,但这个解决方案最好,因为它可以保持代码的清晰。我发现唯一的限制是 Logger.log(...) 调用不能包含换行符。 - Waruyama

2

1
string-replace-webpack-plugin 是一个很好的建议,但它已经不再维护,并且在较新的Webpack版本中已经失效。 - rinogo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接