Node: On Windows, Node can be inconsistent in what case builtin functions use for drive letters

Created on 6 May 2016  路  8Comments  路  Source: nodejs/node

  • Version: 6.0.0
  • Platform: Windows 7 x64
  • Subsystem: path, module, process

When cmd.exe is run via a shortcut that has a lowercase drive letter in its 'Start in' field (e.g. d:\dev) and Node is run from this cmd instance, Node's builtin functions behave in an unexpected way. Some of them return the drive letter in upper case (D:\dev\foo) whereas the other in lower (d:\dev\foo).

test.js:

var exprs = ['__dirname', '__filename', 'require.resolve("./test")', 
    'require("path").resolve("test.js")', 'process.cwd()'];
for (var expr of exprs) {
    console.log(expr, eval(expr));
}

In cmd:

d:\dev\foo>node test
__dirname D:\dev\foo
__filename D:\dev\foo\test.js
require.resolve("./test") D:\dev\foo\test.js
require("path").resolve("test.js") d:\dev\foo\test.js
process.cwd() d:\dev\foo

If I change the case of the drive letter in the "Start in" field of the shortcut for cmd, everything becomes consistent.

D:\dev\foo>node test
__dirname D:\dev\foo
__filename D:\dev\foo\test.js
require.resolve("./test") D:\dev\foo\test.js
require("path").resolve("test.js") D:\dev\foo\test.js
process.cwd() D:\dev\foo

This leads to issues like webpack/webpack#2362.

So what can be done about it?
1) It'd be great if Node always used upper case.
2) Also now Node resolves d:\test.js and D:\test.js as two different modules. Should it stay like this?

d:\dev\foo>echo console.log('load')>bar.js
d:\dev\foo>node
> require('d:\\dev\\foo\\bar.js')
load
{}
> require('d:\\dev\\foo\\bar.js')
{}
> require('D:\\dev\\foo\\bar.js')
load
{}
module path windows

Most helpful comment

This is causing issues in webpack. Waiting eagerly for a fix.

All 8 comments

3594 might be part of this issue.

1) It'd great if Node always used upper case.

Node changed behavior a few times in the past. From what I can reacall, what was finally deemed the 'proper' way was to never have Node normalize the drive case. So it could change based on the process current directory, as you noted, but at least it would be consistent everywhere internally.

Are you seeing any place where Node is changing the case and making it different than process.cwd or what was passed in the command line? If so it should be considered a bug, IMO.

Also now Node resolves d:\test.js and D:\test.js as two different modules. Should it stay like this?

I think it shouldn't. See https://github.com/nodejs/node-v0.x-archive/pull/6774. I'll add it to my todo list to revive that.

Are you seeing any place where Node is changing the case and making it different than process.cwd or what was passed in the command line?

Yes.

d:\dev\foo>node test
__dirname D:\dev\foo
__filename D:\dev\foo\test.js
require.resolve("./test") D:\dev\foo\test.js
require("path").resolve("test.js") d:\dev\foo\test.js
process.cwd() d:\dev\foo

YES

Even when using only relative paths to modules './../myModule', something changes require.resolve from using the uppercase C:\ path of a module initially to use the lowercase c:\ path during the loading of a project.

In our case, from looking at the require.cache order of modules, it switches from "C:\..." to "c:\.." after completing the first cycle of module reference chains. My guess is that it might have something to do when require is resolving circular referencing module chains and starts working on the 2nd and n- number of loops to resolve modules.

When this occurs, it can load _some_ modules twice which we just experienced when cwd() is initially set with an uppercase "C:\..."

* Edited *
_Removed suggestion about using uppercase drive letters. It's not a good suggestion..._

node: v4.4.4
Windows 10

/cc @mousetraps

https://github.com/nodejs/node/pull/3594
https://github.com/nodejs/node-v0.x-archive/pull/6774
https://github.com/nodejs/node-v0.x-archive/issues/7031
https://github.com/nodejs/node-v0.x-archive/pull/8145
https://github.com/nodejs/node-v0.x-archive/issues/7806

In cmd:

d:\dev\foo>node test
__dirname D:\dev\foo
__filename D:\dev\foo\test.js
require.resolve("./test") D:\dev\foo\test.js
require("path").resolve("test.js") d:\dev\foo\test.js
process.cwd() d:\dev\foo

This exemplifies the issue very well, thank you!

We could attempt to normalize the casing of __dirname and __filename to match that of process.cwd(). That might have other unwanted side effects though. The real answer is to always make case insensitive path comparisons on Windows.

This is on my queue of fixes.

This is causing issues in webpack. Waiting eagerly for a fix.

So, as of Node 6.4, the case of the drive letter returned by all the builtin functions is consistent and is determined by the case returned by process.cwd().

D:\dev\zzz>node test
__dirname D:\dev\zzz
__filename D:\dev\zzz\test.js
require.resolve("./test") D:\dev\zzz\test.js
require("path").resolve("test.js") D:\dev\zzz\test.js
process.cwd() D:\dev\zzz

D:\dev\zzz>C:

C:\>cd d:\dev\zzz

C:\>d:

d:\dev\zzz>node test
__dirname d:\dev\zzz
__filename d:\dev\zzz\test.js
require.resolve("./test") d:\dev\zzz\test.js
require("path").resolve("test.js") d:\dev\zzz\test.js
process.cwd() d:\dev\zzz

d:\dev\zzz>

Why instead not make it always upper (lower) case? The case returned by process.cwd() is a quasi-random value (see the example above, it depends on just how I typed the cd command). It's effectively never is intentionally chosen. Yet it can unexpectedly change the behaviour of the program.

Also d:\test.js and D:\test.js are still resolved as two different modules.

To get rid of problems with lowercase drive letter on Windows you can try this https://www.npmjs.com/package/driveup as a hotfix for this issue. It changes the drive letter the UpperCase:

e:\your_project_path>driveup

E:\your_project_path>

or to launch your shell:

e:\>startcmd cmder e:\your_project_path

You can setup cmder or cmd launching to always have uppercase drive letter

Was this page helpful?
0 / 5 - 0 ratings