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

Build client-side Mocha using Browserify #1727

Closed
wants to merge 1 commit into from

Conversation

ndhoule
Copy link
Contributor

@ndhoule ndhoule commented Jun 6, 2015

paging @boneskull, @travisjeffery

Still needs some work before merging but wanted to put it out there early since it seems like a better build process is eating up time and making stuff like the plugin API and breaking reporters out into npm-land difficult.

Outstanding issues:

  • Still some cleanup to do, current transition is a little messy. And I bet we can remove a few more shims like lib/browser/events.
  • Did super cursory testing in the browser and even more cursory at the command line; would want to stress test this a bit more before merging.
  • The built Browserify file is still a lot larger than the current build process (~148k currently, 209k under Browserify). Haven't looked into this too deeply yet.
  • Browserified file includes all the reporters, which @tj said shouldn't happen anyway. I think, though, that removing them would break mocha-phantomjs; @metaskills, is that right? Is that something to be concerned about?

Will follow up on these in the next day or so, when I get a bit more time.


Related issues:

Tangentially related:

@@ -143,7 +144,9 @@ Mocha.prototype.reporter = function(reporter, reporterOptions){
} else {
reporter = reporter || 'spec';
var _reporter;
try { _reporter = require('./reporters/' + reporter); } catch (err) {}
// Try to load a built-in reporter.
if (reporters[reporter]) _reporter = reporters[reporter];
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Worth pointing out here is that Browserify doesn't do dynamic requires, so we have to switch to a static approach here. I assumed that reporter is always in lowercase, not sure if that's a safe assumption or if we want to implement a more robust approach to grabbing built-in reporters here (spitballing here: e.g. always normalize to kebab-case)?

Copy link
Contributor

Choose a reason for hiding this comment

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

dunno. I wanted to eliminate them from the core except for spec, so whatever's clever for now.

Choose a reason for hiding this comment

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

Couldn't agree more with @boneskull.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

👍 works for me.

@jbnicolai
Copy link

Note that the failing TravisCI build is only on node v0.8 due to the caret-notation used on the browserify dependency, something older npm versions can't handle.

@@ -1,4 +1,5 @@

BROWSERIFY := node_modules/.bin/browserify

Choose a reason for hiding this comment

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

I guess we could do something like PATH := node_modules/.bin:$(PATH) to simplify the code (slightly). Seeing as you'd also prefer a local dep. over a global one anyway.

Copy link
Contributor

Choose a reason for hiding this comment

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

👎 Makefiles

Choose a reason for hiding this comment

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

@boneskull why? To me this still seems more straightforward than most alternatives (which admittedly says a lot about the alternatives as well..)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, I prefer local dependencies. Gives you everything you need in an npm install and prevents "what version of Browserify are you running, oh, update/downgrade it"-type issues.

I generally just throw all my binaries at the top of the file because I've has issues with the PATH solution in the past (can't remember what those were), I'm open to whatever though

Choose a reason for hiding this comment

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

Nah, the number of paths explicitly stated is small enough that it doesn't matter, although I'm curious what your issues were.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No clue, I can repro it in my other local repos, but not in my local Mocha repo. Weird.

I also prefer the explicit path just because I keep global installations of some binaries (e.g. ESLint) installed for editor integrations, etc. and like to be sure there's nothing funky going on, like a missing local dependency triggering errors because it's falling back on a global installation, which is a heinous thing to debug. More verbose for fewer terrible things to debug, but maybe that's crossed over into paranoia territory.

Anyway, it's working locally so I don't mind either way

@boneskull
Copy link
Contributor

let's just keep the browserify dependency exact. given that you can't build the browser version of Mocha w/o it, I don't want to take any chances

: false;
exports.useColors = process.browser
? false
: (supportsColor || (process.env.MOCHA_COLORS !== undefined));

Choose a reason for hiding this comment

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

A ternary where one of the statements is a boolean constant always seems odd to me. How about

!process.browser && (supportsColor || process.env.MOCHA_COLORS);

Copy link
Contributor

Choose a reason for hiding this comment

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

I'm in agreement here fwiw

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah yeah, I just kept it that way because process.browser is undefined in Node, but I'll stop being lazy

@boneskull
Copy link
Contributor

Browserified file includes all the reporters, which @tj said shouldn't happen anyway. I think, though, that removing them would break mocha-phantomjs; @metaskills, is that right? Is that something to be concerned about?

there's only one reporter in the browser...

@boneskull
Copy link
Contributor

The built Browserify file is still a lot larger than the current build process (~148k currently, 209k under Browserify). Haven't looked into this too deeply yet.

I don't care about this at all

@boneskull
Copy link
Contributor

Still some cleanup to do, current transition is a little messy. And I bet we can remove a few more shims like lib/browser/events

yes please. thanks for the tremendous amount of work here.

@ndhoule
Copy link
Contributor Author

ndhoule commented Jun 6, 2015

@boneskull

there's only one reporter in the browser...

https://github.com/metaskills/mocha-phantomjs#standard-out
I think mocha-phantomjs relies on all the reporters being present in the browser (which is why Mocha.process is exposed).

@jbnicolai
Copy link

thanks for the tremendous amount of work here

yes!

I don't care about this at all

Same. Make it work first, optimize later. ;)

I think, though, that removing them would break mocha-phantomjs; @metaskills, is that right? Is that something to be concerned about?

I wouldn't worry about this. The other reporters should be broken-out and included separately and explicitly by mocha-phantomjs

@ndhoule
Copy link
Contributor Author

ndhoule commented Jun 6, 2015

Bleh, looks like Browserify's deps have carets in them so they hose Node 0.8. Could just add a Make target to install it before building mocha.js I guess, and note in the docs that Mocha works, but is unbuildable on, 0.8. Hacky, but would work—objections?

@jbnicolai
Copy link

Yes.. the issue is not even node 0.8 but the bundled npm version. Any production environment stuck due to whatever complexities on an older version would still easily be able to update npm, so I wouldn't consider it an issue at all.

We could add a line to the .travis.yml like:

before_install:
- npm install -g npm@latest

@jbnicolai
Copy link

The built Browserify file is still a lot larger than the current build process (~148k currently, 209k under Browserify). Haven't looked into this too deeply yet.

I don't care about this at all

If we'd like we could get this down by about 3x using Google's closure compiler.

make
for f in mocha{,.browserified}; do 
  curl --data-urlencode "js_code@$f.js" \ 
    -d "output_format=text&output_info=compiled_code&compilation_level=SIMPLE_OPTIMIZATIONS&language=ECMASCRIPT5" \ 
    http://closure-compiler.appspot.com/compile > "$f.min.js"; 
done
du -hs | gshort -h

88K mocha.browserified.min.js
88K mocha.min.js
208K mocha.browserified.js
208K mocha.js

@boneskull
Copy link
Contributor

I wouldn't worry about this. The other reporters should be broken-out and included separately and explicitly by mocha-phantomjs

I don't think karma-mocha is reliant on the reporters either. It has its own. I'm not sure where it hooks in, though.

@boneskull
Copy link
Contributor

I don't think karma-mocha is reliant on the reporters either. It has its own. I'm not sure where it hooks in, though.

(you can use phantomjs as the browser)

@jbnicolai
Copy link

Played with it a bit more, I'm all for this PR 👍

@ndhoule
Copy link
Contributor Author

ndhoule commented Jun 7, 2015

@jbnicolai

Yes.. the issue is not even node 0.8 but the bundled npm version. Any production environment stuck due to whatever complexities on an older version would still easily be able to update npm, so I wouldn't consider it an issue at all.

We could add a line to the .travis.yml like:

Haha good point, not sure why I didn't think about that. Changed

