前言#
由于uniapp底层在setData之前对数据做了一层diff处理,导致开发时一些问题很难去找到具体地方,所以决定去改下源码的地方,log下diff前后的数据。但最后发现,原来官方有提供DEBUG的入口。
入口#
这里先简单的说下项目启动时的入口(仅mp-weixin)
如果你直接去跟着入口调试,你会发现你压根找不到你想找的代码,因为它实际上自己是一个plugin,注入到vue-cli-serve中。当然,如果你去log所有的plugin就可以看到它。
先来看下package.json里的mp-weixin:dev

这个uni-build很关键,我们直接去到@dcloudio包中找,这里有一个vue-cli-plugin-uni很可疑,点击去看bin/commands,果然,很眼熟。

直接点进去build,果然,这里有我们想要的uni-build

然后线索又断了,但是我们有无敌的vscode debug,我们来看下调用堆栈里是谁调用了它,原来在vue-cli-plugin-uni/index.js中被引入

然后我们顺着这里往下看,这里有一段很可疑的代码,涉及到mp
const type = ['app-plus', 'h5'].includes(process.env.UNI_PLATFORM)
? process.env.UNI_PLATFORM
: 'mp'
const platformOptions = require('./lib/' + type)来看下数据

我们顺着逻辑进到lib/mp/index.js中看下,一看到output字段就很熟悉了,原来这里放的是mp build时需要的config
module.exports = {
vueConfig: {
parallel: false
},
webpackConfig (webpackConfig, vueOptions, api) {
...省略
webpackConfig.optimization.runtimeChunk = {
name: 'common/runtime'
}
...省略
const output = {
pathinfo: true,
filename: '[name].js',
chunkFilename: '[id].js',
globalObject: process.env.UNI_PLATFORM === 'mp-alipay' ? 'my' : 'global'
// sourceMapFilename: '../.sourcemap/' + process.env.UNI_PLATFORM + '/[name].js.map'
}
if (process.env.NODE_ENV === 'production' || process.env.UNI_MINIMIZE === 'true') {
output.pathinfo = false
}
return {
mode: process.env.NODE_ENV === 'production' ? 'production'
: 'development',
entry () {
return process.UNI_ENTRY
},
output,
performance: {
hints: false
},
resolve: {
extensions: ['.nvue'],
alias
},
module: {
rules: [{
test: path.resolve(process.env.UNI_INPUT_DIR, getMainEntry()),
use: [{
loader: path.resolve(__dirname, '../../packages/wrap-loader'),
options: {
before: [
beforeCode + require('../util').getAutomatorCode() + statCode
]
}
}, {
loader: '@dcloudio/webpack-uni-mp-loader/lib/main'
}]
}, {
resourceQuery: /vue&type=script/,
use: [{
loader: '@dcloudio/webpack-uni-mp-loader/lib/script'
}]
}, {
resourceQuery: /vue&type=template/,
use: [{
loader: '@dcloudio/webpack-uni-mp-loader/lib/template'
}, {
loader: '@dcloudio/vue-cli-plugin-uni/packages/webpack-uni-app-loader/page-meta'
}]
}, createTemplateCacheLoader(api), {
resourceQuery: [
/lang=wxs/,
/lang=filter/,
/lang=sjs/,
/blockType=wxs/,
/blockType=filter/,
/blockType=sjs/
],
use: [{
loader: require.resolve(
'@dcloudio/vue-cli-plugin-uni/packages/webpack-uni-filter-loader')
}]
}]
},
plugins
}
...省略
}
}就不分析代码了,不过这里有一段代码十分重要,一看到runtime我们就眼睛放光,这个common/runtime 也不陌生,如果你看过build之后的文件目录你就会发现存在这一个文件
webpackConfig.optimization.runtimeChunk = {
name: 'common/runtime'
}
是的,这就是我们要找的目标,但是build之后代码是经过编译/压缩之后的,所以很难在里面进行调试,我们还是得去找到对应的文件才行。
然后我们还在代码中发现了一个方法getProvides,里面也涉及到runtime
const uniPath = require('@dcloudio/uni-cli-shared/lib/platform').getMPRuntimePath()来看下数据

