 the Toby to build some of our projects. One of our biggest projects is CanGS. I should have preloaded this. Wi-Fi's really fast right now. Awesome. This is one of our biggest projects. It's an open source project to help you build your applications. We gave a small talk about it yesterday. If you're interested about this, feel free to grab me and pull me aside after this session. We can talk about this ad nauseam. But when you're building a large open source project, it gets tricky to maintain it. You have different contributors spread out all over the world, volunteer contributors, et cetera. So you want to automate a few things. I'm going to talk about Grunt and how we use it at Potobi. So a Potobi case study is probably a poor title. We're not actually going to do any analytics behind how we use Grunt. We're just going to deep dive into what the code actually looks like and how we run it at Potobi. So for those that are not familiar with Grunt really quick, this is the awesome logo. Grunt is a project originally written by Ben Allman, still maintained at Boku. Ben Allman's an employee at Boku. To automate tasks, I need to do these things all the time to achieve some results in my project. I need to run the tests. I need to make a distributable. Grunt is one of the projects that helps us achieve this. If you're familiar with, yeah. What's a task runner? Familiar with Ant, Make, Rake, Sake, Maven, Gulp, Jake, Bake. I mean, I could keep going on and on and on with all the different build systems there are. But Grunt is pretty nice. It's specific to or caters to JavaScript engineers at the time when we were putting together our open source projects. It was very, very prominent. A few of the other new ones hadn't been invented yet. We picked up Grunt. We liked how it worked. So that's the reason we're using it. If you're here for yesterday's talk, I'm gonna echo that same sentiment. Don't go back to your companies or your teams and say we need to rebuild everything with Grunt. Don't use it because I'm even telling you to use it. I'm gonna say I'm a fan and I think it's a good idea. But educate yourself about the tools and what options you have and then make the choice based on your education, not on me saying pretty words. So what does a task runner even do for us? Why is this even important? Well, with CanGS, it's very, very complex. So CanGS is an MV architecture framework that helps you build rich applications, rich experiences. But because we want to provide that tool to as many people as possible, we make many different, oh, is it loose? Technical difficulties. Because we wanna give that experience over that tool set to as many developers as possible. We have to make many different distributed packages. So if you're familiar with using things in an AMD format, maybe you're using a required JS. You wanna have things that are defined modules. Maybe you just wanna download a script from a website and drop it in your HTML page. Maybe if you're using a different kind of loader, if you're using something that can parse ES6 or if you're using something like Steel or Browserify, you're gonna want a common JS or different syntax packages for whatever your application provides. We write CanGS with Steel, so now we're starting to write things in ES6. That doesn't mean you have to use ES6. It's our job to build an AMD version and a common JS version, et cetera, et cetera, et cetera. This also means we have to test every single one of those versions to make sure we're exporting things in the right way. So when we write a test, it's not just used once, it's used n number of times over n number of browsers, over or m number of browsers, over o number of operating systems, whatever we wanna deliver on. So maintaining an open source project like CanGS or jQuery requires a little bit more than just don't forget to run the tests. So this starts to get really, really verbose. If we're starting to manipulate all of these tests, let me walk you through what CanGS is actually doing from a build perspective. Running the CanGS tests, this is just running the tests, requires us to say, hey, we're gonna make sure we JS-hint this code base to make sure everybody's following the same style guidelines and code, I don't know what the word there is, to make sure we're all coding in the same fashion. We don't want one code file with a bunch of spaces halfway and a bunch of tabs the other way, people forgetting semicolons or intentionally leaving certain stylistic code implementations out because that makes that code file much, much harder to maintain if I'm looking at something and it looks like an unformatted mess. I don't even wanna read it. So the first thing we do is, hey, make sure we're on the same page in terms of style issues and make sure you're not necessarily throwing out any globals or at all, anything like that. Then we're actually going to build CanGS. I'm gonna get into what that entails because that's actually a very broad word when you build a project. We're going to generate our tests. I'm gonna show you what that means. We actually write one set of tests, but we have to write many different tests or test formats that do the same thing for different formats that we distribute. And then at the end of all this, we need to actually run the tests. Now, many of you may have had projects or you have projects today or one of the main steps before you commit your code or right after you commit your code sometimes is don't forget to run the tests. Hopefully you have some kind of CI, continuous integration server that is running the tests automatically for you. So even if you forget, it'll do it for you. But if you're doing something like this or if you've contributed to jQuery and you've said, hey, I need to run the tests, any time you contribute to jQuery, you're gonna wanna run the tests in their matrix of support, which is more than just whatever browser you happen to be developing at that given time. So these are the kind of, this is the main like overview of what can JS is doing internally in a build perspective. Running JS Hint is as simple as doing this from the command line. This isn't necessarily difficult and you can use different conventions to pattern match a bunch of different files or a directory, but it's something I have to remember to do now. Oh, this is one more thing on that giant list of things that we're gonna go through that I have to remember what to do. And maybe if I'm on a rush, I'm under a deadline, I forget to do this once. And this is just slowly adding to our tech debt within a big project. The build, which was just one bullet, is actually a multitude of steps. The first thing we need to do in a build is wipe out the current disk directory. Pretty simple concept. And then we wanna generate all the necessary formats. We code in a specific format. Right now we're moving towards ES6, but we don't wanna require our users. If you just wanna say canJS in a script tag on an HTML page, you should have the freedom to do that. It's our job to generate all these different formats for you. So right now if you download canJS from like NPM or Bower, you're gonna see many different folders depending on which format you wanna use. So we wanna give you all that kind of in a neat little package. You wanna do common steps for us. We're gonna string replace our virgin numbers and we're gonna make sure we have all the necessary banner and license information stamped at the top of the page. And this is gonna need to be dynamic. We need to do this every single time we do a release. But again if I'm under a deadline, I need to get the next version out and it's due tomorrow, maybe I forget to add the banner. And I fixed the bug I was working on, but I try to push it out. Everything works, it pushes out to NPM but I forgot to change the version number and now you can't use that latest version because I screwed up the version number. So you wanna automate as much of this as possible. Generating and running tests. Like I said, if you have an initial suite of tests that's cool, it's gonna load the original source files and walk through them, make sure everything's passing the way it needs to. But it's not gonna go out into the disk folder and run those tests and make sure they're doing what they need to. So we actually have a script that goes through our original tests and generates new test files, new test pages that says, hey, run this set of tests against the AMD distributable. Run this set of tests against our global distributable and make sure we haven't messed something up. Something works in our ES6, but the compiled version or the transpiled version down to ES5 doesn't work in a global setting because we forgot this particular thing. And then on top of just generating them, we need to run this. This can be done with a weapon of choice. We're using QUnits, we're big fans of the jQuery stack. So the examples you're about to see are all with QUnits. Ideally, all these steps are gonna be in some kind of script. You can just have a shell script that does all of this. There's nothing wrong with that. Shell scripts typically become harder and harder to maintain. Maybe you're using different shells. How many people, I see a lot of people in here using Macs, I see a lot of people here are using Windows machines as well. Already off the bats, you could have a different shell. You could be in a Unix system, like a Mac, and have a preference. By Mac, by default, I think you're gonna have a bash script. A lot of people like the ZSH shell, whatever shell you happen to be on, you could have different scripts needing to be managed to run all of these steps. So you want some kind of abstraction in front of this, some kind of build system that says, hey, this is gonna be a universal way to do steps A, B, and C in your project. Make sense? Cool? All right. Automation is a big thing, because this is something I will never remember to do. This is a quick peek. This is the actual canned.js grunt file. This is part of it, and if I scroll down, you get to see all of it. Okay. Don't worry about everything that's in there. The point of this is just to say that we're doing a lot. More than I will remember to do on every single commit. At the end of this, even running this build file, if I said grunt test, it's gonna run a bunch of different things here. That's gonna take a significant amount of time to build every distributable, to test every distributable. Maybe that's not something I wanted to do individually on my machine. Maybe I'm lazy, maybe I wanna skirt the process, because we're on a deadline. Whatever the reason may be, this is the automation part of that. If you wanna have this automated in some fashion, if you have some kind of continuous integration setup, this is where that comes into play. So with canned.js, every time I make a commit, even if I don't run the tests at all, if I push out to the GitHub repository, we have a CI server. We're using Travis CI. I'll show you that in a moment. Which is free, by the way, for open source projects. And it has a hook to say, every time somebody makes a commit to this repository, I'm gonna run this specified tasks list. So no matter what anybody does, maybe you're making a pull request, maybe I'm making a small simple fix, it's gonna run through, build canned.js up from the ground up, run all of its tests, run all of the JS hints, run every little criteria we need to guarantee this is as clean as possible. And then it'll show us a green light in GitHub saying, hey, you're good, all tests have passed. We see that green light before we even do the code review. That's just step one of getting code into this project. When you have an open source project, or especially something like jQuery, where it's used by many, many different companies around the world, many different projects, there's a lot of care and feeding that go into every single code change. Because something that may be a bug fix to you could be overlooked and cause issues with somebody else's project. So you're gonna have as much of this taken care of as possible, because we're human and we're gonna miss things. This is Travis CI, this is a glimpse. Let me bring up actual Travis here. So this is Travis CI, this is a build yesterday. It says five hours ago, but it's actually longer because I haven't refreshed this page. But this is one of our core contributors, Matt. Let me bring this up. All right, that's a good view. He contributed something, this is commit. Since we've had Travis, this is commit number 4,398. We break it into three segments because this is a pretty big process. We run three different build steps in parallel with Travis. And this was, I think this was a very simple commit. He just had a merge into a minor branch. This is a really small operation that he did, all the tests passed, because it looks like somebody's pull request got approved. And if you go through, Travis is from scratch going to install all the dependencies this project needs and it's gonna start triggering all these tests one by one. You can see down here, we have grunt test. That's one of the first things that kicks off. NPM test is actually the first thing. We were just specifying grunt test in our package.json. If you're familiar with NPM modules, it's basically just a shortcut to what scripts we wanna run. So I'm gonna say grunt test for canned.js, which is gonna kick off a number of different things. We're gonna JS hint our code base. We're gonna say, oh look, almost 200 files are everything we wanted to check looks good. Then it's gonna start running, hey, clean the test directories, clean the build directories, generate some tests. This is gonna generate all the tests we need. And we have a lot of files being created here. Scroll through all those. All the way down to the tests that have been generated, let's build canned.js. Again, we build in many different flavors, many different formats over many different underlying libraries. What canned.js really tries to do at its core is provide you with the tools you need to build your applications, but we don't wanna break you out of your normal pattern, your normal flow. So if you're a jQuery power user, that's awesome. Most of us at Vitovi are, so we love to use canned.js with jQuery. So if I'm using like a canned.hx request or canned.deferred, that's actually just an alias for jQuery is deferred and jQuery is hxrequest. If you're using dojo, canned.hx will make a dojo request or return a dojo deferred. We support Zepto, YUI, Mootools, jQuery and dojo. So we don't wanna break you out of whatever you're normally used to seeing from some of these methods. You can still have the architecture, but you get to keep some of what you're used to. Obviously, we're gonna drop support for YUI eventually because that project is no longer maintained. But one of our big things is also backwards compatibility. So we're probably gonna keep it around for longer than you might think. So because of this, we have to make sure, does one particular method in canned.js work in YUI? Does that same method work in jQuery? Sometimes it does, sometimes it doesn't, and that's up to us to make sure the source code runs off jQuery. That's typically what we develop in day to day, but we wanna make sure the distributables still are maintained in these other platforms, in these other frameworks. So this is automating all of those tests for us. There's the Mootools, there's the YUI tests, or the AMD tests. You can see a lot of this just running the same tests over and over in different formats. There's the generators for the AMD version of canned.js, the global versions of canned.js, the common.js versions of canned.js, and the steel versions of canned.js. So we try to give you as many flavors as possible. This is generating the test files for each flavor. We support jQuery one and jQuery two. We have to test two different times to make sure everything is working as expected in different browsers. And then finally, we get to run the tests. This is the simple core build, this is a simple merge, so this is only running the core tests. Each one of these little dots is an assertion. We have a little over, well, almost 4,500 tests just for the core. Again, this is broken up into three different build steps. This is one of the smaller ones. We test a lot. Sometimes this goes by the wayside in major corporate projects. Testing is kind of like, documentation is definitely by the wayside. Testing is like if we have time, but if you have an open source framework, this is one of the most important things because I don't have a tested framework. If I don't have a documented framework, how many of you would use it? Probably nobody, even if it's free, even if it's the best thing since sliced doses. I don't know. There's a sliced bread thing in there, I don't know. So, rather than show you, like let's break down the entire KANJS grunt file because that's ridiculously large, I'm gonna show you a very simple grunt file that I made on the fly. Here, so here we have a very simple application. Let me just open up this application. Oh, that's the slides, close to A2. There we go. There's our awesome application. It's gonna have an input which takes a name, I'm gonna say Chris Borchers, and it's gonna break up the name on whitespace into two different strings. This is the most complicated app ever. I'll give you guys a source code to this, but feel free to sell it at your heart's delight. But the point is, this is some kind of application that you've built and now you wanna automate some process. Maybe you've written some tests for this. Maybe you have some kind of build step where you wanna turn this into a minified file. You wanna JS hint this. For purposes of this, because I just wanted to show you what grunt can do, I have two steps. I have a JS hint and a test step. JS hint is gonna go through. It's gonna say, hey, give me your grunt file and give me all the JS files. I'm using a wild card match online for, and I'm just saying, hey, all the JS files need to adhere to certain standards in JS hint. I think the only thing I'm changing is, it's okay to expect jQuery to be declared as a global, and I'm using ES6, so I'm saying the ESNext flag should be true. Otherwise it's gonna spit out a bunch of warnings like import is not available. My test step, this is totally weapon of choice. You can use whatever you want. I'm using something called testy because it's able to launch browsers. It's pretty awesome if you test things in phantom.js, how many of you deliver production projects in phantom.js? One person? That's probably true, yeah. If you have a generator, that's true. Typically we don't, right? If you're building a node tool that runs in phantom behind the scenes, then you do deliver things in phantom, but if you're building a web application, if a test passes in phantom, does that mean it works in Chrome? No, it just means it passes in phantom. That's all it means. So for us, we use testy to make sure this actually works in a browser. You get a bunch of different options. Feel free to use whatever test runner you like. For purposes of this example, I'm gonna do this. So for our test, for our setup here, I just have a simple set of key unit tests. And this is running through some objects, some module. In my case, I'm testing the view model for this application, which was really complex as you saw. And I'm just gonna make sure the getters and setters work for whatever I was doing. I was probably saying, hey, getter, return the first name plus a whitespace equal and the last name, that'll give you the input. And for the setter, maybe split on the whitespace and set the first name to the first part and the last name to the second part. So this is cool, but I'm lazy and I do not wanna open up this webpage every time I make a bug fix. So I'm gonna have this automated. First thing you can do is just run this manually from the command line. And then once you get that far, you can run it from CI, which is nice. I'm gonna run grunt. What this is gonna do is it's gonna look for the default task in my grunt file and run, let me scoot this over, run all the tasks sequentially in this array. So when I say grunt, it's gonna say, well, you wanna run js-hint on this library and then you wanna run testy after it. So I'll get you guys here in a second. If I run grunt here, it's gonna fire up js-lint, it's gonna open up Firefox, run the tests, close Firefox, I'm gonna tab back, it doesn't tab back for you, unfortunately, and show our error output. This is how I can assert that, hey, this test runs in Firefox, we're good to go. I'm gonna switch over my task here to canary. Do the same thing, it's gonna run js-hint, open up canary, run the tests, blink out, go back, see our reports, we're good. This is really why we use testy, so we can do stuff like this on test both of them. Testy is very alpha, use it at your own peril, it's like version zero, two, but I like it. You run an array, it's gonna open up two browsers, there's Firefox, there's Chrome, both went away, and we got everything, there's six assertions passing, we see queunits on Firefox, three tests pass, queunits on Chrome, that version, three tests pass. Yes, question. Default reports us, this is up to the task. So I'm not actually here to talk about testy. Yeah, do you want something like x-unit? All right, I think I got like 30 seconds left. x-unit, I'm not sure if I can do this by default if it's gonna give me a file. I think I might just put the output in the console here, let's see what happens. Yeah, there it is, there's an x-unit file. So you could pipe it, you could take that file and then pipe it to something else. That's a feature of testy, feel free, I feel like most of the runners can do stuff like this, especially when you're using Jenkins, you wanna consume a file like this, that's totally cool. But in a nutshell, this is why we use grunt. There's a lot of things going on and I don't want to remember how to do those things all the time, so be sure to use a task runner. Don't use grunt, because I told you to, don't think this is cool, whatever. Educate yourself about the tools. We used rake until grunt came out for a long, long time, grunt made more sense, we're using that today, we have no real reason to switch off of it, but educate yourself about the different tools out there and make your own educated decision. Yeah, it's up to you. It's up to you, I know you want me to tell you, but I can't. For us, it made sense, Gulp wasn't invented when we wrote CanJS, actually grunt wasn't in existence yet either. We chose grunt because it made sense and we have no real reason to switch off of it. Don't rewrite something just for the sake of having something in a different framework. It's just a tool, everything we use, these are just commodities. Educate yourself about the foundations of what the language and what your application's requirements are and then make your own decision from there. Cool, that's all I got, I gotta get out of here. There's like, the queue is backing up at this point with speakers, I assume. So, thank you very much, and...