头图

It is said that 99% of people don’t know that vue-devtools can open the corresponding component files directly? Reveal the principle of this article

1 Introduction

Hello, my name is , WeChat search Vision" 160a0d7943d258 Follow me, focus on front-end technology sharing, a vision is to help the front-end to broaden its horizons to the forefront of the public account within 5 years. Welcome to add me on WeChat ruochuan12 for long-term exchange and learning.

This is the launch-editor source code ( 9) of the 160a0d7943d2ea learning source code overall architecture series. Learning Source overall architecture series ( What are the must-see JS library ): jQuery , Underscore , lodash , Sentry , vuex , Axios , KOA , Redux . The term “overall architecture” seems a bit big. Let’s say it is the overall structure of the source code. The main thing is to learn the overall structure of the code, and not to delve into the implementation of other specific functions that are not the main line. This article learns the code of the actual warehouse. The next article should be " learn the overall architecture of Vuex 4 source code, and understand its principles and provide/inject principles ".

warehouse address of this article is : git clone https://github.com/lxchuan12/open-in-editor.git , the best way to read this article, clone the warehouse and debug by yourself, easy to absorb and digest.

If someone talks about how to read the source code, if you are reading the article, you can recommend my source code series article, it is really not reporting 160a0d7943d338.

My article is written as far as possible so that readers who want to read the source code but don't know how to read it can understand. I always recommend using build the environment breakpoint debugging source code to learn , where does not point , watching while debugging, instead of just looking at . As the goes: 160a0d7943d364 It is better to teach people to fish than to teach people to fish .

After reading this article, you will learn:

  1. How to solve the error of this function
  2. How to debug learning source code
  3. launch-editor-middleware、launch-editor and other realization principles

1.1 Scenarios where the source file corresponding to the page cannot be found for a short time

I don’t know if you have encountered such a scene. When you open a page developed by yourself (or your colleague), it is difficult to find the corresponding source file in a short time.

At this time, you may want to have click the page button to automatically use the editor to open the corresponding file function, that would be great.

And vue-devtools provides such a function, maybe you don't know. I don’t think a lot of people know it, because many people don’t use vue-devtools .

open-in-editor

You may ask, I don’t use vue . I use react Is there a similar function? Yes, please see react-dev-inspector . You might also ask, what editor supports Yeah, mainstream vscode、webstorm、atom、sublime are all supported, you can see more this list Editors Supported .

This article is based on learning the launch-editor source code, which knowing it, knowing why , and exploring the vue-devtools "open component in editor" function.

1.2 Briefly describe its principle in one sentence

code path/to/file

Briefly describe the principle in one sentence: using nodejs in child_process , execute a code path/to/file , and then the corresponding editor opens the corresponding file, and the corresponding editor executes ps x in the process ( Window uses Get-Process command 060a0d7943d53d) Of course, you can also specify the editor yourself.

1.3 The error resolution of the component that cannot be opened when the editor is opened

When you actually use this function, you may encounter an error saying that the file cannot be opened.

Could not open App.vue in the editor.

To specify an editor, specify the EDITOR env variable or add "editor" field to your Vue project config.

控制台不能打开编辑器的错误提示

Here is a description of the Windows computer, VSCode editor, and terminal tools used Ubuntu At the same time, I recommend my article Use ohmyzsh to create efficient terminal command line tool windows, ubuntu, mac systems, used .

solution to 160a0d7943d5fe is also simple, which is the English meaning of .

1.3.1 Method 1: First make sure that the editor you use can be opened with a command in the terminal. The article takes VSCode as an example

If your command line itself cannot run code such as 060a0d7943d658 to open the editor, it must be an error. At this time, you need to VSCode into the command line terminal.
The injection method is also simple. A small partner in my communication group provided a screenshot of mac

mac computer is VSCode command + shift + p , Windows is ctrl + shift + p . Then enter shell and choose to install code . As shown below:

Install 'code' command in PATH

So you can open VSCode in the terminal.

If you can open it in the terminal and use the command editor to open it, but it still reports an error, then there is a high probability that your editor is not recognized.
Then you can set the designated editor through method two.

1.3.2 Method 2: Specify the editor, specify the editor in the environment variable

In vue project, the corresponding article is: vue3-project , add the .env.delelopment file, and its content is EDITOR=code . highlights here under my vue-cli version 4.5.12 , as if vue-cli 3.5 above and only supports custom EDITOR this environment variable .

# .env.development
# 当然,我的命令行终端已经有了code这个命令。
EDITOR=code
There is no need to specify the corresponding path of the editor ( c/Users/lxchu/AppData/Local/Programs/Microsoft VS Code/bin/code ), because an error will be reported. Why do I get an error, because I read the source code and tried it. Because it will be truncated according to the space and become c/Users/lxchu/AppData/Local/Programs/Microsoft , of course an error will be reported.

It is also possible that your editor path has a Chinese path and an error is reported. You can add your editor path to the environment variable.

If you pass the above methods, the error reporting problem has not been resolved. Welcome to leave a message, or add me to ruochuan12 communicate. After all, the computer environment is different, it is difficult to ensure that everyone can perform normally, but we know the principle, it is easy to solve the problem .

Next, we explore the implementation principle of the "open component in editor" function from the source code point of view.

2. vue-devtools Open component in editor document

Before exploring the principle, let's take a look at the official document of vue-devtools

vuejs/vue-devtools
Documentation

Open component in editor

To enable this feature, follow this guide.

This guide writes that Vue CLI 3 is out of the box in .

Vue CLI 3 supports this feature out-of-the-box when running vue-cli-service serve.

It also wrote in detail how to use Webpack

# 1. Import the package:
var openInEditor = require('launch-editor-middleware')
# 2. In the devServer option, register the /__open-in-editor HTTP route:
devServer: {
  before (app) {
    app.use('/__open-in-editor', openInEditor())
  }
}
# 3. The editor to launch is guessed. You can also specify the editor app with the editor option. See the supported editors list.
# 用哪个编辑器打开会自动猜测。你也可以具体指明编辑器。这里显示更多的支持编辑器列表
openInEditor('code')
# 4. You can now click on the name of the component in the Component inspector pane (if the devtools knows about its file source, a tooltip will appear).
# 如果`vue-devtools`开发者工具有提示点击的组件的显示具体路径,那么你可以在编辑器打开。

It also wrote how to use Node.js

Node.js

You can use the launch-editor package to setup an HTTP route with the /__open-in-editor path. It will receive file as an URL variable.

For more information, see this guide .

3. Environmental preparation

Readers who are familiar with me all know that I am recommended for debugging to look at the source code , as the goes: 160a0d7943d975 does not point where . And debugging is generally written in great detail, hoping to help some people know how to read the source code. So I specially built a new warehouse open-in-editor git clone https://github.com/lxchuan12/open-in-editor.git for everyone to clone and learn.

Install vue-cli

npm install -g @vue/cli
# OR
yarn global add @vue/cli
node -V
# v14.16.0
vue -V 
# @vue/cli 4.5.12
vue create vue3-project
# 这里选择的是vue3、vue2也是一样的。
# Please pick a preset: Default (Vue 3 Preview) ([Vue 3] babel, eslint)
npm install
# OR
yarn install

Here also explain my version of vscode.

code -v
1.55.2

Vue CLI 3 mentioned above, 160a0d7943d9dc can be out of the box and Webpack .

vue3-project/package.json has a debug button.

debug示意图

Select the first item, serve vue-cli-service serve .

Let's search for 'launch-editor-middleware' . Generally speaking node_modules cannot be searched, and need to be set. Of course there is also a simple way. That is, there is a setting icon on the right side of "Excluded files" "Use "Troubleshooting settings" and "Ignore files"", click down.

I won’t repeat the rest. You can read this answer: 160a0d7943da40 How to set vscode to search for files contained in node_modules?

At this time, this middleware vue3-project/node_modules/@vue/cli-service/lib/commands/serve.js

As shown below:

搜索node_modules下的文件 - launch-editor-middleware 中间件

4. vue-devtools out of the box with specific source code implementation

Next, let's look at the specific source code implementation Vue CLI 3 out of the box.

// vue3-project/node_modules/@vue/cli-service/lib/commands/serve.js
// 46行
const launchEditorMiddleware = require('launch-editor-middleware')
// 192行
before (app, server) {
    // launch editor support.
    // this works with vue-devtools & @vue/cli-overlay
    app.use('/__open-in-editor', launchEditorMiddleware(() => console.log(
        `To specify an editor, specify the EDITOR env variable or ` +
        `add "editor" field to your Vue project config.\n`
    )))
    // 省略若干代码...
}

When you click on vue-devtools , there will be a request, http://localhost:8080/__open-in-editor?file=src/App.vue , and the component will be opened without accident.

open src/App.vue in editor

Then we implemented launchEditorMiddleware

5. launch-editor-middleware

When looking at the source code, first look at the debug screenshot.

debug-launch

The role in the launch-editor-middleware middleware is to finally call launch-editor open the file.

// vue3-project/node_modules/launch-editor-middleware/index.js
const url = require('url')
const path = require('path')
const launch = require('launch-editor')

module.exports = (specifiedEditor, srcRoot, onErrorCallback) => {
  // specifiedEditor => 这里传递过来的则是 () => console.log() 函数
  // 所以和 onErrorCallback 切换下,把它赋值给错误回调函数
  if (typeof specifiedEditor === 'function') {
    onErrorCallback = specifiedEditor
    specifiedEditor = undefined
  }

  // 如果第二个参数是函数,同样把它赋值给错误回调函数
  // 这里传递过来的是undefined
  if (typeof srcRoot === 'function') {
    onErrorCallback = srcRoot
    srcRoot = undefined
  }

  // srcRoot 是传递过来的参数,或者当前node进程的目录
  srcRoot = srcRoot || process.cwd()

  // 最后返回一个函数, express 中间件
  return function launchEditorMiddleware (req, res, next) {
    // 省略 ...
  }
}

previous paragraph of 160a0d7943db71, this way of switching parameters is very common in many source codes. In order to facilitate the user to pass parameters when calling. Although there are multiple parameters, one or two can be passed.

You can set a breakpoint according to the situation. For example, here I will break launch(path.resolve(srcRoot, file), specifiedEditor, onErrorCallback)

// vue3-project/node_modules/launch-editor-middleware/index.js
module.exports = (specifiedEditor, srcRoot, onErrorCallback) => {
  // 省略上半部分
  return function launchEditorMiddleware (req, res, next) {
    // 根据请求解析出file路径
    const { file } = url.parse(req.url, true).query || {}
    // 如果没有文件路径,则报错
    if (!file) {
      res.statusCode = 500
      res.end(`launch-editor-middleware: required query param "file" is missing.`)
    } else {
      // 否则拼接路径,用launch打开。
      launch(path.resolve(srcRoot, file), specifiedEditor, onErrorCallback)
      res.end()
    }
  }
}

6. launch-editor

Following the breakpoints, I came to the launchEditor function.

// vue3-project/node_modules/launch-editor/index.js
function launchEditor (file, specifiedEditor, onErrorCallback) {
  // 解析出文件路径和行号列号等信息
  const parsed = parseFile(file)
  let { fileName } = parsed
  const { lineNumber, columnNumber } = parsed

  // 判断文件是否存在,不存在,直接返回。
  if (!fs.existsSync(fileName)) {
    return
  }
  // 所以和 onErrorCallback 切换下,把它赋值给错误回调函数
  if (typeof specifiedEditor === 'function') {
    onErrorCallback = specifiedEditor
    specifiedEditor = undefined
  }
  // 包裹一层函数
  onErrorCallback = wrapErrorCallback(onErrorCallback)

  // 猜测当前进程运行的是哪个编辑器
  const [editor, ...args] = guessEditor(specifiedEditor)
  if (!editor) {
    onErrorCallback(fileName, null)
    return
  }
  // 省略剩余部分,后文再讲述...
}

6.1 wrapErrorCallback wrap error function callback

onErrorCallback = wrapErrorCallback(onErrorCallback)

This code is to pass the error callback function, wrapErrorCallback returned to a new function, and wrapErrorCallback executed, onErrorCallback(cb) is executed.

I believe that readers can understand, I come alone to tell, mainly because this form wrapped in many functions in the source code are common .

This is the code position output by the Could not open App.vue in the editor. at the beginning of the article.

// vue3-project/node_modules/launch-editor/index.js
function wrapErrorCallback (cb) {
  return (fileName, errorMessage) => {
    console.log()
    console.log(
      chalk.red('Could not open ' + path.basename(fileName) + ' in the editor.')
    )
    if (errorMessage) {
      if (errorMessage[errorMessage.length - 1] !== '.') {
        errorMessage += '.'
      }
      console.log(
        chalk.red('The editor process exited with an error: ' + errorMessage)
      )
    }
    console.log()
    if (cb) cb(fileName, errorMessage)
  }
}

6.2 guessEditor guess the editor currently in use

This function mainly does the following four things:

  1. If the editor is specified, it will be parsed and returned.
  2. Find out which editor is running in the current process. macOS and Linux use ps x command
    windows use Get-Process command
  3. If none is found, use process.env.VISUAL or process.env.EDITOR . This is why the initial error prompts that you can use environment variables to specify the editor.
  4. In the end [null] it is not found, and an error will be reported.
const [editor, ...args] = guessEditor(specifiedEditor)
if (!editor) {
    onErrorCallback(fileName, null)
    return
}
// vue3-project/node_modules/launch-editor/guess.js
const shellQuote = require('shell-quote')
const childProcess = require('child_process')

