Skip to content

Instantly share code, notes, and snippets.

@insin
Last active September 15, 2016 08:35
Show Gist options
  • Star 15 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save insin/8521968 to your computer and use it in GitHub Desktop.
Save insin/8521968 to your computer and use it in GitHub Desktop.
gulpfile for use with React, with flat imports from uniquely-named modules under /src
/*
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"
}
}
@yairEO
Copy link

yairEO commented Mar 17, 2014

where does this gutil.env.production variable is coming from?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment