UNPKG

@lzwme/feps-webpack-plugin

Version:

This plug-in is used for function execution performance statistics. It calculates the execution time by injecting statistical code and finds slow functions.

131 lines (115 loc) 4.05 kB
/* * @Author: lzw * @Date: 2021-12-13 18:45:53 * @LastEditors: lzw * @LastEditTime: 2022-05-19 16:11:13 * @Description: */ // @ts-check /** @typedef {import("estree").Program} Program */ /** @typedef {import("estree").Node} AnyNode */ /** @typedef {import("webpack/lib/javascript/JavascriptParser")} JavascriptParser */ /** @typedef {import("webpack-sources").ReplaceSource} ReplaceSource */ /** @typedef {import("webpack/lib/Dependency")} Dependency */ /** @typedef {import("webpack/lib/DependencyTemplate").DependencyTemplateContext} DependencyTemplateContext */ /** * @typedef {{ * debug?: boolean; * disabled?: boolean; * timeLimit?: number; * logger?: string; // 'console.warn' * rootDir?: string; * minFnCodeLength?: number; * include?: (string | RegExp)[] | ((p: string) => boolean); * exclude?: (string | RegExp)[] | ((p: string) => boolean); * excludeNodeType?: AnyNode['type'][]; *}} FepsOptions */ const PLUGIN_NAME = 'FEPSPlugin'; exports.PLUGIN_NAME = PLUGIN_NAME; function getMarkTimeCode(timeLimit = 50, logger = 'console.warn', filepath = '') { return `\nconst markTime = (() => { let lastLabel = null; const skipMap = new Map(); const markTimeMap = new Map(); return (label) => { try { if (typeof ${logger} !== 'function') return; } catch(e) { if (typeof console) console.error(e); return; } const skip = skipMap.get(label); if (skip) return; const start = markTimeMap.get(label); if (start) { markTimeMap.delete(label); if (lastLabel === label) { skipMap.set(label, true); } else { const cost = Date.now() - start; if (cost > ${timeLimit}) { ${logger}('[Performance]', cost + 'ms', '${filepath}', new Error().stack.replace(/\\((\\S+?)\\)/g, '').replace(/at file\\S+/g, '').replace(/\\s+at\\s+/g, ' <- ').replace('Error <- ', '').trim()); } } lastLabel = label; } else { markTimeMap.set(label, Date.now()); } } })();\n`; } exports.getMarkTimeCode = getMarkTimeCode; /** * @param {JavascriptParser} parser * @param {FepsOptions} options * @param {(isMatch: boolean, ast: Program, relativePath: string) => void} callback */ function astHandler(parser, options, callback) { parser.hooks.program.tap(PLUGIN_NAME, (ast, _comments) => { if (!parser.state || !parser.state.module) return; let isMatch = true; /** @type string */ let relativePath = parser.state.module.resource.replace(options.rootDir, ''); if (process.platform === 'win32') relativePath = relativePath.replace(/\\/g, '/'); if (typeof options.exclude === 'function') { isMatch = options.exclude(relativePath); } else if (options.exclude.length) { const isExMatch = options.exclude.some(d => { if (typeof d === 'string') return relativePath.includes(d); if (d instanceof RegExp) return d.test(relativePath); }); isMatch = !isExMatch; } if (isMatch) { if (typeof options.include === 'function') { isMatch = options.include(relativePath); } else if (options.include.length) { isMatch = options.include.some(d => { if (typeof d === 'string') return relativePath.includes(d); if (d instanceof RegExp) return d.test(relativePath); }); } } callback(isMatch, ast, relativePath); }); } exports.astHandler = astHandler; exports.getDefaultOptions = () => { /** @type {FepsOptions} */ const options = { debug: !!process.env.DEBUG, rootDir: process.cwd(), timeLimit: 50, minFnCodeLength: 300, include: [/(jsx?|tsx?)$/], exclude: ['node_modules'], excludeNodeType: [], logger: 'console.warn', disabled: false, }; return options; }; exports.getColors = () => { return require('console-log-colors').color; }