Wakakawa’s reading that 99% of people don’t know vue-DevTools can open component files directly? This article principle revealed: juejin.cn/post/695934… How to install vue-DevTools developed by Yuxi, and why few people know the function of opening files? : juejin. Cn/post / 699428…

Chuan ge recently organized a source code reading activities. I read about 200 lines of source code a week. If you are interested, you can follow his public account, Ruochuan Vision.

To prepare

  1. Go over Trango’s article. Get your goals straight
  2. Learning objective: Understand the implementation principle of vue-DevTools open component

Specific operation

Components used

Use of the main launch-editor-Middleware and launch-Editor libraries

launch-editor-middleware

The main purpose of the launch-editor-middleware middleware is to call launch-Editor

The source code calls

// vue3-project/node_modules/@vue/cli-service/lib/commands/serve.js
/ / 46
const launchEditorMiddleware = require('launch-editor-middleware')
/ / 192 rows
before (app, server) {
    // launch editor support.
    / / call launchEditorMiddleware
    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`
    )))
    // omit some code...
}
Copy the code
const url = require('url')
const path = require('path')
const launch = require('launch-editor')

// specifiedEditor passes in a function that returns console.log()
module.exports = (specifiedEditor, srcRoot, onErrorCallback) = > {
  if (typeof specifiedEditor === 'function') {
    onErrorCallback = specifiedEditor// Assign to onErrorCallback
    specifiedEditor = undefined
  }

  if (typeof srcRoot === 'function') {
    onErrorCallback = srcRoot
    srcRoot = undefined
  }

  // srcRoot is the parameter passed in, or the directory of the current Node process
  srcRoot = srcRoot || process.cwd()

  // Returns the middleware function
  return function launchEditorMiddleware (req, res, next) {
    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 {
      // Join the path using launch
      launch(path.resolve(srcRoot, file), specifiedEditor, onErrorCallback)
      res.end()
    }
  }
}
Copy the code

To break point debugging, click the red dot to the left and stop at the breakpoint when the file comes in is clicked

launch-editor

But resolve resolves the path and enters the launchEditor function

// vue3-project/node_modules/launch-editor/index.js
function launchEditor (file, specifiedEditor, onErrorCallback) {
  // Parse the file path
  const parsed = parseFile(file)
  let { fileName } = parsed
  const { lineNumber, columnNumber } = parsed
	
  // Check whether the file exists
  if(! fs.existsSync(fileName)) {return
  }

  if (typeof specifiedEditor === 'function') {
    onErrorCallback = specifiedEditor
    specifiedEditor = undefined
  }

  onErrorCallback = wrapErrorCallback(onErrorCallback)

  // Editor gets the compiler's parameters
  const [editor, ...args] = guessEditor(specifiedEditor)
  if(! editor) { onErrorCallback(fileName,null)
    return
  }
  // ...
  Child_process is a module of Node.js that provides the ability to spawn child processes. By default, stdin, stdout, and stderr pipes are created between the parent node.js process and the spawned child.
  if (process.platform === 'win32') {
    // On Windows, launch the editor in a shell because spawn can only
    // launch .exe files.
    // Use the editor command to open the file
    _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)
  })

}
Copy the code

guessEditor

This function does four things:

  1. If an editor is specified, the parser returns.
  2. Find out which editor is running in the current process. MacOS and Linux use ps x and Windows use get-process
  1. If none is found, use process.env.VISUAL or process.env.Editor. This is why the initial error prompts you to specify the editor using an environment variable.
  2. If [null] is returned, an error is reported.

GuessEditor deconstructs the parameter display after the assignment

function guessEditor (specifiedEditor) {
  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 {
    // Determine the platform
    if (process.platform === 'darwin') {
      const output = childProcess.execSync('ps x').toString()
      const processNames = Object.keys(COMMON_EDITORS_OSX)
      for (let i = 0; i < processNames.length; i++) {
        const processName = processNames[i]
        if(output.indexOf(processName) ! = = -1) {
          return [COMMON_EDITORS_OSX[processName]]
        }
      }
    } else if (process.platform === 'win32') {
      const output = childProcess
        .execSync('powershell -Command "Get-Process | Select-Object Path"', {
          stdio: ['pipe'.'pipe'.'ignore']
        })
        .toString()
      const runningProcesses = output.split('\r\n')
      for (let i = 0; i < runningProcesses.length; i++) {
        // `Get-Process` sometimes returns empty lines
        if(! runningProcesses[i]) {continue
        }

        const fullProcessPath = runningProcesses[i].trim()
        const shortProcessName = path.basename(fullProcessPath)

        if(COMMON_EDITORS_WIN.indexOf(shortProcessName) ! = = -1) {
          return [fullProcessPath]
        }
      }
    } else if (process.platform === 'linux') {
      // --no-heading No header line
      // x List all processes owned by you
      // -o comm Need only names column
      const output = childProcess
        .execSync('ps x --no-heading -o comm --sort=comm')
        .toString()
      const processNames = Object.keys(COMMON_EDITORS_LINUX)
      for (let i = 0; i < processNames.length; i++) {
        const processName = processNames[i]
        if(output.indexOf(processName) ! = = -1) {
          return [COMMON_EDITORS_LINUX[processName]]
        }
      }
    }
  } 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]}Copy the code

conclusion

  1. Vue-devtool is able to open files through the code command
code /path/file
Copy the code
  1. Use node childProcess to run commands. Learn how to use childProcess
  2. The main steps are divided into two steps:
1. Click open to enter launch middleware 2. Parse relevant paths 3. Use childProcess to start the childProcess and use CMD to run the code command to open the path fileCopy the code