镜像站点 · 本页由第三方 GitHub 只读镜像提供,非 GitHub 官方站点,不接受任何登录或凭据输入。前往 github.com
Skip to content

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

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.

Activity

  1. added
    moduleIssues and PRs related to the module subsystem.
    on Jan 20, 2016
  2. cjihrig commented on Jan 20, 2016

    @cjihrig
    Contributor

    What version of Node are you using? The following script (and the variations of it that I tried) work for me on v5.4.1.

    'use strict';
    const assert = require('assert');
    const fs = require('fs');
    const file = './test.foo.bar';
    
    fs.writeFileSync(file, 'NOT_JS', 'utf8');
    
    require.extensions['.foo.bar'] = (module, path) => {
      console.log('required .foo.bar', path);
    };
    
    assert.throws(() => {
      require(file);
    });
    
    require.extensions['.bar'] = (module, path) => {
      console.log('required .bar', path);
    };
    
    delete require.extensions['.foo.bar']
    
    assert.doesNotThrow(() => {
      require(file);
    });
  3. sgentle commented on Jan 22, 2016

    @sgentle
    Author

    Sorry, to be clear, the _findPath/tryExtensions code only happens when the file is required with no extension. Try replacing your last require(file) with require('./test').

  4. cjihrig commented on Jan 22, 2016

    @cjihrig
    Contributor

    Ok, here is the reproduction:

    'use strict';
    const fs = require('fs');
    
    fs.writeFileSync('./test.foo.bar', 'NOT_JS', 'utf8');
    require.extensions['.foo.bar'] = (module, path) => {};
    // delete require.extensions['.foo.bar'];
    require.extensions['.bar'] = (module, path) => {
      console.log(`loaded ${path}`);
    };
    
    require('./test');

    Toggle the commented out line to see the issue. This seems, to me, like something that should be fixed, but module system. What do others think?

  5. added a commit that references this issue on Mar 16, 2016
  6. Trott commented on Jul 7, 2017

    @Trott
    Member

    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.

    @sgentle Fortunately, this is no longer true. And while we are unlikely to add new features or change the intended behavior of existing features, fixing bugs in module is now totally on the table. If you feel up to fixing, by all means, please submit a pull request.

  7. added
    help wantedIssues that need assistance from volunteers or PRs that need help to proceed.
    on Apr 20, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    confirmed-bugIssues and PRs for 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