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

bundle.require doesn't appear to work in prebundle hook #63

Closed
nickstenning opened this issue Dec 10, 2014 · 11 comments
Closed

bundle.require doesn't appear to work in prebundle hook #63

nickstenning opened this issue Dec 10, 2014 · 11 comments

Comments

@nickstenning
Copy link

I'm currently in the process of trying to work out why a set of tests have recently started failing, and while I'm not certain that karma-browserify is at fault, I have been able to reduce the testcase to a point where I figured it would be useful to open a discussion here.

Here's the code, in the form of a gist: https://gist.github.com/nickstenning/d70fea282c5897658452

Specifically, I was previously able to call bundle.require(...) in a prebundle hook in order to expose a library to the browserify bundle with a specific name (using browserify's expose option). This no longer appears to work.

Here's the output of karma start karma.conf.js --single-run on the above-linked project:

INFO [karma]: Karma v0.12.28 server started at http://localhost:9876/
INFO [launcher]: Starting browser PhantomJS
ERROR [framework.browserify]: bundle error
ERROR [framework.browserify]: Error: Cannot find module 'foo' from '<homedir>/bundlerequire'
INFO [PhantomJS 1.9.8 (Mac OS X)]: Connected on socket ghbV-cdMt-BQHjVpAzsV with id 46640088
PhantomJS 1.9.8 (Mac OS X) ERROR
  TEST RUN WAS CANCELLED because this file contains some errors:
    /var/folders/8r/_p3vfgtn6d991_lrz2vw1w1m0000gn/T/c1e197606dd046b68f412728a2f0b12dbb763706.browserify
PhantomJS 1.9.8 (Mac OS X): Executed 0 of 0 ERROR (0.01 secs / 0 secs)
@bendrucker
Copy link
Collaborator

Did a little investigation and this would have worked with karma-bro < 0.7

@bendrucker
Copy link
Collaborator

So the reason this is happening is that the bundle gets reset on rebuilds:

https://github.com/Nikku/karma-browserify/blob/master/lib/bro.js#L208

Immediate fix is to do this in prebundle:

bundle.require('./foo', {expose: 'foo'});
bundle.on('reset', function () {
    bundle.require('./foo', {expose: 'foo'});
});

external among other bundle configuration calls is not reset on reset. Technically running prebundle on every run wouldn't break anything but it would balloon arrays like b._external with long running watchify instances. I think the answer here is to provide an extra hook that runs on every bundle call but I'll wait on @nikku's thoughts before we ship anything.

@nickstenning
Copy link
Author

Thanks for digging @bendrucker.

To pre-empt questions about why on earth I'd want or need to do this: I have a project, "foo", which contains some plugins. These plugins depend on "foo-plugintool", an external dependency which in turn depends on "foo". When testing, I'd like that require('foo') to resolve back to the working copy of the project rather than the released version. Hope that makes sense.

@nikku
Copy link
Owner

nikku commented Dec 11, 2014

Haha, I already had an update for that behavior implemented but reverted it again because no reported a bug on it yet.

The intention during early karma-bro times was to actually be able to configure the whole bundle thing once. Too bad browserify nowadays resets file configurations and so forth.

My suggestion is: We fire a custom event users can listen to that resembles the configuration before actual bundling for the users:

bundle.on('prebundle', function () {
  bundle.require('./foo', {expose: 'foo'});
});

We could then rename the actual method to something like configure or the like to indicate manual configuration of browserify. Prebundle is definitely the wrong name for what it offers today.

@nikku
Copy link
Owner

nikku commented Dec 11, 2014

Looks like this is absolutely equivalent:

bundle.on('reset', function () {
  bundle.require('./foo', {expose: 'foo'});
});

The initial configuration is not needed as we always reset the bundle prior to any bundling operations.

@bendrucker
Copy link
Collaborator

You're right. Honestly I'm inclined to just document this. The gain from having a clearer event name isn't worth creating code that isn't portable (i.e. wouldn't work with regular watchify). configure makes sense but would also mean a major version change.

aron added a commit to openannotation/annotator that referenced this issue Dec 11, 2014
As described in the GitHub issue[1]. Unfortunately now we fail further
down the stack...

[1]: nikku/karma-browserify#63 (comment)
aron added a commit to openannotation/annotator that referenced this issue Dec 11, 2014
As described in the GitHub issue[1]. Unfortunately now we fail further
down the stack...

[1]: nikku/karma-browserify#63 (comment)
@nickstenning
Copy link
Author

This sounds fine as far as it goes, but it seems that it introduces another related bug. If you do

bundle.on('reset', function () {
  bundle.require('./foo', {expose: 'foo'});
});

then certainly require('foo') works, but oddly require('./foo') no longer does. This is at odds with the usual behaviour of browserify AFAICT. If I have foo.js:

module.exports = 4;

and relative.js:

var foo = require('./foo');
console.log("foo =", foo);

then I can still browserify this using

browserify -r ./foo.js:foo relative.js | node

and the relative require continues to work.

@nikku
Copy link
Owner

nikku commented Dec 11, 2014

This is related to #52 and a browserify/watchify bug. It looks as if watchify cannot handle files that are required using their relative path names and a global alias at the same time.

As much as I can tell there are two options to fix this, none of them is without pain.

@nikku
Copy link
Owner

nikku commented Dec 19, 2014

We are going to fix this in karma-browserify by exposing all files via their absolute path.

This is something watchify requires. In order for the above code to work, you should use

bundle.require('abs-path-to-foo', {expose: 'foo'});

nikku added a commit that referenced this issue Dec 20, 2014
This commit removes the prebundle hook to configure and adds the
prebundle event that may be used to perform additional configuration.

This allows users to reliably hook into the bundling process in
browserify@7 times.

Closes #63
nikku added a commit that referenced this issue Dec 20, 2014
This commit removes the prebundle hook to configure and adds the
prebundle event that may be used to perform additional configuration.

This allows users to reliably hook into the bundling process in
browserify@7 times.

Closes #63
@nikku
Copy link
Owner

nikku commented Dec 20, 2014

Forget what I posted before 😀.

The next version of karma-browserify will remove the prebundle hook in favor of a configure hook.
Users may hook into prebundle actions by listening to the prebundle event.

Example configuration:

{

  files: [ ],
  preprocessors: [ ],

  browserify: {
    configure: function(b) {
      b.on('prebundle', function() {
        b.external('lib/external.js');
      });
    }
  }
}

@nikku nikku closed this as completed in 5c4e9bc Dec 21, 2014
@nickstenning
Copy link
Author

Thank you! 🍰

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

No branches or pull requests

3 participants