Skip to content

[commonjs] Output contains references to __filename #523

Closed

Description

@ctjlewis
  • Rollup Plugin Name: plugin-commonjs
  • Rollup Plugin Version: 14.0.0
  • Rollup Version: rollup v2.23.0
  • Operating System (or Browser): Ubuntu 20.04
  • Node Version: v14.5.0
  • Link to reproduction (⚠️ read below):
    https://repl.it/@christiantjl/rollup-filename-cjs-esm (use yarn test to get started)

Expected Behavior

With output.format = 'esm', output bundle should:

  1. ❌ Hardcode references to __filename and __dirname (couldn't they be written to a relative version of the output file, i.e. ./output/bundle.mjs here? since everything will be bundled into that spot by definition?)
  2. ✔️ Include ES2015 syntax to export top-level exports in output bundle (this works)
  3. ❌ Not include CJS syntax like module.exports (as seen on repl.it)

Actual Behavior

In my real-life code, I get an error because the ESM output references __filename:

file:///home/christian/Projects/gdev/dev/cli.mjs:14587
  debug$1('initializing', __filename);
                          ^

ReferenceError: __filename is not defined

And on repl.it, in addition to ESM output containing _filename, the output also includes a module.exports declaration at the top, which throws an error immediately:

output/bundle.mjs

module.exports = {
  test: __filename
};

var test = /*#__PURE__*/Object.freeze({
  __proto__: null
});

/**
 * Import a CJS module, log it, export it.
 */

console.log(test);

var index = {
  test
};

/**
 * `node index.mjs` or `node .` prints (as expected):
 *
 * [Module] {
 *   default: { test: '/home/runner/rollup-filename-cjs-esm/importme.cjs' }
 * }
 */

export default index;

Additional Information

Any advice related to working around the __filename error is especially appreciated, I expect the inclusion of module.exports at the top of the repl.it bundle is related to the lower Node version, but I figured I would point that out.

Activity

  1. lukastaegert commented on Aug 2, 2020

    @lukastaegert
    Member

    I expect the inclusion of module.exports at the top of the repl.it bundle is related to the lower Node version, but I figured I would point that out.

    No, it is because of your use of the .cjs extension which is not included by this plugin by default. If you add it to the extensions option of this plugin, it works correctly. Unfortunately, nobody has done a PR to fix the default for this option yet.

    Otherwise, __filename and __dirname are not "fixed" for various reasons:

    • hardcoding them to the source modules is likely not desired as this would hard-code paths on the file system into the bundle and make the build machine specific.
    • hardcoding them to the generated modules is rather hard because they are not known at the time when the CommonJS plugin does its work and Rollup core itself never sees any CommonJS.
    • hardcoding may actually not be desired when the output format is 'cjs'. Only for other formats there is a problem.
    • hardcoding them to the generated modules would still make the build likely depend on the machine it was done, or it will need to contain some "dreamed up" paths.

    You could write a plugin that uses the renderChunk hook to do a post-processing transformation to replace __filename and __dirname with whatever makes the most sense to you.

    Alternatively, one could write a plugin that transforms __filename and __dirname using something import.meta.url related. But due to the reasons outlined above, I wonder if this should be a separate plugin.

  2. ctjlewis commented on Aug 2, 2020

    @ctjlewis
    ContributorAuthor

    @lukastaegert Thank you for your insight and fast response Lukas. I would probably agree that it should be a separate plugin. I'd be happy to write it.

    No, it is because of your use of the .cjs extension which is not included by this plugin by default. If you add it to the extensions option of this plugin, it works correctly. Unfortunately, nobody has done a PR to fix the default for this option yet.

    Thank you for this! I put one in at #524, please let me know if it is insufficient.


    For a bit more background, my goal is to take an ES module that relies on Node dependencies, coerce all import logic to ES2015, and spit out a massive bundle whose only import statements are NodeJS builtins. I can compile an ES module that has all the node_modules imports at the top (e.g. import chalk from 'chalk'; import someOtherThirdParty from 'third-party' ...), but rolling those in with node-resolve is quite the challenge.

    I can achieve this for a CJS output using Rollup or Webpack, but Webpack can't create an ESM output, so I would sooner invest time into getting Rollup to handle this case than work harder to use both of them.

    I would be very interested in getting your specific judgment on how to approach the __filename issue for this specific case: One entry point, one output file, and the only leftover imports are NodeJS builtins, with all third party dependencies are rolled in. I appreciate the information you've offered so far.

    Re. __filename logic:

    Hardcoding them to the source modules is likely not desired as this would hard-code paths on the file system into the bundle and make the build machine specific.

    This was my primary concern when thinking about this, but I'm thinking primarily about this use case. If the output is always going to exist in the same place relative to the module (i.e., at ./dist/output.mjs), we are guaranteed to have only one output, and that output will have rolled in all the possible source codes for any module that is referencing __filename pr __dirname, won't those always be the same at runtime, since the plugins are embedded in the output bundle? __filename = ./dist/output.mjs, __dirname = ./dist? Replace with path.resolve('./dist/output.mjs') if necessary?

    Hardcoding them to the generated modules is rather hard because they are not known at the time when the CommonJS plugin does its work and Rollup core itself never sees any CommonJS.

    For this case where we are compiling one large output that will have resolved all non-builtin modules, all generated modules will be the same file: One big bundle at dist/output.mjs.

    Hardcoding may actually not be desired when the output format is 'cjs'. Only for other formats there is a problem.

    Thought the same thing: This would only be for the case when output.format = 'esm' - I guess this would be the only time anyone would want to include this plugin. Maybe include it in the name: esm-filename-dirname or something.

    Alternatively, one could write a plugin that transforms __filename and __dirname using something import.meta.url related.

    I thought about this as well, but interestingly, for this case, at the end of the build process, any non-builtin module that was required by any dependency will all exist in the same file: The output bundle.

    All of this is for an ESM development environment that relies on just Rollup and Closure Compiler - once this issue is solved I will have full ESM-CJS interop, and will be able to ship backwards-compatible packages with no dependencies. Very sorry for talking your ear off (figuratively speaking) and very much appreciate any thoughts you have.

  3. changed the title [-]CommonJS -> ES2015: Output contains references to __filename[/-] [+][commonjs] Output contains references to __filename[/+] on Aug 4, 2020
  4. shellscape commented on Sep 6, 2020

    @shellscape
    Collaborator

    @ctjlewis it looks like there's consensus around a separate plugin to handle the original case. Can we close this?

  5. lukastaegert commented on Sep 6, 2020

    @lukastaegert
    Member

    By the way @ctjlewis did you look into https://www.npmjs.com/package/rollup-plugin-node-globals ? It promises a solution for the issue you described.

  6. ctjlewis commented on Sep 6, 2020

    @ctjlewis
    ContributorAuthor

    I use a custom workspace environment, gnv, to deal with this now. I did not end up using the node-globals plugin.

  7. ctjlewis commented on Nov 13, 2020

    @ctjlewis
    ContributorAuthor

    Since the Node-ES interop proposal has not been closed at #539 and this would require an out-of-the-box approach to __filename and __dirname, I am reopening this for now.

  8. stale commented on Jan 14, 2021

    @stale

    Hey folks. This issue hasn't received any traction for 60 days, so we're going to close this for housekeeping. If this is still an ongoing issue, please do consider contributing a Pull Request to resolve it. Further discussion is always welcome even with the issue closed. If anything actionable is posted in the comments, we'll consider reopening it. ⓘ

  9. ZeldOcarina commented on Apr 10, 2024

    @ZeldOcarina

    I don't think this should be closed.

  10. shellscape commented on Apr 10, 2024

    @shellscape
    Collaborator

    @ZeldOcarina we'd appreciate your contribution and would happily reopen if you'd like to own it.

  11. ZeldOcarina commented on Apr 10, 2024

    @ZeldOcarina

    I don't think I have the experience on this repo to own such a delicate issue I just think it shouldn't be closed by happy "stale" bot, I didn't mean to be mean if it arrived that way sorry.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions