Skip to content

Instantly share code, notes, and snippets.

@llazzaro
Forked from insin/gulpfile.js
Created August 20, 2014 13:23
Show Gist options
  • Save llazzaro/3dacb6e1bac7b3c2eac3 to your computer and use it in GitHub Desktop.
Save llazzaro/3dacb6e1bac7b3c2eac3 to your computer and use it in GitHub Desktop.
/*
gulpfile from one of my React applications which has a gulp --production build
set up.
Assumptions:
1. All your own .js/.jsx modules are somewhere under ./src, have unique
filenames and use Node.js-style requires WITHOUT any path information, just
the name of another module somewhere under ./src
2. Dependencies are stored in the following directory structure:
./vendor
/js - uncompressed / dev builds of JS deps
/ min - pre-minified versions of JS deps
/css - uncompressed / dev builds of CSS deps
/ min - pre-minified versions of CSS deps
3. JS and CSS dependency filenames are in dep-name-1.2.3(.ext|.min.ext) format
Assumptions specific to the app this was pulled from:
1. Things there are only one of:
- Single JS entry point in ./src/app.js
- Single CSS file in ./public/css/style.css
- Single HTML file in ./public/index.html
2. Using Bootstrap, with glpyhicon fonts in ./vendor/fonts
*/
var gulp = require('gulp')
var glob = require('glob')
var browserify = require('gulp-browserify')
var clean = require('gulp-clean')
var concat = require('gulp-concat')
var flatten = require('gulp-flatten')
var jshint = require('gulp-jshint')
var minifyCSS = require('gulp-minify-css')
var plumber = require('gulp-plumber')
var react = require('gulp-react')
var rename = require('gulp-rename')
var template = require('gulp-template')
var uglify = require('gulp-uglify')
var gutil = require('gulp-util')
// foo/bar/something-whatevs-1.2.3.blah => something-whatevs
function depName(path) { return path.split('/').pop().split(/-\d/).shift() }
// Creates a sorter which sorts files acording an object which maps dep names
// (see depname()) to orders.
function depSorter(order) {
return function(a, b) { return order[depName(a)] - order[depName(b)] }
}
// foo/bar/something-whatevs-1.2.3.blah => something-whatevs-1.2.3.blah
function fileName(path) { return path.split('/').pop() }
// Creates front-end paths with the given prefix and path file name (see fileName())
function browserPaths(prefix, paths) {
return paths.map(function(path) { return prefix + fileName(path) })
}
// Props are portion of dependency filenames prior to the version number
var jsDepOrder = {
jquery: 1
, bootstrap: 2
, react: 3
, validator: 4
}
var cssDepOrder = {
bootstrap: 1
, 'bootstrap-theme': 2
}
// JS files to be copied to /dist
var depDistJS = glob.sync(gutil.env.production
? './vendor/js/min/*.js'
: './vendor/js/*.js').sort(depSorter(jsDepOrder))
var appDistJS = gutil.env.production ? './build/js/app.min.js' : './build/js/app.js'
var allDistJS = depDistJS.concat(appDistJS)
// Paths to be used as <script> src attributes
var headScripts = browserPaths('js/', allDistJS)
var appScript = headScripts.pop()
// CSS files to be copied to /dist
var depDistCSS = glob.sync(gutil.env.production
? './vendor/css/min/*.css'
: './vendor/css/*.css').sort(depSorter(cssDepOrder))
var appDistCSS = gutil.env.production ? './build/css/style.min.css' : './build/css/style.css'
var allDistCSS = depDistCSS.concat(appDistCSS)
// Paths to be used as <link> href attributes
var headStyles = browserPaths('css/', allDistCSS)
// Deletes everything in the build and dist directories
gulp.task('clean', function() {
return gulp.src(['./build', './dist'], {read: false})
.pipe(clean())
})
// Copies .js files directly into the build modules dir
gulp.task('copy-js-src', function() {
return gulp.src('./src/**/*.js')
.pipe(flatten())
.pipe(gulp.dest('./build/modules'))
})
// Compiles .jsx files to .js and copies directly into the build modules dir
gulp.task('compile-jsx', function() {
return gulp.src('./src/**/*.jsx')
.pipe(plumber())
.pipe(react())
.on('error', function(e) {
console.error(e.message + '\n in ' + e.fileName)
})
.pipe(flatten())
.pipe(gulp.dest('./build/modules'))
})
// Lints the build modules dir
gulp.task('lint', ['copy-js-src', 'compile-jsx'], function() {
return gulp.src('./build/modules/*.js')
.pipe(jshint('./.jshintrc'))
.pipe(jshint.reporter('jshint-stylish'))
})
// Bundles the app into a single file, hooking up the flat requires with same-
// named modules in the build modules dir.
gulp.task('build-js', ['lint'], function(){
var stream = gulp.src(['./build/modules/app.js'])
.pipe(plumber())
.pipe(browserify({
debug: !gutil.env.production
}))
.on('prebundle', function(bundle) {
// Setting cwd as gulp-browserify is forcing browserify's basedir to be
// the dir containing the entry file.
glob.sync('*.js', {cwd: './build/modules'}).forEach(function(module) {
var expose = module.split('.').shift()
if (expose == 'app') return
bundle.require('./' + module, {expose: expose})
})
})
.on('error', function(e) {
console.error(e)
})
.pipe(concat('app.js'))
.pipe(gulp.dest('./build/js'))
if (gutil.env.production) {
stream = stream
.pipe(rename('app.min.js'))
.pipe(uglify())
.pipe(gulp.dest('./build/js'))
}
return stream
})
// Minifies CSS if this is a production build
gulp.task('build-css', function() {
var stream = gulp.src('./public/css/*.css')
.pipe(gulp.dest('./build/css'))
if (gutil.env.production) {
stream = stream
.pipe(minifyCSS())
.pipe(rename({ext: '.min.css'}))
.pipe(gulp.dest('./build/css'))
}
return stream
})
// Templates index.html to link to the appropriate resources for the environment
// being built for.
gulp.task('dist-html', function() {
return gulp.src('./public/index.html')
.pipe(template({
headScripts: headScripts
, appScript: appScript
, headStyles: headStyles
}))
.pipe(gulp.dest('./dist'))
})
// Copies built JS and dependencies to /dist
gulp.task('dist-js', ['build-js'], function() {
return gulp.src(allDistJS)
.pipe(gulp.dest('./dist/js'))
})
// Copies built CSS and dependencies to /dist
gulp.task('dist-css', ['build-css'], function() {
return gulp.src(allDistCSS)
.pipe(gulp.dest('./dist/css'))
})
// Copies images to /dist
gulp.task('dist-img', function() {
return gulp.src('./public/img/*')
.pipe(gulp.dest('./dist/img'))
})
// Copies fonts to /dist (for Bootstrap glyphicons)
gulp.task('dist-fonts', function() {
return gulp.src('./vendor/fonts/*')
.pipe(gulp.dest('./dist/fonts'))
})
// Rebuild/copy to dist when resources are changed
gulp.task('watch', function() {
gulp.watch(['./src/**/*.js', './src/**/*.jsx'], ['dist-js'])
gulp.watch('./public/css/*.css', ['dist-css'])
gulp.watch('./public/img/*', ['dist-img'])
gulp.watch('./public/index.html', ['dist-html'])
})
gulp.task('default', ['clean'], function() {
gulp.start('dist-js', 'dist-css', 'dist-img', 'dist-html', 'dist-fonts', 'watch')
})
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title></title>
<% _.forEach(headStyles, function(href) { %>
<link rel="stylesheet" href="<%= href %>"><% }); %>
<% _.forEach(headScripts, function(src) { %>
<script src="<%= src %>"></script><% }); %>
</head>
<body>
<script src="<%= appScript %>"></script>
</body>
</html>
{
"devDependencies": {
"browserify": "~3.20.0",
"glob": "~3.2.8",
"gulp": "~3.5.0",
"gulp-browserify": "~0.3.4",
"gulp-clean": "~0.2.4",
"gulp-concat": "~2.1.7",
"gulp-flatten": "0.0.2",
"gulp-jshint": "~1.3.4",
"gulp-minify-css": "~0.2.0",
"gulp-plumber": "~0.5.6",
"gulp-react": "~0.1.2",
"gulp-rename": "~0.2.2",
"gulp-template": "~0.1.1",
"gulp-uglify": "~0.2.0",
"gulp-util": "~2.2.13",
"jshint-stylish": "~0.1.5"
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment