Implementation of Quick Preview Debugging for Mobile Development

Laws are created and discovered, and memory is the derivation and extraction of laws

background

When I was working on the vue2 mobile terminal project, I made a quick scan code preview function on the mobile terminal. It was very useful in the debugging phase, so I wanted to move it into the vue3 project. I thought it was very simple, but I encountered several problems. stuck me for a long time

  1. Introduction of global variables
  2. custom directive
  3. The instructions of createApp are not shared (the instructions must have been mounted on the element when rendering)

need

When developing on the web side, if you want to quickly see the effect on the mobile phone side, scanning the code and opening it on the browser side is the most convenient choice. At the same time, if you want to preview in the app, the copy function is provided, and the webview synchronization preview is realized through the app's read and paste content + scheme jump function.

Realize ideas

  1. Use hmr to synchronize the debug page of the same ip
  2. Dynamically obtain the native IP in the development stage and inject it into the development environment
  3. Build the component, dynamically generate the corresponding debugging url according to the IP, and generate the corresponding QR code and copy content
  4. Determine whether to display the component by routing the query parameter

accomplish

Use hmr to synchronize the debug page of the same ip

Both webpack and vite provide the hmr function

Dynamically obtain the native IP in the development stage and inject it into the development environment

nodejs can easily get the native ip:

const os = require("os");
function GetIp() {
  let ifaces = os.networkInterfaces();
  for (let i in ifaces) {
    for (let j in ifaces[i]) {
      let alias = ifaces[i][j];
      if (
        alias.family === "IPv4" &&
        alias.address !== "127.0.0.1" &&
        !alias.internal
      ) {
        return alias.address;
      }
    }
  }
}
export default GetIp()
复制代码

After getting the ip, webpack injects it through process.env

new webpack.DefinePlugin({
      'process.env': {IP: GetIp()}
  })
复制代码

vite is injected through define

  define: {
    VITE_DEV_IP: JSON.stringify(GetIp())
  }
复制代码

build components

Only the components of vue3 are shown here

<style lang="less" scoped>
.dev-code {
  position: fixed;
  top: 50%;
  transform: translateY(-50%);
  right: 0;
  background-color: #ffffff;
  .tips {
    font-size: 0.18rem;
    color: #000;
    margin: 0.1rem 0;
    text-align: center;
  }
  .close-btn {
    width: 0.4rem;
    height: 0.4rem;
    position: absolute;
    left: 0;
    right: 0;
    bottom: -0.5rem;
    margin: auto;
    img {
      width: 100%;
      height: 100%;
    }
  }
}
</style>
<template>
  <Teleport to="body">
    <section
      class="dev-code"
      v-show="visible == true"
      v-clipboard:copy="url"
      v-clipboard:success="Tip"
    >
      <qrcode :value="url" id="qrcode" />
      <div class="tips">扫码手机联调</div>
      <div class="tips">点击复制链接</div>
      <a href="javascript:;" class="close-btn" @click.stop="visible = false">
        <img src="https://xxxcdn.xxx.cn/common/close-grey.png" />
      </a>
    </section>
  </Teleport>
</template>
<script lang="ts" setup>
// 调试用二维码
import qrcode from "../qrcode.vue";
import { ref } from "vue";
import { toast } from "../toast/useToast";
defineProps({
  url: {
    type: String,
    // 这里vite通过define定义的全局变量会注入到window对象上,所以命名要独特
    default: `${location.protocol}//${window.VITE_DEV_IP}:${location.port}${location.pathname
      }${location.search.replace("debug=1", "")}`,
  },
});
const visible = ref(true);
function Tip() {
  toast("已成功复制,去浏览器打开吧,注意要和电脑在同一局域网哦~");
}
</script>

// 构建渲染函数
import { mountComponent } from "../../lib/utils/mount-component";
import devCodeConstructor from "./devCode.vue";
const debug = () => {
  return mountComponent(devCodeConstructor);
};
export default debug;
复制代码

The rendering function can refer toprevious post

Determine whether to display the component by routing the query parameter

Add an interceptor to the router, and display the component when the specified query parameter is read in the development environment

router.afterEach((to, from) => {
  if (import.meta.env.MODE === 'development' 
  && !!to.query.debug 
  && +to.query.debug === 1) {
    debug();
  }
});
复制代码

question

Introduction of global variables

Previously, webpack used DefinePlugin to inject process.env to achieve

The new framework uses vite, and vite also provides the function of global variable injection, mainly using dotenv to load additional environment variables from files in your environment directory, but dotenv files are static, I don't want other developers to have to Check the ip and write it in by yourself, all you can find is the define options to inject dynamic variables into the window object, but this method needs to pay attention, the injected data must be the string deserialized by Json.stringify, and the string itself must be reversed . Serialize it , everything is for laziness ^_^

The global variables injected by dotenv can be obtained through import.meta.env.development.xxx, you can参考官方文档, define options 也可以参考官方文档

自定义指令

自定义指令主要为了实现复制功能,可以参考我之前的一篇文章

createApp的指令不共用(render的时候指令要已经挂载到元素上)

新的createApp不会公用其他createApp实例的指令,于是对之前的方法做了一个扩展:

import { Component, createApp } from "vue";
import DirectiveExtensions from "../../directive";
export function mountComponent(rootComponent: Component) {
  // 添加自定义 指令
  const app = createApp(rootComponent).use(DirectiveExtensions);
  const root = document.createElement("div");
  document.body.appendChild(root);
  return {
    instance: app.mount(root),
    unmount() {
      app.unmount();
      document.body.removeChild(root);
    },
  };
}
复制代码

实现效果

微信图片_20220325175222.png

Guess you like

Origin juejin.im/post/7078981127435714596