-
Notifications
You must be signed in to change notification settings - Fork 187
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Vue Devtools unable to detect child Vue components when vce used in root #150
Comments
Hi, unfortunately I didn't test it with Vue DevTools, but I can see that indeed custom element's made with this library are not detected. As this is non-critical issue, I will postpone fixing it. If you want to contribute - feel free to prepare PR. Regards! |
They seem to be detected if you refresh the devtools using their refresh button, but the children are just a no go.. |
It can be due to timing - e.g. if DevTools check the page for Vue components before Web Component's Custom Elements jump in. But it have to be checked with DevTools source code - https://github.com/vuejs/vue-devtools/tree/dev/src. |
I tried it using stand alone dev tool desktop app but no luck. |
I made a small work-around, but it doesn't seem to work recursively.
Now I'm trying to make the custom elements inside my root custom element show in devtool as well. |
I made a script that seemingly fixes the issue without downsides. I don't know if this will lead to consequences on the Vue-side of things, but Vue Devtools now works fine. Include this wherever you are serving the static html file and things should work. <script>
// problem statement, aka why this hack script exists.
// Vue Devtools, when populating a tree of vue components, will find a root vue mount point,
// then traverse down the vue component's "known" vue component children.
// but for our Custom Element implementation, Vue mount points are created at each custom element.
// This means that since Vue Devtools only searched from the first known mount point, and the first mount
// point doesn't know anything about any descendant mount points, vue devtools won't know about them.
//
// in storybook, this means that we'll only see the storybook vue component
// if we were to only mount the custom element, we would only see the custom element's vue instance,
// but not the descendant custom elements (like atoms etc.).
// this script aims to fix that. Hopefully Vue Devtools works as intended after this, otherwise we'll have to
// find more ways to patch it, I guess.
//
// by wbern
var extractVueComponentFromVueMountPoint = c => {
if (c.constructor.name === 'Vue') {
return c.$children[0];
}
return c;
};
var getVueInstance = el => el.__vue__ || el.__vue_custom_element__;
var walk = treeNode => {
var traverse = elements => {
elements.forEach(el => {
if (el.__vue_custom_element__) {
// we found a custom element,
// this _could_ be the best way to "ignore" the custom element layer.
el.__vue__ =
el.__vue_custom_element__.$children[0].$children[0];
// shouldn't be necessary
// getVueInstance(el).$options.name =
// "Custom Element: " +
// el.tagName.toLowerCase().replace(/^[A-z]/, a => a.toUpperCase());
}
if (getVueInstance(el)) {
// we found a vue component, extract it,
// create a new tree node level,
// and finally keep searching from it
var childTreeNode = {
ref: extractVueComponentFromVueMountPoint(
getVueInstance(el),
),
tagName: el.tagName.toLowerCase(),
children: [],
};
treeNode.children.push(childTreeNode);
walk(childTreeNode);
} else if (el.children && el.children.length > 0) {
// keep looking downwards for vue components
traverse(el.children);
}
});
};
if (treeNode.ref.$el.children) {
traverse(treeNode.ref.$el.children);
}
};
var repair = treeNode => {
// now we "restore" the $children reference across the components
// so that Vue Devtools can find them properly. This is hacky as hell. :-)
treeNode.children.forEach(childTreeNode => {
if (!treeNode.ref.$children.includes(childTreeNode.ref)) {
treeNode.ref.$children.push(childTreeNode.ref);
}
// keep traversing downwards
repair(childTreeNode);
});
};
// initiates everything. can be run multiple times.
var glueThePage = (rootSelector, forceVueDevtoolsRefresh = false) => {
var root = extractVueComponentFromVueMountPoint(
document.querySelector(rootSelector).__vue__,
);
var tree = {
ref: extractVueComponentFromVueMountPoint(root),
tagName: root.$el.tagName.toLowerCase(),
children: [],
};
// find all the vue components, put in the "tree" variable
walk(tree);
// put up links between the vue components, across vue mount points.
repair(tree);
let hookIsAvailable = !!window.__VUE_DEVTOOLS_GLOBAL_HOOK__;
let vueDevtoolsIsOnComponentsTab =
hookIsAvailable &&
window.__VUE_DEVTOOLS_GLOBAL_HOOK__.currentTab === 'components';
if (vueDevtoolsIsOnComponentsTab || forceVueDevtoolsRefresh) {
if (hookIsAvailable) {
window.__VUE_DEVTOOLS_GLOBAL_HOOK__.emit('flush');
} else {
throw new Error(
'Cannot force a refresh in Vue Devtools as it does not seem to be available.',
);
}
}
};
// this is the root element of where your first Vue mount point is
// for storybook, it should be 'body > #root'
var myRootElementSelector = 'body > #root';
// lets us adapt to changes, and makes sure we don't do scanning unnecessarily early.
window.addEventListener(
'DOMContentLoaded',
() => {
// check if the root element is already available
if (
document.querySelector(myRootElementSelector) &&
document.querySelector(myRootElementSelector).__vue__
) {
glueThePage(myRootElementSelector);
}
// listen for future changes
var subscriber = new MutationObserver((mutations, observer) => {
mutations.forEach(mutation =>
mutation.addedNodes.forEach(node => {
let isRootElement =
document.querySelector(myRootElementSelector) ===
node;
let isVueInstance = !!node.__vue__;
let isCustomElement = !!node.__vue_custom_element__;
if (
isRootElement ||
isVueInstance ||
isCustomElement
) {
glueThePage(myRootElementSelector);
}
}),
);
}).observe(document.body, { childList: true, subtree: true });
},
false,
);
</script> Edit: Updated the script to work a little better. |
Thank you so much for this, much appreciated! |
Does this still work? Its giving me errors and can't seem to make it work. Using Vue 2. |
Hi.
I'm wondering why I cannot inspect Vue components inside the vce on the page.
Is this a limitation with Vue Devtools, or is it something that can be fixed? Happy to hear of any work-arounds if there are any.
Thanks in advance.
The text was updated successfully, but these errors were encountered: