├── .gitignore ├── README.md ├── bin └── www ├── karma.conf.js ├── package.json ├── public └── index.html ├── server.js ├── src └── app │ ├── home │ ├── home.config.js │ ├── home.ctrl.js │ ├── home.ctrl.test.js │ ├── home.html │ └── index.js │ ├── index.js │ └── main │ ├── index.js │ ├── main.config.js │ ├── main.ctrl.js │ ├── main.ctrl.test.js │ └── main.html └── webpack.config.js /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | ### Node template 3 | # Logs 4 | logs 5 | *.log 6 | 7 | # Runtime data 8 | pids 9 | *.pid 10 | *.seed 11 | 12 | # Directory for instrumented libs generated by jscoverage/JSCover 13 | lib-cov 14 | 15 | # Coverage directory used by tools like istanbul 16 | coverage 17 | 18 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 19 | .grunt 20 | 21 | # node-waf configuration 22 | .lock-wscript 23 | 24 | # Compiled binary addons (http://nodejs.org/api/addons.html) 25 | build/Release 26 | 27 | # Dependency directory 28 | # https://docs.npmjs.com/misc/faq#should-i-check-my-node-modules-folder-into-git 29 | node_modules 30 | .idea 31 | 32 | 33 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Angualr Webpack Boilerplate 2 | 3 | > quick boilerplate for angular project using webpack includes tests (no css framework) 4 | 5 | ### Usage 6 | clone this repo and then `npm install` for dependencies. `npm test` to run tests and `npm start` to run dev server. 7 | visit: `http://loclhost:8080` 8 | 9 | ### Libs 10 | - dev server is based on express.js using webpack dev middleware 11 | - test using karma, chai mocha and sinon 12 | - angular-ui-router for routing 13 | 14 | I used my opinionated architecture here, however it is very easy to implement your own idea. 15 | 16 | --- 17 | 18 | feel free to fork, suggest, open issues or ask anything. 19 | -------------------------------------------------------------------------------- /bin/www: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | /** 4 | * Module dependencies. 5 | */ 6 | 7 | var app = require('../server'); 8 | var debug = require('debug')('ng-biolerplate:server'); 9 | var http = require('http'); 10 | 11 | /** 12 | * Get port from environment and store in Express. 13 | */ 14 | 15 | var port = normalizePort(process.env.PORT || '8080'); 16 | app.set('port', port); 17 | 18 | /** 19 | * Create HTTP server. 20 | */ 21 | 22 | var server = http.createServer(app); 23 | 24 | /** 25 | * Listen on provided port, on all network interfaces. 26 | */ 27 | 28 | server.listen(port); 29 | server.on('error', onError); 30 | server.on('listening', onListening); 31 | 32 | /** 33 | * Normalize a port into a number, string, or false. 34 | */ 35 | 36 | function normalizePort(val) { 37 | var port = parseInt(val, 10); 38 | 39 | if (isNaN(port)) { 40 | // named pipe 41 | return val; 42 | } 43 | 44 | if (port >= 0) { 45 | // port number 46 | return port; 47 | } 48 | 49 | return false; 50 | } 51 | 52 | /** 53 | * Event listener for HTTP server "error" event. 54 | */ 55 | 56 | function onError(error) { 57 | if (error.syscall !== 'listen') { 58 | throw error; 59 | } 60 | 61 | var bind = typeof port === 'string' 62 | ? 'Pipe ' + port 63 | : 'Port ' + port; 64 | 65 | // handle specific listen errors with friendly messages 66 | switch (error.code) { 67 | case 'EACCES': 68 | console.error(bind + ' requires elevated privileges'); 69 | process.exit(1); 70 | break; 71 | case 'EADDRINUSE': 72 | console.error(bind + ' is already in use'); 73 | process.exit(1); 74 | break; 75 | default: 76 | throw error; 77 | } 78 | } 79 | 80 | /** 81 | * Event listener for HTTP server "listening" event. 82 | */ 83 | 84 | function onListening() { 85 | var addr = server.address(); 86 | var bind = typeof addr === 'string' 87 | ? 'pipe ' + addr 88 | : 'port ' + addr.port; 89 | debug('Listening on ' + bind); 90 | } 91 | -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration 2 | var path = require('path'); 3 | var webpack = require('webpack'); 4 | var ngAnnotatePlugin = require('ng-annotate-webpack-plugin'); 5 | 6 | module.exports = function (config) { 7 | config.set({ 8 | 9 | // base path, that will be used to resolve files and exclude 10 | basePath: './src', 11 | 12 | 13 | // frameworks to use 14 | frameworks: ['mocha', 'sinon-chai'], 15 | 16 | 17 | // list of files / patterns to load in the browser 18 | files: [ 19 | 'app/index.js', 20 | '../node_modules/angular-mocks/angular-mocks.js', 21 | 'app/**/*.test.js' 22 | ], 23 | 24 | 25 | // list of preprocessors 26 | preprocessors: { 27 | 'app/index.js': ['webpack'] 28 | }, 29 | 30 | 31 | webpack: { 32 | module: { 33 | loaders: [ 34 | {test: /\.(css|less)$/, loader: 'null'}, 35 | {test: /\.html$/, loader: 'raw'}, 36 | {test: /\.json$/, loader: 'json'}, 37 | {test: /jquery\.js$/, loader: 'expose?$'}, 38 | {test: /jquery\.js$/, loader: 'expose?jQuery'} 39 | ], 40 | 41 | noParse: [ 42 | /^jquery(\-.*)?$/, 43 | /^angular(\-.*)?$/ 44 | ] 45 | }, 46 | 47 | devtool: 'eval', 48 | 49 | plugins: [ 50 | new ngAnnotatePlugin({ 51 | add: true 52 | }) 53 | ] 54 | }, 55 | 56 | 57 | webpackMiddleware: { 58 | stats: { 59 | colors: true 60 | } 61 | }, 62 | 63 | 64 | // test results reporter to use 65 | // possible values: 'dots', 'progress', 'junit', 'growl', 'coverage' 66 | reporters: ['mocha'], 67 | 68 | 69 | // web server port 70 | port: 9876, 71 | 72 | 73 | // enable / disable colors in the output (reporters and logs) 74 | colors: true, 75 | 76 | 77 | // level of logging 78 | // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG 79 | logLevel: config.LOG_INFO, 80 | 81 | 82 | // enable / disable watching file and executing tests whenever any file changes 83 | autoWatch: true, 84 | 85 | 86 | // Start these browsers, currently available: 87 | // - Chrome 88 | // - ChromeCanary 89 | // - Firefox 90 | // - Opera (has to be installed with `npm install karma-opera-launcher`) 91 | // - Safari (only Mac; has to be installed with `npm install karma-safari-launcher`) 92 | // - PhantomJS 93 | // - IE (only Windows; has to be installed with `npm install karma-ie-launcher`) 94 | browsers: ['PhantomJS'], 95 | 96 | 97 | // If browser does not capture in given timeout [ms], kill it 98 | captureTimeout: 60000, 99 | 100 | 101 | // Continuous Integration mode 102 | // if true, it capture browsers, run tests and exit 103 | singleRun: false, 104 | 105 | 106 | // List plugins explicitly, since autoloading karma-webpack 107 | // won't work here 108 | plugins: [ 109 | require('karma-webpack'), 110 | require('karma-mocha'), 111 | require('karma-sinon-chai'), 112 | require('karma-mocha-reporter'), 113 | require('karma-phantomjs-launcher') 114 | ] 115 | }); 116 | }; 117 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-webpack-biolerplate", 3 | "version": "1.0.0", 4 | "description": "boilerplate for bootstraping angular app using webpack including tests (no css framework)", 5 | "main": "./server.js", 6 | "scripts": { 7 | "test": "karma start karma.conf.js --no-auto-watch --single-run", 8 | "start": "node ./bin/www", 9 | "build:production": "webpack -p --devtool --progress" 10 | }, 11 | "author": "Alon Valadji", 12 | "license": "MIT", 13 | "dependencies": { 14 | "angular": "^1.4.5", 15 | "angular-ui-router": "^0.2.15", 16 | "body-parser": "^1.13.3", 17 | "cookie-parser": "^1.3.5", 18 | "debug": "^2.2.0", 19 | "express": "^4.13.3", 20 | "jquery": "^2.1.4", 21 | "morgan": "^1.6.1" 22 | }, 23 | "devDependencies": { 24 | "angular-mocks": "^1.4.5", 25 | "expose-loader": "^0.7.0", 26 | "file-loader": "^0.8.4", 27 | "json-loader": "^0.5.2", 28 | "karma": "^0.13.9", 29 | "karma-mocha": "^0.2.0", 30 | "karma-mocha-reporter": "^1.1.1", 31 | "karma-phantomjs-launcher": "^0.2.1", 32 | "karma-sinon-chai": "^1.0.0", 33 | "karma-webpack": "^1.7.0", 34 | "mocha": "^2.3.2", 35 | "ng-annotate-webpack-plugin": "^0.1.2", 36 | "phantomjs": "^1.9.18", 37 | "raw-loader": "^0.5.1", 38 | "webpack": "^1.12.1", 39 | "webpack-dev-middleware": "^1.2.0" 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 |{{home.title}}
-------------------------------------------------------------------------------- /src/app/home/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var angular = require('angular'); 4 | 5 | module.exports = angular.module('home', [ 6 | require('angular-ui-router') 7 | ]) 8 | 9 | .config(require('./home.config')) 10 | 11 | .controller('HomeCtrl', require('./home.ctrl')) 12 | 13 | .name 14 | 15 | ; 16 | -------------------------------------------------------------------------------- /src/app/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var $ = require('jquery'); 4 | var angular = require('angular'); 5 | 6 | angular.module('ng.boilerplate', [ 7 | require('./main'), 8 | require('./home') 9 | ]) 10 | 11 | ; -------------------------------------------------------------------------------- /src/app/main/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var angular = require('angular'); 4 | 5 | module.exports = angular.module('main', [ 6 | require('angular-ui-router') 7 | ]) 8 | 9 | .config(require('./main.config')) 10 | 11 | .controller('MainCtrl', require('./main.ctrl')) 12 | 13 | .name 14 | 15 | ; 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/app/main/main.config.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /* @ngInject */ 4 | function mainConfig($urlRouterProvider, $locationProvider, $stateProvider){ 5 | $urlRouterProvider.rule(function ($i, $location) { 6 | var path = $location.path(); 7 | var normalized = path.toLowerCase(); 8 | if (path != normalized) return normalized; 9 | }); 10 | 11 | $urlRouterProvider.otherwise('/'); 12 | 13 | $locationProvider.html5Mode(false); 14 | 15 | $stateProvider 16 | .state('main', { 17 | abstract: true, 18 | template: require('./main.html') 19 | }) 20 | } 21 | 22 | module.exports = mainConfig; -------------------------------------------------------------------------------- /src/app/main/main.ctrl.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /* @ngInject */ 4 | function MainCtrl($scope){ 5 | this.title = 'Angular Boilerplate'; 6 | } 7 | 8 | module.exports = MainCtrl; -------------------------------------------------------------------------------- /src/app/main/main.ctrl.test.js: -------------------------------------------------------------------------------- 1 | describe('Main controller', function(){ 2 | beforeEach(module('main')); 3 | 4 | beforeEach(inject(function (_$controller_, _$rootScope_, $q) { 5 | this.$controller = _$controller_; 6 | this.$rootScope = _$rootScope_; 7 | this.$scope = this.$rootScope.$new(); 8 | 9 | this.Ctrl = this.$controller('MainCtrl', { 10 | $scope: this.$scope 11 | }); 12 | })); 13 | 14 | it('should provide a controller', function () { 15 | expect(this.Ctrl).to.not.be.null 16 | }); 17 | 18 | it('has title', function () { 19 | expect(this.Ctrl.title).to.equal('Angular Boilerplate') 20 | }); 21 | }); -------------------------------------------------------------------------------- /src/app/main/main.html: -------------------------------------------------------------------------------- 1 |