├── .gitignore
├── LICENSE
├── README.md
├── babel.config.js
├── package-lock.json
├── package.json
├── src
├── app
│ ├── App.vue
│ ├── components
│ │ ├── Map.vue
│ │ ├── NavBar.vue
│ │ └── WebMetrics.vue
│ ├── containers
│ │ └── MainContainer.vue
│ ├── index.js
│ └── styles
│ │ └── styles.css
└── extension
│ └── build
│ ├── app.bundle.js
│ ├── app.bundle.js.LICENSE.txt
│ ├── assets
│ └── oVUElord_logo.png
│ ├── background.bundle.js
│ ├── background.js
│ ├── content.bundle.js
│ ├── content_script.js
│ ├── devtools.html
│ ├── devtools.js
│ ├── fontAwesome.js
│ ├── manifest.json
│ ├── panel.html
│ ├── script.bundle.js
│ └── script.js
└── webpack.config.js
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | .DS_Store
3 | bundles/*
4 | src/extension/build/app.bundle.js
5 | src/extension/build/app.bundle.js.LICENSE.txt
6 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 Reactime-Vue
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # KangaVue
2 |
3 |
KangaVue is a performance and debugging tool for Vue developers (currently in Beta version) . It displays a snapshot whenever a target application's state is changed. It also displays key web metrics from loading of the application for SEO strategies and overal app performance.
4 |
5 | After installing KangaVue, you can test its functionalities with your Vue application in development mode.
6 |
7 | ## Installation
8 |
9 |
10 |
11 |
12 | NOTE: The Vue Developer Tools [extension](https://chrome.google.com/webstore/detail/vuejs-devtools/nhdogjmejiglipccpnnnanhbledajbpd?hl=en) is also required for KangaVue to run, if you do not already have it installed on your browser.
13 |
14 | ## How to Use
15 |
16 | After installing the Chrome extension, just open up your project in the browser.
17 |
18 | Then open up your Chrome DevTools and navigate to the KangaVue panel.
19 |
20 | ## Troubleshooting
21 |
22 | ### ❓ I found a bug in KangaVue
23 |
24 | KangaVue is an open source project, and we’d really appreciate your help with improving user experience. Please, create a pull request (or issue) to propose and collaborate on changes to a repository.
25 |
26 | ## Features
27 |
28 | ### 🔹 Component Hierarchy
29 |
30 | You can click on the component tree tab in the navigation bar to view your app's component heirarchy. State can be visualized in a Component Graph.
31 |
32 | ### 🔹 Web Metrics
33 |
34 | When your app loads or refreshes, the initial loading metrics will be rendered in a visual display under the Web Metrics Panel. Use these metrics to pinpoint performance issues that may affect your user experience and/or search optimization efforts.
35 |
36 |
37 | ## Read More
38 |
39 | - [KangaVue — Vue.js web metrics in a devtool pouch](https://dxbernstein.medium.com/kangavue-vue-js-web-metrics-in-a-devtool-pouch-3aee7f128a3f)
40 |
41 | ## Authors
42 | - **Harry Fox** - [@StackOverFlowWhereArtThou](https://github.com/StackOverFlowWhereArtThou)
43 | - **Nathan Richardson** - [@BagelEnthusiast](https://github.com/BagelEnthusiast)
44 | - **David Bernstein** - [@dangitbobbeh](https://github.com/dangitbobbeh)
45 | - **Joseph Stern** - [@josephiswhere](https://github.com/josephiswhere))
46 |
47 | ## License
48 |
49 | This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details
50 |
--------------------------------------------------------------------------------
/babel.config.js :
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [
3 | [
4 | "@babel/preset-env",
5 | {
6 | useBuiltIns: "usage",
7 | corejs: 3,
8 | },
9 | ],
10 | ],
11 | };
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "KangaVue",
3 | "version": "1.0.0",
4 | "description": "Developer tool for vue",
5 | "main": "index.js",
6 | "scripts": {
7 | "build": "webpack --mode production",
8 | "start": "webpack serve --mode development"
9 | },
10 | "repository": {
11 | "type": "git",
12 | "url": "git+https://github.com/StackOverFlowWhereArtThou/KangaVue.git"
13 | },
14 | "author": "",
15 | "license": "ISC",
16 | "bugs": {
17 | "url": "https://github.com/StackOverFlowWhereArtThou/KangaVue/issues"
18 | },
19 | "homepage": "https://github.com/StackOverFlowWhereArtThou/KangaVue#readme",
20 | "dependencies": {
21 | "apexcharts": "^3.26.0",
22 | "core-js": "^3.10.0",
23 | "d3": "^6.6.2",
24 | "sass": "^1.32.8",
25 | "vue": "^2.6.12",
26 | "vue-apexcharts": "^1.6.1",
27 | "vue-router": "^3.5.1",
28 | "vued3tree": "^5.1.0",
29 | "vuetify": "^2.4.9",
30 | "web-vitals": "^1.1.1"
31 | },
32 | "devDependencies": {
33 | "@babel/core": "^7.13.14",
34 | "@babel/preset-env": "^7.13.12",
35 | "autoprefixer": "^9.0.2",
36 | "babel-loader": "^8.2.2",
37 | "css-loader": "^5.2.1",
38 | "mini-css-extract-plugin": "^1.4.1",
39 | "node-sass": "^5.0.0",
40 | "postcss-loader": "^3.0.0",
41 | "sass-loader": "^11.0.1",
42 | "style-loader": "^2.0.0",
43 | "vue-loader": "^15.9.6",
44 | "vue-template-compiler": "^2.6.12",
45 | "webpack": "^5.30.0",
46 | "webpack-cli": "^4.6.0",
47 | "webpack-dev-server": "^3.11.2"
48 | },
49 | "browserslist": [
50 | "> 1%",
51 | "last 2 versions",
52 | "not dead"
53 | ]
54 | }
55 |
--------------------------------------------------------------------------------
/src/app/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
39 |
--------------------------------------------------------------------------------
/src/app/components/Map.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
12 |
13 |
14 |
15 |
16 |
17 |
46 |
68 |
--------------------------------------------------------------------------------
/src/app/components/NavBar.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
Component Tree
4 |
Web Metrics
5 |
Set Tree
6 |
7 |
8 |
9 |
37 |
38 |
--------------------------------------------------------------------------------
/src/app/components/WebMetrics.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
{{this.webMetricTitle}}
4 |
5 | {{this.webMetricDescription}}
6 |
7 |
8 |
9 |
10 |
108 |
109 |
111 |
--------------------------------------------------------------------------------
/src/app/containers/MainContainer.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
37 |
38 |
--------------------------------------------------------------------------------
/src/app/index.js:
--------------------------------------------------------------------------------
1 | // import Vue from 'vue';
2 |
3 | // const app = new Vue({
4 | // el: '#vue-root',
5 | // data: {
6 | // message: 'Hello Vue!',
7 | // },
8 | // });
9 |
10 | // document.addEventListener("DOMContentLoaded", () => {
11 | // console.log('index.js has been triggered!!!');
12 | // const NAME = 'Bobby Schmurda';
13 | // const rootApp = document.getElementById('app');
14 | // rootApp.innerHTML = `Hello, ${NAME}
`;
15 | // });
16 |
17 | import Vue from 'vue';
18 | import App from './App.vue';
19 | import './styles/styles.css';
20 |
21 | import VueApexCharts from 'vue-apexcharts'
22 |
23 | Vue.component('apexchart', VueApexCharts);
24 |
25 | new Vue({
26 | el: '#app',
27 | data:{
28 | treemap: {},
29 | },
30 | render: h => h(App)
31 | });
--------------------------------------------------------------------------------
/src/app/styles/styles.css:
--------------------------------------------------------------------------------
1 | html {
2 | margin: 0;
3 | padding: 0;
4 | height: 100%;
5 | }
6 |
7 | body {
8 | margin: 0;
9 | height: 100%;
10 | padding: 0px;
11 | background-color: white;
12 | }
13 |
14 | #app {
15 | height: 100%;
16 |
17 | }
--------------------------------------------------------------------------------
/src/extension/build/app.bundle.js.LICENSE.txt:
--------------------------------------------------------------------------------
1 | /*!
2 | * ApexCharts v3.26.0
3 | * (c) 2018-2021 Juned Chhipa
4 | * Released under the MIT License.
5 | */
6 |
7 | /*!
8 | * Vue.js v2.6.12
9 | * (c) 2014-2020 Evan You
10 | * Released under the MIT License.
11 | */
12 |
13 | /*! svg.draggable.js - v2.2.2 - 2019-01-08
14 | * https://github.com/svgdotjs/svg.draggable.js
15 | * Copyright (c) 2019 Wout Fierens; Licensed MIT */
16 |
17 | /*! svg.filter.js - v2.0.2 - 2016-02-24
18 | * https://github.com/wout/svg.filter.js
19 | * Copyright (c) 2016 Wout Fierens; Licensed MIT */
20 |
21 | /**!
22 | * @fileOverview Kickass library to create and place poppers near their reference elements.
23 | * @version 1.15.0
24 | * @license
25 | * Copyright (c) 2016 Federico Zivolo and contributors
26 | *
27 | * Permission is hereby granted, free of charge, to any person obtaining a copy
28 | * of this software and associated documentation files (the "Software"), to deal
29 | * in the Software without restriction, including without limitation the rights
30 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
31 | * copies of the Software, and to permit persons to whom the Software is
32 | * furnished to do so, subject to the following conditions:
33 | *
34 | * The above copyright notice and this permission notice shall be included in all
35 | * copies or substantial portions of the Software.
36 | *
37 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
38 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
39 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
40 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
41 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
42 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
43 | * SOFTWARE.
44 | */
45 |
--------------------------------------------------------------------------------
/src/extension/build/assets/oVUElord_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/oslabs-beta/KangaVue/f4afae0c6f41e21aca96d7e55460aca07308d4a0/src/extension/build/assets/oVUElord_logo.png
--------------------------------------------------------------------------------
/src/extension/build/background.bundle.js:
--------------------------------------------------------------------------------
1 | !function(){var e={};chrome.tabs.query({active:!0,currentWindow:!0},(function(e){console.log("backgroundjs tabs check:",e)})),chrome.runtime.onConnect.addListener((function(n){var o=function(o,t,s){if("init"==o.name)return e[o.tabId]=n,void console.log("message.tabId background.js ln 27 = ",o.tabId)};n.onMessage.addListener(o),n.onDisconnect.addListener((function(n){n.onMessage.removeListener(o);for(var t=Object.keys(e),s=0,i=t.length;s {
80 | // console.log("Reqeust and Sender \n", req, sender);
81 |
82 | // if (req.name) {
83 | // tabsObj[req.name] = req.value;
84 | // console.log(tabsObj);
85 | // }
86 | // });
87 |
--------------------------------------------------------------------------------
/src/extension/build/content.bundle.js:
--------------------------------------------------------------------------------
1 | !function(){"use strict";var e,t,n,i,a=function(e,t){return{name:e,value:void 0===t?-1:t,delta:0,entries:[],id:"v1-".concat(Date.now(),"-").concat(Math.floor(8999999999999*Math.random())+1e12)}},r=function(e,t){try{if(PerformanceObserver.supportedEntryTypes.includes(e)){var n=new PerformanceObserver((function(e){return e.getEntries().map(t)}));return n.observe({type:e,buffered:!0}),n}}catch(e){}},o=function(e,t){var n=function n(i){"pagehide"!==i.type&&"hidden"!==document.visibilityState||(e(i),t&&(removeEventListener("visibilitychange",n,!0),removeEventListener("pagehide",n,!0)))};addEventListener("visibilitychange",n,!0),addEventListener("pagehide",n,!0)},c=function(e){addEventListener("pageshow",(function(t){t.persisted&&e(t)}),!0)},u="function"==typeof WeakSet?new WeakSet:new Set,s=function(e,t,n){var i;return function(){t.value>=0&&(n||u.has(t)||"hidden"===document.visibilityState)&&(t.delta=t.value-(i||0),(t.delta||void 0===i)&&(i=t.value,e(t)))}},m=-1,d=function(){return"hidden"===document.visibilityState?0:1/0},f=function(){o((function(e){var t=e.timeStamp;m=t}),!0)},p=function(){return m<0&&(m=d(),f(),c((function(){setTimeout((function(){m=d(),f()}),0)}))),{get timeStamp(){return m}}},v={passive:!0,capture:!0},l=new Date,h=function(i,a){e||(e=a,t=i,n=new Date,S(removeEventListener),g())},g=function(){if(t>=0&&t1e12?new Date:performance.now())-e.timeStamp;"pointerdown"==e.type?function(e,t){var n=function(){h(e,t),a()},i=function(){a()},a=function(){removeEventListener("pointerup",n,v),removeEventListener("pointercancel",i,v)};addEventListener("pointerup",n,v),addEventListener("pointercancel",i,v)}(t,e):h(t,e)}},S=function(e){["mousedown","keydown","touchstart","pointerdown"].forEach((function(t){return e(t,y,v)}))};let E=document.createElement("script");E.src=chrome.runtime.getURL("script.bundle.js"),E.type="module",E.onload=function(){this.remove()},(document.head||document.documentElement).appendChild(E);const w={},L=({name:e,value:t})=>{w[e]=t,chrome.runtime.sendMessage({type:"performance:metric",name:e,value:t,id:"webMetric"})};!function(e){var t,n=a("TTFB");t=function(){try{var t=performance.getEntriesByType("navigation")[0]||function(){var e=performance.timing,t={entryType:"navigation",startTime:0};for(var n in e)"navigationStart"!==n&&"toJSON"!==n&&(t[n]=Math.max(e[n]-e.navigationStart,0));return t}();n.value=n.delta=t.responseStart,n.entries=[t],e(n)}catch(e){}},"complete"===document.readyState?setTimeout(t,0):addEventListener("pageshow",t)}(L),function(e,t){var n,i=p(),m=a("LCP"),d=function(e){var t=e.startTime;t {
16 | metrics[name] = value;
17 |
18 | chrome.runtime.sendMessage({
19 | type: 'performance:metric',
20 | name,
21 | value,
22 | id: 'webMetric',
23 | });
24 | };
25 |
26 | // Functions that calculate web metric values.
27 | getTTFB(gatherMetrics);
28 | getLCP(gatherMetrics);
29 | getFID(gatherMetrics);
30 | getFCP(gatherMetrics);
31 | getCLS(gatherMetrics);
32 |
33 |
34 | // chrome.runtime.onConnect.addListener(function(port) {
35 | // console.assert(port.name == "content_script / NavBar");
36 | // port.onMessage.addListener(function(msg) {
37 | // console.log("message recieved on Nav Bar" + msg);
38 | // });
39 | // });
40 |
41 | window.addEventListener('message', function(event) {
42 | // Only accept messages from the same frame
43 | if (event.source !== window) {
44 | return;
45 | }
46 |
47 | var message = event.data;
48 |
49 | // Only accept messages that we know are ours
50 | if (typeof message !== 'object' || message === null ||
51 | !message.source === 'KangaVUE') {
52 | return;
53 | }
54 | console.log("content script sending message, ln45:", message)
55 | chrome.runtime.sendMessage(message);
56 | });
--------------------------------------------------------------------------------
/src/extension/build/devtools.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | KangaVue Devtools Page
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/src/extension/build/devtools.js:
--------------------------------------------------------------------------------
1 | chrome.devtools.panels.create('KangaVue', 'assets/oVUElord_logo.png', 'panel.html', () => {});
2 |
3 | var backgroundPageConnection = chrome.runtime.connect({
4 | name: "panel"
5 | });
6 |
7 | let frontEndConnection = chrome.runtime.connect({
8 | name: "frontEnd"
9 | });
10 |
11 | backgroundPageConnection.postMessage({
12 | name: 'init',
13 | tabId: chrome.devtools.inspectedWindow.tabId
14 | });
15 |
16 | // let backgroundPageConnection = chrome.runtime.connect({
17 | // name: "devtools-page"
18 | // });
19 |
20 | backgroundPageConnection.onMessage.addListener(function (message,) {
21 | chrome.runtime.onMessage.addListener((message, callback) => {
22 | if (message == "runContentScript"){
23 | chrome.scripting.executeScript({
24 | file: 'content_script.js'
25 | });
26 | }else if(message.id === 'filteredMap'){
27 | // console.log("backpagecon:", backgroundPageConnection)
28 | // console.log('frontendcon:', frontEndConnection)
29 | console.log("msg:", message)
30 | console.log("message.tabId:", message.tabId)
31 | localStorage.setItem('treemap', JSON.stringify(message.map))
32 | console.log("localstorage:", window.localStorage)
33 | } else if(message.id === 'webMetric'){
34 | console.log('Web Metric Received!', message.name, message.value);
35 | localStorage.setItem(message.name, message.value);
36 | }
37 | });});
38 |
39 |
40 | // // Relay the tab ID to the background page
41 | // chrome.runtime.sendMessage({
42 | // tabId: chrome.devtools.inspectedWindow.tabId,
43 | // scriptToInject: "content_script.js"
44 | // });
45 |
46 |
--------------------------------------------------------------------------------
/src/extension/build/fontAwesome.js:
--------------------------------------------------------------------------------
1 | window.FontAwesomeKitConfig = {"asyncLoading":{"enabled":false},"autoA11y":{"enabled":true},"baseUrl":"https://ka-f.fontawesome.com","baseUrlKit":"https://kit.fontawesome.com","detectConflictsUntil":null,"iconUploads":{},"id":45213814,"license":"free","method":"css","minify":{"enabled":true},"token":"2babf6893c","v4FontFaceShim":{"enabled":true},"v4shim":{"enabled":true},"version":"5.15.3"};
2 | !function(t){"function"==typeof define&&define.amd?define("kit-loader",t):t()}((function(){"use strict";function t(e){return(t="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(e)}function e(t,e,n){return e in t?Object.defineProperty(t,e,{value:n,enumerable:!0,configurable:!0,writable:!0}):t[e]=n,t}function n(t,e){var n=Object.keys(t);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(t);e&&(r=r.filter((function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),n.push.apply(n,r)}return n}function r(t){for(var r=1;rt.length)&&(e=t.length);for(var n=0,r=new Array(e);n2&&void 0!==arguments[2]?arguments[2]:function(){},o=e.document||o,i=u.bind(u,o,["fa","fab","fas","far","fal","fad","fak"]),f=Object.keys(t.iconUploads||{}).length>0;t.autoA11y.enabled&&n(i);var s=[{id:"fa-main",addOn:void 0}];t.v4shim.enabled&&s.push({id:"fa-v4-shims",addOn:"-v4-shims"}),t.v4FontFaceShim.enabled&&s.push({id:"fa-v4-font-face",addOn:"-v4-font-face"}),f&&s.push({id:"fa-kit-upload",customCss:!0});var d=s.map((function(n){return new _((function(o,i){P(n.customCss?a(t):c(t,{addOn:n.addOn,minify:t.minify.enabled}),e).then((function(i){o(U(i,r(r({},e),{},{baseUrl:t.baseUrl,version:t.version,id:n.id,contentFilter:function(t,e){return C(t,e.baseUrl,e.version)}})))})).catch(i)}))}));return _.all(d)}function U(t,e){var n=e.contentFilter||function(t,e){return t},r=document.createElement("style"),o=document.createTextNode(n(t,e));return r.appendChild(o),r.media="all",e.id&&r.setAttribute("id",e.id),e&&e.detectingConflicts&&e.detectionIgnoreAttr&&r.setAttributeNode(document.createAttribute(e.detectionIgnoreAttr)),r}function k(t,e){e.autoA11y=t.autoA11y.enabled,"pro"===t.license&&(e.autoFetchSvg=!0,e.fetchSvgFrom=t.baseUrl+"/releases/"+("latest"===t.version?"latest":"v".concat(t.version))+"/svgs",e.fetchUploadedSvgFrom=t.uploadsUrl);var n=[];return t.v4shim.enabled&&n.push(new _((function(n,o){P(c(t,{addOn:"-v4-shims",minify:t.minify.enabled}),e).then((function(t){n(I(t,r(r({},e),{},{id:"fa-v4-shims"})))})).catch(o)}))),n.push(new _((function(n,o){P(c(t,{minify:t.minify.enabled}),e).then((function(t){var o=I(t,r(r({},e),{},{id:"fa-main"}));n(function(t,e){var n=e&&void 0!==e.autoFetchSvg?e.autoFetchSvg:void 0,r=e&&void 0!==e.autoA11y?e.autoA11y:void 0;void 0!==r&&t.setAttribute("data-auto-a11y",r?"true":"false");n&&(t.setAttributeNode(document.createAttribute("data-auto-fetch-svg")),t.setAttribute("data-fetch-svg-from",e.fetchSvgFrom),t.setAttribute("data-fetch-uploaded-svg-from",e.fetchUploadedSvgFrom));return t}(o,e))})).catch(o)}))),_.all(n)}function I(t,e){var n=document.createElement("SCRIPT"),r=document.createTextNode(t);return n.appendChild(r),n.referrerPolicy="strict-origin",e.id&&n.setAttribute("id",e.id),e&&e.detectingConflicts&&e.detectionIgnoreAttr&&n.setAttributeNode(document.createAttribute(e.detectionIgnoreAttr)),n}function L(t){var e,n=[],r=document,o=r.documentElement.doScroll,i=(o?/^loaded|^c/:/^loaded|^i|^c/).test(r.readyState);i||r.addEventListener("DOMContentLoaded",e=function(){for(r.removeEventListener("DOMContentLoaded",e),i=1;e=n.shift();)e()}),i?setTimeout(t,0):n.push(t)}function T(t){"undefined"!=typeof MutationObserver&&new MutationObserver(t).observe(document,{childList:!0,subtree:!0})}try{if(window.FontAwesomeKitConfig){var x=window.FontAwesomeKitConfig,M={detectingConflicts:x.detectConflictsUntil&&new Date<=new Date(x.detectConflictsUntil),detectionIgnoreAttr:"data-fa-detection-ignore",fetch:window.fetch,token:x.token,XMLHttpRequest:window.XMLHttpRequest,document:document},D=document.currentScript,N=D?D.parentElement:document.head;(function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};return"js"===t.method?k(t,e):"css"===t.method?F(t,e,(function(t){L(t),T(t)})):void 0})(x,M).then((function(t){t.map((function(t){try{N.insertBefore(t,D?D.nextSibling:null)}catch(e){N.appendChild(t)}})),M.detectingConflicts&&D&&L((function(){D.setAttributeNode(document.createAttribute(M.detectionIgnoreAttr));var t=function(t,e){var n=document.createElement("script");return e&&e.detectionIgnoreAttr&&n.setAttributeNode(document.createAttribute(e.detectionIgnoreAttr)),n.src=c(t,{baseFilename:"conflict-detection",fileSuffix:"js",subdir:"js",minify:t.minify.enabled}),n}(x,M);document.body.appendChild(t)}))})).catch((function(t){console.error("".concat("Font Awesome Kit:"," ").concat(t))}))}}catch(t){console.error("".concat("Font Awesome Kit:"," ").concat(t))}}));
3 |
4 | // script for manifest file
5 | // "content_security_policy": "script-src 'self' https://kit.fontawesome.com/2babf6893c.js; object-src 'self'",
--------------------------------------------------------------------------------
/src/extension/build/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "KangaVue",
3 | "description": "Developer Tool for Vue",
4 | "version": "1.0",
5 | "permissions": [
6 | "contextMenus",
7 | "tabs",
8 | "activeTab",
9 | "storage"
10 | ],
11 | "host_permissions": [
12 | "http://localhost/*",
13 | "https://localhost/*"
14 | ],
15 | "manifest_version": 3,
16 | "minimum_chrome_version": "10.0",
17 | "devtools_page": "devtools.html",
18 | "background": {
19 | "service_worker": "background.bundle.js"
20 | },
21 | "content_scripts": [
22 | {
23 | "matches": [
24 | "http://localhost/*",
25 | "https://localhost/*"
26 | ],
27 | "js": [
28 | "content.bundle.js"
29 | ],
30 | "run_at": "document_start"
31 | }
32 | ],
33 | "web_accessible_resources": [
34 | {
35 | "resources": [
36 | "script.bundle.js"
37 | ],
38 | "matches": [
39 | "http://localhost/*",
40 | "https://localhost/*"
41 | ]
42 | }
43 | ]
44 |
45 | }
--------------------------------------------------------------------------------
/src/extension/build/panel.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | KangaVue Extension Panel
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/src/extension/build/script.bundle.js:
--------------------------------------------------------------------------------
1 | window.addEventListener("keydown",(()=>{let e=function e(n,t={children:[]}){if(!n.$children)return t;let i=n.$vnode.tag;return i.startsWith("vue-component-")&&(i=i.slice(14)),t.name=i,n.$children.forEach((n=>t.children.push(e(n)))),t}(window.__VUE_DEVTOOLS_INSTANCE_MAP__.get("1:3"));window.postMessage({map:e,source:"kangaVUE",id:"filteredMap"},"*")}));
--------------------------------------------------------------------------------
/src/extension/build/script.js:
--------------------------------------------------------------------------------
1 | window.addEventListener('keydown', () => {
2 | function getMap(c, output = { children: [] }) {
3 | if (!c.$children) {
4 | return output;
5 | }
6 | let tag = c.$vnode.tag
7 | if(tag.startsWith("vue-component-")){
8 | tag = tag.slice(14)
9 | }
10 | output.name = tag;
11 | c.$children.forEach((child) => output.children.push(getMap(child)));
12 | return output;
13 | }
14 | let map = getMap(window.__VUE_DEVTOOLS_INSTANCE_MAP__.get('1:3'))
15 | window.postMessage({
16 | map: map,
17 | source: 'kangaVUE',
18 | id: 'filteredMap'
19 | }, '*')
20 | // chrome.storage.sync.set(
21 | // {currTab: window.__VUE_DEVTOOLS_INSTANCE_MAP__}, () => {console.log("stored on", currTab)}
22 | // )
23 | });
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 | const { VueLoaderPlugin } = require('vue-loader');
3 | const MiniCssExtractPlugin = require('mini-css-extract-plugin');
4 | // const autoprefixer = require("autoprefixer");
5 | // const ChromeExtensionReloader = require('webpack-chrome-extension-reloader'); // enable hot reloading while developing a chrome extension
6 |
7 | const isDevelopment = process.env.NODE_ENV !== 'production';
8 |
9 | module.exports = {
10 | entry: {
11 | app: './src/app/index.js',
12 | background: './src/extension/build/background.js',
13 | content: './src/extension/build/content_script.js',
14 | script: './src/extension/build/script.js',
15 | // backend: './src/backend/index.ts',
16 | },
17 | output: {
18 | path: path.resolve(__dirname, 'src/extension/build'),
19 | filename: '[name].bundle.js',
20 | },
21 | module: {
22 | rules: [
23 | {
24 | test: /\.txt$/,
25 | use: 'raw-loader',
26 | },
27 | {
28 | test: /\.js$/,
29 | exclude: /node_modules/,
30 | use: {
31 | loader: 'babel-loader',
32 | },
33 | },
34 | {
35 | test: /\.vue$/,
36 | loader: 'vue-loader',
37 | options: {
38 | loaders: {
39 | // Since sass-loader (weirdly) has SCSS as its default parse mode, we map
40 | // the "scss" and "sass" values for the lang attribute to the right configs here.
41 | // other preprocessors should work out of the box, no loader config like this nessessary.
42 | scss: 'vue-style-loader!css-loader!sass-loader',
43 | sass: 'vue-style-loader!css-loader!sass-loader?indentedSyntax',
44 | },
45 | // other vue-loader options go here
46 | },
47 | },
48 | {
49 | test: /\.css$/,
50 | use: ['vue-style-loader', 'css-loader'],
51 | },
52 | // {
53 | // test: /\.s?css$/,
54 | // use: [
55 | // "style-loader",
56 | // MiniCssExtractPlugin.loader,
57 | // "css-loader",
58 | // {
59 | // loader: "postcss-loader",
60 | // options: {
61 | // plugins: () => [autoprefixer()],
62 | // },
63 | // },
64 | // "sass-loader",
65 | // ],
66 | // },
67 | // {
68 | // test: /\.module\.s(a|c)ss$/,
69 | // loader: [
70 | // isDevelopment ? 'style-loader' : MiniCssExtractPlugin.loader,
71 | // {
72 | // loader: 'css-loader',
73 | // options: {
74 | // modules: true,
75 | // sourceMap: isDevelopment,
76 | // },
77 | // },
78 | // {
79 | // loader: 'sass-loader',
80 | // options: {
81 | // sourceMap: isDevelopment,
82 | // },
83 | // },
84 | // ],
85 | // },
86 | // {
87 | // test: /\.s(a|c)ss$/,
88 | // exclude: /\.module.(s(a|c)ss)$/,
89 | // loader: [
90 | // isDevelopment ? 'style-loader' : MiniCssExtractPlugin.loader,
91 | // 'css-loader',
92 | // {
93 | // loader: 'sass-loader',
94 | // options: {
95 | // sourceMap: isDevelopment,
96 | // },
97 | // },
98 | // ],
99 | // },
100 | ],
101 | },
102 | plugins: [
103 | new VueLoaderPlugin(),
104 | // new MiniCssExtractPlugin(),
105 | new MiniCssExtractPlugin({
106 | filename: isDevelopment ? '[name].css' : '[name].[hash].css',
107 | chunkFilename: isDevelopment ? '[id].css' : '[id].[hash].css',
108 | }),
109 | ],
110 | // resolve: {
111 | // // alias: {
112 | // // vue$: "vue/dist/vue.runtime.esm.js",
113 | // // },
114 | // // extensions: ["*", ".js", ".vue", ".json"],
115 | // extensions: ['.js', '.jsx', '.scss'],
116 | // },
117 | };
118 |
--------------------------------------------------------------------------------