├── README.md └── template ├── .gitignore ├── bower.json ├── gulpfile.coffee ├── karma.conf.coffee ├── package.json ├── src ├── app.coffee ├── app.spec.coffee └── index.html └── webpack.config.coffee /README.md: -------------------------------------------------------------------------------- 1 | Webpack + Angular + Bower + Gulp 2 | ================================ 3 | 4 | [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/jeffling/angular-webpack-example?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) 5 | 6 | *This template is kept bare-bones on purpose. If you have any questions or need advice on folder structure feel free to make an issue* 7 | 8 | Minimal boilerplate with webpack (run from gulp) that supports angular (from bower), with some common settings. 9 | 10 | It uses coffeescript, but you could very easily use the same configuration by stripping out the coffee loaders. 11 | 12 | It uses https://github.com/segmentio/khaos to generate the template. 13 | 14 | ``` 15 | npm install -g khaos 16 | khaos create jeffling/angular-webpack-example 17 | ``` 18 | 19 | What it has 20 | 21 | * webpack configured with the bower path included `bower/` 22 | * angular. Globally loaded 23 | * karma. looks for .spec.coffee files. 24 | 25 | Optional stuff: 26 | 27 | * facebook/flo for live reloading in the browser. 28 | * SASS loader 29 | 30 | 31 | We use something close to this at @BenchLabs. It allows us to compose our entire app from strictly isolated angular modules. http://labs.bench.co/2015/1/21/componentized-angular 32 | -------------------------------------------------------------------------------- /template/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | bower_components/ 3 | target/ 4 | -------------------------------------------------------------------------------- /template/bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "{{name}}", 3 | "version": "0.0.0", 4 | "homepage": "{{homepage}}", 5 | "authors": [ 6 | "{{author}}" 7 | ], 8 | "description": "{{description}}", 9 | "main": "src/index.html", 10 | "license": "MIT", 11 | "private": true, 12 | "ignore": [ 13 | "**/.*", 14 | "node_modules", 15 | "bower_components", 16 | "test", 17 | "tests" 18 | ], 19 | "dependencies": { 20 | "angular": "~1.2.25", 21 | "angular-mocks": "~1.2.25" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /template/gulpfile.coffee: -------------------------------------------------------------------------------- 1 | # gulp plugins 2 | gulp = require 'gulp' 3 | changed = require 'gulp-changed' 4 | gutil = require 'gulp-util' 5 | 6 | # misc 7 | spawn = require('child_process').spawn 8 | argv = require('minimist')(process.argv.slice(2)) 9 | 10 | # webpack 11 | webpack = require 'webpack' 12 | webpackConfig = require './webpack.config' 13 | ngminPlugin = require 'ngmin-webpack-plugin' 14 | 15 | if argv.production # --production option 16 | webpackConfig.plugins = webpackConfig.plugins.concat new ngminPlugin(), 17 | new webpack.optimize.UglifyJsPlugin() 18 | webpackConfig.devtool = false 19 | webpackConfig.debug = false 20 | 21 | ports = 22 | livereload: 35729 23 | 24 | paths = 25 | other: [ 26 | 'src/**' 27 | '!src/**/*.js' 28 | '!src/**/*.coffee' 29 | '!src/**/*.scss' 30 | ] 31 | targetDir: './target/' 32 | 33 | gulp.task 'webpack', (cb) -> 34 | webpack webpackConfig, (err, stats) -> 35 | if (err) 36 | throw new gutil.PluginError 'webpack', err 37 | gutil.log '[webpack]', stats.toString 38 | colors: true 39 | cb() 40 | 41 | # gulp other, moves changed files from source to other 42 | gulp.task 'other', -> 43 | gulp.src paths.other 44 | .pipe changed paths.targetDir 45 | .pipe gulp.dest paths.targetDir 46 | 47 | # gulp clearTarget 48 | # clears target directory 49 | rimraf = require 'rimraf' 50 | gulp.task 'clearTarget', -> 51 | rimraf.sync paths.targetDir, gutil.log 52 | 53 | #gulp build 54 | gulp.task 'build', [ 55 | 'clearTarget' 56 | 'webpack' 57 | 'other' 58 | ] 59 | 60 | # gulp watch 61 | gulp.task 'watch', ['clearTarget', 'other'], -> 62 | {{#fbFlo}} 63 | fs = require 'fs' 64 | path = require 'path' 65 | flo = require 'fb-flo' 66 | flo paths.targetDir, 67 | port: 8888 68 | host: 'localhost' 69 | verbose: false 70 | glob: [ 71 | '**/*.js' 72 | '**/*.css' 73 | '**/*.html' 74 | ] 75 | , (filepath, callback) -> 76 | url = filepath 77 | reload = true # set as true as angular doesn't support hotswapping 78 | if (path.extname filepath) is '.html' 79 | url = '/' 80 | callback 81 | resourceURL: url 82 | contents: fs.readFileSync paths.targetDir + filepath 83 | reload: reload 84 | {{/fbFlo}} 85 | 86 | webpack webpackConfig 87 | .watch 200, (err, stats) -> 88 | if (err) 89 | throw new gutil.PluginError 'webpack', err 90 | gutil.log '[webpack]', stats.toString 91 | colors: true 92 | 93 | gulp.watch paths.other, ['other'] 94 | 95 | # gulp 96 | gulp.task 'default', ['build'] 97 | 98 | -------------------------------------------------------------------------------- /template/karma.conf.coffee: -------------------------------------------------------------------------------- 1 | # Karma configuration 2 | # Generated on Mon Jun 09 2014 01:16:57 GMT-0700 (PDT) 3 | 4 | fullWebpackConfig = require './webpack.config.coffee' 5 | 6 | webpackConfig = 7 | module: fullWebpackConfig.module 8 | resolve: fullWebpackConfig.resolve 9 | plugins: fullWebpackConfig.plugins 10 | devtool: 'eval' 11 | cache: true 12 | 13 | module.exports = (config) -> 14 | config.set 15 | 16 | # base path that will be used to resolve all patterns (eg. files, exclude) 17 | basePath: '' 18 | 19 | # frameworks to use 20 | # available frameworks: https://npmjs.org/browse/keyword/karma-adapter 21 | frameworks: ['mocha', 'chai'] 22 | 23 | # list of files / patterns to load in the browser 24 | files: [ 25 | 'bower_components/angular/angular.js' 26 | 'bower_components/angular-mocks/angular-mocks.js' 27 | 'src/**/*.spec.coffee' 28 | ] 29 | 30 | # list of files to exclude 31 | exclude: [ 32 | 33 | ] 34 | 35 | # preprocess matching files before serving them to the browser 36 | # available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor 37 | preprocessors: { 38 | '**/*.coffee': ['webpack'] 39 | } 40 | 41 | webpack: webpackConfig 42 | 43 | # test results reporter to use 44 | # possible values: 'dots', 'progress' 45 | # available reporters: https://npmjs.org/browse/keyword/karma-reporter 46 | reporters: ['progress'] 47 | 48 | # web server port 49 | port: 9876 50 | 51 | # enable / disable colors in the output (reporters and logs) 52 | colors: true 53 | 54 | # level of logging 55 | # possible values: 56 | # - config.LOG_DISABLE 57 | # - config.LOG_ERROR 58 | # - config.LOG_WARN 59 | # - config.LOG_INFO 60 | # - config.LOG_DEBUG 61 | logLevel: config.LOG_INFO 62 | 63 | # enable / disable watching file and executing tests whenever any file changes 64 | autoWatch: true 65 | 66 | # start these browsers 67 | # available browser launchers: https://npmjs.org/browse/keyword/karma-launcher 68 | browsers: ['Chrome'] 69 | 70 | # Continuous Integration mode 71 | # if true, Karma captures browsers, runs the tests and exits 72 | singleRun: false 73 | -------------------------------------------------------------------------------- /template/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "{{ name }}", 3 | "version": "0.0.0", 4 | "description": "{{ description }}", 5 | "main": "target/index.html", 6 | "scripts": { 7 | "start": "node server", 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "keywords": [], 11 | "engines": { 12 | "node": "0.10.x" 13 | }, 14 | {{#private}} 15 | "private": true, 16 | {{/private}} 17 | "repository": "{{ author }}/{{ name }}", 18 | "author": "{{ author }}", 19 | "homepage": "{{homepage}}", 20 | "devDependencies": { 21 | "chai": "^1.9.1", 22 | "coffee-loader": "*", 23 | "coffee-script": "~1.8.0", 24 | "css-loader": "*", 25 | "exports-loader": "*", 26 | "gulp": "~3.8.8", 27 | "gulp-cached": "1.0.1", 28 | "gulp-changed": "^1.0.0", 29 | "gulp-git": "^0.5.1", 30 | "gulp-util": "~3.0.1", 31 | "imports-loader": "*", 32 | "karma": "^0.12.23", 33 | "karma-chai": "^0.1.0", 34 | "karma-chrome-launcher": "^0.1.4", 35 | "karma-mocha": "^0.1.9", 36 | "karma-webpack": "^1.2.2", 37 | "minimist": "1.1.0", 38 | "mocha": "^1.21.4", 39 | "ngmin-webpack-plugin": "^0.1.3", 40 | "raw-loader": "*", 41 | "rimraf": "^2.2.8", 42 | "style-loader": "*", 43 | "webpack": "^1.4.1-beta1", 44 | "webpack-core": "^0.4.8" 45 | {{#sass}} 46 | ,"sass-loader": "*" 47 | {{/sass}} 48 | {{#fbFlo}} 49 | ,"fb-flo": "*" 50 | {{/fbFlo}} 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /template/src/app.coffee: -------------------------------------------------------------------------------- 1 | # angular is required globally 2 | {{name}} = angular.module '{{name}}', [] 3 | 4 | module.exports = {{name}} 5 | -------------------------------------------------------------------------------- /template/src/app.spec.coffee: -------------------------------------------------------------------------------- 1 | # you would probably not test your app.coffee but if you were to 2 | # you would put it here. -------------------------------------------------------------------------------- /template/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {{name}} 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /template/webpack.config.coffee: -------------------------------------------------------------------------------- 1 | path = require 'path' 2 | webpack = require 'webpack' 3 | ngminPlugin = require 'ngmin-webpack-plugin' 4 | 5 | appRoot = "#{__dirname}/src" 6 | bowerRoot = "#{__dirname}/bower_components" 7 | {{#sass}} 8 | styleRoot = "#{appRoot}/assets/styles" 9 | {{/sass}} 10 | 11 | module.exports = 12 | cache: true 13 | debug: true 14 | 15 | # The entry point 16 | entry: [ 17 | "#{appRoot}/app.coffee" 18 | ] 19 | 20 | output: 21 | path: './target' 22 | filename: 'bundle.js' 23 | chunkFilename: "[id].bundle.js" 24 | 25 | module: 26 | loaders: [ 27 | # required to write 'require('./style.css')' 28 | test: /\.css$/ 29 | loaders: ['style','css'] 30 | , 31 | {{#sass}} 32 | # required to write 'require('./style.scss')' 33 | test: /\.scss$/ 34 | loaders: ['style','css',"sass?includePaths[]=#{styleRoot}"] 35 | , 36 | {{/sass}} 37 | test: /\.coffee$/ 38 | loader: 'coffee' 39 | , 40 | # require raw html for partials 41 | test: /\.html$/ 42 | loader: 'raw' 43 | , 44 | # required for bootstrap icons 45 | test: /\.woff$/ 46 | loader: 'url?prefix=font/&limit=5000&mimetype=application/font-woff' 47 | , 48 | test: /\.ttf$/ 49 | loader: 'file?prefix=font/' 50 | , 51 | test: /\.eot$/ 52 | loader: 'file?prefix=font/' 53 | , 54 | test: /\.svg$/ 55 | loader: 'file?prefix=font/' 56 | ] 57 | 58 | # don't parse some dependencies to speed up build. 59 | # can probably do this non-AMD/CommonJS deps 60 | noParse: [ 61 | path.join bowerRoot, '/angular' 62 | path.join bowerRoot, '/angular-route' 63 | path.join bowerRoot, '/angular-ui-router' 64 | path.join bowerRoot, '/angular-mocks' 65 | path.join bowerRoot, '/jquery' 66 | ] 67 | 68 | resolve: 69 | alias: 70 | bower: bowerRoot 71 | 72 | extensions: [ 73 | '' 74 | '.js' 75 | '.coffee' 76 | '.scss' 77 | '.css' 78 | ] 79 | 80 | root: appRoot 81 | 82 | plugins: [ 83 | # bower.json resolving 84 | new webpack.ResolverPlugin [ 85 | new webpack.ResolverPlugin.DirectoryDescriptionFilePlugin "bower.json", ["main"] 86 | ], ["normal", "loader"] 87 | 88 | # disable dynamic requires 89 | new webpack.ContextReplacementPlugin(/.*$/, /a^/) 90 | 91 | new webpack.ProvidePlugin 92 | 'angular': 'exports?window.angular!bower/angular' 93 | ] 94 | 95 | devtool: 'eval' 96 | --------------------------------------------------------------------------------