Skip to content

Commit 9b06716

Browse files
author
Guillaume Chau
committed
New _custom object API + component value support in state inspector
1 parent 5a6ef08 commit 9b06716

File tree

8 files changed

+121
-25
lines changed

8 files changed

+121
-25
lines changed

shells/dev/target/Date.vue renamed to shells/dev/target/NativeTypes.vue

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,26 +5,48 @@
55
<p>
66
<button @click="updateDate">Update Date</button>
77
</p>
8+
9+
<hr>
10+
11+
<TestComponent ref="component" />
12+
13+
<p>
14+
<button @click="sendComponent">Vuex mutation</button>
15+
</p>
816
</div>
917
</template>
1018

1119
<script>
1220
import { mapState, mapGetters, mapMutations } from 'vuex'
1321
1422
export default {
23+
components: {
24+
TestComponent: {
25+
data: () => ({ foo: '42' }),
26+
props: { bar: { default: 'hey' }},
27+
render: h => h('div', '<TestComponent />')
28+
}
29+
},
1530
data () {
1631
return {
17-
localDate: new Date()
32+
localDate: new Date(),
33+
testComponent: null
1834
}
1935
},
2036
computed: {
2137
...mapState(['date']),
2238
...mapGetters(['hours'])
2339
},
40+
mounted () {
41+
this.testComponent = this.$refs.component
42+
},
2443
methods: {
2544
...mapMutations({
2645
updateDate: 'UPDATE_DATE'
27-
})
46+
}),
47+
sendComponent () {
48+
this.$store.commit('TEST_COMPONENT', this.testComponent)
49+
}
2850
},
2951
filters: {
3052
prototypeString: val => Object.prototype.toString.call(val)

shells/dev/target/index.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import store from './store'
33
import Target from './Target.vue'
44
import Other from './Other.vue'
55
import Counter from './Counter.vue'
6-
import Date from './Date.vue'
6+
import NativeTypes from './NativeTypes.vue'
77
import Events from './Events.vue'
88
import MyClass from './MyClass.js'
99

@@ -23,7 +23,7 @@ new Vue({
2323
h(Target, {props:{msg: 'hi', ins: new MyClass()}}),
2424
h(Other),
2525
h(Events),
26-
h(Date)
26+
h(NativeTypes)
2727
])
2828
},
2929
data: {

shells/dev/target/store.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ export default new Vuex.Store({
1313
DECREMENT: state => state.count--,
1414
UPDATE_DATE: state => {
1515
state.date = new Date()
16-
}
16+
},
17+
TEST_COMPONENT: state => {}
1718
},
1819
getters: {
1920
isPositive: state => state.count >= 0,

src/backend/index.js

Lines changed: 37 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ const hook = window.__VUE_DEVTOOLS_GLOBAL_HOOK__
2121
const rootInstances = []
2222
const propModes = ['default', 'sync', 'once']
2323

24-
const instanceMap = window.__VUE_DEVTOOLS_INSTANCE_MAP__ = new Map()
24+
export const instanceMap = window.__VUE_DEVTOOLS_INSTANCE_MAP__ = new Map()
2525
const consoleBoundInstances = Array(5)
2626
let currentInspectedId
2727
let bridge
@@ -320,18 +320,46 @@ function getInstanceDetails (id) {
320320
return {
321321
id: id,
322322
name: getInstanceName(instance),
323-
state: processProps(instance).concat(
324-
processState(instance),
325-
processComputed(instance),
326-
processRouteContext(instance),
327-
processVuexGetters(instance),
328-
processFirebaseBindings(instance),
329-
processObservables(instance)
330-
)
323+
state: getInstanceState(instance)
331324
}
332325
}
333326
}
334327

328+
function getInstanceState (instance) {
329+
return processProps(instance).concat(
330+
processState(instance),
331+
processComputed(instance),
332+
processRouteContext(instance),
333+
processVuexGetters(instance),
334+
processFirebaseBindings(instance),
335+
processObservables(instance)
336+
)
337+
}
338+
339+
export function getCustomInstanceDetails (instance) {
340+
const state = getInstanceState(instance)
341+
return {
342+
_custom: {
343+
type: 'component',
344+
id: instance.__VUE_DEVTOOLS_UID__,
345+
display: getInstanceName(instance),
346+
state: reduceStateList(state)
347+
}
348+
}
349+
}
350+
351+
export function reduceStateList (list) {
352+
if (!list.length) {
353+
return undefined
354+
}
355+
return list.reduce((map, item) => {
356+
const key = item.type || 'data'
357+
const obj = map[key] = map[key] || {}
358+
obj[item.key] = item.value
359+
return map
360+
}, {})
361+
}
362+
335363
/**
336364
* Get the appropriate display name for an instance.
337365
*

src/devtools/components/DataField.vue

Lines changed: 45 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,14 @@
88
:class="{ rotated: expanded }"
99
v-show="isExpandableType">
1010
</span>
11-
<span class="key">{{ field.key }}</span>
12-
<span class="colon">:<div class="meta" v-if="field.meta">
11+
<span class="key" :class="{ special: field.noDisplay }">{{ field.key }}</span>
12+
<span class="colon"><span v-if="!field.noDisplay">:</span><div class="meta" v-if="field.meta">
1313
<div class="meta-field" v-for="(val, key) in field.meta">
1414
<span class="key">{{ key }}</span>
1515
<span class="value">{{ val }}</span>
1616
</div>
1717
</div></span>
18-
<span class="value" :class="valueType">{{ formattedValue }}</span>
18+
<span class="value" :class="valueClass">{{ formattedValue }}</span>
1919
</div>
2020
<div class="children" v-if="expanded && isExpandableType">
2121
<data-field
@@ -44,7 +44,7 @@ import {
4444
} from 'src/util'
4545
4646
const rawTypeRE = /^\[object (\w+)]$/
47-
const specialTypeRE = /^\[native \w+ (.*)\]$/
47+
const specialTypeRE = /^\[native (\w+) (.*)\]$/
4848
4949
function subFieldCount (value) {
5050
if (Array.isArray(value)) {
@@ -81,32 +81,41 @@ export default {
8181
value === NAN
8282
) {
8383
return 'literal'
84+
} else if (value && value._custom) {
85+
return 'custom'
8486
} else if (specialTypeRE.test(value)) {
85-
return 'native'
87+
const [, type] = specialTypeRE.exec(value)
88+
return `native ${type}`
8689
} else if (type === 'string' && !rawTypeRE.test(value)) {
8790
return 'string'
8891
}
8992
},
9093
isExpandableType () {
9194
const value = this.field.value
92-
return Array.isArray(value) || isPlainObject(value)
95+
return Array.isArray(value) ||
96+
(this.valueType === 'custom' && value._custom.state) ||
97+
(this.valueType !== 'custom' && isPlainObject(value))
9398
},
9499
formattedValue () {
95100
const value = this.field.value
96-
if (value === null) {
101+
if (this.field.noDisplay) {
102+
return ''
103+
} else if (value === null) {
97104
return 'null'
98105
} else if (value === UNDEFINED) {
99106
return 'undefined'
100107
} else if (value === NAN) {
101108
return 'NaN'
102109
} else if (value === INFINITY) {
103110
return 'Infinity'
111+
} else if (this.valueType === 'custom') {
112+
return value._custom.display
104113
} else if (Array.isArray(value)) {
105114
return 'Array[' + value.length + ']'
106115
} else if (isPlainObject(value)) {
107116
return 'Object' + (Object.keys(value).length ? '' : ' (empty)')
108-
} else if (this.valueType === 'native') {
109-
return specialTypeRE.exec(value)[1]
117+
} else if (this.valueType.includes('native')) {
118+
return specialTypeRE.exec(value)[2]
110119
} else if (typeof value === 'string') {
111120
var typeMatch = value.match(rawTypeRE)
112121
if (typeMatch) {
@@ -126,15 +135,29 @@ export default {
126135
value: item
127136
}))
128137
} else if (typeof value === 'object') {
138+
const isCustom = this.valueType === 'custom'
139+
if (isCustom) {
140+
value = value._custom.state
141+
}
129142
value = sortByKey(Object.keys(value).map(key => ({
130143
key,
131-
value: value[key]
144+
value: value[key],
145+
noDisplay: isCustom
132146
})))
133147
}
134148
return value
135149
},
136150
limitedSubFields () {
137151
return this.formattedSubFields.slice(0, this.limit)
152+
},
153+
valueClass () {
154+
const cssClass = [this.valueType]
155+
if (this.valueType === 'custom') {
156+
const value = this.field.value
157+
value._custom.type && cssClass.push(`type-${value._custom.type}`)
158+
value._custom.class && cssClass.push(value._custom.class)
159+
}
160+
return cssClass
138161
}
139162
},
140163
methods: {
@@ -175,6 +198,8 @@ export default {
175198
transform rotate(90deg)
176199
.key
177200
color #881391
201+
&.special
202+
color $blueishGrey
178203
.colon
179204
margin-right .5em
180205
position relative
@@ -186,6 +211,16 @@ export default {
186211
color #999
187212
&.literal
188213
color #0033cc
214+
&.custom
215+
&.type-component
216+
color $green
217+
&::before,
218+
&::after
219+
color $darkerGrey
220+
&::before
221+
content '<'
222+
&::after
223+
content '>'
189224
190225
.type
191226
color $background-color

src/devtools/variables.styl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
// Colors
22
$blue = #44A1FF
33
$grey = #DDDDDD
4+
$darkerGrey = #CCC
5+
$blueishGrey = #486887
46
$green = #42B983
57
$darkerGreen = #3BA776
68
$slate = #242424

src/devtools/views/components/ComponentInstance.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ export default {
186186
transform rotate(90deg)
187187
188188
.angle-bracket
189-
color #ccc
189+
color $darkerGrey
190190
191191
.instance-name
192192
color $component-color

src/util.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import CircularJSON from 'circular-json-es6'
22

3+
import { instanceMap, getCustomInstanceDetails } from 'src/backend'
4+
35
function cached (fn) {
46
const cache = Object.create(null)
57
return function cachedFn (str) {
@@ -56,6 +58,8 @@ function replacer (key) {
5658
return `[native RegExp ${val.toString()}]`
5759
} else if (val instanceof Date) {
5860
return `[native Date ${val.toString()}]`
61+
} else if (val && val._isVue) {
62+
return getCustomInstanceDetails(val)
5963
} else {
6064
return sanitize(val)
6165
}
@@ -76,6 +80,10 @@ function reviver (key, val) {
7680
return Infinity
7781
} else if (val === NAN) {
7882
return NaN
83+
} else if (val && val._custom) {
84+
if (val._custom.type === 'component') {
85+
return instanceMap.get(val._custom.id)
86+
}
7987
} else if (specialTypeRE.test(val)) {
8088
const [, type, string] = specialTypeRE.exec(val)
8189
return new window[type](string)

0 commit comments

Comments
 (0)