Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

__dirname returns '/' when js file is built with webpack #1599

Closed
AJShippify opened this issue Nov 7, 2015 · 68 comments
Closed

__dirname returns '/' when js file is built with webpack #1599

AJShippify opened this issue Nov 7, 2015 · 68 comments
Labels

Comments

@AJShippify
Copy link

I have a working express file, which I 'webpack' it but when the bundled file is run the __dirname global changes to '/'. I need the absolute path for certain functions as res.sendFile. Any help?

@sokra
Copy link
Member

sokra commented Nov 7, 2015

See node option in the documentation.

@AJShippify
Copy link
Author

Ok, I set the

node: {
 __dirname: true
    }

But now the __dirname is empty, ''

@AJShippify
Copy link
Author

Could you provide a sample code for retrieving the proper directory name?. I'm currently using a module called app-root-path but I'd like to know if there is a webpack-native way of doing it

@IngwiePhoenix
Copy link

Typically, __dirname is set to options.output.publicPath. Switching to node, shouldl resolve this.
However, you also need to set target: "node".

@goodseller
Copy link

I got the same result after trying the above config.
Here is my config:

webpack.config.js

var webpack = require('webpack');
var path = require('path');
var fs = require('fs');

var nodeModules = {};
fs.readdirSync('node_modules')
  .filter(function(x) {
    return ['.bin'].indexOf(x) === -1;
  })
  .forEach(function(mod) {
    nodeModules[mod] = 'commonjs ' + mod;
  });

var exts = ['express'];
module.exports = {
  entry: ['./server/index.js'],
  context: __dirname,
  node: {
    __filename: true,
    __dirname: true
  },
  target: 'node',
  output: {
    path: path.join(__dirname, 'build'),
    filename: '[name].bundle.js',
    chunkFilename: "[id].bundle.js"
  },
  externals: nodeModules,
  plugins: [
    new webpack.IgnorePlugin(/\.(css|less)$/),
    new webpack.BannerPlugin('require("source-map-support").install();',
                             { raw: true, entryOnly: false }),
  ],
  devtool: 'sourcemap',
}

src: ./server/index.js

...
app.use('/static', express.static(path.join(__dirname, '..', 'public')));
...

It works for directly run the source. Am I missing something?

@fritx
Copy link

fritx commented Feb 20, 2016

Same 👍
How to disable __dirname injection, leaving it as original?

---UPDATE---

For now, I use this hack:

plugins: [
  new webpack.DefinePlugin({
    $dirname: '__dirname',
  }),
]

@goodseller
Copy link

@fritx I cannot find any related to your usage in the document. May I know how does it works?

@fritx
Copy link

fritx commented Feb 21, 2016

@goodseller Just replace __dirname with $dirname, and it works.
The $dirname would be equivalent to __dirname, regardless of the webpack injection.

@fritx
Copy link

fritx commented Feb 21, 2016

Sorry, I found the hack unnecessary.

// the webpack config just works
target: 'node',
node: {
  __dirname: false,
  __filename: false,
}

@kellyrmilligan
Copy link

wow, that works for me too, the setting seems counterintuitive. wish we had explanations for what true, false mean in each case.

@kellyrmilligan
Copy link

if I have a node module requiring in a module for me, through a config file, how can I have webpack include the files that are being required in for me so that they are in the build directory? basically I have a hapijs app, and am trying out webpack for the node build. Glue module reads in a config, and the __dirname is now the build directory, and the modules are still in src since they are not being required in explicitly. thoughts?

@fritx
Copy link

fritx commented Mar 8, 2016

@kellyrmilligan 😵 I think you need to make those modules (in trouble) commonjs?

plugins: [
  new webpack.ExternalsPlugin('commonjs', ['a', 'b'])
]

or just make them all commonjs:

