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

Dynamically calculate __dirname and __filename when --node is passed #1725

Merged
merged 1 commit into from Feb 7, 2018
Merged

Dynamically calculate __dirname and __filename when --node is passed #1725

merged 1 commit into from Feb 7, 2018

Conversation

jviotti
Copy link

@jviotti jviotti commented May 17, 2017

When --no-commondir is set (as a consequence of --node for example),
it will cause the final bundle to hardcode absolute values of the
machine that generated the bundle in order to resolve __dirname and
__filename. For example, consider a foo.js file containing:

console.log(__dirname);
console.log(__filename);

Calling browserify --node on it results in:

(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
(function (__filename,__dirname){
console.log(__dirname);
console.log(__filename);

}).call(this,"/Users/jviotti/Projects/playground/node-browserify/foo.js","/Users/jviotti/Projects/playground/node-browserify")
},{}]},{},[1]);

Notice the absolute paths at the end of the bundle. This means that
Browserify node users can't generate a bundle in one machine, and expect
it to run without issues on another machine.

As a solution, we can use the final bundle's __dirname to dynamically
resolve every file's __dirname and __filename. This change only
takes place when --node is set, and keeps Browserify backwards
compatible.

For example, the above output might contain the following line:

}).call(this,require("path").join(__dirname,"foo.js"),require("path").join(__dirname,"."))

Fixes: #1723
See: balena-io/etcher#1429
See: balena-io/etcher#1409
Signed-off-by: Juan Cruz Viotti jviotti@openmailbox.org

jviotti pushed a commit to balena-io/etcher that referenced this pull request May 17, 2017
We encountered a Browserify bug when releasing the CLI, where absolute
paths would be hard-coded in the final bundle. Since we were in the
middle of a release process, we added a quick and dirty
search-and-replace workaround on `concatenate-javascript.sh`.

After the release, we submitted a PR to Browserify which fixes the
issue. This commit makes use of my personal fork to be able to use such
fix while it gets merged to the main project.

See: browserify/browserify#1725
See: #1409
Fixes: #1429
Signed-off-by: Juan Cruz Viotti <jviotti@openmailbox.org>
index.js Outdated
return 'require("path").join(__dirname,"' + dir.split(path.sep).join('","') + '")';
},
__filename: function(file) {
var filename = path.relative(basedir, file);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Possibly-stupid first question:
How come __dirname has the parameters (file, basedir), but __filename only has the parameter file? In that case, where does the basedir variable in this line come from?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops, fixed!

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So how come this wasn't being picked up by the tests? Does it imply that it'd be worth testing __dirname and __filename separately, rather than testing them together?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like there is another basedir variable defined above (https://github.com/substack/node-browserify/blob/master/index.js#L428):

var basedir = defined(opts.basedir, process.cwd());

And that happens to have the right one as well (its basically what gets passed to the __filename function).

I'll see if I can somehow break it and test it.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I give up. The variable declared above is always valid, and I can't find a way to break it. I guess a linter should be the correct way to detect these kinds of subtle issues.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I guess only a linter is able to automatically spot 'conflicting' variable names and suggest that one of them gets renamed, but that's obviously well outside the scope of this PR ;-)

@@ -68,3 +75,72 @@ test('bare inserts __filename,__dirname but not process,global,Buffer', function
t.equal(code, 0);
});
});

test('bare inserts dynamic __filename,__dirname', function (t) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Possibly-stupid second question:
The test description mentions both __filename and __dirname, but AFAICT this is only testing __dirname?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These tests execute the following file: https://github.com/substack/node-browserify/pull/1725/files#diff-df4230a729c19a353d1405d5459df60d, which prints both __dirname, and __filename (and we assert the result of both)

jviotti pushed a commit to balena-io/etcher that referenced this pull request May 22, 2017
We encountered a Browserify bug when releasing the CLI, where absolute
paths would be hard-coded in the final bundle. Since we were in the
middle of a release process, we added a quick and dirty
search-and-replace workaround on `concatenate-javascript.sh`.

After the release, we submitted a PR to Browserify which fixes the
issue. This commit makes use of my personal fork to be able to use such
fix while it gets merged to the main project.

See: browserify/browserify#1725
See: #1409
Fixes: #1429
Signed-off-by: Juan Cruz Viotti <jviotti@openmailbox.org>
jviotti pushed a commit to balena-io/etcher that referenced this pull request May 22, 2017
We encountered a Browserify bug when releasing the CLI, where absolute
paths would be hard-coded in the final bundle. Since we were in the
middle of a release process, we added a quick and dirty
search-and-replace workaround on `concatenate-javascript.sh`.

After the release, we submitted a PR to Browserify which fixes the
issue. This commit makes use of my personal fork to be able to use such
fix while it gets merged to the main project.

See: browserify/browserify#1725
See: #1409
Fixes: #1429
Signed-off-by: Juan Cruz Viotti <jviotti@openmailbox.org>
@inDream
Copy link

inDream commented Aug 4, 2017

@substack @feross When will this fix be merged?

@AKK9
Copy link

AKK9 commented Dec 12, 2017

Is it possible to have this fixed?

index.js Outdated
opts.insertGlobalVars = xtend({
__dirname: function(file, basedir) {
var dir = path.dirname(path.relative(basedir, file));
return 'require("path").join(__dirname,"' + dir.split(path.sep).join('","') + '")';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

paths can contain " on some filesystems, could you use JSON.stringify here instead of manually wrapping the path in quotes?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good, done!

@@ -551,6 +552,19 @@ Browserify.prototype._createDeps = function (opts) {
return through();
}
}

if (opts.commondir === false && opts.builtins === false) {
opts.insertGlobalVars = xtend({
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could this be done in cmd/args.js, in the same place as the other node: option stuff?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure I understand this comment. Do you mean setting commondir: false and builtins: false if node: true, and then just check for node: true here?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh sorry nevermind, i misunderstood what this check is doing--i thought you were using this to essentially check if --node was passed, but opts.commondir actually is the one causing the issue.

When `--no-commondir` is set (as a consequence of `--node` for example),
it will cause the final bundle to hardcode absolute values of the
machine that generated the bundle in order to resolve `__dirname` and
`__filename`. For example, consider a `foo.js` file containing:

```js
console.log(__dirname);
console.log(__filename);
```

Calling `browserify --node` on it results in:

```js
(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
(function (__filename,__dirname){
console.log(__dirname);
console.log(__filename);

}).call(this,"/Users/jviotti/Projects/playground/node-browserify/foo.js","/Users/jviotti/Projects/playground/node-browserify")
},{}]},{},[1]);
```

Notice the absolute paths at the end of the bundle. This means that
Browserify node users can't generate a bundle in one machine, and expect
it to run without issues on another machine.

As a solution, we can use the final bundle's `__dirname` to dynamically
resolve every file's `__dirname` and `__filename`. This change only
takes place when `--node` is set, and keeps Browserify backwards
compatible.

For example, the above output might contain the following line:

```
}).call(this,require("path").join(__dirname,"foo.js"),require("path").join(__dirname,"."))
```

Fixes: #1723
See: balena-io/etcher#1429
See: balena-io/etcher#1409
Signed-off-by: Juan Cruz Viotti <jviotti@openmailbox.org>
Signed-off-by: Juan Cruz Viotti <jv@jviotti.com>
Copy link
Member

@goto-bus-stop goto-bus-stop left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm, thanks for your patience 🙏 do you think we need a major version bump for this?

@jviotti
Copy link
Author

jviotti commented Dec 26, 2017

Awesome, thanks a lot and sorry for the delay addressing the comments!

@jviotti
Copy link
Author

jviotti commented Dec 26, 2017

@goto-bus-stop

do you think we need a major version bump for this?

Since all the previous tests are passing, this is a backwards compatible change, which I guess should be minor version bump.

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

Successfully merging this pull request may close these issues.

Using __dirname and --node causes absolute paths in the final bundle
5 participants