ff-stream-web

git clone git://archive.git.mtrnord.blog/MTRNord/ff-stream-web.git
Log | Files | Refs | README | LICENSE

commit aac5e419725b1fb9c6bad5110b7f014efc5907ae
parent 52abd70a5d8ebb43fa30922767d32405806ce483
Author: Konstantin Tarkus <hello@tarkus.me>
Date:   Fri, 29 Aug 2014 13:10:25 +0400

Refactor gulpfile.js; add BrowserSync, autoprefixer, csscomb, gh-pages, imagemin plug-ins

Diffstat:
MREADME.md | 42+++++++++++++++++++++++++++---------------
Mconfig/webpack.config.js | 16++++++++--------
Mgulpfile.js | 228++++++++++++++++++++++++++++++++++++++++---------------------------------------
Mpackage.json | 10+++++++++-
4 files changed, 159 insertions(+), 137 deletions(-)

diff --git a/README.md b/README.md @@ -1,19 +1,25 @@ # Facebook React Starter Kit -> **Web Application Front-end Starter Kit** built with [Facebook React](https://github.com/facebook/react). +> This project template is a skeleton for a typical web application or +> single-page application (SPA) based on Facebook React. You can use it +> to quickly bootstrap your web application projects. It contains only +> client-side components and development tools and is recommended to be +> paired with a server-side project similar to [ASP.NET Server Template] +> (https://github.com/kriasoft/AspNet-Server-Template). -**Source**: [https://github.com/kriasoft/React-Seed](https://github.com/kriasoft/React-Seed) +**Source**: [https://github.com/kriasoft/react-seed](https://github.com/kriasoft/React-Seed) -#### Runtime Components: +#### Runtime Components * [React](https://facebook.github.io/react/) - A JavaScript library for building user interfaces, developed by Facebook * [Bootstrap](http://getbootstrap.com/) - CSS framework for developing responsive, mobile first interfaces * [jQuery](http://jquery.com/) - a JavaScript library designed to simplify the client-side scripting of HTML -#### Development Tools: +#### Development Tools - * [Webpack](http://webpack.github.io/) - Compiles front-end source code into modules / bundles + * [BrowserSync](http://www.browsersync.io/) - Lightweight HTTP server for development * [Gulp](http://gulpjs.com/) - JavaScript streaming build system and task automation + * [Webpack](http://webpack.github.io/) - Compiles front-end source code into modules / bundles * [Karma](http://karma-runner.github.io/) - JavaScript unit-test runner (coming) * [Protractor](https://github.com/angular/protractor) - End-to-end test framework (coming) @@ -21,7 +27,6 @@ ``` . -├── /bower_components/ # 3rd party client-side libraries ├── /build/ # The folder for compiled output ├── /docs/ # Documentation files ├── /node_modules/ # Node.js-based dev tools and utilities @@ -46,7 +51,8 @@ To get started you can simply clone the repo and install the dependencies: ```shell -> git clone https://github.com/kriasoft/React-Seed MyApp && cd MyApp +> git clone -o base https://github.com/kriasoft/React-Seed MyApp +> cd MyApp > npm install -g gulp # Install Gulp task runner globally > npm install # Install Node.js components listed in ./package.json ``` @@ -54,7 +60,7 @@ To get started you can simply clone the repo and install the dependencies: To compile the application and start a dev server just run: ```shell -> gulp --watch # or, `gulp --watch --release` +> gulp # or, `gulp --release` ``` To build the project, without starting a web server run: @@ -63,18 +69,24 @@ To build the project, without starting a web server run: > gulp build # or, `gulp build --release` ``` -Now browse to the app at [http://localhost:3000/](http://localhost:3000/) +To deploy the application, run: + +```shell +> gulp deploy # or, `gulp deploy --production` +``` -### Authors +### Contributors - * [Konstantin Tarkus](https://angel.co/koistya) ([@koistya](https://twitter.com/koistya)), KriaSoft LLC +Konstantin Tarkus — [@koistya](https://twitter.com/koistya) ### Support -Need help or willing to contribute? Contact me via email: [hello@tarkus.me](mailto:hello@tarkus.me) or Skype: koistya +Have questions, feedback or need help? Contact [support@kriasoft.com](mailto:support@kriasoft.com) +or schedule a mentoring session on [codementor.io/koistya](https://www.codementor.io/koistya). ### Copyright - * Source code is licensed under the MIT License. See [LICENSE.txt](./LICENSE.txt) file in the project root. - * Documentation to the project is licensed under the [CC BY 4.0](http://creativecommons.org/licenses/by/4.0/) license. - * React logo image is a trademark of Facebook, Inc. +Source code is licensed under the MIT License. See [LICENSE.txt](./LICENSE.txt) +file in the project root. Documentation to the project is licensed under the +[CC BY 4.0](http://creativecommons.org/licenses/by/4.0/) license. React logo +image is a trademark of Facebook, Inc. diff --git a/config/webpack.config.js b/config/webpack.config.js @@ -4,13 +4,13 @@ */ /* - * Webpack Configuration - * http://webpack.github.io/docs/configuration.html + * Webpack configuration. For more information visit + * http://webpack.github.io/docs/configuration */ var webpack = require('webpack'); -module.exports = function (isDebug) { +module.exports = function (release) { return { output: { publicPatch: './build/', @@ -18,23 +18,23 @@ module.exports = function (isDebug) { filename: 'app.js' }, - cache: isDebug, - debug: isDebug, + cache: !release, + debug: !release, devtool: false, entry: './src/app.jsx', stats: { colors: true, - reasons: isDebug + reasons: !release }, - plugins: isDebug ? [] : [ + plugins: release ? [ new webpack.DefinePlugin({'process.env.NODE_ENV': '"production"'}), new webpack.optimize.DedupePlugin(), new webpack.optimize.UglifyJsPlugin(), new webpack.optimize.OccurenceOrderPlugin(), new webpack.optimize.AggressiveMergingPlugin() - ], + ] : [], module: { preLoaders: [ diff --git a/gulpfile.js b/gulpfile.js @@ -9,33 +9,53 @@ // See: https://github.com/gulpjs/gulp/blob/master/docs/API.md var gulp = require('gulp'); var $ = require('gulp-load-plugins')(); -var es = require('event-stream'); +var del = require('del'); var path = require('path'); +var merge = require('merge-stream'); var runSequence = require('run-sequence'); var webpack = require('webpack'); +var browserSync = require('browser-sync'); var argv = require('minimist')(process.argv.slice(2)); // Settings -var DEST = './build'; -var DEBUG = !argv.release; -var WATCH = !!argv.watch; -var LOG = !!argv.log; +var DEST = './build'; // The build output folder +var RELEASE = !!argv.release; // Minimize and optimize during a build? +var GOOGLE_ANALYTICS_ID = 'UA-XXXXX-X'; // https://www.google.com/analytics/web/ +var AUTOPREFIXER_BROWSERS = [ // https://github.com/ai/autoprefixer + 'ie >= 10', + 'ie_mob >= 10', + 'ff >= 30', + 'chrome >= 34', + 'safari >= 7', + 'opera >= 23', + 'ios >= 7', + 'android >= 4.4', + 'bb >= 10' +]; + +var src = {}; +var watch = false; +var reload = browserSync.reload; +var pkgs = (function () { + var temp = {}; + var map = function (source) { + for (var key in source) { + temp[key.replace(/[^a-z0-9]/gi, '')] = source[key].substring(1); + } + }; + map(require('./package.json').dependencies); + return temp; +}()); -// Node.js runtime dependencies and their version numbers -var pkgs = require('./package.json').dependencies; -Object.keys(pkgs).forEach(function (key) { return pkgs[key] = pkgs[key].substring(1); }); +// The default task +gulp.task('default', ['serve']); // Clean up -// ----------------------------------------------------------------------------- -gulp.task('clean', function (cb) { - var rimraf = require('rimraf'); - rimraf(DEST, cb); -}); +gulp.task('clean', del.bind(null, [DEST])); -// Copy vendor files -// ----------------------------------------------------------------------------- +// 3rd party libraries gulp.task('vendor', function () { - return es.merge( + return merge( gulp.src('./node_modules/jquery/dist/**') .pipe(gulp.dest(DEST + '/vendor/jquery-' + pkgs.jquery)), gulp.src('./node_modules/bootstrap/dist/fonts/**') @@ -43,50 +63,66 @@ gulp.task('vendor', function () { ); }); -// Copy static files / assets -// ----------------------------------------------------------------------------- +// Static files gulp.task('assets', function () { - return es.merge( - gulp.src('./src/assets/**') - .pipe(gulp.dest(DEST)), - gulp.src('./src/images/**') - .pipe(gulp.dest(DEST + '/images/')), - gulp.src('./src/*.html') - .pipe(DEBUG ? $.util.noop() : $.htmlmin({ - removeComments: true, - collapseWhitespace: true, - minifyJS: true - })) - .pipe(DEBUG ? $.embedlr() : $.util.noop()) - .pipe(gulp.dest(DEST)) - ); + src.assets = 'src/assets/**'; + return gulp.src(src.assets) + .pipe(gulp.dest(DEST)) + .pipe($.if(watch, reload({stream: true}))); }); -// CSS stylesheets -// ----------------------------------------------------------------------------- +// Images +gulp.task('images', function () { + src.images = 'src/images/**'; + return gulp.src(src.images) + .pipe($.cache($.imagemin({ + progressive: true, + interlaced: true + }))) + .pipe(gulp.dest(DEST + '/images')) + .pipe($.if(watch, reload({stream: true}))); +}); + +// HTML pages +gulp.task('pages', function () { + src.pages = 'src/**/*.html'; + return gulp.src(src.pages) + .pipe($.if(RELEASE, $.htmlmin({ + removeComments: true, + collapseWhitespace: true, + minifyJS: true + }))) + .pipe(gulp.dest(DEST)) + .pipe($.if(watch, reload({stream: true}))); +}); + +// CSS style sheets gulp.task('styles', function () { - return gulp.src('./src/styles/bootstrap.less') + src.styles = 'src/styles/**/*.{css,less}'; + return gulp.src('src/styles/bootstrap.less') .pipe($.plumber()) - .pipe($.less({sourceMap: DEBUG, sourceMapBasepath: __dirname})) + .pipe($.less({sourceMap: !RELEASE, sourceMapBasepath: __dirname})) .on('error', $.util.log) - .pipe(DEBUG ? $.util.noop() : $.minifyCss()) - .pipe(gulp.dest(DEST + '/css')); + .pipe($.autoprefixer(AUTOPREFIXER_BROWSERS)) + .pipe($.csscomb()) + .pipe($.if(RELEASE, $.minifyCss())) + .pipe(gulp.dest(DEST + '/css')) + .pipe($.if(watch, reload({stream: true}))); }); -// Create JavaScript bundle -// ----------------------------------------------------------------------------- +// Bundle gulp.task('bundle', function (cb) { - var bundler = webpack(require('./config/webpack.config.js')(DEBUG)); + var bundler = webpack(require('./config/webpack.config.js')(RELEASE)); function bundle (err, stats) { if (err) { throw new $.util.PluginError('webpack', err); } - LOG && $.util.log('[webpack]', stats.toString({colors: true})); + //VERBOSE && $.util.log('[webpack]', stats.toString({colors: true})); return cb(); } - if (WATCH) { + if (watch) { bundler.watch(200, bundle); } else { bundler.run(bundle); @@ -94,81 +130,48 @@ gulp.task('bundle', function (cb) { }); // Build the app from source code -// ----------------------------------------------------------------------------- gulp.task('build', ['clean'], function (cb) { - runSequence(['vendor', 'assets', 'styles', 'bundle'], cb); + runSequence(['vendor', 'assets', 'images', 'pages', 'styles', 'bundle'], cb); }); // Launch a lightweight HTTP Server -// ----------------------------------------------------------------------------- -gulp.task('serve', ['build'], function (next) { - var url = require('url'); - var server = require('ecstatic')({root: './', cache: 'no-cache', showDir: true}); - var port = 3000; - - require('http').createServer() - .on('request', function (req, res) { - // For non-existent files output the contents of /index.html page in order to make HTML5 routing work - var urlPath = url.parse(req.url).pathname; - if (urlPath === '/') { - req.url = DEST.substring(1) + '/index.html'; - } else if (['src', 'bower_components'].indexOf(urlPath.split('/')[1]) === -1) { - if (urlPath.length > 3 && - ['src', 'bower_components'].indexOf(urlPath.split('/')[1]) === -1 && - ['css', 'html', 'ico', 'js', 'png', 'txt', 'xml'].indexOf(urlPath.split('.').pop()) == -1 && - ['fonts', 'images', 'vendor', 'views'].indexOf(urlPath.split('/')[1]) == -1) { - req.url = DEST.substring(1) + '/index.html'; - } else { - req.url = DEST.substring(1) + req.url; - } - } - server(req, res); - }) - .listen(port, function () { - $.util.log('Server is listening on ' + $.util.colors.magenta('http://localhost:' + port + '/')); - next(); - }); -}); - -// Watch for changes in source files -// ----------------------------------------------------------------------------- -gulp.task('watch', ['serve'], function () { - var path = require('path'); - var lr = require('gulp-livereload'); - - // Watch for changes in source files - gulp.watch('./src/assets/**', ['assets']); - gulp.watch('./src/**/*.less', ['styles']); - - // Watch for changes in 'compiled' files - gulp.watch(DEST + '/**', function (file) { - var relPath = DEST.substring(2) + '\\' + path.relative(DEST, file.path); - $.util.log('File changed: ' + $.util.colors.magenta(relPath)); - lr.changed(file.path); +gulp.task('serve', ['build'], function () { + + browserSync({ + notify: false, + // Run as an https by uncommenting 'https: true' + // Note: this uses an unsigned certificate which on first access + // will present a certificate warning in the browser. + // https: true, + server: { + baseDir: ['build'] + } }); - lr.listen(); + gulp.watch(src.assets, ['assets']); + gulp.watch(src.images, ['images']); + gulp.watch(src.pages, ['pages']); + gulp.watch(src.styles, ['styles']); + gulp.watch(src.bundle, ['bundle']); + watch = true; }); -// Deploy to GitHub Pages. See: https://pages.github.com -// ----------------------------------------------------------------------------- -gulp.task('deploy', ['build'], function (cb) { - var url = 'https://github.com/{name}/{name}.github.io.git'; - var exec = require('child_process').exec; - var cwd = path.join(__dirname, DEST); - var cmd = 'git init && git remote add origin ' + url + ' && ' + - 'git add . && git commit -m Release && ' + - 'git push -f origin master'; - - exec(cmd, { 'cwd': cwd }, function (err, stdout, stderr) { - if (err !== null) { - cb(err); - } else { - $.util.log(stdout, stderr); - cb(); - } - }); -}); +// Deploy to GitHub Pages +gulp.task('deploy', function () { -// The default task -gulp.task('default', ['watch']); -\ No newline at end of file + // Remove temp folder + if (argv.clean) { + var os = require('os'); + var path = require('path'); + var repoPath = path.join(os.tmpdir(), 'tmpRepo'); + $.util.log('Delete ' + $.util.colors.magenta(repoPath)); + del.sync(repoPath, {force: true}); + } + + return gulp.src(DEST + '/**/*') + .pipe($.if('**/robots.txt', !argv.production ? $.replace('Disallow:', 'Disallow: /') : $.util.noop())) + .pipe($.ghPages({ + remoteUrl: 'https://github.com/{name}/{name}.github.io.git', + branch: 'master' + })); +}); diff --git a/package.json b/package.json @@ -10,12 +10,19 @@ "react": "^0.11.1" }, "devDependencies": { + "browser-sync": "^1.3.6", + "del": "^0.1.2", "ecstatic": "^0.5.4", - "event-stream": "^3.1.7", "gulp": "^3.8.7", + "gulp-autoprefixer": "0.0.10", + "gulp-cache": "^0.2.1", "gulp-changed": "^1.0.0", + "gulp-csscomb": "^3.0.2", "gulp-embedlr": "^0.5.2", + "gulp-gh-pages": "^0.3.3", "gulp-htmlmin": "^0.2.0", + "gulp-if": "^1.2.4", + "gulp-imagemin": "^1.0.1", "gulp-jshint": "^1.8.4", "gulp-less": "^1.3.5", "gulp-livereload": "^2.1.1", @@ -27,6 +34,7 @@ "jshint-stylish": "^0.4.0", "jsx-loader": "^0.11.0", "karma": "^0.12.23", + "merge-stream": "^0.1.5", "minimist": "^1.1.0", "protractor": "^1.1.1", "rimraf": "^2.2.8",