Structuring a Web App with Spine JS and AMD
This repository walks through the process of setting up a web app using Yeoman, Spine, CoffeeScript, and Require JS for Asynchronous Module Definition (AMD), and it provides sample code that should be usable for another project.
Set Up Yeoman
Yeoman is a command line tool that speeds up front-end web app development. First, let's open the terminal and install yeoman, then create a directory for your project and initialize a new yeoman project. I'll refer to your project directory as ~ from now on in file paths.
$ yeoman init
Then, you'll see:
Running "init:yeoman" (init) task This task will create one or more files in the current directory, based on the environment and the answers to a few questions. Note that answering "?" to any question will show question-specific help and answering "none" to most questions will leave its value blank. "yeoman" template notes: invoke app _-----_ | | |--(o)--| .--------------------------. `---------´ | Welcome to Yeoman, | ( _´U`_ ) | ladies and gentlemen! | /___A___\ '__________________________' | ~ | __'.___.'__ ´ ` |° ´ Y ` Out of the box I include HTML5 Boilerplate, jQuery and Modernizr. Please answer the following: [?] Would you like to include Twitter Bootstrap for Compass instead of CSS? (Y/n) Y [?] Would you like to include the Twitter Bootstrap JS plugins? (Y/n) Y [?] Would you like to include RequireJS (for AMD support)? (Y/n) Y [?] Would you like to support writing ECMAScript 6 modules? (Y/n) n [?] Do you need to make any changes to the above before continuing? (y/N) N
Make sure to include RequireJS. I also highly recommend including Twitter Bootstrap for Compass instead of CSS. Now use yeoman to install Spine:
$ yeoman install spine
Running "bower:install:spine" (bower) task GET https://bower.herokuapp.com/packages/spine bower cloning git://github.com/maccman/spine.git bower cached git://github.com/maccman/spine.git bower fetching spine bower checking out spine#v1.0.8 bower copying /Users/vailgold/.bower/spine/4fa4cf26fbbf541d61628bb868c135ec bower installing spine#1.0.8 Done, without errors.
Now run the app and make sure you see Yeoman's confirmation page:
$ yeoman server
~/app/components/spine/src and run the following command to build the .coffee files into one, which will give you the Spine build for your test server.
$ cat spine.coffee list.coffee manager.coffee route.coffee relation.coffee ajax.coffee local.coffee > spine-build.coffee
If you included Twitter Bootstrap JS plugins with yeoman, then you'll see the following block of HTML in
~/app/index.html. I prefer to just download one file from Twitter Bootstrap that contains what I want and include it using Require, so I usually remove this code.
<!-- build:js scripts/plugins.js --> <script src="scripts/vendor/bootstrap/bootstrap-affix.js"></script> <script src="scripts/vendor/bootstrap/bootstrap-alert.js"></script> <script src="scripts/vendor/bootstrap/bootstrap-dropdown.js"></script> <script src="scripts/vendor/bootstrap/bootstrap-tooltip.js"></script> <script src="scripts/vendor/bootstrap/bootstrap-modal.js"></script> <script src="scripts/vendor/bootstrap/bootstrap-transition.js"></script> <script src="scripts/vendor/bootstrap/bootstrap-button.js"></script> <script src="scripts/vendor/bootstrap/bootstrap-popover.js"></script> <script src="scripts/vendor/bootstrap/bootstrap-typeahead.js"></script> <script src="scripts/vendor/bootstrap/bootstrap-carousel.js"></script> <script src="scripts/vendor/bootstrap/bootstrap-scrollspy.js"></script> <script src="scripts/vendor/bootstrap/bootstrap-collapse.js"></script> <script src="scripts/vendor/bootstrap/bootstrap-tab.js"></script> <!-- endbuild -->
The good thing about the code above is that it demonstrates how to use Yeoman's build process to concatenate and minify a script. However, that only occurs when calling
yeoman build, so it may not be helpful while building the application. Here is what that method would look like for Spine. Make sure to have spine.js at the top of the list, and then the order of the rest doesn't matter.
<!-- build:js scripts/vendor/spine-build.js --> <script src="components/spine/lib/spine.js"></script> <script src="components/spine/lib/manager.js"></script> <script src="components/spine/lib/list.js"></script> <script src="components/spine/lib/relation.js"></script> <script src="components/spine/lib/route.js"></script> <script src="components/spine/lib/ajax.js"></script> <script src="components/spine/lib/local.js"></script> <!-- endbuild -->
Configure Font Awesome in Compass
I downloaded Font Awesome as a zip archive (I'll refer to this zip archive as ~FA), and I copied the contents of the
~/app/styles/compass_twitter_bootstrap/_font-awesome.scss is an old version of Font Awesome, so follow these steps:
- Find the last line of
- Copy the rest of
~/Gruntfile.js, add a reference to the fonts directory:
~/app/styles/main.scss, change to import statement at the top of the file to:
~/app/index.html, I generally like to have just one div with an ID unique for my application into which I insert the structure of the DOM that I need.
I also put some sample localStorage data here to help with local development.
Prepare Third Party Libraries
I added jQuery, Underscore, jQueryUI, Bootstrap, ES5 Shim, Moment, Spin, and a jQuery plugin for file uploads to
~/app/scripts/vendor. I also added text.js to
~/app/scripts, which will let us import files as text using Require, useful for templating.
Set Up Application
We're using CoffeeScript, so I converted main.js and app.js to main.coffee and app.coffee. One note of caution is to be careful of any requirements that your libraries have. As an example, the jQuery fileupload plugin requires "jquery.ui.widget" in its own code out of the box, so I had to change that reference to "jquery-ui", which is the name I used in
~/app/scripts/main.coffee. Also, the RequireJS docs state that setting up paths and shims for a library does not actually load it, which is why
~/app/scripts/main.coffee loads those libraries explicitly.
Inside of the actual module, we instantiate the App when the document is ready and save it to the global namespace, and then start Spine's Stack (it controls the URL routing) after a master promise resolves, which we'll see in the application definition happens after all model fetching occurs.
Notice that we pass the
el parameter into the instantiation call to the App controller. When using Spine, for any controller that is connected to the DOM, you should always provide that element to the controller on instantiation. In general, you can achieve this goal by providing specific elements in each controller's template to pass to any controllers that will be connected to DOM elements within the parent controller's element. To see this in action. look at
~/app/scripts/views/structure.html. You can see elements specifically set aside to provide to the Navigation and Footer controllers. #app-body is the exception here, because it will be the direct parent of the navigation-level controllers.
Take note of
~/app/scripts/deployment.txt, which is a quick, albeit hacky, way to use HTML5's localStorage to run your app locally for development purposes without having to have an API up and running. In
~/app/scripts/models/account.coffee, the model either incorporates Spine's Local or Ajax extension based on the value of