When developing mobile terminal projects based on vue. js, in some specific problems and scenarios, the project can only be run on the mobile terminal to reproduce and track the problems (such as in wechat terminal and App container), and Devtools on the desktop will not be available. After installing the Electron version of DevTools several times, I found it too cumbersome to debug, so I decided to move DevTools into vConsole

If you don’t know what vConsole is, you can look herevConsole Readme

End result:

Sample Code Experience address: CodePen

Welcome to Star at Github address

It’s very simple to introduce

import VConsole from "vconsole";
import Devtools from 'vue-vconsole-devtools'
Devtools.initPlugin(new VConsole());
Copy the code

Effect:

The implementation process

After analyzing the source code for Vue, VUe-Devtools, and vConsole, it seems feasible. The steps are as follows:

  1. Strip the vue-devtools@front part
  2. Communicates with @Backend and @front
  3. Implement front injection of iframe
  4. Embedded iframe vConsole
  5. Create and distribute NPM packages

1. Peel off the front

First of all, vue-DevTools is not a library, so it is not available on NPM and cannot be referenced. Second, this project is not suitable for library output, because it is packaged in a special way, and the purpose of this project itself is packaged into an executable App or Chrome plug-in. So if you want to reference the code inside it, I think the easiest way is to copy it… So stripping frontend is very simple. Add script “buildvc” to vue-devTools package. Json: “cd packages/shell-dev && cross-env NODE_ENV=production webpack –progress –hide-modules”, Also add a file called inject.js in shell-dev:

import { initDevTools } from '@front'
import Bridge from '@utils/bridge'

const targetWindow = window.parent;
document.body.style.overflow = "scroll";
initDevTools({
  connect (cb) {
    cb(new Bridge({
      listen (fn) {
        window.addEventListener('message'.evt= > {
          fn(evt.data)
        })
      },
      send (data) {
        targetWindow.postMessage(data, The '*') } })) }, onReload (reloadFn) { reloadFn.call(); }})Copy the code

Inject: ‘./ SRC /inject.js’

The typed package is the front part we want, and finally embedded in the iframe.

2. Achieve communication

Inject. Js contains the front part of the code to receive and send messages. The backend sends and receives messages.

import { initBackend } from '@back'
import Bridge from '@utils/bridge'

const initBackendWithTargetWindow = function(win,targetWindow){
  const bridge = new Bridge({
    listen (fn) {
      win.addEventListener('message'.evt= > {
        fn(evt.data)})
    },
    send (data) {
      targetWindow.postMessage(data, The '*')
    }
  })
  
  initBackend(bridge)
}

export default { initBackendWithTargetWindow }
Copy the code

3. Front embedded iframe

This is quite troublesome and also encountered some compatibility problems. The final solution is:

  1. Rename the inject.js packed in step 1 to inject.txt
  2. Add a rawLoader rule to identify TXT
  3. Insert into the script tag as script.txt and then into the body of the iframe
import injectString from './inject.txt'

function inject (scriptContent, done) {
  const script = document.getElementById('vue-iframe').contentWindow.document.createElement('script')
  script.text = scriptContent
  document.getElementById('vue-iframe').contentWindow.document.body.appendChild(script)
}

inject(injectString)
Copy the code

4. Iframe is embedded in vConsole

Implement a plugin class, inherit the VConsolePlugin, and then implement the corresponding method. For details, see the VConsole document VConsole Readme

class VConsoleVueTab extends VConsolePlugin {

  constructor(. args) {
    super(... args); }onRenderTab(cb){
    cb(``);
  }
  onReady() {
    target = document.getElementById('vue-iframe')
    targetWindow = target.contentWindow;
    be.initBackendWithTargetWindow(window,targetWindow);    
  }

  onShow() {    
    injectOnce(injectString)
  }
}
Copy the code

5. Create an NPM package and distribute it

This step needs to be packaged and released, and optimized

const initPlugin = function(vConsole){
  var tab = new VConsoleVueTab('vue'.'Vue');
  vConsole.addPlugin(tab);
}
export default {
  initPlugin
}
Copy the code

Updated 21-08-03, support CDN introduction

<script src="https://unpkg.com/vconsole/dist/vconsole.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue_plugin.js"></script>
<script>
  var vConsole = new window.VConsole();
  const Devtools = window.vueVconsoleDevtools["default"];
  Devtools.initPlugin(vConsole);
</script>
Copy the code