From 617135b47d62b232c0dbe467d5a2cdd03fe1898e Mon Sep 17 00:00:00 2001 From: Guillaume Chau Date: Thu, 18 Mar 2021 18:35:48 +0100 Subject: [PATCH 01/18] feat: setup devtools integration --- package.json | 3 +++ rollup.config.js | 6 ++++-- src/plugins/devtool.js | 36 ++++++++++++------------------------ src/store.js | 11 +++++------ yarn.lock | 5 +++++ 5 files changed, 29 insertions(+), 32 deletions(-) diff --git a/package.json b/package.json index b7b358e42..a04654e31 100644 --- a/package.json +++ b/package.json @@ -92,5 +92,8 @@ "webpack": "^4.43.0", "webpack-dev-middleware": "^3.7.2", "webpack-hot-middleware": "^2.25.0" + }, + "dependencies": { + "@vue/devtools-api": "^6.0.0-beta.7" } } diff --git a/rollup.config.js b/rollup.config.js index 845ec6495..eed90392d 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -48,11 +48,13 @@ function createEntry(config) { c.output.name = c.output.name || 'Vuex' } + const useBuildFlags = config.format !== 'iife' && !config.browser c.plugins.push(replace({ __VERSION__: pkg.version, - __DEV__: config.format !== 'iife' && !config.browser + __DEV__: useBuildFlags ? `(process.env.NODE_ENV !== 'production')` - : config.env !== 'production' + : config.env !== 'production', + __VUE_PROD_DEVTOOLS__: useBuildFlags ? '__VUE_PROD_DEVTOOLS__' : 'false' })) if (config.transpile !== false) { diff --git a/src/plugins/devtool.js b/src/plugins/devtool.js index 7473b73d8..5825c3ec4 100644 --- a/src/plugins/devtool.js +++ b/src/plugins/devtool.js @@ -1,26 +1,14 @@ -const target = typeof window !== 'undefined' - ? window - : typeof global !== 'undefined' - ? global - : {} -const devtoolHook = target.__VUE_DEVTOOLS_GLOBAL_HOOK__ - -export default function devtoolPlugin (store) { - if (!devtoolHook) return - - store._devtoolHook = devtoolHook - - devtoolHook.emit('vuex:init', store) - - devtoolHook.on('vuex:travel-to-state', targetState => { - store.replaceState(targetState) +import { setupDevtoolsPlugin } from '@vue/devtools-api' + +export function addDevtools (app, store) { + setupDevtoolsPlugin({ + id: 'vuex', + app, + label: 'Vuex', + homepage: 'https://next.vuex.vuejs.org/', + logo: 'https://vuejs.org/images/icons/favicon-96x96.png', + packageName: 'vuex' + }, api => { + // @TODO }) - - store.subscribe((mutation, state) => { - devtoolHook.emit('vuex:mutation', mutation, state) - }, { prepend: true }) - - store.subscribeAction((action, state) => { - devtoolHook.emit('vuex:action', action, state) - }, { prepend: true }) } diff --git a/src/store.js b/src/store.js index 68113a5d2..721e20aa4 100644 --- a/src/store.js +++ b/src/store.js @@ -1,6 +1,6 @@ import { reactive, watch } from 'vue' import { storeKey } from './injectKey' -import devtoolPlugin from './plugins/devtool' +import { addDevtools } from './plugins/devtool' import ModuleCollection from './module/module-collection' import { forEachValue, isObject, isPromise, assert, partial } from './util' @@ -57,16 +57,15 @@ export class Store { // apply plugins plugins.forEach(plugin => plugin(this)) - - const useDevtools = options.devtools !== undefined ? options.devtools : /* Vue.config.devtools */ true - if (useDevtools) { - devtoolPlugin(this) - } } install (app, injectKey) { app.provide(injectKey || storeKey, this) app.config.globalProperties.$store = this + + if (__DEV__ || __VUE_PROD_DEVTOOLS__) { + addDevtools(app, this) + } } get state () { diff --git a/yarn.lock b/yarn.lock index 0493e754d..777dec944 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1619,6 +1619,11 @@ "@vue/compiler-dom" "3.0.5" "@vue/shared" "3.0.5" +"@vue/devtools-api@^6.0.0-beta.7": + version "6.0.0-beta.7" + resolved "https://registry.yarnpkg.com/@vue/devtools-api/-/devtools-api-6.0.0-beta.7.tgz#1d306613c93b9a837a3776b1b9255502662f850f" + integrity sha512-mIfqX8ZF6s2ulelIzfxGk9sFoigpoeK/2/DlWrtBGWfvwaK3kR1P2bxNkZ0LbJeuKHfcRP6hGZtGist7nxUN9A== + "@vue/reactivity@3.0.5": version "3.0.5" resolved "https://registry.yarnpkg.com/@vue/reactivity/-/reactivity-3.0.5.tgz#e3789e4d523d845f9ae0b4d770e2b45594742fd2" From 8d9ad88563d614376097bb3e4077cd9f021e468a Mon Sep 17 00:00:00 2001 From: Eduardo San Martin Morote Date: Wed, 24 Mar 2021 15:43:50 +0100 Subject: [PATCH 02/18] feat(devtools): add basic state+getters inspection and timeline --- src/plugins/devtool.js | 180 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 170 insertions(+), 10 deletions(-) diff --git a/src/plugins/devtool.js b/src/plugins/devtool.js index 5825c3ec4..889677483 100644 --- a/src/plugins/devtool.js +++ b/src/plugins/devtool.js @@ -1,14 +1,174 @@ import { setupDevtoolsPlugin } from '@vue/devtools-api' +const LABEL_VUEX_BINDINGS = 'vuex bindings' +/** @type {boolean | undefined} */ +let isAlreadyInstalled + +const MUTATIONS_LAYER_ID = 'vuex:mutations' +const INSPECTOR_ID = 'vuex' + export function addDevtools (app, store) { - setupDevtoolsPlugin({ - id: 'vuex', - app, - label: 'Vuex', - homepage: 'https://next.vuex.vuejs.org/', - logo: 'https://vuejs.org/images/icons/favicon-96x96.png', - packageName: 'vuex' - }, api => { - // @TODO - }) + setupDevtoolsPlugin( + { + id: 'org.vuejs.vuex', + app, + label: 'Vuex', + homepage: 'https://next.vuex.vuejs.org/', + logo: 'https://vuejs.org/images/icons/favicon-96x96.png', + packageName: 'vuex', + componentStateTypes: [LABEL_VUEX_BINDINGS] + }, + (api) => { + if (!isAlreadyInstalled) { + api.addTimelineLayer({ + id: MUTATIONS_LAYER_ID, + label: 'Vuex', + color: COLOR_LIME_500 + }) + + api.addInspector({ + id: INSPECTOR_ID, + label: 'Vuex', + icon: 'storage', + treeFilterPlaceholder: 'Filter stores...' + }) + + isAlreadyInstalled = true + + api.on.getInspectorTree((payload) => { + if (payload.app === app && payload.inspectorId === INSPECTOR_ID) { + // TODO: filter with payload + payload.rootNodes = [ + formatStoreForInspectorTree(store._modules.root, '') + ] + } + }) + + api.on.getInspectorState((payload) => { + if (payload.app === app && payload.inspectorId === INSPECTOR_ID) { + const modulePath = payload.nodeId + payload.state = formatStoreForInspectorState( + getStoreModule(store._modules, modulePath), + store._makeLocalGettersCache, + modulePath + ) + } + }) + } else { + api.notifyComponentUpdate() + api.sendInspectorTree(INSPECTOR_ID) + api.sendInspectorState(INSPECTOR_ID) + } + + store.subscribe((mutation, state) => { + const data = { state } + + if (mutation.payload) { + data.payload = mutation.payload + } + + api.notifyComponentUpdate() + api.sendInspectorTree(INSPECTOR_ID) + api.sendInspectorState(INSPECTOR_ID) + + api.addTimelineEvent({ + layerId: MUTATIONS_LAYER_ID, + event: { + time: Date.now(), + title: mutation.type, + data + } + }) + }) + } + ) +} + +/** + * Extracted from tailwind palette + */ +const COLOR_PINK_500 = 0xec4899 +const COLOR_BLUE_600 = 0x2563eb +const COLOR_LIME_500 = 0x84cc16 +const COLOR_CYAN_400 = 0x22d3ee +const COLOR_ORANGE_400 = 0xfb923c +// const COLOR_GRAY_100 = 0xf4f4f5 +const COLOR_DARK = 0x666666 +const COLOR_WHITE = 0xffffff + +const TAG_NAMESPACED = { + label: 'namespaced', + textColor: COLOR_WHITE, + backgroundColor: COLOR_DARK +} + +/** + * + * @param {string} path + */ +function extractNameFromPath (path) { + return path && path !== 'root' ? path.split('/').slice(-2, -1)[0] : 'Root' +} + +/** + * + * @param {*} module + * @return {import('@vue/devtools-api').CustomInspectorNode} + */ +function formatStoreForInspectorTree (module, path) { + return { + id: path || 'root', + // all modules end with a `/`, we want the last segment only + // cart/ -> cart + // nested/cart/ -> cart + label: extractNameFromPath(path), + tags: module.namespaced ? [TAG_NAMESPACED] : [], + children: Object.keys(module._children).map((moduleName) => + formatStoreForInspectorTree( + module._children[moduleName], + path + moduleName + '/' + ) + ) + } +} + +/** + * + * @param {*} module + * @return {import('@vue/devtools-api').CustomInspectorState} + */ +function formatStoreForInspectorState (module, getters, path) { + getters = path === 'root' ? getters : getters[path] + const gettersKeys = Object.keys(getters) + const storeState = { + state: Object.keys(module.state).map((key) => ({ + key, + editable: true, + value: module.state[key] + })) + } + + if (gettersKeys.length) { + storeState.getters = gettersKeys.map((key) => ({ + key: key.endsWith('/') ? extractNameFromPath(key) : key, + editable: false, + value: getters[key] + })) + } + + return storeState +} + +function getStoreModule (moduleMap, path) { + const names = path.split('/').filter((n) => n) + return names.reduce( + (module, moduleName, i) => { + const child = module[moduleName] + if (!child) { + throw new Error(`Missing module "${moduleName}" for path "${path}".`) + } + return i === names.length - 1 ? child : child._children + }, + path === 'root' ? moduleMap : moduleMap.root._children + ) } From 3a7f734ff21d392050a6f13cfe6cc85e5d089286 Mon Sep 17 00:00:00 2001 From: Guillaume Chau Date: Tue, 20 Apr 2021 13:55:18 +0200 Subject: [PATCH 03/18] fix(devtools): payload before state --- src/plugins/devtool.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/plugins/devtool.js b/src/plugins/devtool.js index 889677483..d1b5a80fe 100644 --- a/src/plugins/devtool.js +++ b/src/plugins/devtool.js @@ -61,12 +61,14 @@ export function addDevtools (app, store) { } store.subscribe((mutation, state) => { - const data = { state } + const data = {} if (mutation.payload) { data.payload = mutation.payload } + data.state = state + api.notifyComponentUpdate() api.sendInspectorTree(INSPECTOR_ID) api.sendInspectorState(INSPECTOR_ID) From f4766b75abff67735e03776021abbcaaa7a3e935 Mon Sep 17 00:00:00 2001 From: Guillaume Chau Date: Tue, 20 Apr 2021 14:36:46 +0200 Subject: [PATCH 04/18] feat(devtools): actions timeline layer --- .babelrc | 8 ++- examples/classic/shopping-cart/api/shop.js | 24 +++++--- .../shopping-cart/store/modules/cart.js | 20 +++---- .../shopping-cart/store/modules/products.js | 7 +-- src/plugins/devtool.js | 58 ++++++++++++++++++- src/store.js | 7 ++- 6 files changed, 100 insertions(+), 24 deletions(-) diff --git a/.babelrc b/.babelrc index 1320b9a32..9d8eb6f14 100644 --- a/.babelrc +++ b/.babelrc @@ -1,3 +1,9 @@ { - "presets": ["@babel/preset-env"] + "presets": [ + ["@babel/preset-env", { + "exclude": [ + "transform-regenerator" + ] + }] + ] } diff --git a/examples/classic/shopping-cart/api/shop.js b/examples/classic/shopping-cart/api/shop.js index 708a5b77b..45c0cd38c 100644 --- a/examples/classic/shopping-cart/api/shop.js +++ b/examples/classic/shopping-cart/api/shop.js @@ -8,16 +8,26 @@ const _products = [ ] export default { - getProducts (cb) { - setTimeout(() => cb(_products), 100) + async getProducts () { + await wait(100) + return _products }, - buyProducts (products, cb, errorCb) { - setTimeout(() => { + async buyProducts (products) { + await wait(1000) + if ( // simulate random checkout failure. (Math.random() > 0.5 || navigator.webdriver) - ? cb() - : errorCb() - }, 100) + ) { + return + } else { + throw new Error('Checkout error') + } } } + +function wait (ms) { + return new Promise(resolve => { + setTimeout(resolve, ms) + }) +} diff --git a/examples/classic/shopping-cart/store/modules/cart.js b/examples/classic/shopping-cart/store/modules/cart.js index fcdd3b565..856e8779c 100644 --- a/examples/classic/shopping-cart/store/modules/cart.js +++ b/examples/classic/shopping-cart/store/modules/cart.js @@ -29,20 +29,20 @@ const getters = { // actions const actions = { - checkout ({ commit, state }, products) { + async checkout ({ commit, state }, products) { const savedCartItems = [...state.items] commit('setCheckoutStatus', null) // empty cart commit('setCartItems', { items: [] }) - shop.buyProducts( - products, - () => commit('setCheckoutStatus', 'successful'), - () => { - commit('setCheckoutStatus', 'failed') - // rollback to the cart saved before sending the request - commit('setCartItems', { items: savedCartItems }) - } - ) + try { + await shop.buyProducts(products) + commit('setCheckoutStatus', 'successful') + } catch (e) { + console.error(e) + commit('setCheckoutStatus', 'failed') + // rollback to the cart saved before sending the request + commit('setCartItems', { items: savedCartItems }) + } }, addProductToCart ({ state, commit }, product) { diff --git a/examples/classic/shopping-cart/store/modules/products.js b/examples/classic/shopping-cart/store/modules/products.js index 4dd0ebc18..a71bc360f 100644 --- a/examples/classic/shopping-cart/store/modules/products.js +++ b/examples/classic/shopping-cart/store/modules/products.js @@ -10,10 +10,9 @@ const getters = {} // actions const actions = { - getAllProducts ({ commit }) { - shop.getProducts(products => { - commit('setProducts', products) - }) + async getAllProducts ({ commit }) { + const products = await shop.getProducts() + commit('setProducts', products) } } diff --git a/src/plugins/devtool.js b/src/plugins/devtool.js index d1b5a80fe..ed9d36b85 100644 --- a/src/plugins/devtool.js +++ b/src/plugins/devtool.js @@ -5,6 +5,7 @@ const LABEL_VUEX_BINDINGS = 'vuex bindings' let isAlreadyInstalled const MUTATIONS_LAYER_ID = 'vuex:mutations' +const ACTIONS_LAYER_ID = 'vuex:actions' const INSPECTOR_ID = 'vuex' export function addDevtools (app, store) { @@ -22,7 +23,13 @@ export function addDevtools (app, store) { if (!isAlreadyInstalled) { api.addTimelineLayer({ id: MUTATIONS_LAYER_ID, - label: 'Vuex', + label: 'Vuex Mutations', + color: COLOR_LIME_500 + }) + + api.addTimelineLayer({ + id: ACTIONS_LAYER_ID, + label: 'Vuex Actions', color: COLOR_LIME_500 }) @@ -82,6 +89,55 @@ export function addDevtools (app, store) { } }) }) + + store.subscribeAction({ + before: (action, state) => { + const data = {} + if (action.payload) { + data.payload = action.payload + } + action.time = Date.now() + data.state = state + + api.addTimelineEvent({ + layerId: ACTIONS_LAYER_ID, + event: { + time: action.time, + title: action.type, + groupId: action.id, + subtitle: 'start', + data + } + }) + }, + after: (action, state) => { + const data = {} + const duration = Date.now() - action.time + data.duration = { + _custom: { + type: 'duration', + display: `${duration}ms`, + tooltip: 'Action duration', + value: duration + } + } + if (action.payload) { + data.payload = action.payload + } + data.state = state + + api.addTimelineEvent({ + layerId: ACTIONS_LAYER_ID, + event: { + time: Date.now(), + title: action.type, + groupId: action.id, + subtitle: 'end', + data + } + }) + } + }) } ) } diff --git a/src/store.js b/src/store.js index 721e20aa4..53f881aeb 100644 --- a/src/store.js +++ b/src/store.js @@ -23,6 +23,7 @@ export class Store { // store internal state this._committing = false this._actions = Object.create(null) + this._actionId = 0 this._actionSubscribers = [] this._mutations = Object.create(null) this._wrappedGetters = Object.create(null) @@ -122,7 +123,11 @@ export class Store { payload } = unifyObjectStyle(_type, _payload) - const action = { type, payload } + const action = { + id: this._actionId++, + type, + payload + } const entry = this._actions[type] if (!entry) { if (__DEV__) { From 511b480952b491b27008b28b4f33ef33489ba214 Mon Sep 17 00:00:00 2001 From: Guillaume Chau Date: Tue, 20 Apr 2021 14:43:57 +0200 Subject: [PATCH 05/18] chore(examples): nested module example --- examples/classic/shopping-cart/store/modules/cart.js | 6 +++++- examples/classic/shopping-cart/store/modules/nested.js | 9 +++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 examples/classic/shopping-cart/store/modules/nested.js diff --git a/examples/classic/shopping-cart/store/modules/cart.js b/examples/classic/shopping-cart/store/modules/cart.js index 856e8779c..9fc7abd88 100644 --- a/examples/classic/shopping-cart/store/modules/cart.js +++ b/examples/classic/shopping-cart/store/modules/cart.js @@ -1,4 +1,5 @@ import shop from '../../api/shop' +import nested from './nested' // initial state // shape: [{ id, quantity }] @@ -88,5 +89,8 @@ export default { state, getters, actions, - mutations + mutations, + modules: { + nested + } } diff --git a/examples/classic/shopping-cart/store/modules/nested.js b/examples/classic/shopping-cart/store/modules/nested.js new file mode 100644 index 000000000..e849e26a0 --- /dev/null +++ b/examples/classic/shopping-cart/store/modules/nested.js @@ -0,0 +1,9 @@ +export default { + namespaced: true, + state: () => ({ + foo: 'bar' + }), + getters: { + twoBars: state => state.foo.repeat(2) + } +} From a60f3d7f9e10491564ccca005a0f835b65adbfe1 Mon Sep 17 00:00:00 2001 From: Guillaume Chau Date: Tue, 20 Apr 2021 14:44:20 +0200 Subject: [PATCH 06/18] fix(devtools): vuex inspector not found after closing/re-opening the devtools --- src/plugins/devtool.js | 77 ++++++++++++++++++------------------------ 1 file changed, 33 insertions(+), 44 deletions(-) diff --git a/src/plugins/devtool.js b/src/plugins/devtool.js index ed9d36b85..d93a7bb11 100644 --- a/src/plugins/devtool.js +++ b/src/plugins/devtool.js @@ -1,9 +1,6 @@ import { setupDevtoolsPlugin } from '@vue/devtools-api' const LABEL_VUEX_BINDINGS = 'vuex bindings' -/** @type {boolean | undefined} */ -let isAlreadyInstalled - const MUTATIONS_LAYER_ID = 'vuex:mutations' const ACTIONS_LAYER_ID = 'vuex:actions' const INSPECTOR_ID = 'vuex' @@ -20,52 +17,44 @@ export function addDevtools (app, store) { componentStateTypes: [LABEL_VUEX_BINDINGS] }, (api) => { - if (!isAlreadyInstalled) { - api.addTimelineLayer({ - id: MUTATIONS_LAYER_ID, - label: 'Vuex Mutations', - color: COLOR_LIME_500 - }) - - api.addTimelineLayer({ - id: ACTIONS_LAYER_ID, - label: 'Vuex Actions', - color: COLOR_LIME_500 - }) + api.addTimelineLayer({ + id: MUTATIONS_LAYER_ID, + label: 'Vuex Mutations', + color: COLOR_LIME_500 + }) - api.addInspector({ - id: INSPECTOR_ID, - label: 'Vuex', - icon: 'storage', - treeFilterPlaceholder: 'Filter stores...' - }) + api.addTimelineLayer({ + id: ACTIONS_LAYER_ID, + label: 'Vuex Actions', + color: COLOR_LIME_500 + }) - isAlreadyInstalled = true + api.addInspector({ + id: INSPECTOR_ID, + label: 'Vuex', + icon: 'storage', + treeFilterPlaceholder: 'Filter stores...' + }) - api.on.getInspectorTree((payload) => { - if (payload.app === app && payload.inspectorId === INSPECTOR_ID) { + api.on.getInspectorTree((payload) => { + if (payload.app === app && payload.inspectorId === INSPECTOR_ID) { // TODO: filter with payload - payload.rootNodes = [ - formatStoreForInspectorTree(store._modules.root, '') - ] - } - }) + payload.rootNodes = [ + formatStoreForInspectorTree(store._modules.root, '') + ] + } + }) - api.on.getInspectorState((payload) => { - if (payload.app === app && payload.inspectorId === INSPECTOR_ID) { - const modulePath = payload.nodeId - payload.state = formatStoreForInspectorState( - getStoreModule(store._modules, modulePath), - store._makeLocalGettersCache, - modulePath - ) - } - }) - } else { - api.notifyComponentUpdate() - api.sendInspectorTree(INSPECTOR_ID) - api.sendInspectorState(INSPECTOR_ID) - } + api.on.getInspectorState((payload) => { + if (payload.app === app && payload.inspectorId === INSPECTOR_ID) { + const modulePath = payload.nodeId + payload.state = formatStoreForInspectorState( + getStoreModule(store._modules, modulePath), + store._makeLocalGettersCache, + modulePath + ) + } + }) store.subscribe((mutation, state) => { const data = {} From 915e502cd43832859b0917a8eced092ab08f26f0 Mon Sep 17 00:00:00 2001 From: Guillaume Chau Date: Tue, 20 Apr 2021 14:46:32 +0200 Subject: [PATCH 07/18] refactor: action id only in devtools code --- src/plugins/devtool.js | 3 +++ src/store.js | 7 +------ 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/plugins/devtool.js b/src/plugins/devtool.js index d93a7bb11..2494caf57 100644 --- a/src/plugins/devtool.js +++ b/src/plugins/devtool.js @@ -5,6 +5,8 @@ const MUTATIONS_LAYER_ID = 'vuex:mutations' const ACTIONS_LAYER_ID = 'vuex:actions' const INSPECTOR_ID = 'vuex' +let actionId = 0 + export function addDevtools (app, store) { setupDevtoolsPlugin( { @@ -85,6 +87,7 @@ export function addDevtools (app, store) { if (action.payload) { data.payload = action.payload } + action.id = actionId++ action.time = Date.now() data.state = state diff --git a/src/store.js b/src/store.js index 53f881aeb..721e20aa4 100644 --- a/src/store.js +++ b/src/store.js @@ -23,7 +23,6 @@ export class Store { // store internal state this._committing = false this._actions = Object.create(null) - this._actionId = 0 this._actionSubscribers = [] this._mutations = Object.create(null) this._wrappedGetters = Object.create(null) @@ -123,11 +122,7 @@ export class Store { payload } = unifyObjectStyle(_type, _payload) - const action = { - id: this._actionId++, - type, - payload - } + const action = { type, payload } const entry = this._actions[type] if (!entry) { if (__DEV__) { From 2bf9c48f231e01553e6f1afbfb6dfc81aec6b714 Mon Sep 17 00:00:00 2001 From: Guillaume Chau Date: Tue, 20 Apr 2021 14:47:46 +0200 Subject: [PATCH 08/18] fix(devtools): use _ for devtools action properties --- src/plugins/devtool.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/plugins/devtool.js b/src/plugins/devtool.js index 2494caf57..390e2fc75 100644 --- a/src/plugins/devtool.js +++ b/src/plugins/devtool.js @@ -87,16 +87,16 @@ export function addDevtools (app, store) { if (action.payload) { data.payload = action.payload } - action.id = actionId++ - action.time = Date.now() + action._id = actionId++ + action._time = Date.now() data.state = state api.addTimelineEvent({ layerId: ACTIONS_LAYER_ID, event: { - time: action.time, + time: action._time, title: action.type, - groupId: action.id, + groupId: action._id, subtitle: 'start', data } @@ -104,7 +104,7 @@ export function addDevtools (app, store) { }, after: (action, state) => { const data = {} - const duration = Date.now() - action.time + const duration = Date.now() - action._time data.duration = { _custom: { type: 'duration', @@ -123,7 +123,7 @@ export function addDevtools (app, store) { event: { time: Date.now(), title: action.type, - groupId: action.id, + groupId: action._id, subtitle: 'end', data } From 8f8146269b9ca7f4f9cb8779882f18039860cce3 Mon Sep 17 00:00:00 2001 From: Guillaume Chau Date: Tue, 20 Apr 2021 14:49:27 +0200 Subject: [PATCH 09/18] fix: test --- examples/classic/shopping-cart/api/shop.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/classic/shopping-cart/api/shop.js b/examples/classic/shopping-cart/api/shop.js index 45c0cd38c..64f4e0dbb 100644 --- a/examples/classic/shopping-cart/api/shop.js +++ b/examples/classic/shopping-cart/api/shop.js @@ -14,7 +14,7 @@ export default { }, async buyProducts (products) { - await wait(1000) + await wait(100) if ( // simulate random checkout failure. (Math.random() > 0.5 || navigator.webdriver) From afa3460d2b4d3b5ead53c557ada9f67568dcf37c Mon Sep 17 00:00:00 2001 From: Guillaume Chau Date: Tue, 20 Apr 2021 15:06:45 +0200 Subject: [PATCH 10/18] feat(devtools): module filter --- src/plugins/devtool.js | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/src/plugins/devtool.js b/src/plugins/devtool.js index 390e2fc75..cb6dd310d 100644 --- a/src/plugins/devtool.js +++ b/src/plugins/devtool.js @@ -40,10 +40,15 @@ export function addDevtools (app, store) { api.on.getInspectorTree((payload) => { if (payload.app === app && payload.inspectorId === INSPECTOR_ID) { - // TODO: filter with payload - payload.rootNodes = [ - formatStoreForInspectorTree(store._modules.root, '') - ] + if (payload.filter) { + const nodes = [] + flattenStoreForInspectorTree(nodes, store._modules.root, payload.filter, '') + payload.rootNodes = nodes + } else { + payload.rootNodes = [ + formatStoreForInspectorTree(store._modules.root, '') + ] + } } }) @@ -182,6 +187,26 @@ function formatStoreForInspectorTree (module, path) { } } +/** + * + * @param {import('@vue/devtools-api').CustomInspectorNode[]} result + * @param {*} module + * @param {string} filter + * @param {string} path + */ +function flattenStoreForInspectorTree (result, module, filter, path) { + if (path.includes(filter)) { + result.push({ + id: path || 'root', + label: path.endsWith('/') ? path.slice(0, path.length - 1) : path || 'Root', + tags: module.namespaced ? [TAG_NAMESPACED] : [] + }) + } + Object.keys(module._children).forEach(moduleName => { + flattenStoreForInspectorTree(result, module._children[moduleName], filter, path + moduleName + '/') + }) +} + /** * * @param {*} module From cbb4f3813925377afd9500c514201662bad64baa Mon Sep 17 00:00:00 2001 From: Guillaume Chau Date: Wed, 21 Apr 2021 15:28:39 +0200 Subject: [PATCH 11/18] feat: state edit --- src/plugins/devtool.js | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/plugins/devtool.js b/src/plugins/devtool.js index cb6dd310d..77a49a983 100644 --- a/src/plugins/devtool.js +++ b/src/plugins/devtool.js @@ -63,6 +63,19 @@ export function addDevtools (app, store) { } }) + api.on.editInspectorState((payload) => { + if (payload.app === app && payload.inspectorId === INSPECTOR_ID) { + const modulePath = payload.nodeId + let path = payload.path + if (modulePath !== 'root') { + path = [...modulePath.split('/').filter(Boolean), ...path] + } + store._withCommit(() => { + payload.set(store._state.data, path, payload.state.value) + }) + } + }) + store.subscribe((mutation, state) => { const data = {} From 1f83669bcb9a7dc9caf5d3d6d4d2f254e30bce74 Mon Sep 17 00:00:00 2001 From: Guillaume Chau Date: Wed, 21 Apr 2021 15:54:40 +0200 Subject: [PATCH 12/18] fix(devtools): module getters not initialized --- src/plugins/devtool.js | 2 + src/store-util.js | 278 +++++++++++++++++++++++++++++++++++++++ src/store.js | 288 ++--------------------------------------- 3 files changed, 290 insertions(+), 278 deletions(-) create mode 100644 src/store-util.js diff --git a/src/plugins/devtool.js b/src/plugins/devtool.js index 77a49a983..f75ecaf7c 100644 --- a/src/plugins/devtool.js +++ b/src/plugins/devtool.js @@ -1,4 +1,5 @@ import { setupDevtoolsPlugin } from '@vue/devtools-api' +import { makeLocalGetters } from '../store-util' const LABEL_VUEX_BINDINGS = 'vuex bindings' const MUTATIONS_LAYER_ID = 'vuex:mutations' @@ -55,6 +56,7 @@ export function addDevtools (app, store) { api.on.getInspectorState((payload) => { if (payload.app === app && payload.inspectorId === INSPECTOR_ID) { const modulePath = payload.nodeId + makeLocalGetters(store, modulePath) payload.state = formatStoreForInspectorState( getStoreModule(store._modules, modulePath), store._makeLocalGettersCache, diff --git a/src/store-util.js b/src/store-util.js new file mode 100644 index 000000000..cea5d8b02 --- /dev/null +++ b/src/store-util.js @@ -0,0 +1,278 @@ +import { reactive, watch } from 'vue' +import { forEachValue, isObject, isPromise, assert, partial } from './util' + +export function genericSubscribe (fn, subs, options) { + if (subs.indexOf(fn) < 0) { + options && options.prepend + ? subs.unshift(fn) + : subs.push(fn) + } + return () => { + const i = subs.indexOf(fn) + if (i > -1) { + subs.splice(i, 1) + } + } +} + +export function resetStore (store, hot) { + store._actions = Object.create(null) + store._mutations = Object.create(null) + store._wrappedGetters = Object.create(null) + store._modulesNamespaceMap = Object.create(null) + const state = store.state + // init all modules + installModule(store, state, [], store._modules.root, true) + // reset state + resetStoreState(store, state, hot) +} + +export function resetStoreState (store, state, hot) { + const oldState = store._state + + // bind store public getters + store.getters = {} + // reset local getters cache + store._makeLocalGettersCache = Object.create(null) + const wrappedGetters = store._wrappedGetters + const computedObj = {} + forEachValue(wrappedGetters, (fn, key) => { + // use computed to leverage its lazy-caching mechanism + // direct inline function use will lead to closure preserving oldState. + // using partial to return function with only arguments preserved in closure environment. + computedObj[key] = partial(fn, store) + Object.defineProperty(store.getters, key, { + // TODO: use `computed` when it's possible. at the moment we can't due to + // https://github.com/vuejs/vuex/pull/1883 + get: () => computedObj[key](), + enumerable: true // for local getters + }) + }) + + store._state = reactive({ + data: state + }) + + // enable strict mode for new state + if (store.strict) { + enableStrictMode(store) + } + + if (oldState) { + if (hot) { + // dispatch changes in all subscribed watchers + // to force getter re-evaluation for hot reloading. + store._withCommit(() => { + oldState.data = null + }) + } + } +} + +export function installModule (store, rootState, path, module, hot) { + const isRoot = !path.length + const namespace = store._modules.getNamespace(path) + + // register in namespace map + if (module.namespaced) { + if (store._modulesNamespaceMap[namespace] && __DEV__) { + console.error(`[vuex] duplicate namespace ${namespace} for the namespaced module ${path.join('/')}`) + } + store._modulesNamespaceMap[namespace] = module + } + + // set state + if (!isRoot && !hot) { + const parentState = getNestedState(rootState, path.slice(0, -1)) + const moduleName = path[path.length - 1] + store._withCommit(() => { + if (__DEV__) { + if (moduleName in parentState) { + console.warn( + `[vuex] state field "${moduleName}" was overridden by a module with the same name at "${path.join('.')}"` + ) + } + } + parentState[moduleName] = module.state + }) + } + + const local = module.context = makeLocalContext(store, namespace, path) + + module.forEachMutation((mutation, key) => { + const namespacedType = namespace + key + registerMutation(store, namespacedType, mutation, local) + }) + + module.forEachAction((action, key) => { + const type = action.root ? key : namespace + key + const handler = action.handler || action + registerAction(store, type, handler, local) + }) + + module.forEachGetter((getter, key) => { + const namespacedType = namespace + key + registerGetter(store, namespacedType, getter, local) + }) + + module.forEachChild((child, key) => { + installModule(store, rootState, path.concat(key), child, hot) + }) +} + +/** + * make localized dispatch, commit, getters and state + * if there is no namespace, just use root ones + */ +function makeLocalContext (store, namespace, path) { + const noNamespace = namespace === '' + + const local = { + dispatch: noNamespace ? store.dispatch : (_type, _payload, _options) => { + const args = unifyObjectStyle(_type, _payload, _options) + const { payload, options } = args + let { type } = args + + if (!options || !options.root) { + type = namespace + type + if (__DEV__ && !store._actions[type]) { + console.error(`[vuex] unknown local action type: ${args.type}, global type: ${type}`) + return + } + } + + return store.dispatch(type, payload) + }, + + commit: noNamespace ? store.commit : (_type, _payload, _options) => { + const args = unifyObjectStyle(_type, _payload, _options) + const { payload, options } = args + let { type } = args + + if (!options || !options.root) { + type = namespace + type + if (__DEV__ && !store._mutations[type]) { + console.error(`[vuex] unknown local mutation type: ${args.type}, global type: ${type}`) + return + } + } + + store.commit(type, payload, options) + } + } + + // getters and state object must be gotten lazily + // because they will be changed by state update + Object.defineProperties(local, { + getters: { + get: noNamespace + ? () => store.getters + : () => makeLocalGetters(store, namespace) + }, + state: { + get: () => getNestedState(store.state, path) + } + }) + + return local +} + +export function makeLocalGetters (store, namespace) { + if (!store._makeLocalGettersCache[namespace]) { + const gettersProxy = {} + const splitPos = namespace.length + Object.keys(store.getters).forEach(type => { + // skip if the target getter is not match this namespace + if (type.slice(0, splitPos) !== namespace) return + + // extract local getter type + const localType = type.slice(splitPos) + + // Add a port to the getters proxy. + // Define as getter property because + // we do not want to evaluate the getters in this time. + Object.defineProperty(gettersProxy, localType, { + get: () => store.getters[type], + enumerable: true + }) + }) + store._makeLocalGettersCache[namespace] = gettersProxy + } + + return store._makeLocalGettersCache[namespace] +} + +function registerMutation (store, type, handler, local) { + const entry = store._mutations[type] || (store._mutations[type] = []) + entry.push(function wrappedMutationHandler (payload) { + handler.call(store, local.state, payload) + }) +} + +function registerAction (store, type, handler, local) { + const entry = store._actions[type] || (store._actions[type] = []) + entry.push(function wrappedActionHandler (payload) { + let res = handler.call(store, { + dispatch: local.dispatch, + commit: local.commit, + getters: local.getters, + state: local.state, + rootGetters: store.getters, + rootState: store.state + }, payload) + if (!isPromise(res)) { + res = Promise.resolve(res) + } + if (store._devtoolHook) { + return res.catch(err => { + store._devtoolHook.emit('vuex:error', err) + throw err + }) + } else { + return res + } + }) +} + +function registerGetter (store, type, rawGetter, local) { + if (store._wrappedGetters[type]) { + if (__DEV__) { + console.error(`[vuex] duplicate getter key: ${type}`) + } + return + } + store._wrappedGetters[type] = function wrappedGetter (store) { + return rawGetter( + local.state, // local state + local.getters, // local getters + store.state, // root state + store.getters // root getters + ) + } +} + +function enableStrictMode (store) { + watch(() => store._state.data, () => { + if (__DEV__) { + assert(store._committing, `do not mutate vuex store state outside mutation handlers.`) + } + }, { deep: true, flush: 'sync' }) +} + +export function getNestedState (state, path) { + return path.reduce((state, key) => state[key], state) +} + +export function unifyObjectStyle (type, payload, options) { + if (isObject(type) && type.type) { + options = payload + payload = type + type = type.type + } + + if (__DEV__) { + assert(typeof type === 'string', `expects string as the type, but found ${typeof type}.`) + } + + return { type, payload, options } +} diff --git a/src/store.js b/src/store.js index 721e20aa4..95d2d5bb3 100644 --- a/src/store.js +++ b/src/store.js @@ -1,8 +1,16 @@ -import { reactive, watch } from 'vue' +import { watch } from 'vue' import { storeKey } from './injectKey' import { addDevtools } from './plugins/devtool' import ModuleCollection from './module/module-collection' -import { forEachValue, isObject, isPromise, assert, partial } from './util' +import { assert } from './util' +import { + genericSubscribe, + getNestedState, + installModule, + resetStore, + resetStoreState, + unifyObjectStyle +} from './store-util' export function createStore (options) { return new Store(options) @@ -249,279 +257,3 @@ export class Store { this._committing = committing } } - -function genericSubscribe (fn, subs, options) { - if (subs.indexOf(fn) < 0) { - options && options.prepend - ? subs.unshift(fn) - : subs.push(fn) - } - return () => { - const i = subs.indexOf(fn) - if (i > -1) { - subs.splice(i, 1) - } - } -} - -function resetStore (store, hot) { - store._actions = Object.create(null) - store._mutations = Object.create(null) - store._wrappedGetters = Object.create(null) - store._modulesNamespaceMap = Object.create(null) - const state = store.state - // init all modules - installModule(store, state, [], store._modules.root, true) - // reset state - resetStoreState(store, state, hot) -} - -function resetStoreState (store, state, hot) { - const oldState = store._state - - // bind store public getters - store.getters = {} - // reset local getters cache - store._makeLocalGettersCache = Object.create(null) - const wrappedGetters = store._wrappedGetters - const computedObj = {} - forEachValue(wrappedGetters, (fn, key) => { - // use computed to leverage its lazy-caching mechanism - // direct inline function use will lead to closure preserving oldState. - // using partial to return function with only arguments preserved in closure environment. - computedObj[key] = partial(fn, store) - Object.defineProperty(store.getters, key, { - // TODO: use `computed` when it's possible. at the moment we can't due to - // https://github.com/vuejs/vuex/pull/1883 - get: () => computedObj[key](), - enumerable: true // for local getters - }) - }) - - store._state = reactive({ - data: state - }) - - // enable strict mode for new state - if (store.strict) { - enableStrictMode(store) - } - - if (oldState) { - if (hot) { - // dispatch changes in all subscribed watchers - // to force getter re-evaluation for hot reloading. - store._withCommit(() => { - oldState.data = null - }) - } - } -} - -function installModule (store, rootState, path, module, hot) { - const isRoot = !path.length - const namespace = store._modules.getNamespace(path) - - // register in namespace map - if (module.namespaced) { - if (store._modulesNamespaceMap[namespace] && __DEV__) { - console.error(`[vuex] duplicate namespace ${namespace} for the namespaced module ${path.join('/')}`) - } - store._modulesNamespaceMap[namespace] = module - } - - // set state - if (!isRoot && !hot) { - const parentState = getNestedState(rootState, path.slice(0, -1)) - const moduleName = path[path.length - 1] - store._withCommit(() => { - if (__DEV__) { - if (moduleName in parentState) { - console.warn( - `[vuex] state field "${moduleName}" was overridden by a module with the same name at "${path.join('.')}"` - ) - } - } - parentState[moduleName] = module.state - }) - } - - const local = module.context = makeLocalContext(store, namespace, path) - - module.forEachMutation((mutation, key) => { - const namespacedType = namespace + key - registerMutation(store, namespacedType, mutation, local) - }) - - module.forEachAction((action, key) => { - const type = action.root ? key : namespace + key - const handler = action.handler || action - registerAction(store, type, handler, local) - }) - - module.forEachGetter((getter, key) => { - const namespacedType = namespace + key - registerGetter(store, namespacedType, getter, local) - }) - - module.forEachChild((child, key) => { - installModule(store, rootState, path.concat(key), child, hot) - }) -} - -/** - * make localized dispatch, commit, getters and state - * if there is no namespace, just use root ones - */ -function makeLocalContext (store, namespace, path) { - const noNamespace = namespace === '' - - const local = { - dispatch: noNamespace ? store.dispatch : (_type, _payload, _options) => { - const args = unifyObjectStyle(_type, _payload, _options) - const { payload, options } = args - let { type } = args - - if (!options || !options.root) { - type = namespace + type - if (__DEV__ && !store._actions[type]) { - console.error(`[vuex] unknown local action type: ${args.type}, global type: ${type}`) - return - } - } - - return store.dispatch(type, payload) - }, - - commit: noNamespace ? store.commit : (_type, _payload, _options) => { - const args = unifyObjectStyle(_type, _payload, _options) - const { payload, options } = args - let { type } = args - - if (!options || !options.root) { - type = namespace + type - if (__DEV__ && !store._mutations[type]) { - console.error(`[vuex] unknown local mutation type: ${args.type}, global type: ${type}`) - return - } - } - - store.commit(type, payload, options) - } - } - - // getters and state object must be gotten lazily - // because they will be changed by state update - Object.defineProperties(local, { - getters: { - get: noNamespace - ? () => store.getters - : () => makeLocalGetters(store, namespace) - }, - state: { - get: () => getNestedState(store.state, path) - } - }) - - return local -} - -function makeLocalGetters (store, namespace) { - if (!store._makeLocalGettersCache[namespace]) { - const gettersProxy = {} - const splitPos = namespace.length - Object.keys(store.getters).forEach(type => { - // skip if the target getter is not match this namespace - if (type.slice(0, splitPos) !== namespace) return - - // extract local getter type - const localType = type.slice(splitPos) - - // Add a port to the getters proxy. - // Define as getter property because - // we do not want to evaluate the getters in this time. - Object.defineProperty(gettersProxy, localType, { - get: () => store.getters[type], - enumerable: true - }) - }) - store._makeLocalGettersCache[namespace] = gettersProxy - } - - return store._makeLocalGettersCache[namespace] -} - -function registerMutation (store, type, handler, local) { - const entry = store._mutations[type] || (store._mutations[type] = []) - entry.push(function wrappedMutationHandler (payload) { - handler.call(store, local.state, payload) - }) -} - -function registerAction (store, type, handler, local) { - const entry = store._actions[type] || (store._actions[type] = []) - entry.push(function wrappedActionHandler (payload) { - let res = handler.call(store, { - dispatch: local.dispatch, - commit: local.commit, - getters: local.getters, - state: local.state, - rootGetters: store.getters, - rootState: store.state - }, payload) - if (!isPromise(res)) { - res = Promise.resolve(res) - } - if (store._devtoolHook) { - return res.catch(err => { - store._devtoolHook.emit('vuex:error', err) - throw err - }) - } else { - return res - } - }) -} - -function registerGetter (store, type, rawGetter, local) { - if (store._wrappedGetters[type]) { - if (__DEV__) { - console.error(`[vuex] duplicate getter key: ${type}`) - } - return - } - store._wrappedGetters[type] = function wrappedGetter (store) { - return rawGetter( - local.state, // local state - local.getters, // local getters - store.state, // root state - store.getters // root getters - ) - } -} - -function enableStrictMode (store) { - watch(() => store._state.data, () => { - if (__DEV__) { - assert(store._committing, `do not mutate vuex store state outside mutation handlers.`) - } - }, { deep: true, flush: 'sync' }) -} - -function getNestedState (state, path) { - return path.reduce((state, key) => state[key], state) -} - -function unifyObjectStyle (type, payload, options) { - if (isObject(type) && type.type) { - options = payload - payload = type - type = type.type - } - - if (__DEV__) { - assert(typeof type === 'string', `expects string as the type, but found ${typeof type}.`) - } - - return { type, payload, options } -} From a8ee38f5e3664737eae8045757a81bfd0f2b8d56 Mon Sep 17 00:00:00 2001 From: Kia King Ishii Date: Mon, 10 May 2021 23:04:05 +0900 Subject: [PATCH 13/18] style: adjust code style --- package.json | 6 +++--- src/plugins/devtool.js | 4 ---- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/package.json b/package.json index a04654e31..b049440ca 100644 --- a/package.json +++ b/package.json @@ -54,6 +54,9 @@ "peerDependencies": { "vue": "^3.0.2" }, + "dependencies": { + "@vue/devtools-api": "^6.0.0-beta.7" + }, "devDependencies": { "@babel/core": "^7.12.10", "@babel/preset-env": "^7.12.11", @@ -92,8 +95,5 @@ "webpack": "^4.43.0", "webpack-dev-middleware": "^3.7.2", "webpack-hot-middleware": "^2.25.0" - }, - "dependencies": { - "@vue/devtools-api": "^6.0.0-beta.7" } } diff --git a/src/plugins/devtool.js b/src/plugins/devtool.js index f75ecaf7c..3671259e3 100644 --- a/src/plugins/devtool.js +++ b/src/plugins/devtool.js @@ -173,7 +173,6 @@ const TAG_NAMESPACED = { } /** - * * @param {string} path */ function extractNameFromPath (path) { @@ -181,7 +180,6 @@ function extractNameFromPath (path) { } /** - * * @param {*} module * @return {import('@vue/devtools-api').CustomInspectorNode} */ @@ -203,7 +201,6 @@ function formatStoreForInspectorTree (module, path) { } /** - * * @param {import('@vue/devtools-api').CustomInspectorNode[]} result * @param {*} module * @param {string} filter @@ -223,7 +220,6 @@ function flattenStoreForInspectorTree (result, module, filter, path) { } /** - * * @param {*} module * @return {import('@vue/devtools-api').CustomInspectorState} */ From 61de7ece4fbeba429111a7689dc543b6f4137a22 Mon Sep 17 00:00:00 2001 From: Kia King Ishii Date: Mon, 10 May 2021 23:04:31 +0900 Subject: [PATCH 14/18] fix: linter error --- .eslintrc.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.eslintrc.json b/.eslintrc.json index af0ad7581..fd2d71204 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -4,6 +4,7 @@ "plugin:vue-libs/recommended" ], "globals": { - "__DEV__": true + "__DEV__": true, + "__VUE_PROD_DEVTOOLS__": true } } From e122bec038790b23b5579a247e8c6cccf9530916 Mon Sep 17 00:00:00 2001 From: Kia King Ishii Date: Mon, 10 May 2021 23:46:57 +0900 Subject: [PATCH 15/18] fix: use devtools option to on/off it --- src/store.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/store.js b/src/store.js index 95d2d5bb3..3ae6898f9 100644 --- a/src/store.js +++ b/src/store.js @@ -25,7 +25,8 @@ export class Store { const { plugins = [], - strict = false + strict = false, + devtools } = options // store internal state @@ -38,6 +39,7 @@ export class Store { this._modulesNamespaceMap = Object.create(null) this._subscribers = [] this._makeLocalGettersCache = Object.create(null) + this._devtools = devtools // bind commit and dispatch to self const store = this @@ -71,7 +73,11 @@ export class Store { app.provide(injectKey || storeKey, this) app.config.globalProperties.$store = this - if (__DEV__ || __VUE_PROD_DEVTOOLS__) { + const useDevtools = this._devtools !== undefined + ? this._devtools + : __DEV__ || __VUE_PROD_DEVTOOLS__ + + if (useDevtools) { addDevtools(app, this) } } From 1b2df2b904110863a2059458fb69d9b69864d599 Mon Sep 17 00:00:00 2001 From: Kia King Ishii Date: Mon, 10 May 2021 23:47:07 +0900 Subject: [PATCH 16/18] style: fix linter error --- src/plugins/devtool.js | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/plugins/devtool.js b/src/plugins/devtool.js index 3671259e3..f68bf6823 100644 --- a/src/plugins/devtool.js +++ b/src/plugins/devtool.js @@ -154,15 +154,8 @@ export function addDevtools (app, store) { ) } -/** - * Extracted from tailwind palette - */ -const COLOR_PINK_500 = 0xec4899 -const COLOR_BLUE_600 = 0x2563eb +// extracted from tailwind palette const COLOR_LIME_500 = 0x84cc16 -const COLOR_CYAN_400 = 0x22d3ee -const COLOR_ORANGE_400 = 0xfb923c -// const COLOR_GRAY_100 = 0xf4f4f5 const COLOR_DARK = 0x666666 const COLOR_WHITE = 0xffffff From 346d439575d6d00c09f6622fb9f326eddcfda411 Mon Sep 17 00:00:00 2001 From: Kia King Ishii Date: Fri, 21 May 2021 00:27:57 +0900 Subject: [PATCH 17/18] build: include devtools plugin in a global bundle --- rollup.config.js | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/rollup.config.js b/rollup.config.js index eed90392d..6382c2c9f 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -25,6 +25,9 @@ function createEntries() { } function createEntry(config) { + const isGlobalBuild = config.format === 'iife' + const isBunderBuild = config.format !== 'iife' && !config.browser + const c = { external: ['vue'], input: config.input, @@ -44,17 +47,20 @@ function createEntry(config) { } } - if (config.format === 'iife' || config.format === 'umd') { + if (isGlobalBuild) { c.output.name = c.output.name || 'Vuex' } - const useBuildFlags = config.format !== 'iife' && !config.browser + if (!isGlobalBuild) { + c.external.push('@vue/devtools-api') + } + c.plugins.push(replace({ __VERSION__: pkg.version, - __DEV__: useBuildFlags + __DEV__: isBunderBuild ? `(process.env.NODE_ENV !== 'production')` : config.env !== 'production', - __VUE_PROD_DEVTOOLS__: useBuildFlags ? '__VUE_PROD_DEVTOOLS__' : 'false' + __VUE_PROD_DEVTOOLS__: isBunderBuild ? '__VUE_PROD_DEVTOOLS__' : 'false' })) if (config.transpile !== false) { From 0fc1447ce2bb95e5cf8e5b1bdd4b43470e1b6197 Mon Sep 17 00:00:00 2001 From: Kia King Ishii Date: Fri, 21 May 2021 00:35:17 +0900 Subject: [PATCH 18/18] build: update devtools --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index b049440ca..ea805d907 100644 --- a/package.json +++ b/package.json @@ -55,7 +55,7 @@ "vue": "^3.0.2" }, "dependencies": { - "@vue/devtools-api": "^6.0.0-beta.7" + "@vue/devtools-api": "^6.0.0-beta.10" }, "devDependencies": { "@babel/core": "^7.12.10", diff --git a/yarn.lock b/yarn.lock index 777dec944..1ce9991d3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1619,10 +1619,10 @@ "@vue/compiler-dom" "3.0.5" "@vue/shared" "3.0.5" -"@vue/devtools-api@^6.0.0-beta.7": - version "6.0.0-beta.7" - resolved "https://registry.yarnpkg.com/@vue/devtools-api/-/devtools-api-6.0.0-beta.7.tgz#1d306613c93b9a837a3776b1b9255502662f850f" - integrity sha512-mIfqX8ZF6s2ulelIzfxGk9sFoigpoeK/2/DlWrtBGWfvwaK3kR1P2bxNkZ0LbJeuKHfcRP6hGZtGist7nxUN9A== +"@vue/devtools-api@^6.0.0-beta.10": + version "6.0.0-beta.10" + resolved "https://registry.yarnpkg.com/@vue/devtools-api/-/devtools-api-6.0.0-beta.10.tgz#f39da7618cee292e39c7274227c34163e30eb3ca" + integrity sha512-nktQYRnIFrh4DdXiCBjHnsHOMZXDIVcP9qlm/DMfxmjJMtpMGrSZCOKP8j7kDhObNHyqlicwoGLd+a4hf4x9ww== "@vue/reactivity@3.0.5": version "3.0.5"