Skip to content

Latest commit

 

History

History
313 lines (201 loc) · 9.45 KB

README.md

File metadata and controls

313 lines (201 loc) · 9.45 KB

{{name}}

{{description}}

Application Stack

This environment is intended to be used in a modular way. Everything is a Component and should work and be testable independently.

Generated with the Grail Generator for Yeoman.

Tasking

Task management is done with Gulp, so your project is easily extendible. This stack already uses some Gulp Plugins:

Scripting

Codes are written mainly in CoffeeScript and bundled together with Browserify. Out of the box it comes with some transforms for Browserify:

Styling

Styles are written mainly in Stylus.

Watching

Watching for file changes is crucial if you pre-compile the Scripts and Styles. For the Script re-bundle Watchify is in charge.

Since the Styles are not in the JS bundle, Chokidar is used to watch and rebuild them. gulp.watch isn't used here, since it does not pick up newly created files.

For the rest of the files (HTML, Images) it uses gulp.watch.

Serving

The generated and bundled files will be served with BrowserSync. That means the Application is automatically reloaded if Scripts or Styles are changing.

Testing

Component tests written in CoffeeScript, bundled by Browserify and run by Mocha.

Gulp Tasks

Source of all tasks is ./client and destination is ./public.

gulp html

Copies the HTML Entry Point.

gulp fonts

Copies fonts. This tasks copies the fonts of Font Awesome included by Semantic-UI by default, but note that you need to run yo grail:extend, so the files are available.

gulp stylus

Bundles the Style Entry Point with Stylus. Also prefix CSS3 properties with Autoprefixer.

gulp images

Copies all images.

gulp browserify

Bundles the Script Entry Point with Browserify. It executes several transforms:

  • coffeeify - transforms the CoffeeScript to JavaScript
  • html2js - transforms the HTML templates to JavaScript strings
  • debowerify - require() modules installed by Bower
  • deamdify - require() modules that are wrapped by AMD

gulp browserify-watch

Watches files in the source directory and re-bundles the Script Entry Point.

gulp watch

  • Run browserify-watch
  • Run stylus whenever a ./client/**/*.styl changes
  • Run images whenever a file in ./client/images/* changes
  • Run html whenever a ./client/*.html changes

gulp server

Starts a BrowserSync web server. Also starts the watch task. Whenever a file in the source directory changes, the Script or Style Entry Point is re-bundled and the browser reloaded. Styles are directly injected in the page without a reload.

gulp test

Bundles the Application Components and Tests together and run them in Mocha.

gulp test-watch

Whenever a Application or Test file changes re-run the test Task.

gulp build

Run browserify, stylus, images and html. gulp without a task name will also run this task.

gulp production

Run this task if you want to release the Application for the audience. Note that you need to run gulp build before!

  • Run browserify and minify JS with Uglify
  • Run stylus and minify CSS with CSSO
  • Run images and minify them with Imagemin

gulp bump

Bumps up the version number in package.json.

Application Structure

This is a one page application. It has three different entry points.

HTML entry point - ./client/index.html

This is your typical index.html page which is loaded first. It has references to the Script and Stylesheet entry points.

Markup that is initially loaded (the Layout), is stored here.

Script entry point - ./client/index.coffee

Here you initialize components. Since the Script Bundle is packed with Browserify you can simply require() the components you want to use:

Post = require('./components/post')
post = new Post

It is recommended to require() third party dependencies in the components rather than having globals. But if you install the libraries with Bower, the respective global will be defined without declaring it:

require('jQuery') # $ is globally defined

However, if you declare it this way your tests may brake because they are run in Node.js by default (todo: run them in PhantomJS).

Stylesheet entry point - ./client/index.styl

Here you initialize stylesheets, third party stylesheets and variables. Stylus will take care of the bundling, so all you need is @import.

For third party styles, include a .css file in a relative path:

@import '../bower_components/normalize-css/normalize.css'

To import a module style:

@import './components/post/style'

Note that you don't need to include every single Component style since by default every style.styl from the ./client/components is imported.

If you define variables, you can use them in your imported components:

backgroundColor = #eee

And in ./client/components/post/style.styl:

@import './colors'
body
  background: backgroundColor

Component Structure

A component can have three different things: A Script, a Template, and a Style. All three are optional, since it's in your hands how you initialize each part of a component.

Naming Convention

Again, you can name them like you want, really. I recommend this structure:

./client/components/[component-name]
  /index.coffee
  /template.html
  /style.styl

Why this naming? You can leave out the file extension when require()ing them (which would not possible if every component-part has the same name):

post     = require('../post')    # respectively index.coffee
template = require('./template') # respectively template.html

With the component-name as identifier, and index.coffee as Script entry point, you describe with the filename which part of the component you want to require(): post (respectively index.coffee), post/template and post/style.

A disadvantage of this method is that it might not be clear if you are editing multiple components in your editor. But you should work on one component at a time anyway.

Testing a Component

You can and should test your Components. Just like the Application Script Entry Point, the Tests have a Entry Point too in ./test/client/index.coffee. There you require() the components and tests:

postTest = require('./components/post')

Then just create the component test a file named like the component: ./test/client/components/post.coffee:

should = require('should')
Post   = require('../../../client/components/post')
post   = new Post

describe 'Post Component', ->
  it 'should have the correct template', ->
    post.template.should.equal 'testing'

To bundle the Application and Tests, and run it in Mocha:

gulp test

To automatically re-run the test task whenever Application or Test files change, run:

gulp test-watch

Workflow

Using third party Scripts

Third party libraries can be either installed with NPM or Bower. In the end, you just need to require() the library.

NPM

npm install moment --save

Bower

bower install zepto --save

Then you can require the libraries wherever you want (usually in the Component):

$      = require('zepto')
moment = require('moment')

Manually

In the rare case you can't install a library from NPM or Bower, you also can require() the .js from everywhere:

lib = require('../path/to/lib.js')

Using third party Styles

Install it via Bower:

bower install foundation --save

And @import it in ./client/index.styl:

@import '../bower_components/foundation/css/foundation.css'