0%

Vue生产环境如何还原debugger

最近刚遇到个问题,我要给自己做的网站加个无限 debugger 反爬,网站是基于 Vue.js 开发的,比如我就想在 main.js 里面加这么一段:

1
2
3
4
setInterval(() => {
debugger
console.log('debugger')
}, 1000)

当时在 Debug 环境下一切好好的,但是到了 build 之后,再运行发现 debugger 就没了,这就神奇了。

我搜了很久,最后终于找到了解决方案,这里记录下。

开发环境和生产环境

这里首先说下 Vue.js 是有开发环境和生产环境之分的,这里它用了一个关键词,叫做 mode。

我们先来看看两个常用的命令:

1
2
npm run serve
npm run build

这两个命令如果大家开发 Vue.js 的话一定不会陌生,但它们是怎么实现的呢?

顺着一找,其实他们定义在了 package.json 里面,是这样的:

1
2
3
4
5
6
7
8
9
10
{
"version": "0.1.0",
"private": true,
"scripts": {
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint"
},
...
}

这里其实就是调用了 vue-cli-service 的几个命令而已。

vue-cli-service 又是哪里来的呢?很简单,在刚开始初始化项目的时候装了个 Vue CLI:

1
2
3
npm install -g @vue/cli
# OR
yarn global add @vue/cli

它提供了 vue-cli-service 这个命令。

然后我们再来详细看看这个 serve 和 build 命令。

serve

用法如下:

1
2
3
4
5
6
7
8
9
10
11
12
Usage: vue-cli-service serve [options] [entry]

Options:

--open open browser on server start
--copy copy url to clipboard on server start
--mode specify env mode (default: development)
--host specify host (default: 0.0.0.0)
--port specify port (default: 8080)
--https use https (default: false)
--public specify the public network URL for the HMR client
--skip-plugins comma-separated list of plugin names to skip for this run

看到了吧,这里有个 mode,指的就是运行环境,这里默认为 development,即开发环境。

build

用法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Usage: vue-cli-service build [options] [entry|pattern]

Options:

--mode specify env mode (default: production)
--dest specify output directory (default: dist)
--modern build app targeting modern browsers with auto fallback
--no-unsafe-inline build app without introducing inline scripts
--target app | lib | wc | wc-async (default: app)
--formats list of output formats for library builds (default: commonjs,umd,umd-min)
--inline-vue include the Vue module in the final bundle of library or web component target
--name name for lib or web-component mode (default: "name" in package.json or entry filename)
--filename file name for output, only usable for 'lib' target (default: value of --name),
--no-clean do not remove the dist directory before building the project
--report generate report.html to help analyze bundle content
--report-json generate report.json to help analyze bundle content
--skip-plugins comma-separated list of plugin names to skip for this run
--watch watch for changes

这里也有一个 mode,默认就是 production 了,即生产环境。

所以,到这里我们就明白了,调用 build 命令之后,实际上是生产环境了,然后生产环境可能做了一些特殊的配置,把一些 debugger 给去除了,所以就没了。

还原

那咋还原呢?

这里我们就需要用到 Vue.js 的另外一个知识了。

Vue.js 同样是基于 Webpack 构建的,利用了 Webpack 的打包技术,不过为了更加方便开发者配置,Vue.js 在 Webpack 的基础上又封装了一层,一些配置我们不需要再实现 webpack.config.js 了,而是可以实现 vue.config.js,配置更加简单。

在 vue.config.js 里面,它为 Webpack 暴露了几个重要的配置入口,一个就是 configureWebpack,一个是 chainWebpack。

具体的教程大家可以参考官方文档:https://cli.vuejs.org/zh/guide/webpack.html。

比如前者可以这么配置:

1
2
3
4
5
6
7
module.exports = {
configureWebpack: {
plugins: [
new MyAwesomeWebpackPlugin()
]
}
}

后者可以这么配置:

1
2
3
4
5
6
7
8
9
10
11
12
// vue.config.js
module.exports = {
chainWebpack: config => {
config.module
.rule('vue')
.use('vue-loader')
.loader('vue-loader')
.tap(options => {
return options
})
}
}

这里,我们如果要修改 Webpack 构建的一些配置的话,可以利用 chainWebpack。

TerserPlugin

然后,这里又需要引入另外一个 Webpack 插件了,叫做 TerserPlugin,官方介绍链接为 https://webpack.js.org/plugins/terser-webpack-plugin/。

而这个库又是依赖 terser 的,官方介绍链接为 https://github.com/terser/terser。

官方介绍为:

A JavaScript parser and mangler/compressor toolkit for ES6+.

OK,反正就是类似一个 JavaScript 压缩转换器,比如它可以将一些 JavaScript 代码转码、混淆、压缩等等。

这里我们就需要借助于它来实现 debugger 的还原。

这里由于我使用的 Webpack 是 4.x 版本,所以 TerserPlugin 也需要是 4.x 版本,5.x 版本我测试过了不行。

安装配置如下,添加到 package.json 的 devDependencies 里面:

1
"terser-webpack-plugin": "^4.2.3",

然后:

1
npm install

接着 vue.config.js 改写如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
const TerserPlugin = require('terser-webpack-plugin')
module.exports = {
...
productionSourceMap: false,
chainWebpack: config => {
config.optimization.minimizer([
new TerserPlugin({
terserOptions: {
mangle: true,
compress: {
drop_debugger: false
}
}
})
]
)
}
}

这里我就保留了 chainWebpack 的配置,然后这里面通过 config 的 optimization 的 minimizer 方法配置了 plugins,然后这里 TerserPlugin 需要声明一个 terserOptions,然后 compress 里面的 drop_debugger 需要设置为 false。

这样,生产环境的 debugger 语句就不会丢了。