是一个路径,那么我们顺着这个路径去到对应文件中uni-mp-weixin/dist/index.js
代码太长太多,这里就简单说下,是的,这个也是个runtime,你可以清晰的看到和小程序相关的代码,比如
const componentOptions = {
options,
data: initData(vueOptions, Vue.prototype),
behaviors: initBehaviors(vueOptions, initBehavior),
properties: initProperties(vueOptions.props, false, vueOptions.__file),
lifetimes: {
attached () {
...省略
},
ready () {
...省略
},
detached () {
this.$vm && this.$vm.$destroy();
}
},
pageLifetimes: {
show (args) {
this.$vm && this.$vm.__call_hook('onPageShow', args);
},
hide () {
this.$vm && this.$vm.__call_hook('onPageHide');
},
resize (size) {
this.$vm && this.$vm.__call_hook('onPageResize', size);
}
},
...省略
}; 但你会发现这里面并没有我们想要的common/runtime,为什么呢?看文件夹的名字就知道的,一个是common,另一个是mp-weixin,说明common/runtime是一个通用的mp runtime 。而这个mp-weixin的runtime只是小程序自己的。
那么线索又断了,我们怎么知道common/runtime打包前在哪呢?既然是runtime,那就肯定会参与打包,所以肯定在这build的流程中,我们可以注意到这个runtime和main.js是邻居,都在common文件夹下,这说明它很有可能是和entry入口一样最早被打包的文件。

不过我们也不知道这个main打包的位置,这就很尴尬。让我们回到配置config中,看下entry
entry () {
return process.UNI_ENTRY
}, 这里突然发现居然是每个文件单独做一个入口,即多入口

但是这里面依旧没有我们想要的common/untime,那么这个runtime相关的文件就是在entry之前做的打包,接着我发现config.module有单独对main的入口做特殊配置
module: {
rules: [{
test: path.resolve(process.env.UNI_INPUT_DIR, getMainEntry()),
use: [{
loader: path.resolve(__dirname, '../../packages/wrap-loader'),
options: {
before: [
beforeCode + require('../util').getAutomatorCode() + statCode
]
}
}, {
loader: '@dcloudio/webpack-uni-mp-loader/lib/main'
}]
}
...省略 test指向src/main.js/tswrap-loader: 没什么好分析的,就对代码进行小调整beforeCode:

getAutomatorCode: 这里面引得uni-mp-weixin/automator.js经过压缩处理,已经看不出是啥了。。webpack-uni-mp-loader: 这里面也没什么好说的,就是判断不同打包类型做特殊处理。
好家伙,线索又断了。没办法,我们只能回到build里看下还有哪里值得深入的
const webpackConfigs = getWebpackConfigs(api, args, options) 这一句和webpack有关的,我们先看下数据,都是config相关。

然后继续往下看
// resolve raw webpack config
const webpackConfig = require('@vue/cli-service/lib/commands/build/resolveAppConfig')(api, args, options)这里面就已经是进入到和vue-cli打包相关的内容了,所以我这里将省略掉其它文件,顺着调用关系进入到node_modules\@dcloudio\vue-cli-plugin-uni\lib\configure-webpack.js中,这里面调用了一个方法getPlatformVue,点进去一看,发现是一个引用路径'@dcloudio/vue-cli-plugin-uni/packages/mp-vue'

然后点进去mp.runtime.esm.js你就会发现中大奖了,这就是我们一直在找的runtime
这一段没头没脑的。。。。 但是分析这块实在是太绕了,说完估计人都晕了。
开启调试#

你会发现官方实际上在这里留了调试入口,只需要在env文件中配置VUE_APP_DEBUG = true即可看到数据变化

虽然是以字符串的形式,如果你想看json格式的,可以自行改动这块的代码,只是记得不要带上dep中。
发布于 2022-09-26 15:09
