├── .gitignore ├── src ├── images │ └── gulp.png ├── sass │ ├── _scss-mixins.scss │ ├── app.sass │ ├── _typography.sass │ └── _icons.sass ├── javascript │ ├── vendor │ │ └── jquery-plugin.js │ ├── global.coffee │ ├── template.hbs │ ├── __tests__ │ │ └── page-test.coffee │ ├── page.js │ └── view.coffee ├── icons │ ├── uE001-facebook.svg │ ├── uE002-linkedin.svg │ ├── uE004-twitter.svg │ └── uE003-pinterest.svg └── htdocs │ └── index.html ├── gulp ├── tasks │ ├── default.js │ ├── browserSync.js │ ├── watchify.js │ ├── production.js │ ├── markup.js │ ├── karma.js │ ├── uglifyJs.js │ ├── minifyCss.js │ ├── iconFont │ │ ├── index.js │ │ ├── generateIconSass.js │ │ └── template.sass.swig │ ├── images.js │ ├── watch.js │ ├── sass.js │ └── browserify.js ├── util │ ├── handleErrors.js │ └── bundleLogger.js └── config.js ├── gulpfile.js ├── LICENSE.md ├── karma.conf.js ├── package.json └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .sass-cache 3 | build 4 | Desktop.ini 5 | node_modules 6 | -------------------------------------------------------------------------------- /src/images/gulp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ATA/gulp-starter/master/src/images/gulp.png -------------------------------------------------------------------------------- /gulp/tasks/default.js: -------------------------------------------------------------------------------- 1 | var gulp = require('gulp'); 2 | 3 | gulp.task('default', ['sass', 'images', 'markup', 'watch']); 4 | -------------------------------------------------------------------------------- /src/sass/_scss-mixins.scss: -------------------------------------------------------------------------------- 1 | @mixin font-smoothing { 2 | -moz-osx-font-smoothing: grayscale; 3 | -webkit-font-smoothing: antialiased; 4 | } 5 | -------------------------------------------------------------------------------- /src/javascript/vendor/jquery-plugin.js: -------------------------------------------------------------------------------- 1 | window.plugin = function() { 2 | $('body').append('
This line was generated by a non common-js plugin that depends on jQuery!
'); 3 | }; 4 | -------------------------------------------------------------------------------- /src/javascript/global.coffee: -------------------------------------------------------------------------------- 1 | # Browserify entry point for the global.js bundle (yay CoffeeScript!) 2 | View = require './view' 3 | view = new View(el: '#content') 4 | console.log 'global.js loaded!' 5 | -------------------------------------------------------------------------------- /src/javascript/template.hbs: -------------------------------------------------------------------------------- 1 |2 | {{description}} 3 |
4 |
10 |
--------------------------------------------------------------------------------
/src/javascript/__tests__/page-test.coffee:
--------------------------------------------------------------------------------
1 | require '../page'
2 | $ = require 'jquery'
3 |
4 | describe 'page.js', ->
5 | it 'contains a love letter', ->
6 | loveLetter = $('.love-letter').length
7 | loveLetter.should.equal 1
8 |
--------------------------------------------------------------------------------
/gulp/tasks/browserSync.js:
--------------------------------------------------------------------------------
1 | var browserSync = require('browser-sync');
2 | var gulp = require('gulp');
3 | var config = require('../config').browserSync;
4 |
5 | gulp.task('browserSync', function() {
6 | browserSync(config);
7 | });
8 |
--------------------------------------------------------------------------------
/gulp/tasks/watchify.js:
--------------------------------------------------------------------------------
1 | var gulp = require('gulp');
2 | var browserifyTask = require('./browserify');
3 |
4 | gulp.task('watchify', function() {
5 | // Start browserify task with devMode === true
6 | return browserifyTask(true);
7 | });
8 |
--------------------------------------------------------------------------------
/src/sass/app.sass:
--------------------------------------------------------------------------------
1 | @import scss-mixins
2 | @import typography
3 | @import icons
4 |
5 | .social-icons
6 | h4
7 | display: inline-block
8 | margin: 20px 10px 0 0
9 |
10 | .icon
11 | display: inline-block
12 | margin: 0 5px
13 |
--------------------------------------------------------------------------------
/gulp/tasks/production.js:
--------------------------------------------------------------------------------
1 | var gulp = require('gulp');
2 |
3 | // Run this to compress all the things!
4 | gulp.task('production', ['karma'], function(){
5 | // This runs only if the karma tests pass
6 | gulp.start(['markup', 'images', 'iconFont', 'minifyCss', 'uglifyJs'])
7 | });
8 |
--------------------------------------------------------------------------------
/gulp/tasks/markup.js:
--------------------------------------------------------------------------------
1 | var gulp = require('gulp');
2 | var config = require('../config').markup;
3 | var browserSync = require('browser-sync');
4 |
5 | gulp.task('markup', function() {
6 | return gulp.src(config.src)
7 | .pipe(gulp.dest(config.dest))
8 | .pipe(browserSync.reload({stream:true}));
9 | });
10 |
--------------------------------------------------------------------------------
/gulp/tasks/karma.js:
--------------------------------------------------------------------------------
1 | var gulp = require('gulp');
2 | var karma = require('karma');
3 |
4 | var karmaTask = function(done) {
5 | karma.server.start({
6 | configFile: process.cwd() + '/karma.conf.js',
7 | singleRun: true
8 | }, done);
9 | };
10 |
11 | gulp.task('karma', karmaTask);
12 |
13 | module.exports = karmaTask;
14 |
--------------------------------------------------------------------------------
/src/sass/_typography.sass:
--------------------------------------------------------------------------------
1 | body
2 | +font-smoothing // <- _mixins.scss
3 | color: #555
4 | font-family: sans-serif
5 |
6 | small
7 | font-weight: normal
8 | display: block
9 | font-size: 14px
10 |
11 | code
12 | background-color: lightgrey
13 | border-radius: 3px
14 | font-family: monospace
15 | padding: 0 .5em
16 |
--------------------------------------------------------------------------------
/gulp/tasks/uglifyJs.js:
--------------------------------------------------------------------------------
1 | var gulp = require('gulp');
2 | var config = require('../config').production;
3 | var size = require('gulp-filesize');
4 | var uglify = require('gulp-uglify');
5 |
6 | gulp.task('uglifyJs', ['browserify'], function() {
7 | return gulp.src(config.jsSrc)
8 | .pipe(uglify())
9 | .pipe(gulp.dest(config.dest))
10 | .pipe(size());
11 | });
12 |
--------------------------------------------------------------------------------
/gulp/tasks/minifyCss.js:
--------------------------------------------------------------------------------
1 | var gulp = require('gulp');
2 | var config = require('../config').production;
3 | var minifyCSS = require('gulp-minify-css');
4 | var size = require('gulp-filesize');
5 |
6 | gulp.task('minifyCss', ['sass'], function() {
7 | return gulp.src(config.cssSrc)
8 | .pipe(minifyCSS({keepBreaks:true}))
9 | .pipe(gulp.dest(config.dest))
10 | .pipe(size());
11 | })
12 |
--------------------------------------------------------------------------------
/gulp/util/handleErrors.js:
--------------------------------------------------------------------------------
1 | var notify = require("gulp-notify");
2 |
3 | module.exports = function() {
4 |
5 | var args = Array.prototype.slice.call(arguments);
6 |
7 | // Send error to notification center with gulp-notify
8 | notify.onError({
9 | title: "Compile Error",
10 | message: "<%= error %>"
11 | }).apply(this, args);
12 |
13 | // Keep gulp from hanging on this task
14 | this.emit('end');
15 | };
--------------------------------------------------------------------------------
/gulp/tasks/iconFont/index.js:
--------------------------------------------------------------------------------
1 | var gulp = require('gulp');
2 | var iconfont = require('gulp-iconfont');
3 | var config = require('../../config').iconFonts;
4 | var generateIconSass = require('./generateIconSass');
5 |
6 | gulp.task('iconFont', function() {
7 | return gulp.src(config.src)
8 | .pipe(iconfont(config.options))
9 | .on('codepoints', generateIconSass)
10 | .pipe(gulp.dest(config.dest));
11 | });
12 |
--------------------------------------------------------------------------------
/gulp/tasks/images.js:
--------------------------------------------------------------------------------
1 | var changed = require('gulp-changed');
2 | var gulp = require('gulp');
3 | var imagemin = require('gulp-imagemin');
4 | var config = require('../config').images;
5 | var browserSync = require('browser-sync');
6 |
7 | gulp.task('images', function() {
8 | return gulp.src(config.src)
9 | .pipe(changed(config.dest)) // Ignore unchanged files
10 | .pipe(imagemin()) // Optimize
11 | .pipe(gulp.dest(config.dest))
12 | .pipe(browserSync.reload({stream:true}));
13 | });
14 |
--------------------------------------------------------------------------------
/gulp/tasks/watch.js:
--------------------------------------------------------------------------------
1 | /* Notes:
2 | - gulp/tasks/browserify.js handles js recompiling with watchify
3 | - gulp/tasks/browserSync.js watches and reloads compiled files
4 | */
5 |
6 | var gulp = require('gulp');
7 | var config = require('../config');
8 |
9 | gulp.task('watch', ['watchify','browserSync'], function() {
10 | gulp.watch(config.sass.src, ['sass']);
11 | gulp.watch(config.images.src, ['images']);
12 | gulp.watch(config.markup.src, ['markup']);
13 | // Watchify will watch and recompile our JS, so no need to gulp.watch it
14 | });
15 |
--------------------------------------------------------------------------------
/gulpfile.js:
--------------------------------------------------------------------------------
1 | /*
2 | gulpfile.js
3 | ===========
4 | Rather than manage one giant configuration file responsible
5 | for creating multiple tasks, each task has been broken out into
6 | its own file in gulp/tasks. Any files in that directory get
7 | automatically required below.
8 |
9 | To add a new task, simply add a new task file that directory.
10 | gulp/tasks/default.js specifies the default set of tasks to run
11 | when you run `gulp`.
12 | */
13 |
14 | var requireDir = require('require-dir');
15 |
16 | // Require all tasks in gulp/tasks, including subfolders
17 | requireDir('./gulp/tasks', { recurse: true });
18 |
--------------------------------------------------------------------------------
/src/icons/uE001-facebook.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
--------------------------------------------------------------------------------
/gulp/tasks/sass.js:
--------------------------------------------------------------------------------
1 | var gulp = require('gulp');
2 | var browserSync = require('browser-sync');
3 | var sass = require('gulp-sass');
4 | var sourcemaps = require('gulp-sourcemaps');
5 | var handleErrors = require('../util/handleErrors');
6 | var config = require('../config').sass;
7 | var autoprefixer = require('gulp-autoprefixer');
8 |
9 | gulp.task('sass', function () {
10 | return gulp.src(config.src)
11 | .pipe(sourcemaps.init())
12 | .pipe(sass(config.settings))
13 | .on('error', handleErrors)
14 | .pipe(sourcemaps.write())
15 | .pipe(autoprefixer({ browsers: ['last 2 version'] }))
16 | .pipe(gulp.dest(config.dest))
17 | .pipe(browserSync.reload({stream:true}));
18 | });
19 |
--------------------------------------------------------------------------------
/src/icons/uE002-linkedin.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
--------------------------------------------------------------------------------
/src/htdocs/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Made with <%= feels %> at <%= bestCompanyEvar %>!
"); 12 | 13 | var message = messageTemplate({ 14 | bestCompanyEvar: 'Viget', 15 | feels: '♥', 16 | url: 'http://viget.com' 17 | }); 18 | 19 | $('body').append(message); 20 | 21 | console.log('page.js loaded!'); 22 | -------------------------------------------------------------------------------- /gulp/tasks/iconFont/generateIconSass.js: -------------------------------------------------------------------------------- 1 | var gulp = require('gulp'); 2 | var config = require('../../config').iconFonts; 3 | var swig = require('gulp-swig'); 4 | var rename = require('gulp-rename'); 5 | 6 | module.exports = function(codepoints, options) { 7 | gulp.src(config.template) 8 | .pipe(swig({ 9 | data: { 10 | icons: codepoints.map(function(icon) { 11 | return { 12 | name: icon.name, 13 | code: icon.codepoint.toString(16) 14 | } 15 | }), 16 | 17 | fontName: config.options.fontName, 18 | fontPath: config.fontPath, 19 | className: config.className, 20 | comment: 'DO NOT EDIT DIRECTLY!\n Generated by gulp/tasks/iconFont.js\n from ' + config.template 21 | } 22 | })) 23 | .pipe(rename(config.sassOutputName)) 24 | .pipe(gulp.dest(config.sassDest)); 25 | }; 26 | -------------------------------------------------------------------------------- /gulp/tasks/iconFont/template.sass.swig: -------------------------------------------------------------------------------- 1 | // {{comment}} 2 | 3 | @font-face 4 | font-family: {{fontName}} 5 | src: url("{{fontPath}}/{{fontName}}.eot") 6 | src: url("{{fontPath}}/{{fontName}}.eot?#iefix") format('embedded-opentype'), url("{{fontPath}}/{{fontName}}.woff") format('woff'), url("{{fontPath}}/{{fontName}}.ttf") format('truetype'), url("{{fontPath}}/{{fontName}}.svg#{{fontName}}") format('svg') 7 | font-weight: normal 8 | font-style: normal 9 | 10 | =icon($content) 11 | &:before 12 | -moz-osx-font-smoothing: grayscale 13 | -webkit-font-smoothing: antialiased 14 | content: $content 15 | font-family: '{{fontName}}' 16 | font-style: normal 17 | font-variant: normal 18 | font-weight: normal 19 | line-height: 1 20 | speak: none 21 | text-transform: none 22 | @content 23 | 24 | {% for icon in icons -%} 25 | =icon--{{icon.name}} 26 | +icon("\{{icon.code}}") 27 | @content 28 | 29 | .icon 30 | &.-{{icon.name}} 31 | +icon--{{icon.name}} 32 | 33 | {% endfor %} 34 | -------------------------------------------------------------------------------- /src/javascript/view.coffee: -------------------------------------------------------------------------------- 1 | _ = require 'underscore' 2 | Backbone = require 'backbone' 3 | Backbone.$ = require 'jquery' 4 | plugin = require 'plugin' 5 | 6 | module.exports = Backbone.View.extend 7 | 8 | template: require './template' 9 | 10 | initialize: -> 11 | underscoreTest = _.last([0,1,2, 'hi mom!']) 12 | @render() 13 | 14 | render: -> 15 | @$el.html @template 16 | description: 'Starter Gulp + Browserify project to demonstrate some common tasks:' 17 | tools: [ 18 | 'CommonJS bundling and watching' 19 | 'Working with multiple bundles' 20 | 'Factoring out shared dependencies' 21 | 'Live reloading across devices' 22 | 'JS transforms and compiling' 23 | 'CSS preprocessing: node-sass (Lightning fast libsass!)' 24 | 'Iconfont generation' 25 | 'Image optimization' 26 | 'Non common-js plugins with common-js dependencies' 27 | 'Using modules already bundled with other modules' 28 | ] 29 | 30 | plugin() 31 | -------------------------------------------------------------------------------- /src/icons/uE004-twitter.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Daniel Tello 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/icons/uE003-pinterest.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | -------------------------------------------------------------------------------- /src/sass/_icons.sass: -------------------------------------------------------------------------------- 1 | // DO NOT EDIT DIRECTLY! 2 | Generated by gulp/tasks/iconFont.js 3 | from ./gulp/tasks/iconFont/template.sass.swig 4 | 5 | @font-face 6 | font-family: Post-Creator-Icons 7 | src: url("fonts/Post-Creator-Icons.eot") 8 | src: url("fonts/Post-Creator-Icons.eot?#iefix") format('embedded-opentype'), url("fonts/Post-Creator-Icons.woff") format('woff'), url("fonts/Post-Creator-Icons.ttf") format('truetype'), url("fonts/Post-Creator-Icons.svg#Post-Creator-Icons") format('svg') 9 | font-weight: normal 10 | font-style: normal 11 | 12 | =icon($content) 13 | &:before 14 | -moz-osx-font-smoothing: grayscale 15 | -webkit-font-smoothing: antialiased 16 | content: $content 17 | font-family: 'Post-Creator-Icons' 18 | font-style: normal 19 | font-variant: normal 20 | font-weight: normal 21 | line-height: 1 22 | speak: none 23 | text-transform: none 24 | @content 25 | 26 | =icon--facebook 27 | +icon("\e001") 28 | @content 29 | 30 | .icon 31 | &.-facebook 32 | +icon--facebook 33 | 34 | =icon--linkedin 35 | +icon("\e002") 36 | @content 37 | 38 | .icon 39 | &.-linkedin 40 | +icon--linkedin 41 | 42 | =icon--pinterest 43 | +icon("\e003") 44 | @content 45 | 46 | .icon 47 | &.-pinterest 48 | +icon--pinterest 49 | 50 | =icon--twitter 51 | +icon("\e004") 52 | @content 53 | 54 | .icon 55 | &.-twitter 56 | +icon--twitter 57 | 58 | 59 | -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration 2 | // Generated on Fri Jan 23 2015 17:22:58 GMT-0500 (EST) 3 | 4 | module.exports = function(config) { 5 | config.set({ 6 | 7 | // base path that will be used to resolve all patterns (eg. files, exclude) 8 | basePath: '', 9 | 10 | // frameworks to use 11 | // available frameworks: https://npmjs.org/browse/keyword/karma-adapter 12 | frameworks: ['mocha', 'sinon-chai', 'browserify'], 13 | 14 | // list of files / patterns to load in the browser 15 | files: [ 16 | 'src/javascript/**/__tests__/*' 17 | ], 18 | 19 | // list of files to exclude 20 | exclude: [ 21 | ], 22 | 23 | // preprocess matching files before serving them to the browser 24 | // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor 25 | preprocessors: { 26 | 'src/javascript/**/__tests__/*': ['browserify'] 27 | }, 28 | 29 | browserify: { 30 | debug: true, 31 | extensions: ['.js', '.coffee', '.hbs'] 32 | }, 33 | 34 | // test results reporter to use 35 | // possible values: 'dots', 'progress' 36 | // available reporters: https://npmjs.org/browse/keyword/karma-reporter 37 | reporters: ['nyan'], 38 | 39 | // web server port 40 | port: 9876, 41 | 42 | // enable / disable colors in the output (reporters and logs) 43 | colors: true, 44 | 45 | // level of logging 46 | // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG 47 | logLevel: config.LOG_INFO, 48 | 49 | // enable / disable watching file and executing tests whenever any file changes 50 | autoWatch: true, 51 | 52 | // start these browsers 53 | // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher 54 | browsers: ['Chrome'], 55 | 56 | // Continuous Integration mode 57 | // if true, Karma captures browsers, runs the tests and exits 58 | singleRun: false 59 | }); 60 | }; 61 | -------------------------------------------------------------------------------- /gulp/config.js: -------------------------------------------------------------------------------- 1 | var dest = "./build"; 2 | var src = './src'; 3 | 4 | module.exports = { 5 | browserSync: { 6 | server: { 7 | // Serve up our build folder 8 | baseDir: dest 9 | } 10 | }, 11 | sass: { 12 | src: src + "/sass/**/*.{sass,scss}", 13 | dest: dest, 14 | settings: { 15 | indentedSyntax: true, // Enable .sass syntax! 16 | imagePath: 'images' // Used by the image-url helper 17 | } 18 | }, 19 | images: { 20 | src: src + "/images/**", 21 | dest: dest + "/images" 22 | }, 23 | markup: { 24 | src: src + "/htdocs/**", 25 | dest: dest 26 | }, 27 | iconFonts: { 28 | name: 'Gulp Starter Icons', 29 | src: src + '/icons/*.svg', 30 | dest: dest + '/fonts', 31 | sassDest: src + '/sass', 32 | template: './gulp/tasks/iconFont/template.sass.swig', 33 | sassOutputName: '_icons.sass', 34 | fontPath: 'fonts', 35 | className: 'icon', 36 | options: { 37 | fontName: 'Post-Creator-Icons', 38 | appendCodepoints: true, 39 | normalize: false 40 | } 41 | }, 42 | browserify: { 43 | // A separate bundle will be generated for each 44 | // bundle config in the list below 45 | bundleConfigs: [{ 46 | entries: src + '/javascript/global.coffee', 47 | dest: dest, 48 | outputName: 'global.js', 49 | // Additional file extentions to make optional 50 | extensions: ['.coffee', '.hbs'], 51 | // list of modules to make require-able externally 52 | require: ['jquery', 'backbone/node_modules/underscore'] 53 | // See https://github.com/greypants/gulp-starter/issues/87 for note about 54 | // why this is 'backbone/node_modules/underscore' and not 'underscore' 55 | }, { 56 | entries: src + '/javascript/page.js', 57 | dest: dest, 58 | outputName: 'page.js', 59 | // list of externally available modules to exclude from the bundle 60 | external: ['jquery', 'underscore'] 61 | }] 62 | }, 63 | production: { 64 | cssSrc: dest + '/*.css', 65 | jsSrc: dest + '/*.js', 66 | dest: dest 67 | } 68 | }; 69 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gulp-starter", 3 | "version": "0.1.1", 4 | "description": "Gulp starter with common tasks and scenarios", 5 | "repository": { 6 | "type": "git", 7 | "url": "git://github.com/greypants/gulp-starter.git" 8 | }, 9 | "//": [ 10 | "The following 'underscore' example demonstrates exposing a module included ", 11 | "by another module. If you were to npm install underscore separately and ", 12 | "require('underscore'), you'd end up with two copies in your bundle. The one", 13 | "you installed, and the one that shipped with another package (backbone in ", 14 | "this example). This is an edge case and should rarely happen.", 15 | "", 16 | "The 'plugin' example makes that file requireable with `require('plugin')`,", 17 | "and available to browserify-shim as 'plugin' on line 30." 18 | ], 19 | "browser": { 20 | "underscore": "backbone/node_modules/underscore", 21 | "plugin": "./src/javascript/vendor/jquery-plugin.js" 22 | }, 23 | "browserify": { 24 | "transform": [ 25 | "browserify-shim", 26 | "coffeeify", 27 | "hbsfy" 28 | ] 29 | }, 30 | "browserify-shim": { 31 | "plugin": { 32 | "exports": "plugin", 33 | "depends": [ 34 | "jquery:$" 35 | ] 36 | } 37 | }, 38 | "devDependencies": { 39 | "browser-sync": "~2.2.2", 40 | "browserify": "^9.0.3", 41 | "browserify-shim": "^3.8.2", 42 | "coffeeify": "~1.0.0", 43 | "gulp": "^3.8.11", 44 | "gulp-autoprefixer": "^2.1.0", 45 | "gulp-changed": "^1.1.1", 46 | "gulp-filesize": "0.0.6", 47 | "gulp-iconfont": "^1.0.0", 48 | "gulp-imagemin": "^2.2.1", 49 | "gulp-minify-css": "~0.5.1", 50 | "gulp-notify": "^2.2.0", 51 | "gulp-rename": "^1.2.0", 52 | "gulp-sass": "~1.3.3", 53 | "gulp-sourcemaps": "^1.5.0", 54 | "gulp-swig": "^0.7.4", 55 | "gulp-uglify": "^1.1.0", 56 | "gulp-util": "^3.0.4", 57 | "handlebars": "^3.0.0", 58 | "hbsfy": "~2.2.1", 59 | "karma": "^0.12.31", 60 | "karma-browserify": "^4.0.0", 61 | "karma-chrome-launcher": "^0.1.7", 62 | "karma-coffee-preprocessor": "^0.2.1", 63 | "karma-mocha": "^0.1.10", 64 | "karma-nyan-reporter": "0.0.51", 65 | "karma-sinon-chai": "^0.3.0", 66 | "lodash": "^3.3.1", 67 | "merge-stream": "^0.1.7", 68 | "pretty-hrtime": "~1.0.0", 69 | "require-dir": "^0.1.0", 70 | "vinyl-source-stream": "~1.0.0", 71 | "watchify": "^2.4.0" 72 | }, 73 | "dependencies": { 74 | "backbone": "~1.1.2", 75 | "jquery": "~2.1.0" 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /gulp/tasks/browserify.js: -------------------------------------------------------------------------------- 1 | /* browserify task 2 | --------------- 3 | Bundle javascripty things with browserify! 4 | 5 | This task is set up to generate multiple separate bundles, from 6 | different sources, and to use Watchify when run from the default task. 7 | 8 | See browserify.bundleConfigs in gulp/config.js 9 | */ 10 | 11 | var browserify = require('browserify'); 12 | var browserSync = require('browser-sync'); 13 | var watchify = require('watchify'); 14 | var mergeStream = require('merge-stream'); 15 | var bundleLogger = require('../util/bundleLogger'); 16 | var gulp = require('gulp'); 17 | var handleErrors = require('../util/handleErrors'); 18 | var source = require('vinyl-source-stream'); 19 | var config = require('../config').browserify; 20 | var _ = require('lodash'); 21 | 22 | var browserifyTask = function(devMode) { 23 | 24 | var browserifyThis = function(bundleConfig) { 25 | 26 | if(devMode) { 27 | // Add watchify args and debug (sourcemaps) option 28 | _.extend(bundleConfig, watchify.args, { debug: true }); 29 | // A watchify require/external bug that prevents proper recompiling, 30 | // so (for now) we'll ignore these options during development. Running 31 | // `gulp browserify` directly will properly require and externalize. 32 | bundleConfig = _.omit(bundleConfig, ['external', 'require']); 33 | } 34 | 35 | var b = browserify(bundleConfig); 36 | 37 | var bundle = function() { 38 | // Log when bundling starts 39 | bundleLogger.start(bundleConfig.outputName); 40 | 41 | return b 42 | .bundle() 43 | // Report compile errors 44 | .on('error', handleErrors) 45 | // Use vinyl-source-stream to make the 46 | // stream gulp compatible. Specify the 47 | // desired output filename here. 48 | .pipe(source(bundleConfig.outputName)) 49 | // Specify the output destination 50 | .pipe(gulp.dest(bundleConfig.dest)) 51 | .pipe(browserSync.reload({ 52 | stream: true 53 | })); 54 | }; 55 | 56 | if(devMode) { 57 | // Wrap with watchify and rebundle on changes 58 | b = watchify(b); 59 | // Rebundle on update 60 | b.on('update', bundle); 61 | bundleLogger.watch(bundleConfig.outputName); 62 | } else { 63 | // Sort out shared dependencies. 64 | // b.require exposes modules externally 65 | if(bundleConfig.require) b.require(bundleConfig.require); 66 | // b.external excludes modules from the bundle, and expects 67 | // they'll be available externally 68 | if(bundleConfig.external) b.external(bundleConfig.external); 69 | } 70 | 71 | return bundle(); 72 | }; 73 | 74 | // Start bundling with Browserify for each bundleConfig specified 75 | return mergeStream.apply(gulp, _.map(config.bundleConfigs, browserifyThis)); 76 | 77 | }; 78 | 79 | gulp.task('browserify', function() { 80 | return browserifyTask() 81 | }); 82 | 83 | // Exporting the task so we can call it directly in our watch task, with the 'devMode' option 84 | module.exports = browserifyTask; 85 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | **Lots of new stuff happening in the [2.0 branch](https://github.com/greypants/gulp-starter/tree/2.0)** 2 | 3 | **Use Rails?** Check out http://viget.com/extend/gulp-rails-asset-pipeline and https://github.com/vigetlabs/gulp-rails-pipeline 4 | 5 | gulp-starter 6 | ============ 7 | 8 | Starter Gulp + Browserify project with examples of how to accomplish some common tasks and workflows. Read the [blog post](http://viget.com/extend/gulp-browserify-starter-faq) for more context, and check out the [Wiki](https://github.com/greypants/gulp-starter/wiki) for some good background knowledge. 9 | 10 | Includes the following tools, tasks, and workflows: 11 | 12 | - [Browserify](http://browserify.org/) (with [browserify-shim](https://github.com/thlorenz/browserify-shim)) 13 | - [Watchify](https://github.com/substack/watchify) (caching version of browserify for super fast rebuilds) 14 | - [SASS](http://sass-lang.com/) (super fast libsass with [source maps](https://github.com/sindresorhus/gulp-ruby-sass#sourcemap), and [autoprefixer](https://github.com/sindresorhus/gulp-autoprefixer)) 15 | - [CoffeeScript](http://coffeescript.org/) (with source maps!) 16 | - [BrowserSync](http://browsersync.io) for live reloading and a static server 17 | - [Image optimization](https://www.npmjs.com/package/gulp-imagemin) 18 | - Error handling in the console [and in Notification Center](https://github.com/mikaelbr/gulp-notify) 19 | - Shimming non common-js vendor code with other dependencies (like a jQuery plugin) 20 | - **New** Multiple bundles with shared dependencies 21 | - **New** Separate compression task for production builds 22 | - **New** Icon Font generation 23 | 24 | If you've never used Node or npm before, you'll need to install Node. 25 | If you use homebrew, do: 26 | 27 | ``` 28 | brew install node 29 | ``` 30 | 31 | Otherwise, you can download and install from [here](http://nodejs.org/download/). 32 | 33 | ### Install npm dependencies 34 | ``` 35 | npm install 36 | ``` 37 | 38 | This runs through all dependencies listed in `package.json` and downloads them to a `node_modules` folder in your project directory. 39 | 40 | ### The `gulp` command 41 | To run the version of gulp installed local to the project, in the root of your this project, you'd run 42 | 43 | ``` 44 | ./node_modules/.bin/gulp 45 | ``` 46 | 47 | **WAT.** Why can't I just run `gulp`? Well, you could install gulp globally with `npm install -g gulp`, which will add the gulp script to your global bin folder, but it's always better to use the version that's specified in your project's package.json. My solution to this is to simply alias `./node_modules/.bin/gulp` to `gulp`. Open up `~/.zshrc` or `~./bashrc` and add the following line: 48 | 49 | ``` 50 | alias gulp='node_modules/.bin/gulp' 51 | ``` 52 | Now, running `gulp` in the project directory will use the version specified and installed from the `package.json` file. 53 | 54 | ### Run gulp and be amazed. 55 | The first time you run the app, you'll also need to generate the iconFont, since this is not something we want to run every time with our `default` task. 56 | ``` 57 | gulp iconFont 58 | ``` 59 | 60 | After that, just run the `default` gulp task with: 61 | ``` 62 | gulp 63 | ``` 64 | 65 | This will run the `default` gulp task defined in `gulp/tasks/default.js`, which has the following task dependencies: `['sass', 'images', 'markup', 'watch']` 66 | - The `sass` task compiles your css files. 67 | - `images` moves images copies images from a source folder, performs optimizations, the outputs them into the build folder 68 | - `markup` doesn't do anything but copy an html file over from src to build, but here is where you could do additional templating work. 69 | - `watch` has `watchify` as a dependency, which will run the browserifyTask with a `devMode` flag that enables sourcemaps and watchify, a browserify add-on that enables caching for super fast recompiling. The task itself starts watching source files and will re-run the appropriate tasks when those files change. 70 | 71 | ### Configuration 72 | All paths and plugin settings have been abstracted into a centralized config object in `gulp/config.js`. Adapt the paths and settings to the structure and needs of your project. 73 | 74 | ### Additional Features and Tasks 75 | 76 | #### Icon Fonts 77 | 78 | ``` 79 | gulp iconFont 80 | ``` 81 | 82 | Generating and re-generating icon fonts is an every once and a while task, so it's not included in `tasks/default.js`. Run the task separately any time you add an svg to your icons folder. This task has a couple of parts. 83 | 84 | ##### The task 85 | The task calls `gulp-iconfont` and passes the options we've configured in [`gulp/config.js`](https://github.com/greypants/gulp-starter/blob/icon-font/gulp/config.js#L27). Then it listens for a `codepoints` that triggers the generation of the sass file you'll be importing into your stylesheets. [`gulp/iconFont/generateIconSass`](./gulp/tasks/iconFont/generateIconSass.js) passes the icon data to [a template](./gulp/tasks/iconFont/template.sass.swig), then outputs the resulting file to your sass directory. See the [gulp-iconFont docs](https://github.com/nfroidure/gulp-iconfont) for more config details. You may reconfigure the template to output whatever you'd like. The way it's currently set up will make icons usable as both class names and mixins. 86 | 87 | ```sass 88 | .twitter-button 89 | +icon--twitter // (@include in .scss syntax) 90 | ``` 91 | 92 | or 93 | 94 | ```html 95 | 96 | ``` 97 | 98 | #### Production files 99 | 100 | There is also a `production` task you can run: 101 | ``` 102 | gulp production 103 | ``` 104 | This will run JavaScript tests, then re-build optimized, compressed css and js files to the build folder, as well as output their file sizes to the console. It's a shortcut for running the following tasks: `karma`, `images`, `iconFont` `minifyCss`, `uglifyJs`. 105 | 106 | #### JavaScript Tests with Karma 107 | This repo includes a basic js testing setup with the following: [Karma](http://karma-runner.github.io/0.12/index.html), [Mocha](http://mochajs.org/), [Chai](http://chaijs.com/), and [Sinon](http://sinonjs.org/). There is `karma` gulp task, which the `production` task uses to run the tests before compiling. If any tests fail, the `production` task will abort. 108 | 109 | To run the tests and start monitoring files: 110 | ``` 111 | ./node_modules/karma/bin/karma start 112 | ``` 113 | 114 | Want to just run `karma start`? Either add `alias karma="./node_modules/karma/bin/karma"` to your shell config or install the karma command line interface globally with `npm install -g karma-cli`. 115 | 116 | 117 | -- 118 | 119 | Social icons courtesy of [icomoon.io](https://icomoon.io/#icons-icomoon) 120 | 121 | Made with ♥ at [Viget](http://viget.com)! 122 | --------------------------------------------------------------------------------