UNPKG

@contrast/route-metrics

Version:

`route-metrics` allows server performance, exclusive of network time, to be compared on a route-by-route basis. It was created to compare server performance with and without `@contrast/agent` being loaded and active.

129 lines (108 loc) 4.65 kB
import {fileURLToPath} from 'node:url'; import M from 'node:module'; const require = M.createRequire(import.meta.url); import {mappings} from './common.mjs'; import {getFileType} from './get-file-type.mjs'; import primordials from '../primordials.mjs'; const {StringPrototypeEndsWith} = primordials; // // initialize is called in the loader thread. it receives data passed from the // register() call, including the port to communicate with the main thread. // const initData = {}; async function initialize(data = {}) { Object.assign(initData, data); initData.app_dir = initData.app_dir || '.'; const {port, env} = initData; // add any environment variables passed from the main thread Object.assign(process.env, env); const tid = (await import('node:worker_threads')).threadId; const setupPatcher = require('../setup-patcher.js'); function patchListener(m) { port.postMessage({type: 'patch', ts: Date.now(), tid, m}); } let loadListener; if (env.CSI_RM_LOG_ALL_LOADS) { // listen for load events and forward them to main thread for logging. loadListener = (m) => { port.postMessage({type: 'load', ts: Date.now(), tid, m}); }; } setupPatcher(patchListener, loadListener); port.postMessage({type: 'status', ts: Date.now(), m: {status: 'initializing'}}); } /** * @param {string} specifier * @param {Object} context * @param {string[]} context.conditions Export conditions of the relevant package.json * @param {Object=} context.importAssertions An object whose key-value pairs represent the assertions for the module to import (before v21) * @param {Object=} context.importAttributes An object whose key-value pairs represent the attributes for the module to import (after v21) * @param {string=} context.parentURL The module importing this one, or undefined if this is the Node.js entry point * @param {(specifier, context) => Promise<ResolveResult>} nextResolve The subsequent resolve hook in the chain, or the Node.js default resolve hook after the last user-supplied resolve hook * @returns {Promise<ResolveResult>} */ async function resolve(specifier, context, nextResolve) { let isFlaggedToPatch = false; if (context.parentURL) { isFlaggedToPatch = new URL(context.parentURL).searchParams.has('csi-flag'); } if (!isFlaggedToPatch && specifier in mappings) { return { url: mappings[specifier], format: 'module', shortCircuit: true, }; } return protectedNextResolve(specifier, context, nextResolve); } /** * @param {string} url The URL returned by the resolve chain * @param {Object} context * @param {string[]} context.conditions Export conditions of the relevant package.json * @param {string=} context.format The format optionally supplied by the resolve hook chain * @param {Object=} context.importAssertions (before v21) * @param {Object=} context.importAttributes (after v21) * @param {(url, context) => Promise<LoadResult>} nextLoad The subsequent load hook in the chain, or the Node.js default load hook after the last user-supplied load hook * @returns {Promise<LoadResult>} */ async function load(url, context, nextLoad) { const urlObject = new URL(url); const type = await getFileType(url, initData.app_dir); // if it's not a builtin or a flagged file, it needs to be rewritten. // if it's not an es module it will be rewritten by the require hooks. if (urlObject.searchParams.has('csi-flag') || type !== 'module') { return nextLoad(url, context); } const filename = fileURLToPath(url); // Handles the event that other hooks redirect an import to a `.node` addon. if (StringPrototypeEndsWith.call(filename, '.node')) { return { source: `module.exports = require("${filename}");`, format: 'commonjs', shortCircuit: true, }; } return nextLoad(url, context); } /** * from https://github.com/iambumblehead/esmock/blob/main/src/esmockLoader.js#L89 * * new versions of node: when multiple loaders are used and context * is passed to nextResolve, the process crashes in a recursive call * see: /esmock/issues/#48 * * old versions of node: if context.parentURL is defined, and context * is not passed to nextResolve, the tests fail * * later versions of node v16 include 'node-addons' * @type {typeof resolve} */ async function protectedNextResolve(specifier, context, nextResolve) { if (context.parentURL) { if (context.conditions.at(-1) === 'node-addons' || context.importAssertions || context.importAttributes) { return nextResolve(specifier, context); } } return nextResolve(specifier); } export {initialize, resolve, load};