| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194 |
- const path = require("path");
- const fs = require("fs");
- const chalk = require("chalk");
- const { WrappedPlugin, clear } = require("./WrappedPlugin");
- const {
- getModuleName,
- getLoaderNames,
- prependLoader,
- tap,
- } = require("./utils");
- const {
- getHumanOutput,
- getMiscOutput,
- getPluginsOutput,
- getLoadersOutput,
- smpTag,
- } = require("./output");
- const NS = path.dirname(fs.realpathSync(__filename));
- module.exports = class SpeedMeasurePlugin {
- constructor(options) {
- this.options = options || {};
- this.timeEventData = {};
- this.smpPluginAdded = false;
- this.wrap = this.wrap.bind(this);
- this.getOutput = this.getOutput.bind(this);
- this.addTimeEvent = this.addTimeEvent.bind(this);
- this.apply = this.apply.bind(this);
- this.provideLoaderTiming = this.provideLoaderTiming.bind(this);
- }
- wrap(config) {
- if (this.options.disable) return config;
- if (Array.isArray(config)) return config.map(this.wrap);
- if (typeof config === "function")
- return (...args) => this.wrap(config(...args));
- config.plugins = (config.plugins || []).map(plugin => {
- const pluginName =
- Object.keys(this.options.pluginNames || {}).find(
- pluginName => plugin === this.options.pluginNames[pluginName]
- ) ||
- (plugin.constructor && plugin.constructor.name) ||
- "(unable to deduce plugin name)";
- return new WrappedPlugin(plugin, pluginName, this);
- });
- if (config.optimization && config.optimization.minimizer) {
- config.optimization.minimizer = config.optimization.minimizer.map(
- plugin => {
- return new WrappedPlugin(plugin, plugin.constructor.name, this);
- }
- );
- }
- if (config.module && this.options.granularLoaderData) {
- config.module = prependLoader(config.module);
- }
- if (!this.smpPluginAdded) {
- config.plugins = config.plugins.concat(this);
- this.smpPluginAdded = true;
- }
- return config;
- }
- getOutput() {
- const outputObj = {};
- if (this.timeEventData.misc)
- outputObj.misc = getMiscOutput(this.timeEventData.misc);
- if (this.timeEventData.plugins)
- outputObj.plugins = getPluginsOutput(this.timeEventData.plugins);
- if (this.timeEventData.loaders)
- outputObj.loaders = getLoadersOutput(this.timeEventData.loaders);
- if (this.options.outputFormat === "json")
- return JSON.stringify(outputObj, null, 2);
- if (typeof this.options.outputFormat === "function")
- return this.options.outputFormat(outputObj);
- return getHumanOutput(outputObj, {
- verbose: this.options.outputFormat === "humanVerbose",
- });
- }
- addTimeEvent(category, event, eventType, data = {}) {
- const allowFailure = data.allowFailure;
- delete data.allowFailure;
- const tED = this.timeEventData;
- if (!tED[category]) tED[category] = {};
- if (!tED[category][event]) tED[category][event] = [];
- const eventList = tED[category][event];
- const curTime = new Date().getTime();
- if (eventType === "start") {
- data.start = curTime;
- eventList.push(data);
- } else if (eventType === "end") {
- const matchingEvent = eventList.find(e => {
- const allowOverwrite = !e.end || !data.fillLast;
- const idMatch = e.id !== undefined && e.id === data.id;
- const nameMatch =
- !data.id && e.name !== undefined && e.name === data.name;
- return allowOverwrite && (idMatch || nameMatch);
- });
- const eventToModify =
- matchingEvent || (data.fillLast && eventList.find(e => !e.end));
- if (!eventToModify) {
- console.error(
- "Could not find a matching event to end",
- category,
- event,
- data
- );
- if (allowFailure) return;
- throw new Error("No matching event!");
- }
- eventToModify.end = curTime;
- }
- }
- apply(compiler) {
- if (this.options.disable) return;
- tap(compiler, "compile", () => {
- this.addTimeEvent("misc", "compile", "start", { watch: false });
- });
- tap(compiler, "done", () => {
- clear();
- this.addTimeEvent("misc", "compile", "end", { fillLast: true });
- const outputToFile = typeof this.options.outputTarget === "string";
- chalk.enabled = !outputToFile;
- const output = this.getOutput();
- chalk.enabled = true;
- if (outputToFile) {
- const writeMethod = fs.existsSync(this.options.outputTarget)
- ? fs.appendFileSync
- : fs.writeFileSync;
- writeMethod(this.options.outputTarget, output + "\n");
- console.log(
- smpTag() + "Outputted timing info to " + this.options.outputTarget
- );
- } else {
- const outputFunc = this.options.outputTarget || console.log;
- outputFunc(output);
- }
- this.timeEventData = {};
- });
- tap(compiler, "compilation", compilation => {
- tap(compilation, "normal-module-loader", loaderContext => {
- loaderContext[NS] = this.provideLoaderTiming;
- });
- tap(compilation, "build-module", module => {
- const name = getModuleName(module);
- if (name) {
- this.addTimeEvent("loaders", "build", "start", {
- name,
- fillLast: true,
- loaders: getLoaderNames(module.loaders),
- });
- }
- });
- tap(compilation, "succeed-module", module => {
- const name = getModuleName(module);
- if (name) {
- this.addTimeEvent("loaders", "build", "end", {
- name,
- fillLast: true,
- });
- }
- });
- });
- }
- provideLoaderTiming(info) {
- const infoData = { id: info.id };
- if (info.type !== "end") {
- infoData.loader = info.loaderName;
- infoData.name = info.module;
- }
- this.addTimeEvent("loaders", "build-specific", info.type, infoData);
- }
- };
|