Skip to content

Removal of resolve module fallback in v8.0.0 can cause resolution issues in (webpack) bundled code #120

@wpessers

Description

@wpessers

Context

Recently a fallback on the resolve module was removed in: 67076ff#diff-e727e4bdf3657fd1d798edcd6b099d6e092f8573cba266154583a746bba0f346L73-L82 This was part of the 8.0.0 release.

This fallback seems not to have been intended to support resolving external modules from inside bundled code, but as a side effect it actually did. When bundling code with Webpack, at runtime Webpack provides its own loader instead of the node.js native require.resolve. In short this means that when using require.resolve inside code bundled with Webpack, it can only resolve modules that are contained in the bundle. So external modules can't possibly be resolved this way.

The above linked commit basically removes a fallback to the resolve module for when (require.resolve && require.resolve.paths) doesn't evaluate to truthy. Webpack doesn't have require.resolve.paths on its "stubbed" require.resolve since it isn't useful / needed for the way that module resolution works in the Webpack runtime. So the check would fail since the require.resolve.paths is undefined (and thus falsy). This lead to the resolve module being used instead, with which you were able to actually resolve those external modules.

The reason I found this was because we did some dependency upgrades in the https://github.com/open-telemetry/opentelemetry-lambda layer for nodejs. Upgrading instrumentation libraries that use RITM indirectly through @opentelemetry/instrumentation. The latter upgraded the RITM version from 7.1.1 to 8.0.0. And now since the code for the node.js layer is bundled with Webpack, that means RITM inside our bundle will be actually using Webpack's stubbed require.resolve. This results in breaking instrumentation that needs to hook any non-core modules through RITM. Because those modules need to be external (not included in the bundle) for instrumentation libraries to be able to detect them being loaded.

Solutions

We have temporarily fixed this in the lambda layer by externalizing RITM from the webpack bundle (open-telemetry/opentelemetry-lambda#2037), but would like to see if any alternative solutions are possible.

I suppose the removal of the resolve module was a very deliberate choice to reduce footprint / increase performance?

One solution I could think of would be to have some check for when ritm is running inside a webpack bundle, pseudo-code but could look something like this:

function resolve (moduleName, basedir) {
    let _resolve = function (moduleName, basedir) {
        return require.resolve(moduleName, { paths: [basedir] })
    }
    if (webpackDetected) {
        _resolve = function (moduleName, basedir) {
            return __non_webpack_require__.resolve(moduleName, { paths: [basedir] })
        }
    }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions