This project is an application skeleton for an AngularJS web application. It is based on the experience we have building our first enterprise scale angular application at Kunstmaan. With this you can quickly bootstrap your angular application and dev environment.
This seed contains a small sample AngularJS application which shows you how we like to structure our code and how the code should interact.
- Feature based modules
- Environment specific configuration
- State based routing (AngularUI Router)
- Configurable routing (states.json in feature folders)
- Mixins
- Resolvers
- Unit (karma + mocha with sinon & chai) and e2e (protractor + cucumber & chai-as-promised) testing preconfigured
To get started you can simply clone this repository and install the necessary dependencies:
Clone the angular-seed repository using git:
git clone https://github.com/Kunstmaan/angular-super-seed
cd angular-super-seed
There are two kinds of dependencies you need for this project:
- tools which helps us manage and test the application, these dependencies can be managed using node package manager.
npm install
- AngularJS and other 3rd party libraries are managed via bower.
bower install
npm install
will also trigger bower install
after npm is finished installing.
When the dependencies are successfully installed you should find two extra folders in your project.
./node_modules
- contains the npm packages for the tools we need./app/bower_vendor
- contains the 3rd party libraries
We have configured a simple development web server in this project based on grunt-contrib-connect.
This is automatically started on port 9000 when running grunt
.
To easily start this web server with the standard development environment:
grunt
It will automatically open your browser and navigate to the right url.
app/
|- index.html --> the main template file.
|- .htaccess --> apache2 configuration file.
|- scss/ --> scss files.
|- img/ --> image files.
|- fonts/ --> font files.
|- config/ --> environment specific configuration.
| |- config.json --> global configuration used across all environments.
| |- config_dev.json --> configuration specific for development environment.
| | will override keys in default config.
| |- config_prod.json --> configuration specific for production environment.
| |- config_test.json --> configuration specific for test environment used in e2e.
|- js/ --> javascript files.
| |- app.js --> define app modules + dependencies.
| |- <my_feature> --> a custom feature folder.
| | |- config/ --> the configuration for this feature.
| | | |- config.json --> the configuration specific for this feature.
| | | └- states.json --> the configured states for this feature.
| | |- views/ --> the views for this feature.
| | | when looking for a template in a feature it'll look here.
| | |- controllers/ --> the controllers for this feature.
| | |- directives/ --> the directives for this feature.
| | |- services/ --> the services for this feature.
| | |- <my_feature>.js --> file containing config / run phases for your feature module (if any).
| | └- */ --> whatever you want! (filters, translations, ...)
| └- common/* --> feature folder to store common code.
| already contains utility services needed for the seed to work.
| common/config/config.js will be automatically generated by grunt config.
| don't modify config.js as it'll be overwritten.
grunt/ --> we've split out grunt config in multiple files for maintainability.
|- middleware/ --> convenient place to store middleware loaded by grunt-contrib-connect.
|- plugins/ --> some custom grunt tasks we created.
|- common.js --> grunt config for cleaning up builds.
|- frontend.js --> grunt config for scss, svg2png, imagemin, modernizr and watches for scss changes.
|- javascript.js --> grunt config related to build and linting + watches for javascript changes.
|- server.js --> grunt-contrib-connect + livereload config.
|- testing.js --> grunt config for karma, protractor + triggering tests on filechange.
└- templates.js --> grunt config related to creating template cache for testing and build.
test/
|- helpers/ --> contains helper functions for the unit tests. check 'Testing' part.
|- unit/ --> contains unit tests. check 'Testing' part.
└- e2e/ --> contains end2end tests. check 'Testing' part.
Gruntfile.js --> grunt configuration. actual grunt task definitions.
package.json --> npm configuration (tools).
bower.json --> bower configuration (3rd party libraries).
grunt
: spins up a development server and opens up the right url in your default browser.
- Watches all your files and executes live reload when necessary.
- Executes unit tests in phantomjs runner after altering javascript files (
brew install phantomjs
on OS X). - Executes jshint after altering javascript files and blocks running unit tests.
important: Unit tests won't run when there are jshint errors. This is because
we believe your tests will often fail when jshint detects an error. Your
code has to be correct before the tests are run. grunt test:default
will run your unit tests no matter the jshint status.
Files are served using grunt-contrib-connect. This allows you to inject custom middlewares which can be very useful. You could for example reverse-proxy your API endpoint as if it were on your local development machine. This allows you to work around CORS (Cross Origin Resource Sharing) issues in browsers that don't follow CORS policy headers like IE8.
grunt build
: builds the app ready for deploy in the ./dist
directory.
- Minifies and concatenates the javascript and css files.
- Creates a template cache.
- Generates the config app, you can specify the environment using
APP_ENV={env}
for example:APP_ENV=prod grunt build
will build the application using the production configuration. - Prefers minified dependencies if they are stored next to the original dependencies. Will take
jquery-2.0.min.js
overjquery-2.0.js
. - File revisioning.
Testing is important in any application. The seed comes packed with karma and protractor pre-configured with sane defaults. We include things like mocha with chai and sinon. We chose mocha because it's more flexible than Jasmine and we were able to choose our own assertion libraries, etc. Chai is a better matcher library that allows you to write cleaner expectations. Sinon allows you to mock, stub and spy to your hearts content.
grunt test:default
: runs all your unit tests using karma in a single run in a chrome browser.
npm test
is an alias for this.
- Configuration for unit tests can be found under
./test/karma-unit.conf.js
. - Unit tests themselves are created under
./test/unit/<feature>/**/*
and follow the same structure as your feature folders. If your original file is located under controllers it should be located under the same controllers folder in the test feature folder.
The unit tests all some contain handy helper functions in the ./test/helpers
folder. When testing directives using app.helpers.loadLocalTemplatesCache()
makes sense to invoke since it'll load in your entire template cache allowing you to test the directives with the actual templates. You won't have to mock the $templateCache
.
It also contains some functions to invoke keypresses and throw events which sometimes go wrong with browserTrigger (which is also included in the ./test/lib/
folder).
Even if jshint fails the tests will still run with grunt test:default
.
grunt test:ci
: runs all your unit tests using karma in a single run in phantomjs and chrome.
- This will generate cobertura coverage reports.
You can ignore files in your coverage by placing
ci:coverage:exclude
somewhere in your file. Preferably in a comment section. - This will generate a junit report.
grunt test:e2e
: runs your end 2 end / integration tests using protractor.
Protractor simulates interaction with our web app and verifies that the application responds correctly. Therefore, our web server needs to be serving up the application, so that protractor can interact with it.
It's configured to use the Cucumber/Gherkin syntax. A sample is included in ./test/e2e
along with some useful steps. I am on state "state_name"
is especially useful because it allows you to move around your app using the states.
You can optionally add a regular expression it needs to check for in order for the state to be accepted. A use-case for this is where your state has a variable in the url. I am on state "news.details" (/news/(\d*))
.
To start the tests you first need a selenium server. Run npm run update-webdriver
to install or update your WebDriver.
If you have the latest webdriver, run npm run protractor
to spin up an instance of protractor. You'll need to have this running in the background.
When a protractor instance is running you can execute the tests using the grunt test:e2e
command.
- The configuration is found at
./test/e2e.conf.js
. - The tests are located in
./test/e2e/<feature>/*
. - Default steps are provided in common which hook into the route configuration.
This seed can create a 'build' using APP_ENV=prod grunt build
which drops a generated application in the ./dist
folder. These are versioned static files which can be hosted anywhere.
You'll need to configure a webserver of choice (nginx, apache, etc) to host the static files.
We recommend to not cache the index.html file as it is the only file that isn't versioned. All other dependencies the index.html links to are versioned and can be cached indefinitely on all proxies.
Keep Cross Origin Resource Sharing in mind when deploying to production.
- Test CI should work on dist files
- Try to implement grunt-bower plugin
- See if we still need this custom reload task
For more information on AngularJS please check out http://angularjs.org/ For more information about angular-super-seed check out http://github.com/Kunstmaan/angular-super-seed/
Created by @daanporon and @spobo with the help of @sambego and @KimGressens. (loosely based on angular-seed)