Small knowledge, big challenge! This article is participating in the creation activity of “Essential Tips for Programmers”.
This article has participated in the “Digitalstar Project” and won a creative gift package to challenge the creative incentive money.
preface
The previous article introduced the Vite startup, HMR and other time acquisition.
You can obtain detailed time information about each phase only from debug logs
This article will implement the interception of debug logs
Plugin Preview
— What does debug do
Project start instruction
vite --debug
Copy the code
Search – debug in the source code, can be in vite/packages/vite/bin/vite, js file location to the target code
const debugIndex = process.argv.findIndex((arg) = > / ^ (? :-d|--debug)$/.test(arg))
if (debugIndex > 0) {
let value = process.argv[debugIndex + 1]
if(! value || value.startsWith(The '-')) {
value = 'vite:*'
} else {
// support debugging multiple flags with comma-separated list
value = value
.split(', ')
.map((v) = > `vite:${v}`)
.join(', ')
}
process.env.DEBUG = value
}
Copy the code
You can see that if the –debug or -d arguments are used, the debug variable is mounted on process.env to indicate that debug is enabled
Locate the log printing method
Each log under debug starts with vite:label, for example
vite:load 1ms [fs] /src/router/routes/index.ts
Copy the code
A global search of vite: Load turns up the following code, which shows that createDebugger returns a method that prints logs
import {
createDebugger,
} from '.. /utils'
const debugLoad = createDebugger('vite:load')
constisDebug = !! process.env.DEBUG/ /.. code
isDebug && debugLoad(`${timeFrom(loadStart)} [fs] ${prettyUrl}`)
Copy the code
CreateDebugger (MSG,…); createDebugger (MSG,… args)
import debug from 'debug'
export function createDebugger(namespace: ViteDebugScope, options: DebuggerOptions = {}) :debug.Debugger['log'] {
const log = debug(namespace)
const { onlyWhenFocused } = options
const focus =
typeof onlyWhenFocused === 'string' ? onlyWhenFocused : namespace
return (msg: string, ... args: any[]) = > {
if(filter && ! msg.includes(filter)) {return
}
if(onlyWhenFocused && ! DEBUG? .includes(focus)) {return} log(msg, ... args) } }Copy the code
The log instance is created using the Debug method, but this debug method is a third-party library visionMedia/Debug
Although this library is small, can be used in Vite must not be simple, view the source code online
Debug method source code analysis
The entry file is relatively simple, so go directly to the logic in./node.js
if (typeof process === 'undefined' || process.type === 'renderer' || process.browser === true || process.__nwjs) {
module.exports = require('./browser.js');
} else {
module.exports = require('./node.js');
}
Copy the code
This section of code is only 264 lines, and the key code is as follows
exports.log = log;
function log(. args) {
returnprocess.stderr.write(util.format(... args) +'\n');
}
module.exports = require('./common') (exports);
Copy the code
./common.js part of the code
function setup(env) {
createDebug.debug = createDebug;
createDebug.default = createDebug;
function createDebug(namespace) {
function debug(. args) {
const self = debug;
const logFn = self.log || createDebug.log;
logFn.apply(self, args);
}
return debug;
}
return createDebug;
}
module.exports = setup;
Copy the code
At this point you can determine that the log is printed as output by the process.stderr.write method
The advantage of this approach is that the output does not wrap directly
So let’s redefine this method in the plug-in to intercept the printed content
Debug Log interception
Define plug-in entry parameters
interface PluginOptions {
/** * Whether to output the original log in the terminal */log? :boolean
/** * default callback */monitor? : MonitorCallback/** * debug callback */debug? : DebugCallback }Copy the code
The write method is overridden directly when the plug-in method is called, and the logic is as follows
- To enable the
--debug
And introduced intomonitor
ordebug
Method to redefine the write method - Parses the obtained log information and passes
monitor
Method passed externally - The original parameters are passed to an external debug method
The parsed parameters correspond to the original log content as follows
import type { Plugin } from 'vite';
import type { PluginOptions } from './types';
export default function Monitor(ops: PluginOptions = {}) :Plugin {
const { log, monitor, debug } = ops;
// If the debug method is started with the --debug parameter added
if ((typeof debug === 'function' || typeof monitor === 'function') && process.env.DEBUG) {
const { write } = process.stderr;
Object.defineProperty(process.stderr, 'write', {
get() {
return function _write(. argv) {
// If log is true, the original printing logic will be executed
if (log && typeof argv[0= = ='string') {
process.stdout.write(argv[0]);
}
const originStr = argv[0];
// Parse the label and print time of the log
const tag = (originStr.match(/vite:(.*?) \s/) | | []) [1];
const time1 = (originStr.replace(/\+\d+ms/.' ').match(/(\d+)ms/) | | []) [1];
const time2 = (originStr.match(/\+(\d+)ms/) | | []) [1];
const time = +(time1 || 0) + +(time2 || 0);
if (tag && monitor) {
monitor(tag, time, {
time1: +(time1 || 0),
time2: +(time2 || 0),
originValue: originStr,
});
}
if(debug) { debug(... argv); }}; }}); }return {
name: 'vite-plugin-monitor'.apply: 'serve',}}; }Copy the code
At this point, the feature to intercept the log is complete, and the initial goal has been set
Experience the plugin
Plug-in source
Install dependencies
yarn add vite-plugin-monitor --dev
Copy the code
Modify the viet.config.js file by importing the plug-in
import { defineConfig } from 'vite'
import vitePluginMonitor from 'vite-plugin-monitor'
export default defineConfig({
plugins: [
vitePluginMonitor({
// log: false,
monitor(label, time, originData) {
const { time1, time2, originValue } = originVal
console.log(originValue)
console.log(label, time1, time2, `${time}ms`)},debug(str) {
// Prints a complete log
// process.stdout.write(str)}}),],})Copy the code
Add –debug to the startup directive
vite --debug
Copy the code
You can get the original log and the simple processed log by using the Monitor and debug methods. Add custom buried monitoring code here
One caveat: when log is false and monitor or DEBUG methods are defined, the original log content will be intercepted by both methods
summary
At present, all contents under debug can be completely intercepted, but it is difficult to extract information due to the characters related to color printing
The next step is to do some formatting of the log extraction to ensure that the full log content is parsed