Skip to content

Inconsistent multiple extension handling between Module._findPath and Module.load #4778

Closed
@sgentle

Description

@sgentle

Let's start by making a file with multiple extensions: test.foo.bar

> fs.writeFileSync('test.foo.bar', 'NOT_JS', 'utf8')
undefined

So we already know that require.extensions doesn't work with multiple extensions:

> require.extensions['.foo.bar'] = (module, path) => console.log('required .foo.bar', path)
[Function]
> require('./test.foo.bar')
ReferenceError: NOT_JS is not defined
[...stack trace elided...]

And that it will use the last component of the extension instead:

> require.extensions['.bar'] = (module, path) => console.log('required .bar', path)
[Function]
> require('./test.foo.bar')
required .bar /private/tmp/test.foo.bar
{}

Which is all perfectly obvious and by design. But did you know that the path searching uses the whole extension? Which means:

> delete require.extensions['.foo.bar'] // Since it's never called anyway
> require('./test')
Error: Cannot find module './test'
[...stack trace elided...]

However:

> require.extensions['.foo.bar'] = "SURPRISE!"
> require('./test')
required .bar /private/tmp/test.foo.bar
{}

In summary: to hook the requiring of a file with multiple extensions without specifying it, you must:

  1. Set require.extensions for the last component of the extension to your hook function
  2. Set require.extensions for the entire extension to any value.

This is due to differences in how Module._findPath and Module.load deal with extensions: the former adds each extension in require.extensions to the basename and tests it for existence (via tryExtensions). The latter works the other way around; it removes everything up to the last part of the extension (via path.extname) and then checks if it is present in require.extensions.

I know it's policy not to fix bugs in module that might help compile-to-js languages, but I figure someone else might come across the same problem and this report could be useful to them.

Metadata

Metadata

Assignees

No one assigned

    Labels

    confirmed-bugIssues with confirmed bugs.help wantedIssues that need assistance from volunteers or PRs that need help to proceed.moduleIssues and PRs related to the module subsystem.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions