diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index c8e3209..c55a025 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -20,3 +20,12 @@ jobs: node-version: ${{ matrix.node }} - run: npm install - run: npm test + # Run the webpack tests for Node.js versions that webpack[-cli] support. + - run: npm run test:webpack + if: ${{ matrix.node != '8.10' + && matrix.node != '10.0' + && matrix.node != '10' + && matrix.node != '12.0' + && matrix.node != '12' + && matrix.node != '14.0' + && matrix.node != '14' }} diff --git a/.gitignore b/.gitignore index ffff996..16e5df5 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ /tmp /require-in-the-middle-*.tgz *.example.js +test/webpack/dist/ diff --git a/index.js b/index.js index d3d49f9..13c3e19 100644 --- a/index.js +++ b/index.js @@ -5,6 +5,14 @@ const Module = require('module') const debug = require('debug')('require-in-the-middle') const moduleDetailsFromPath = require('module-details-from-path') +// Webpack replaces `require` with its own fn that is insufficient for how +// require is used in this package. It is strongly hoped no other +// bundler-specific hacks are needed. +/* global __non_webpack_require__ */ +const nativeRequire = typeof __webpack_require__ === 'function' // eslint-disable-line camelcase + ? __non_webpack_require__ // eslint-disable-line camelcase + : require + // Using the default export is discouraged, but kept for backward compatibility. // Use this instead: // const { Hook } = require('require-in-the-middle') @@ -64,7 +72,7 @@ class ExportsCache { if (this._localCache.has(filename)) { return true } else if (!isBuiltin) { - const mod = require.cache[filename] + const mod = nativeRequire.cache[filename] return !!(mod && this._kRitmExports in mod) } else { return false @@ -76,7 +84,7 @@ class ExportsCache { if (cachedExports !== undefined) { return cachedExports } else if (!isBuiltin) { - const mod = require.cache[filename] + const mod = nativeRequire.cache[filename] return (mod && mod[this._kRitmExports]) } } @@ -84,8 +92,8 @@ class ExportsCache { set (filename, exports, isBuiltin) { if (isBuiltin) { this._localCache.set(filename, exports) - } else if (filename in require.cache) { - require.cache[filename][this._kRitmExports] = exports + } else if (filename in nativeRequire.cache) { + nativeRequire.cache[filename][this._kRitmExports] = exports } else { debug('non-core module is unexpectedly not in require.cache: "%s"', filename) this._localCache.set(filename, exports) @@ -273,7 +281,7 @@ function Hook (modules, options, onrequire) { // figure out if this is the main module file, or a file inside the module let res try { - res = require.resolve(moduleName, { paths: [basedir] }) + res = nativeRequire.resolve(moduleName, { paths: [basedir] }) } catch (e) { debug('could not resolve module: %s', moduleName) self._cache.set(filename, exports, core) diff --git a/package.json b/package.json index fe7cf14..c0569a9 100644 --- a/package.json +++ b/package.json @@ -18,13 +18,16 @@ "roundround": "^0.2.0", "semver": "^6.3.0", "standard": "^14.3.1", - "tape": "^4.11.0" + "tape": "^4.11.0", + "webpack": "^5.105.0", + "webpack-cli": "^5.1.0" }, "scripts": { "test": "npm run test:lint && npm run test:tape && npm run test:babel", "test:lint": "standard", "test:tape": "tape test/*.js", - "test:babel": "node test/babel/babel-register.js" + "test:babel": "node test/babel/babel-register.js", + "test:webpack": "webpack --config test/webpack/webpack.config.js && node test/webpack/dist/bundle.js # requires node 16+" }, "repository": { "type": "git", diff --git a/test/webpack/test.js b/test/webpack/test.js new file mode 100644 index 0000000..7899250 --- /dev/null +++ b/test/webpack/test.js @@ -0,0 +1,22 @@ +'use strict' + +const assert = require('assert') + +const { Hook } = require('../../') + +const hooked = [] + +// Hook all modules as @opentelemetry/instrumentation does. +const hook = new Hook('*', function (exports, name, basedir) { + if (name === 'semver') { + hooked.push(name) + exports.patched = true + } + return exports +}) + +const semver = require('semver') +assert.strictEqual(semver.patched, true) +assert.deepStrictEqual(hooked, ['semver']) + +hook.unhook() diff --git a/test/webpack/webpack.config.js b/test/webpack/webpack.config.js new file mode 100644 index 0000000..7c67eed --- /dev/null +++ b/test/webpack/webpack.config.js @@ -0,0 +1,16 @@ +'use strict' + +const path = require('path') + +module.exports = { + target: 'node', + mode: 'production', + entry: path.join(__dirname, 'test.js'), + output: { + path: path.join(__dirname, 'dist'), + filename: 'bundle.js' + }, + externals: { + semver: 'commonjs semver' + } +}