module.exports = function guessEditor (specifiedEditor) {
  // 如果指定了编辑器,则解析一下,这里没有传入。如果自己指定了路径。
  // 比如 c/Users/lxchu/AppData/Local/Programs/Microsoft VS Code/bin/code 
  //   会根据空格切割成 c/Users/lxchu/AppData/Local/Programs/Microsoft
  if (specifiedEditor) {
    return shellQuote.parse(specifiedEditor)
  }
  // We can find out which editor is currently running by:
  // `ps x` on macOS and Linux
  // `Get-Process` on Windows
  try {
    //  代码有删减
    if (process.platform === 'darwin') {
      const output = childProcess.execSync('ps x').toString()
      // 省略
    } else if (process.platform === 'win32') {
      const output = childProcess
        .execSync('powershell -Command "Get-Process | Select-Object Path"', {
          stdio: ['pipe', 'pipe', 'ignore']
        })
        .toString()
        // 省略
    } else if (process.platform === 'linux') {
      const output = childProcess
        .execSync('ps x --no-heading -o comm --sort=comm')
        .toString()
    }
  } catch (error) {
    // Ignore...
  }

  // Last resort, use old skool env vars
  if (process.env.VISUAL) {
    return [process.env.VISUAL]
  } else if (process.env.EDITOR) {
    return [process.env.EDITOR]
  }

  return [null]
}

After reading the guessEditor function, let's look launch-editor rest of 060a0d7943dd60.

6.3 The rest of launch-editor

You don't need to look at the following code carefully, just look at it carefully when debugging.

// vue3-project/node_modules/launch-editor/index.js
function launchEditor(){
  //  省略上部分...
  if (
    process.platform === 'linux' &&
    fileName.startsWith('/mnt/') &&
    /Microsoft/i.test(os.release())
  ) {
    // Assume WSL / "Bash on Ubuntu on Windows" is being used, and
    // that the file exists on the Windows file system.
    // `os.release()` is "4.4.0-43-Microsoft" in the current release
    // build of WSL, see: https://github.com/Microsoft/BashOnWindows/issues/423#issuecomment-221627364
    // When a Windows editor is specified, interop functionality can
    // handle the path translation, but only if a relative path is used.
    fileName = path.relative('', fileName)
  }

  if (lineNumber) {
    const extraArgs = getArgumentsForPosition(editor, fileName, lineNumber, columnNumber)
    args.push.apply(args, extraArgs)
  } else {
    args.push(fileName)
  }

  if (_childProcess && isTerminalEditor(editor)) {
    // There's an existing editor process already and it's attached
    // to the terminal, so go kill it. Otherwise two separate editor
    // instances attach to the stdin/stdout which gets confusing.
    _childProcess.kill('SIGKILL')
  }

  if (process.platform === 'win32') {
    // On Windows, launch the editor in a shell because spawn can only
    // launch .exe files.
    _childProcess = childProcess.spawn(
      'cmd.exe',
      ['/C', editor].concat(args),
      { stdio: 'inherit' }
    )
  } else {
    _childProcess = childProcess.spawn(editor, args, { stdio: 'inherit' })
  }
  _childProcess.on('exit', function (errorCode) {
    _childProcess = null

    if (errorCode) {
      onErrorCallback(fileName, '(code ' + errorCode + ')')
    }
  })

  _childProcess.on('error', function (error) {
    onErrorCallback(fileName, error.message)
  })
}

In this large segment, the main thing is following code , using the sub-process module. Simply put, the subprocess module has the ability to execute commands.

const childProcess = require('child_process')

if (process.platform === 'win32') {
    // On Windows, launch the editor in a shell because spawn can only
    // launch .exe files.
    _childProcess = childProcess.spawn(
        'cmd.exe',
        ['/C', editor].concat(args),
        { stdio: 'inherit' }
    )
    } else {
    _childProcess = childProcess.spawn(editor, args, { stdio: 'inherit' })
}

At this point in the writing, it is basically close to the end. The principle is actually to use nodejs in child_process to execute a command code path/to/file

7. Summary

Here is a summary: First of all, at the beginning of the article, it proposes "the scenario where the source file corresponding to the page cannot be found in a short time", and gives a solution to the error situation that is easy to encounter.
Secondly, configure the debug learning environment along with the vue-devtools especially the capital used in yyx990803 / Launch Editor- .

7.1 Briefly describe its principle in one sentence

Let's review the content of the principle at the beginning.

code path/to/file

Briefly explain the principle in one sentence: using nodejs in child_process , execute a code path/to/file , and then the corresponding editor opens the corresponding file, and the corresponding editor executes ps x in the process ( Window uses Get-Process ) command. Of course, you can also specify the editor yourself.