// https://github.com/fritx/os-web/blob/dev/task%2Fwebpack.server.js
externals: [
  (ctx, req,  cb) => {
    // if (/^\.?\//.test(req)) return cb()
    if (/^\.\.?\//.test(req)) return cb() // fixed √
    cb(null, `commonjs ${req}`)
  },
],

I have a project (experimental) 😆 which webpacks both client & server side.
Check this out: https://github.com/fritx/os-web

@joegesualdo
Copy link

if I have a node module requiring in a module for me, through a config file, how can I have webpack include the files that are being required in for me so that they are in the build directory? basically I have a hapijs app, and am trying out webpack for the node build. Glue module reads in a config, and the __dirname is now the build directory, and the modules are still in src since they are not being required in explicitly. thoughts?

@kellyrmilligan Have you found a solution?

@kellyrmilligan
Copy link

I ended up abandoning the approach. Kept on running into brick walls

@michaeljota
Copy link

michaeljota commented Sep 14, 2016

I'd like to add that using node option

node: {
  __dirname: false
}

will also work if you are targeting electron.

@mmmeff
Copy link

mmmeff commented Oct 3, 2016

Whatever this flag is doing, setting __dirname: truefixed it for me.

@tswaters
Copy link

Playing with this a bit, assuming I have the following:

./src
  public
    app.js
  server
    app.js

and inside server/app.js I include the following:

app.use(express.static(path.join(__dirname, '../public')))

The following happens based upon what options.node.__dirname is set to:

  • unset - leading slash, /; express will attempt to serve files from the root, /public (d'oh!)
  • true - sets it to the original path of the src filename, in this case src/server
  • false - no injection is performed, global.__dirname is used and it will be options.output.path, effectively.

The unset case seems the most counter-intuitive to me and I have a hard time understanding what the use case of injecting / as __dirname would be.... strange that this is the default.

@amasad
Copy link

amasad commented Dec 12, 2016

FWIW to get the actual behavior in node you need to write your own plugin. This is adapted from the NodeStuffPlugin (which handles the configuration discussed here). Just insert the following into your plugins array:

    {
      apply(compiler) {
        function setModuleConstant(expressionName, fn) {
          compiler.parser.plugin('expression ' + expressionName, function() {
            this.state.current.addVariable(expressionName, JSON.stringify(fn(this.state.module)));
            return true;
          });
        }

        setModuleConstant('__filename', function(module) {
          return module.resource;
        });

        setModuleConstant('__dirname', function(module) {
          return module.context;
        });
     }

@bchr02
Copy link

bchr02 commented Feb 17, 2017

For everyone's reference, I just posted a similar issue here: #4303

@verybluebot
Copy link

I have the same issue but in create-react-app and I don't want to eject the scripts, so don't have access to webpack configs... Any suggestions? getting really frustrated on this one

thanks

@Kupstas
Copy link

Kupstas commented Aug 19, 2019

Still doesn't understand how use it with create-react-app + electron. In dev mode I set __dirname=true; target = 'electron-renderer' and everything works fine but in a production mode it's crashing. I'm using leveldown lib for my local db and can't make it working in production mode

@Kupstas
Copy link

Kupstas commented Aug 19, 2019

@bvaughn
Copy link

bvaughn commented Aug 19, 2019

@Kupstas you might also try process.cwd() (not sure if that would work for you, but it may be worth trying?)

@Kupstas
Copy link

Kupstas commented Aug 19, 2019

@bvaughn I think that problem in some other place. In dev mode in __dirname I see node_modules/leveldown but in production /Users/nikolay.kupstas/Desktop/Work/bus-inspector/dist/mac/Busman.app/Contents/Resources/app.asar/build.

@andrezsanchez
Copy link

I am encountering this issue. I will get around it for now by using process.cwd() and avoiding __dirname and __filename in my app, but that's not ideal.

@royra
Copy link

royra commented Nov 6, 2019

Seems like webpack incorrectly replaces __dirname and __filename for sibling modules in a monorepo (using yarn workspaces). __dirname seems to always be set to the root context (the package webpack is run at).

I got around this by applying an updated version of @amasad's custom plugin above:

    {
      apply(compiler) {
        function setModuleConstant(expressionName, fn) {
          compiler.hooks.normalModuleFactory.tap('MyPlugin', factory => {
            factory.hooks.parser.for('javascript/auto').tap('MyPlugin', (parser, _options) => {
              parser.hooks.expression.for(expressionName).tap('MyPlugin', expression => {
                parser.state.current.addVariable(expressionName, JSON.stringify(fn(parser.state.module)))
                return true
              })
            })
          })
        }

        setModuleConstant('__filename', function (module) {
          return module.resource;
        });

        setModuleConstant('__dirname', function (module) {
          return module.context;
        });
      }
    },

@aprilandjan
Copy link

If you are using webpack to bundle to target electron-renderer and found some __dirname in node_modules does not output as the real path, probably you need to add this module to webpack external.

@inad9300
Copy link

inad9300 commented Jun 6, 2020

Related to this issue, the documentation misleadingly indicates that the default value for both __filename and __dirname is false. However, setting both to false complete changed (fixed) the behaviour for me, meaning the default must be something else.

@alexander-akait
Copy link
Member

Fixed in webpack@5, for node, async-node and electron-main, it is false by default

@sheng-di
Copy link

Same 👍
How to disable __dirname injection, leaving it as original?

---UPDATE---

For now, I use this hack:

plugins: [
  new webpack.DefinePlugin({
    $dirname: '__dirname',
  }),
]

Doesn't work.

@sheng-di
Copy link

@saurabh-deep

I was running into the issue where __dirname was set to / in my electron main process bundle with webpack. I added

node: {
__dirname: false
}

to my config and that did the trick

My full config 👇

const path = require('path');

module.exports = {
    entry: path.join(__dirname, '..', 'main', 'index.js'),
    output: {
        path: path.resolve(__dirname, '..', 'public'),
        filename: 'electron.js',
    },
    target: 'electron-main',
    node: {
        __dirname: false,
    },
};

set __dirname: false worked for me.

@vjpr
Copy link

vjpr commented Nov 9, 2021

I had issues with this working sporadically. I had to clear my cache sometimes. I also changed the resolve.conditionNames which broke things.

So be warned, __dirname might be getting overridden somewhere else when you tweak other settings. I think some comments hinted at sporadic behavior of this issue.

I searched for where __dirname is assigned and found this which might be causing issue. Something to do with the ESM loader.

node:internal/process/execution

Screen Shot 2021-11-09 at 8 27 06 pm

The custom plugin #1599 (comment) is the best solution.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests