This is still a Work In Progress - Please Collaborate
Endorsements
The idea for this styleguide is inspired from john papa's angular style guide which is focused on angular version 1.x, written with ES5.
Some sections are currently taken from john papa's styleguide and are subject to change in the future (as this stylguide grows).
This styleguide is also inspired from @angularclass's boilerplates for angular & es2015.
Purpose
Opinionated Angular.js written with ES2015 and module loadeing style guide for teams by @orizens
If you are looking for an opinionated style guide for syntax, conventions, and structuring Angular.js applications v 1.x with ES2015 and module loading, then this is it. These styles are based on my development experience with Angular.js and the Echoes Player, Open Source Project Development (currently the es2015 branch).
The purpose of this style guide is to provide guidance on building Angular applications with ES2015 and module loading by showing the conventions I use and in order to prepare angular v 1.x code to angular v 2.
Inspirations
NG6-Starter
Angular, Gulp, Browserify
See the Styles in a Sample App
This guide is based on my open source Echoes Player application that follows these styles and patterns. You can clone/fork the code at echoes repository.
Translations
TBD
Table of Contents
Single Responsibility
Rule of 1
Define 1 class per file.
The following example defines the several classes in the same file.
// now-playlist.controllers.js /* avoid */ export class NowPlaylistCtrl {} export class NowPlaylistFilterCtrl {}
The same classes are now separated into their own files.
/* recommended */ // now-playlist.ctrl.js export default class NowPlaylistCtrl {}
/* recommended */ // now-playlist-filter.ctrljs export default class NowPlaylistFilterCtrl {}
Modules
Use ES2015 module loader standards
Why?: it assists in bundling the app and promotes the seperation of concerns. In Addition, Angular 2 is also based on ES2015 module loader standards.
import NowPlaylist from './now-playlist'
Module Loaders Tools
- Browserify
- Webpack
- Typescript CLI
Module Folder Structure
each module directory should be named with a dash seperator (kebab notation).
Why?: it follows the web-component notation of seperating a tag name with a dash. It is easier to read and follow in the code editor.
// name of directory of component - now-playlist
Module files
- each module should contain the following:
- index.js - it should contain:
- angular module definition
- loading sub modules (if exist)
- module config function
- module directive definition
- module services definition
- angular module definition
- a component (directive) file defintion
- should load a controller file
- should load a template file
- should load a controller file
- a controller ES2015 class
- a template file
- a spec file
Controllers
- Use ES2015 class for controller
- User Object.assign to expose injected services to a class methods (make it public)
/* @ngInject */
export default class YoutubeVideosCtrl {
/* @ngInject */
constructor (YoutubePlayerSettings, YoutubeSearch, YoutubeVideoInfo) {
Object.assign(this, { YoutubePlayerSettings, YoutubeVideoInfo });
this.videos = YoutubePlayerSettings.items;
YoutubeSearch.resetPageToken();
if (!this.videos.length) {
YoutubeSearch.search();
}
}
playVideo (video) {
this.YoutubePlayerSettings.queueVideo(video);
this.YoutubePlayerSettings.playVideoId(video);
}
playPlaylist (playlist) {
return this.YoutubeVideoInfo.getPlaylist(playlist.id).then(this.YoutubePlayerSettings.playPlaylist);
}
}
Components
- Define a component in X.component.js file using the directive defintion (pre angular v1.5) or component (from v1.5) definition.
- import controller from a seperate file
- import template form a separate file (use module loader support to load text files)
// playlist-saver.component.js
import PlaylistSaverCtrl from './playlist-saver.ctrl.js';
import template from './playlist-saver.tpl.html';
// Usage:
//
/* @ngInject */
export default function playlistSaver () {
var directive = {
template,
controller: PlaylistSaverCtrl,
controllerAs: 'playlistSaver',
bindToController: true,
restrict: 'E',
replace: true,
scope: {
onSave: '&?',
onCancel: '&?',
tracks: '='
}
};
return directive;
}
Services
Application Structure
Overall Guidelines
[-] src
[-] components
[-] core
[-] components
[-] services
[-] css
* app.js
* index.html
Testing
Unit testing helps maintain clean code, as such I included some of my recommendations for unit testing foundations with links for more information.
Write Tests with Stories
Write a set of tests for every story. Start with an empty test and fill them in as you write the code for the story.
Why?: Writing the test descriptions helps clearly define what your story will do, will not do, and how you can measure success.
it('should have a collection of media items', function() { // TODO }); it('should find fetch metadata for a youtube media', function() { // TODO });
Testing Library
Use Jasmine or Mocha for unit testing.
Why?: Both Jasmine and Mocha are widely used in the Angular community. Both are stable, well maintained, and provide robust testing features.
Note: When using Mocha, also consider choosing an assert library such as Chai. I prefer Mocha.
Test Runner
Use Karma as a test runner.
Why?: Karma is easy to configure to run once or automatically when you change your code.
Why?: Karma hooks into your Continuous Integration process easily on its own or through Grunt or Gulp.
Organizing Tests
- Place unit test files (specs) side-by-side within the component's code.
Place mocks in a tests/mocks folder
Why?: Unit tests have a direct correlation to a specific component and file in source code.
Why?: Mock files (json) should be agnostic to the component which is using them. Multiple components specs might use the same jsom mocks.
Comments
TBD
ES Lint
Use an Options File
- Use eslint.org to deifne es2015 support
Use .eslintrc file for linting and support es2015 features
Why?: Provides a first alert prior to committing any code to source control.
Why?: Provides consistency across your team.
{ arrowFunctions: true, classes: true, modules: true, restParams: true, spread: true, defaultParams: true }
More To Come...
Routing
TBD
Contributing
- Open an issue for discussion
- Create a pull request to suggest additions or changes
License
Share your thoughts with an issue or pull request
Copyright
Copyright (c) 2015-2016 Oren Farhi