Thank you wakagawa for organizing the source code reading group

Push yourself to study after work every day

The following is the original text of Wakawa: juejin.cn/post/695934…

What is vue-devTools?

As a Vue developer (and not), Chrome’s Vue debugging plugin is a must.

Vue-DevTools is a tool for debugging Vue projects in Chrome. It helps developers understand the components and data in the page more clearly when using Vue development.

There are currently two versions of the plug-in, a Vue3 Beta and a Vue2 Beta.

What to know?

A new feature is available in the new version of DevTools: After selecting the component, click the open-in-Editor button to open it in the compiler.

Implementation principle:

This is done through the launch-editor-Middleware and launch-Editor libraries, which in turn create a node child that invokes the compiler to open the selected component by calling Node’s process and child_process capabilities

Preparation before reading:

  1. Prepare the latest version of Vue3 plug-in in Chrome (latest version 6.0.0 beta 15)
  2. vue createCreate a VUE-CLI3 project
  3. Prepare a compiler

Start debugging:

Open in Editor is an out-of-the-box feature in Vue3

How to configure this using: Open Component in Editor

1. Find the entrance and debug it

1.1 Finding the Entrance

According to the project introduction configuration in the documentation above, you need to search for ‘/__open-in-editor’ in the compiler to locate the method in node_modules, with a dot ~ here

If you go to launchEditorMiddleware and see that the middleware calls launch-Editor for subsequent compiler operations, you can put a dot ~ on the line that calls the launch function

1.2 Starting Debugging

Take Vscode as an example:

Enter the package.json of the project, you can see a “debug” or “debug” button on the Script property, click and select Serve to enter the debug mode

I stepped in a little hole here (also due to my lack of caution)

After NPM I is complete, first NPM Run Serve starts the project on port 8080, and then click Debug

This causes the compiler to start another process to start the project on port 8081, which may cause you to fail to access the breakpoint during subsequent debugging

In this case, check whether the debugging project port is the same as the browser port

Next, enter the reading source section ~

Start reading:

1. LaunchEditorMiddleware part

This part of the code is automatically entered when the project starts compiling.

Personally, there are two main things you do in this section of code:

1. Function overload to meet the requirements of different development parameter transmission

2. Obtain the location of the current process from Node. js to prepare for the subsequent startup of the compiler

// serve.js 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` ))) //launch-editor-middleware/index.js module.exports = (specifiedEditor, srcRoot, OnErrorCallback) => {// If the first argument passed is a function, Swap this parameter with the value of the error callback function if (typeof specifiedEditor === 'function') {onErrorCallback = specifiedEditor specifiedEditor = If (typeof srcRoot === 'function') {onErrorCallback = srcRoot srcRoot = undefined} // The ability to call node.js's process if it is not called, To obtain the position of the current process of srcRoot = srcRoot | | process. The CWD () return the function launchEditorMiddleware (the req, res, next) {/ / return a middleware}}Copy the code

Part 2 launch – editor

2.1 Checking paths before Execution

F12 Open the Vue-DevTools debug panel, select a component, and click open-in-Editor to go to the breakpoint

At this point, if you switch to Chrome’s Network bar, you will find that the browser sends a request:

Use (‘/__open-in-editor’, launchEditorMiddleware(…) It’s not hard to see how this is written as middleware, and when the browser sends a request, it goes into the following code logic

module.exports = (specifiedEditor, srcRoot, onErrorCallback) => { // .... Const {file} = url.parse(req. Url, const {file} = url.parse(req. true).query || {} if (! file) { res.statusCode = 500 res.end(`launch-editor-middleware: Required Query param "file" is missing. ')} else {// If the path exists, Launch - Editor logical launch(path.resolve(srcRoot, file), specifiedEditor, onErrorCallback) res.end()}}}Copy the code
2.2 The most important part of implementation

Once you enter the launchEditor function, this is the most important part of the functionality

function launchEditor (file, specifiedEditor, Const parsed = parseFile(file) let {fileName} = parsed const {//2.2.1 Const parsed = parseFile(file) let {fileName} = parsed const { LineNumber, columnNumber} = parsed // 2.2.2 Invoke the node.js method to check whether the path exists synchronically and return if (! Fs.existssync (fileName)) {return} if (typeof specifiedEditor === 'function') {onErrorCallback = SpecifiedEditor specifiedEditor = undefined OnErrorCallback = wrapErrorCallback(onErrorCallback)}Copy the code

In part 2.2.3, decorator mode is adopted (thanks to the summary of the same group’s little sister). The principle is to wrap up the logic to be executed, execute other codes that need to be dealt with first, and then execute the logic of onErrorCallback.

Continue reading about the function ~

Function wrapErrorCallback (cb) {return (fileName, errorMessage) => {console.log(); Extract the last part of the path separated by "/" and use a chalk library. 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) } }Copy the code

If no errors are reported in this section at this time, the rest of the process continues.

2.2.4 At this point, a very “exciting” guessing link will be entered

//launch-editor/index.js function launchEditor (file, specifiedEditor, onErrorCallback) { ... // The code enters the guessing function const [editor, ...args] = guessEditor(specifiedEditor) } // launch-editor/guess.js module.exports = function guessEditor (specifiedEditor) {// first step: If (specifiedEditor) {// If (specifiedEditor) { Parse (specifiedEditor)} // We can find out which editor is currently running by: // 'ps x' on macOS and Linux // 'get-process' on Windows The three lines above also indicate that it is possible to determine which system environment is currently running on. To determine how to start the compiler try {// Get the current operating system by identifying the operating system on which the Node.js process is running // since my system is MacOs, If (process.platform === 'Darwin ') {// If (process.platform ===' Darwin ') {// If (process.platform === 'Darwin ') {// If (process.platform ===' Darwin ') {// If (process.platform === 'Darwin ') ExecSync ('ps x').tostring () // COMMON_EDITORS_OSX 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]] } } } // ... I'm going to leave out the different platforms, The principle is similar // there is a 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

2.2.5 Operations after guessing

function launchEditor (file, specifiedEditor, onErrorCallback) { // ... Const [editor,...args] = guessEditor(specifiedEditor) // If (! Editor) {onErrorCallback(fileName, null) return} 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 {// Since it is MacOs, so Vscode is called, open the ARgs address (project address), and the child process will use the parent process's standard input and output. / / the Node document reference / / http://nodejs.cn/api/child_process.html#child_process_child_process_spawn_command_args_options / / here. _childProcess = childprocess. spawn(Editor, args, {stdio: Inherit '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

conclusion

First of all, a little praise yourself, finally overcome the problem of not reading the source code

🎉 🎉 🎉 🎉 🎉 🎉 🎉

I used to feel that the source code is difficult to understand, the framework is difficult to understand the real principle. However, through this activity, I understood the implementation method of a small module in a tool, which was very interesting.

Thank you very much for organizing this activity.

This reading also revealed that Node can do a lot of things that were not previously understood.

Related documents and materials:

Vue-DevTools:github.com/vuejs/devto…

Launch-editor: github.com/yyx990803/l…

Umijs/launch-editor:github.com/umijs/launc…