Setting up a CanJS project with the generator-canjs and Yeoman
In this blog post I'll show you how to setup a CanJS project with the help of the generator-canjs and Yeoman. I'll also show you some tricks I'm using to get everything working smoothly both in the development and production modes. We'll be setting up the project to use the Bootstrap and FontAwesome for the styles and icons.
Yeoman, Bower and Grunt
We will be using Yeoman, Bower and Grunt for various tasks in our development, so if you don't have them installed, do it now.
They are all implemented on the Node.JS platform so you'll need to install it first. After you've installed the Node.JS run:
$ npm install -g yo bower grunt
We also need the CanJS generator for Yeoman which can be installed by running:
$ npm install -g generator-canjs
With these dependencies installed, we can scaffold the app structure.
Scaffolding the app
To scaffold the app create the directory, enter it and run the generator:
$ mkdir canjs-app && cd canjs-app
$ yo canjs
####
######### ########### #### ####### ######
########### ############# ############### ####
############ ############# ###############
###### ###### ##### ###### #### #######
##### ##### ##### ##### #### #########
##### ############ ##### ##### #### ####
##### ############## ##### ##### #### ####
##### ##### ###### ##### ##### #### #####
###### ##### ##### ##### ##### #### #####
########## ######### ##### ##### ##### #### ####
########## ######## ##### ##### ##### #### ####
####### ##### #### ##### #### #### ########
###### ######
#####
[?] What is the name of your application? canjs-app
[?] Would you like to include RequireJS (for AMD support)? Y/n Y
This generator will set up the basic structure, and we can start pulling in the dependencies.
Dependencies
Dependencies are managed with Bower, and we can immediately install the stuff we already know we'll need:
- Bootstrap - for the grid and the basic styles
- FontAwesome - for the icons
Run the following to install them:
$ bower install -S bootstrap fontawesome
When you ran the app generator the style
folder was created. Usually I use the style/style.less
as the starting point for my CSS styles.
First, let's set up Bootstrap and FontAwesome. Create the variables.less
file in the style
folder and copy the contents from the bower_components/bootstrap/less/variables.less
in to that file.
Copy contents from the bower_components/bootstrap/less/bootstrap.less
to style/style.less
and adjust the paths for all the files except the variables.less
file (we're loading that one from the style
folder).
Your style/style.less
file should look something like this:
// Core variables and mixins
@import "variables.less";
@import "../bower_components/bootstrap/less/mixins.less";
// Reset
@import "../bower_components/bootstrap/less/normalize.less";
@import "../bower_components/bootstrap/less/print.less";
// Core CSS
@import "../bower_components/bootstrap/less/scaffolding.less";
...
@import "../bower_components/bootstrap/less/responsive-utilities.less";
Bootstraping Bootstrap (yeah, I know :)) from the style/style.less
file allows us to make changes to the styles in the isolation from the original Bootstrap code. This makes future upgrades of the Bootstrap library painless and simple.
We'll immediately do a change and include the FontAwesome instead of the original Bootstrap's icons.
Open style/variables.less
file and remove the lines 71 - 80 (@icon-font
related variables):
Remove these lines:
//-- Iconography
//
//## Specify custom locations of the include Glyphicons icon font. Useful for those including Bootstrap via Bower.
@icon-font-path: "../fonts/";
@icon-font-name: "glyphicons-halflings-regular";
@icon-font-svg-id: "glyphicons_halflingsregular";
Now copy the contents from the bower_components/fontawesome/less/variables.less
to the bottom of the style/variables.less
file and adjust the @fa-font-path
variable:
@fa-font-path: "../bower_components/fontawesome/fonts";
We also need to load the FontAwesome library from the style/style.less
file. Remove the line that loads the Glyphicons:
@import "../bower_components/bootstrap/less/glyphicons.less";
And copy contents from the ../bower_components/fontawesome/less/font-awesome.less
to the bottom of that file:
/*!
* Font Awesome 4.1.0 by @davegandy - http://fontawesome.io - @fontawesome
* License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License)
*/
@import "variables.less";
@import "mixins.less";
@import "path.less";
...
@import "icons.less";
Remove the @import "variables.less";
line (since we're already loading this file on the top of the style/style.less
file) and adjust the paths:
/*!
* Font Awesome 4.1.0 by @davegandy - http://fontawesome.io - @fontawesome
* License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License)
*/
@import "../bower_components/fontawesome/less/mixins.less";
@import "../bower_components/fontawesome/less/path.less";
@import "../bower_components/fontawesome/less/core.less";
...
Our base styles are now ready, and we have the complete control over them. Loading the Bootstrap and the FontAwesome .less
files from the style/style.less
file allows us to do easy customizations while keeping the original code intact.
HTML files
App generator created two .html
files in the project root. The canjs-app.html
file and the production.html
file. canjs-app.html
file will be used for the development, as it loads the dev versions of all scripts, while the production.html
loads only the built file.
Let's modify the canjs-app.html
file and load the CSS. Add this line to your <head>
section:
<link rel="stylesheet" href="style/style.css">
Now run $ grunt watch
in one terminal window and $ grunt connect:server
in another one. If you see the following image when you go to localhost:9001/canjs-app.html
everything is set up correctly:
Components
We set up the base app structure, and now is the time to add support for the components. When developing CanJS apps, it is a good practice to develop each component in the complete isolation from the rest of the app. All of it's styles, templates and assets should be contained in one folder, ready for reusing. There is a problem with supporting the image and font paths in the CSS.
We want our CSS to work the same in three different contexts:
- Component development mode (loaded from:
localhost://9001/components/some_component/some_component.html
) - App development mode (loaded from:
localhost://9001/components/app.html
) - App production mode (loaded from:
localhost://9001/components/production.html
)
App development and production mode are pretty much the same, but we have an issue with the component development mode since it will load the CSS from the different location. Thankfully, LESS compiler can rewrite urls in the build step, so we can get the correct urls in the built CSS.
To take advantage of this, I recommend you to use the following technique:
- Create
style/components.less
file and@import
each component's LESS file from there - Import
style/components.less
file from thestyle/style.less
file - Load the built 'style/style.css' file from the component's demo page (eg.
components/users/users.html
) as it will have the correct paths
Let's try it out! Run the following to generate the component:
$ yo canjs:component components/users
[?] Please enter the path to the component eg.: components/users: components/users
create components/users/users.js
create components/users/users.html
create components/users/users.less
create components/users/users.mustache
identical components/users/users.less
Add the following line to style/components.less
file:
@import "../components/users/users.less";
and make sure you're importing the style/components.less
from the style/style.less
file:
@import "variables.less";
...
@import "components.less";
And let's edit the components/users/users.less
file just to check that everything is loading correctly:
users {
display: block;
color: red;
font-size: 100px;
}
Note that we're wrapping the styles with the name of the component tag. This ensures isolation of the component styles from the more general styles located in the style
folder
If you see the following when you load http://localhost:9001/components/users/users.html
everything is set up correctly:
If your changes are not visible, try to restart the grunt watch
process, so it picks up the new files to watch
You can find the code for this example in the GitHub repo, and make sure that if you have any questions, you either comment below or send me an email!