What can be done in the end.

You can look at umijs/launch-editor and react-dev-utils/launchEditor.js . Their codes are almost similar.

You can also use Node.js do some work such as improving development efficiency, and you can learn child_process and other modules at the same time.

also don't imprison your own thinking, imprison the front end in the page, you should broaden your field of vision .

Node.js for our front-end people to explore operating files, operating networks, etc.

If readers find something wrong or can be improved, or if there is no clear place, please comment and point out. In addition, I feel that it is well written, and it is a little helpful to you. You can like, comment, forward and share. It is also a kind of support for me. Thank you very much. If you can pay attention to my front-end public Vision" 160a0d7943df33, it would be better.

on

Hello, I’m , WeChat search Vision" 160a0d7943df8e Follow me, focus on front-end technology sharing, a vision is to help the front-end to broaden its horizons to the forefront of the public account within 5 years. Welcome to add me on WeChat ruochuan12 for long-term exchange and learning.
There are mainly the following series of articles: learning source code overall architecture series , annual summary , JS basic series

Reference link

yyx990803/launch-editor

umijs/launch-editor

vuejs/vue-devtools

vue-devtools open-in-editor.md

"Open in editor" button doesn't work in Win 10 with VSCode if installation path contains spaces

react-dev-utils/launchEditor.js


若川视野公众号
发布前端技术文章和随笔等。公众号若川视野,公众号经常更新,欢迎关注,长期交流学习。

你好,我是若川。写有 《学习源码整体架构系列》 20余篇。

7k 声望
3.2k 粉丝
0 条评论
推荐阅读
尤雨溪推荐神器 ni ,能替代 npm/yarn/pnpm ?简单好用!源码揭秘!
想学源码,极力推荐之前我写的《学习源码整体架构系列》 包含jQuery、underscore、lodash、vuex、sentry、axios、redux、koa、vue-devtools、vuex4、koa-compose、vue-next-release、vue-this、create-vue等十余...

若川6阅读 6.3k

从零搭建 Node.js 企业级 Web 服务器(零):静态服务
过去 5 年,我前后在菜鸟网络和蚂蚁金服做开发工作,一方面支撑业务团队开发各类业务系统,另一方面在自己的技术团队做基础技术建设。期间借着 Node.js 的锋芒做了不少 Web 系统,有的至今生气蓬勃、有的早已夭折...

乌柏木142阅读 11.9k评论 10

从零搭建 Node.js 企业级 Web 服务器(十五):总结与展望
总结截止到本章 “从零搭建 Node.js 企业级 Web 服务器” 主题共计 16 章内容就更新完毕了,回顾第零章曾写道:搭建一个 Node.js 企业级 Web 服务器并非难事,只是必须做好几个关键事项这几件必须做好的关键事项就...

乌柏木60阅读 6k评论 16

再也不学AJAX了!(二)使用AJAX ① XMLHttpRequest
「再也不学 AJAX 了」是一个以 AJAX 为主题的系列文章,希望读者通过阅读本系列文章,能够对 AJAX 技术有更加深入的认识和理解,从此能够再也不用专门学习 AJAX。本篇文章为该系列的第二篇,最近更新于 2023 年 1...

libinfs39阅读 6.2k评论 12

封面图
从零搭建 Node.js 企业级 Web 服务器(一):接口与分层
分层规范从本章起,正式进入企业级 Web 服务器核心内容。通常,一块完整的业务逻辑是由视图层、控制层、服务层、模型层共同定义与实现的,如下图:从上至下,抽象层次逐渐加深。从下至上,业务细节逐渐清晰。视图...

乌柏木39阅读 7.1k评论 6

CSS 绘制一只思否猫
欢迎关注我的公众号:前端侦探练习 CSS 有一个比较有趣的方式,就是发挥想象,绘制各式各样的图案,比如来绘制一只思否猫?思否猫,SegmentFault 思否的吉祥物,是一只独一无二、特立独行、热爱自由的(>^ω^&lt...

XboxYan42阅读 2.8k评论 14

封面图
还在用 JS 做节流吗?CSS 也可以防止按钮重复点击
举个例子:一个保存按钮,为了避免重复提交或者服务器考虑,往往需要对点击行为做一定的限制,比如只允许每300ms提交一次,这时候我想大部分同学都会到网上直接拷贝一段throttle函数,或者直接引用lodash工具库

XboxYan34阅读 2.2k评论 2

封面图

你好,我是若川。写有 《学习源码整体架构系列》 20余篇。

7k 声望
3.2k 粉丝
宣传栏