* @return {string}
*/
function parseInheritance(js) {
return js.replace(/^ *(\w+)\.prototype\.__proto__ * = *(\w+)\.prototype *;?/gm, function(_, child, parent){

Choose a reason for hiding this comment

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

:/ I appreciate the effort, but we really should remove all usages of __proto_ from the codebase. See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/proto for instance.

Couldn't we apply this rewrite rule verbatim to our codebase, rather than at build-time?

git grep __proto lib

lib/hook.js:Hook.prototype.proto = Runnable.prototype;
lib/reporters/dot.js:Dot.prototype.proto = Base.prototype;
lib/reporters/landing.js:Landing.prototype.proto = Base.prototype;
lib/reporters/list.js:List.prototype.proto = Base.prototype;
lib/reporters/min.js:Min.prototype.proto = Base.prototype;
lib/reporters/nyan.js:NyanCat.prototype.proto = Base.prototype;
lib/reporters/progress.js:Progress.prototype.proto = Base.prototype;
lib/reporters/spec.js:Spec.prototype.proto = Base.prototype;
lib/reporters/xunit.js:XUnit.prototype.proto = Base.prototype;
lib/runnable.js:Runnable.prototype.proto = EventEmitter.prototype;
lib/runner.js:Runner.prototype.proto = EventEmitter.prototype;
lib/suite.js:Suite.prototype.proto = EventEmitter.prototype;
lib/test.js:Test.prototype.proto = Runnable.prototype;

It looks like the transform below would change

Hook.prototype.__proto__ = Runnable.prototype;

into

function F(){};
F.prototype = Runnable.prototype;
Hook.prototype = new F;
Hook.prototype.constructor = Hook;

Is there any reason to not just apply this to the entire codebase and remove this rewrite rule?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Haha, no real effort involved, I just ported it from here:

https://github.com/mochajs/mocha/blob/master/support/compile.js#L59

But yeah, we should definitely fix it throughout. I just figured we could handle that as a separate issue and keep this PR's scope strictly to switching to Browserify, since it already runs the risk of breaking so many things

Choose a reason for hiding this comment

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

Completely forgot about that, thought you dug it up somewhere else ;) (heh, my name is even in the edit-list of said file.. oops).

Let's leave this for now :) although a future improvement would definitely be getting rid of these.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Copy link
Contributor

Choose a reason for hiding this comment

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

errr... yeah. we need to get rid of all of these hinky shims and use something well-supported. if we're targeting environments that don't support Object.create() then we should just do something like use lodash.create

@ndhoule
Copy link
Contributor Author

ndhoule commented Jun 7, 2015

Is there an established/easy way to do cross-browser testing against the built lib right now? I can just do some informal Sauce tests if not

@jbnicolai
Copy link

@ndhoule there's not. It might be about time to add some selenium based tests.

@boneskull
Copy link
Contributor

@jbnicolai go for it dude, you're on a roll 😉

@ndhoule
Copy link
Contributor Author

ndhoule commented Jun 7, 2015

Had a chance to do some IE < 9 browser testing; glad I did, exposed a few breakages. Fixed and rebased. I think this is about ready to merge.

Adding CI would be a good thing because it's easy to introduce an ES3-incompatible shim with Browserify. Started an issue over here: #1732

Going to punt on the reporter removal (#1731, feel free to close as a dupe/consolidate issues/etc.) just because I'm concerned it'll break mocha-phantomjs, thinking we should give them some heads up / provide a solution before we remove it. Make sense?

@nathanboktae
Copy link
Contributor

Yes removing the reporters will break mocha-phantomjs and mocha-casperjs - both use the compiled mocha.js and change the reporter as needed. I'll provide more details in #1731

@ndhoule
Copy link
Contributor Author

ndhoule commented Jun 18, 2015

Yeah, open a separate issue. This might solve it but they're not the same issue, so better to track them separately

FWIW you can probably just wrap Mocha and your built stuff in an IIFE and concat the files together.

@wejrowski
Copy link

Using browserify? How would the IIFE solve that? Not totally tracking.

And thanks. I will play with it some more and then open a ticket. Would love to solve this. I'm using Jasmine right now, which is great because it is just one file, but I'm having test issues with it.

@ndhoule
Copy link
Contributor Author

ndhoule commented Jun 18, 2015

@wejrowski basically something like:

// head.js
(function() {
// tail.js
}).call(this);

Then just glue these fragments, mocha, and your browserified bundle together:

cat head.js mocha.js browserified-stuff.js tail.js > build.js

Or something. You'll probably have to play with it a bit to get it working right.

I'm using Jasmine right now, which is great because it is just one file

Isn't mocha just one file too, though? Not totally following

@jbnicolai
Copy link

@ndhoule apologies for the delay, I'm finally back home and ready to put some time in mocha again ;)

It seems the (fantastic!) #1750 has now been merged. Could you rebase this PR to reflect those changes?

@jbnicolai
Copy link

@wejendorp the built mocha file is just single dependency-free file.. please open a separate issue if you'd like to discuss this further.

@ndhoule ndhoule force-pushed the chore/browserify branch 3 times, most recently from 2d24882 to d3b0305 Compare July 5, 2015 01:28
@ndhoule
Copy link
Contributor Author

ndhoule commented Jul 5, 2015

@jbnicolai Rebased.

@ndhoule
Copy link
Contributor Author

ndhoule commented Jul 5, 2015

Removed the __proto__ transform, since #1753 makes it unnecessary

@jbnicolai
Copy link

Ah, was just doing this locally as well. Thanks 👍

@jbnicolai
Copy link

Other than that I think it's good to merge :)

@jbnicolai
Copy link

Oh, could you squash that last commit?

@ndhoule
Copy link
Contributor Author

ndhoule commented Jul 5, 2015

Oh, could you squash that last commit?

Done

@jbnicolai jbnicolai closed this in 39ce95f Jul 5, 2015
@ndhoule
Copy link
Contributor Author

ndhoule commented Jul 5, 2015

Awesome, glad to see it go in 🚢 🚢 🚢

Thanks!

@ndhoule ndhoule deleted the chore/browserify branch July 5, 2015 17:26
@boneskull
Copy link
Contributor

@ndhoule @jbnicolai awesome! thanks much!

@jbnicolai
Copy link

All credits go to @ndhoule, thanks for the (major!) effort, and we'll be sure to mention it in the release notes :)

Great step towards making mocha a more modern and maintainable project!

@boneskull
Copy link
Contributor

@jbnicolai until someone makes a PR building mocha with jspm...

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

Successfully merging this pull request may close these issues.

6 participants