UNPKG

time-analytics-webpack-plugin

Version:
169 lines 9.06 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); /* eslint-disable prefer-rest-params */ /* eslint-disable @typescript-eslint/no-shadow */ const crypto_1 = require("crypto"); const path_1 = __importDefault(require("path")); const analyzer_1 = require("./analyzer"); const const_1 = require("./const"); const utils_1 = require("./utils"); // This is not the same as `require` function, but we hack `require` through override it. // eslint-disable-next-line @typescript-eslint/no-var-requires const originModuleRequire = require('module').prototype.require; // TODO: hack for mjs module, this is how webpack import module // if(url === undefined) url = require("url"); // var loaderUrl = url.pathToFileURL(loader.path); // var modulePromise = eval("import(" + JSON.stringify(loaderUrl.toString()) + ")"); function hackWrapLoaderModule(loaderPaths, wrapLoaderModuleCallback) { const wrapRequire = (requireMethod) => { const wrappedRequire = function (...args) { (0, utils_1.assert)(originModuleRequire === requireMethod); // although `require` should only accept one parameter and `this` binding should be undefined, we do want to make less surprise. const originExport = requireMethod.apply(this, args); // `id` is the input of `require`, like `require(id)` const id = args[0]; const isOriginExportAWebpackLoader = loaderPaths.includes(id); if (isOriginExportAWebpackLoader) { (0, utils_1.assert)(path_1.default.isAbsolute(id), 'Webpack should convert the loader path to absolute path. Although we not use this info.'); // console.log(`Wrap Require: it should be webpack which requires loader, the loader is ${id}`); // eslint-disable-next-line @typescript-eslint/no-use-before-define const isHackLoader = originExport === loader; if (isHackLoader) { // console.log(`Wrap Require: Hack require should not work for ${PACKAGE_LOADER_PATH}`); return originExport; } // if (originExport.__smpHacked) return originExport; // originExport.__smpHacked = true; return wrapLoaderModuleCallback(originExport, id); } return originExport; }; wrappedRequire.resolve = requireMethod.resolve; wrappedRequire.extensions = requireMethod.extensions; wrappedRequire.cache = requireMethod.cache; wrappedRequire.main = requireMethod.main; return wrappedRequire; }; // @ts-ignore if (typeof System === 'object' && typeof System.import === 'function') { // @ts-ignore System.import = wrapReq(System.import); } // eslint-disable-next-line @typescript-eslint/no-var-requires const Module = require('module'); // TODO: check whether thread-loader works for this case or not Module.prototype.require = wrapRequire(originModuleRequire); } const loader = function timeAnalyticHackLoader(source) { // console.log('Time analytics plugin: normal loader is executed'); return source; }; /** * Override `require` method, so that we could return a wrapped loader function. * * Each time the wrapped function is called, we could do some extra work. */ loader.pitch = function () { // console.log('Time analytics plugin: pitch loader is executed, take over the "require" function'); const analyzerInstance = analyzer_1.analyzer; const resourcePath = this.resourcePath; const loaderPaths = this.loaders .map((l) => l.path) .filter((l) => !l.includes(const_1.PACKAGE_NAME)); // Hack ourselves to overwrite the `require` method so we can override the // loadLoaders // `loaderModule` means the cjs or mjs module hackWrapLoaderModule(loaderPaths, function wrapLoaderModuleCallback(loaderModule, path) { const wrapLoaderFunc = (originLoader, loaderType) => { // return originLoader; const uuid = (0, crypto_1.randomUUID)(); // const loaderTypeText = loaderType === LoaderType.pitch ? 'pitch' : 'normal'; const wrappedLoader = function wrappedLoaderFunc() { // const tmp = loaderName; // console.log(`Wrapped loader: ${tmp}'s ${loaderTypeText} function is executed.`); // console.log('origin loader is ', originLoader); let isSync = true; const almostThis = Object.assign({}, this, { async: () => { isSync = false; const originCallback = this.async(arguments); return function () { analyzerInstance.collectLoaderInfo({ callId: uuid, kind: analyzer_1.AnalyzeInfoKind.loader, eventType: analyzer_1.LoaderEventType.end, loaderType, loaderPath: path, resourcePath, time: (0, utils_1.now)(), isAsync: !isSync, }); // const asyncResult = arguments[1]; // console.log(`Origin loader: ${tmp}'s ${loaderTypeText} loader, async result is \n ${chalk.red(asyncResult)} `); originCallback.apply(this, arguments); }; }, }); analyzerInstance.collectLoaderInfo({ callId: uuid, kind: analyzer_1.AnalyzeInfoKind.loader, eventType: analyzer_1.LoaderEventType.start, loaderType, loaderPath: path, resourcePath, time: (0, utils_1.now)(), isAsync: !isSync, }); // @ts-ignore, normal loader and pitch loader is kind of different, but we do not care. const ret = originLoader.apply(almostThis, arguments); // if it's an async loader, we return `undefined`, as webpack request // however, it feels not really matters if (!isSync) { // console.log(`Origin loader: ${tmp}'s ${loaderTypeText} loader, an async loader, return undefined`); return undefined; } else { // console.log(`Origin loader: ${tmp}'s ${loaderTypeText} loader, not an async loader, result is ${chalk.redBright(ret)}`); } analyzerInstance.collectLoaderInfo({ callId: uuid, kind: analyzer_1.AnalyzeInfoKind.loader, eventType: analyzer_1.LoaderEventType.end, loaderType, loaderPath: path, resourcePath, time: (0, utils_1.now)(), isAsync: !isSync, }); return ret; }; // wrappedLoader.__origional_loader = originLoader; // wrappedLoader.__origional_loader_type = loaderTypeText; return wrappedLoader; }; return wrapLoaderModule(loaderModule); function wrapLoaderModule(module) { // do the same check as webpack itself if (typeof module !== 'function' && typeof module !== 'object') { throw new Error('Time analytics plugin tries to use the same checek as webpack, you see this error because Time analytics plugin think it should be a bug which should also be existed in webpack.'); } // get normal loader function according to module is mjs or cjs const originNormalLoaderFunc = typeof module === 'function' ? module : module.default; const originPitchLoaderFunc = module.pitch; const wrappedNormalLoaderFunc = originNormalLoaderFunc ? wrapLoaderFunc(originNormalLoaderFunc, analyzer_1.LoaderType.normal) : undefined; const wrappedPitchLoaderFunc = originPitchLoaderFunc ? wrapLoaderFunc(originPitchLoaderFunc, analyzer_1.LoaderType.pitch) : undefined; // convert the module from either cjs or mjs to a mocked mjs module. const mockModule = { ...module, default: wrappedNormalLoaderFunc, pitch: wrappedPitchLoaderFunc, }; return mockModule; } }); }; module.exports = loader; //# sourceMappingURL=loader.js.map