最近刚遇到个问题,我要给自己做的网站加个无限 debugger 反爬,网站是基于 Vue.js 开发的,比如我就想在 main.js 里面加这么一段:
setInterval(() => {
debugger
console.log('debugger')
}, 1000)
当时在 Debug 环境下一切好好的,但是到了 build 之后,再运行发现 debugger 就没了,这就神奇了。
我搜了很久,最后终于找到了解决方案,这里记录下。
开发环境和生产环境
这里首先说下 Vue.js 是有开发环境和生产环境之分的,这里它用了一个关键词,叫做 mode。
我们先来看看两个常用的命令:
npm run serve
npm run build
这两个命令如果大家开发 Vue.js 的话一定不会陌生,但它们是怎么实现的呢?
顺着一找,其实他们定义在了 package.json 里面,是这样的:
{
"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:
npm install -g @vue/cli
# OR
yarn global add @vue/cli
它提供了 vue-cli-service
这个命令。
然后我们再来详细看看这个 serve 和 build 命令。
serve
用法如下:
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
用法如下:
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。
比如前者可以这么配置:
module.exports = {
configureWebpack: {
plugins: [
new MyAwesomeWebpackPlugin()
]
}
}
后者可以这么配置:
// 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 里面:
"terser-webpack-plugin": "^4.2.3",
然后:
npm install
接着 vue.config.js 改写如下:
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 语句就不会丢了。