ff-stream-web

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

commit b88244d9d84fa706d692e879cd3d48fcc4a225d5
parent c882f383dc0f1f9316e4a45499abe9fd33ab02e0
Author: Konstantin Tarkus <koistya@gmail.com>
Date:   Wed, 12 Aug 2015 02:27:03 +0300

Merge pull request #201 from koistya/tools

Replace Gulp with custom build automation scripts
Diffstat:
M.gitignore | 1+
MREADME.md | 29+++++++++++++++++------------
Dgulpfile.babel.js | 186-------------------------------------------------------------------------------
Mpackage.json | 38+++++++++++++++++++-------------------
Mpreprocessor.js | 7++++---
Atools/build.js | 20++++++++++++++++++++
Atools/bundle.js | 39+++++++++++++++++++++++++++++++++++++++
Atools/clean.js | 25+++++++++++++++++++++++++
Atools/config.js | 181+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Atools/copy.js | 53+++++++++++++++++++++++++++++++++++++++++++++++++++++
Atools/lib/fs.js | 33+++++++++++++++++++++++++++++++++
Atools/serve.js | 28++++++++++++++++++++++++++++
Atools/start.js | 61+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dwebpack.config.js | 166-------------------------------------------------------------------------------
14 files changed, 481 insertions(+), 386 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -3,4 +3,5 @@ build node_modules +ncp-debug.log npm-debug.log diff --git a/README.md b/README.md @@ -48,7 +48,7 @@ Join [#react-starter-kit](https://gitter.im/kriasoft/react-starter-kit) chatroom │ ├── /utils/ # Utility classes and functions │ ├── /app.js # Client-side startup script │ └── /server.js # Server-side startup script -│── gulpfile.babel.js # Configuration file for automated builds +├── /tools/ # Build automation scripts and utilities │── package.json # The list of 3rd party libraries and utilities │── preprocessor.js # ES6 transpiler settings for Jest └── webpack.config.js # Webpack configuration for bundling and optimization @@ -63,37 +63,36 @@ Just [clone](github-windows://openRepo/https://github.com/kriasoft/react-starter $ git clone -o react-starter-kit -b master --single-branch \ https://github.com/kriasoft/react-starter-kit.git MyApp $ cd MyApp -$ npm install -g gulp # Install Gulp task runner globally $ npm install # Install Node.js components listed in ./package.json +$ npm start # Compile and launch ``` ### How to Build ```shell -$ gulp build # or, `gulp build --release` +$ npm run build # or, `npm run build -- release` ``` -By default, it builds in debug mode. If you need to build in release mode, add -`--release` flag. This will minimize your JavaScript; you will also see some warnings from -[uglify](https://github.com/mishoo/UglifyJS) where it removes unused code from your release. +By default, it builds in a *debug* mode. If you need to build in a release +mode, just add `-- release` flag. This will optimize the output bundle for +production deployment. ### How to Run ```shell -$ gulp # or, `gulp --release` +$ npm start # or, `npm start -- release` ``` -This will start a lightweight development server with LiveReload and +This will start a lightweight development server with "live reload" and synchronized browsing across multiple devices and browsers. ### How to Deploy ```shell -$ gulp build --release # Builds the project in release mode -$ gulp deploy # or, `gulp deploy --production` +$ npm run deploy # or, `npm run deploy -- production` ``` -For more information see `deploy` task in `gulpfile.babel.js`. +For more information see `tools/deploy.js`. ### How to Update @@ -150,4 +149,10 @@ the file is. Name the test by appending `-test.js` to the js file. ### License -The MIT License © Konstantin Tarkus ([@koistya](https://twitter.com/koistya)), [Kriasoft](http://www.kriasoft.com) +Copyright © 2014-2015 Kriasoft, LLC. This source code is licensed under the MIT +license found in the [LICENSE.txt](https://github.com/kriasoft/react-starter-kit/blob/master/LICENSE.txt) +file. The documentation to the project is licensed under the +[CC BY-SA 4.0](http://creativecommons.org/licenses/by-sa/4.0/) license. + +--- +Made with ♥ by Konstantin Tarkus ([@koistya](https://twitter.com/koistya)) and [contributors](https://github.com/kriasoft/react-starter-kit/graphs/contributors) diff --git a/gulpfile.babel.js b/gulpfile.babel.js @@ -1,186 +0,0 @@ -/* - * React.js Starter Kit - * Copyright (c) Konstantin Tarkus (@koistya), KriaSoft LLC - * - * This source code is licensed under the MIT license found in the - * LICENSE.txt file in the root directory of this source tree. - */ - -import path from 'path'; -import cp from 'child_process'; -import gulp from 'gulp'; -import gulpLoadPlugins from 'gulp-load-plugins'; -import del from 'del'; -import mkdirp from 'mkdirp'; -import runSequence from 'run-sequence'; -import webpack from 'webpack'; -import minimist from 'minimist'; - -const $ = gulpLoadPlugins(); -const argv = minimist(process.argv.slice(2)); -const src = Object.create(null); - -let watch = false; -let browserSync; - -// The default task -gulp.task('default', ['sync']); - -// Clean output directory -gulp.task('clean', cb => { - del(['.tmp', 'build/*', '!build/.git'], {dot: true}, () => { - mkdirp('build/public', cb); - }); -}); - -// Static files -gulp.task('assets', () => { - src.assets = 'src/public/**'; - return gulp.src(src.assets) - .pipe($.changed('build/public')) - .pipe(gulp.dest('build/public')) - .pipe($.size({title: 'assets'})); -}); - -// Resource files -gulp.task('resources', () => { - src.resources = [ - 'package.json', - 'src/content*/**', - 'src/templates*/**' - ]; - return gulp.src(src.resources) - .pipe($.changed('build')) - .pipe(gulp.dest('build')) - .pipe($.size({title: 'resources'})); -}); - -// Bundle -gulp.task('bundle', cb => { - const config = require('./webpack.config.js'); - const bundler = webpack(config); - const verbose = !!argv.verbose; - let bundlerRunCount = 0; - - function bundle(err, stats) { - if (err) { - throw new $.util.PluginError('webpack', err); - } - - console.log(stats.toString({ - colors: $.util.colors.supportsColor, - hash: verbose, - version: verbose, - timings: verbose, - chunks: verbose, - chunkModules: verbose, - cached: verbose, - cachedAssets: verbose - })); - - if (++bundlerRunCount === (watch ? config.length : 1)) { - return cb(); - } - } - - if (watch) { - bundler.watch(200, bundle); - } else { - bundler.run(bundle); - } -}); - -// Build the app from source code -gulp.task('build', ['clean'], cb => { - runSequence(['assets', 'resources'], ['bundle'], cb); -}); - -// Build and start watching for modifications -gulp.task('build:watch', cb => { - watch = true; - runSequence('build', () => { - gulp.watch(src.assets, ['assets']); - gulp.watch(src.resources, ['resources']); - cb(); - }); -}); - -// Launch a Node.js/Express server -gulp.task('serve', ['build:watch'], cb => { - src.server = [ - 'build/server.js', - 'build/content/**/*', - 'build/templates/**/*' - ]; - let started = false; - let server = (function startup() { - const child = cp.fork('build/server.js', { - env: Object.assign({NODE_ENV: 'development'}, process.env) - }); - child.once('message', message => { - if (message.match(/^online$/)) { - if (browserSync) { - browserSync.reload(); - } - if (!started) { - started = true; - gulp.watch(src.server, function() { - $.util.log('Restarting development server.'); - server.kill('SIGTERM'); - server = startup(); - }); - cb(); - } - } - }); - return child; - })(); - - process.on('exit', () => server.kill('SIGTERM')); -}); - -// Launch BrowserSync development server -gulp.task('sync', ['serve'], cb => { - browserSync = require('browser-sync'); - - browserSync({ - logPrefix: 'RSK', - notify: false, - // Run as an https by setting 'https: true' - // Note: this uses an unsigned certificate which on first access - // will present a certificate warning in the browser. - https: false, - // Informs browser-sync to proxy our Express app which would run - // at the following location - proxy: 'localhost:5000' - }, cb); - - process.on('exit', () => browserSync.exit()); - - gulp.watch(['build/**/*.*'].concat( - src.server.map(file => '!' + file) - ), file => { - browserSync.reload(path.relative(__dirname, file.path)); - }); -}); - -// Deploy via Git -gulp.task('deploy', cb => { - const push = require('git-push'); - const remote = argv.production ? - 'https://github.com/{user}/{repo}.git' : - 'https://github.com/{user}/{repo}-test.git'; - push('./build', remote, cb); -}); - -// Run PageSpeed Insights -gulp.task('pagespeed', cb => { - const pagespeed = require('psi'); - // Update the below URL to the public URL of your site - pagespeed('example.com', { - strategy: 'mobile' - // By default we use the PageSpeed Insights free (no API key) tier. - // Use a Google Developer API key if you have one: http://goo.gl/RkN0vE - // key: 'YOUR_API_KEY' - }, cb); -}); diff --git a/package.json b/package.json @@ -10,7 +10,7 @@ "eventemitter3": "1.1.1", "express": "4.13.3", "fastclick": "1.0.6", - "fbjs": "0.1.0-alpha.6", + "fbjs": "0.1.0-alpha.7", "flux": "2.0.3", "front-matter": "1.0.0", "jade": "1.11.0", @@ -31,28 +31,25 @@ "csscomb": "^3.1.8", "cssnext": "^1.8.3", "del": "^1.2.0", - "eslint": "^1.0.0", - "eslint-loader": "^0.14.2", - "eslint-plugin-react": "^3.2.0", + "eslint": "^1.1.0", + "eslint-loader": "^1.0.0", + "eslint-plugin-react": "^3.2.2", "git-push": "^0.1.1", - "gulp": "^3.9.0", - "gulp-changed": "^1.3.0", - "gulp-if": "^1.2.5", - "gulp-load-plugins": "^1.0.0-rc.1", - "gulp-rename": "^1.2.2", - "gulp-size": "^1.2.3", - "gulp-util": "^3.0.6", + "glob": "^5.0.14", "jest-cli": "^0.4.18", - "minimist": "^1.1.2", "mkdirp": "^0.5.1", + "ncp": "^2.0.0", "postcss": "^4.1.16", "postcss-loader": "^0.5.1", "postcss-nested": "^0.3.2", "psi": "^1.0.6", + "react-hot-loader": "^1.2.8", "run-sequence": "^1.1.2", "style-loader": "^0.12.3", "url-loader": "^0.5.6", - "webpack": "^1.11.0" + "webpack": "^1.11.0", + "webpack-dev-middleware": "^1.2.0", + "webpack-hot-middleware": "^1.2.0" }, "jest": { "rootDir": "./src", @@ -62,12 +59,15 @@ ] }, "scripts": { - "start": "node server.js", - "lint": "eslint src gulpfile.babel.js webpack.config.js && csscomb src/components --lint", - "comb": "csscomb src/components --verbose", + "lint": "eslint src tools", + "csslint": "csscomb src/components --lint --verbose", + "csscomb": "csscomb src/components --verbose", "test": "eslint src && jest", - "build": "gulp build", - "serve": "gulp serve", - "sync": "gulp sync" + "clean": "babel-node --eval \"require('./tools/clean')().catch(err => console.log(err.stack))\"", + "copy": "babel-node --eval \"require('./tools/copy')().catch(err => console.log(err.stack))\"", + "bundle": "babel-node --eval \"require('./tools/bundle')().catch(err => console.log(err.stack))\"", + "build": "babel-node --eval \"require('./tools/build')().catch(err => console.log(err.stack))\"", + "serve": "babel-node --eval \"require('./tools/serve')().catch(err => console.log(err.stack))\"", + "start": "babel-node --eval \"require('./tools/start')().catch(err => console.log(err.stack))\"" } } diff --git a/preprocessor.js b/preprocessor.js @@ -1,6 +1,7 @@ -/* - * React.js Starter Kit - * Copyright (c) Konstantin Tarkus (@koistya), KriaSoft LLC +/** + * React Starter Kit (http://www.reactstarterkit.com/) + * + * Copyright © 2014-2015 Kriasoft, LLC. All rights reserved. * * This source code is licensed under the MIT license found in the * LICENSE.txt file in the root directory of this source tree. diff --git a/tools/build.js b/tools/build.js @@ -0,0 +1,20 @@ +/** + * React Starter Kit (http://www.reactstarterkit.com/) + * + * Copyright © 2014-2015 Kriasoft, LLC. All rights reserved. + * + * This source code is licensed under the MIT license found in the + * LICENSE.txt file in the root directory of this source tree. + */ + +/** + * Compiles the project from source files into a distributable + * format and copies it to the output (build) folder. + */ +export default async () => { + console.log('build'); + await require('./clean')(); + await require('./copy')(); + await require('./bundle')(); +}; + diff --git a/tools/bundle.js b/tools/bundle.js @@ -0,0 +1,39 @@ +/** + * React Starter Kit (http://www.reactstarterkit.com/) + * + * Copyright © 2014-2015 Kriasoft, LLC. All rights reserved. + * + * This source code is licensed under the MIT license found in the + * LICENSE.txt file in the root directory of this source tree. + */ + +import webpack from 'webpack'; +import config from './config'; + +/** + * Bundles JavaScript, CSS and images into one or more packages + * ready to be used in a browser. + */ +export default async () => new Promise((resolve, reject) => { + console.log('bundle'); + const bundler = webpack(config); + let bundlerRunCount = 0; + + function bundle(err, stats) { + if (err) { + return reject(err); + } + + console.log(stats.toString(config[0].stats)); + + if (++bundlerRunCount === (global.watch ? config.length : 1)) { + return resolve(); + } + } + + if (global.watch) { + bundler.watch(200, bundle); + } else { + bundler.run(bundle); + } +}); diff --git a/tools/clean.js b/tools/clean.js @@ -0,0 +1,25 @@ +/** + * React Starter Kit (http://www.reactstarterkit.com/) + * + * Copyright © 2014-2015 Kriasoft, LLC. All rights reserved. + * + * This source code is licensed under the MIT license found in the + * LICENSE.txt file in the root directory of this source tree. + */ + +import del from 'del'; +import fs from './lib/fs'; + +/** + * Cleans up the output (build) directory. + */ +export default () => new Promise((resolve, reject) => { + console.log('clean'); + del(['.tmp', 'build/*', '!build/.git'], {dot: true}, err => { + if (err) { + reject(err); + } else { + fs.makeDir('build/public').then(resolve, reject); + } + }); +}); diff --git a/tools/config.js b/tools/config.js @@ -0,0 +1,181 @@ +/** + * React Starter Kit (http://www.reactstarterkit.com/) + * + * Copyright © 2014-2015 Kriasoft, LLC. All rights reserved. + * + * This source code is licensed under the MIT license found in the + * LICENSE.txt file in the root directory of this source tree. + */ + +import path from 'path'; +import webpack, { DefinePlugin, BannerPlugin } from 'webpack'; +import merge from 'lodash/object/merge'; + +const DEBUG = !process.argv.includes('release'); +const WATCH = global.WATCH === undefined ? false : global.WATCH; +const VERBOSE = process.argv.includes('verbose'); +const STYLE_LOADER = 'style-loader/useable'; +const CSS_LOADER = DEBUG ? 'css-loader' : 'css-loader?minimize'; +const AUTOPREFIXER_BROWSERS = [ + 'Android 2.3', + 'Android >= 4', + 'Chrome >= 20', + 'Firefox >= 24', + 'Explorer >= 8', + 'iOS >= 6', + 'Opera >= 12', + 'Safari >= 6' +]; +const GLOBALS = { + 'process.env.NODE_ENV': DEBUG ? '"development"' : '"production"', + '__DEV__': DEBUG +}; + +// +// Common configuration chunk to be used for both +// client-side (app.js) and server-side (server.js) bundles +// ----------------------------------------------------------------------------- + +const config = { + output: { + publicPath: '/', + sourcePrefix: ' ' + }, + + cache: DEBUG, + debug: DEBUG, + + stats: { + colors: true, + reasons: DEBUG, + hash: VERBOSE, + version: VERBOSE, + timings: VERBOSE, + chunks: VERBOSE, + chunkModules: VERBOSE, + cached: VERBOSE, + cachedAssets: VERBOSE + }, + + plugins: [ + new webpack.optimize.OccurenceOrderPlugin() + ], + + resolve: { + extensions: ['', '.webpack.js', '.web.js', '.js', '.jsx'] + }, + + module: { + loaders: [{ + test: /\.txt/, + loader: 'file?name=[path][name].[ext]' + }, { + test: /\.gif/, + loader: 'url-loader?limit=10000&mimetype=image/gif' + }, { + test: /\.jpg/, + loader: 'url-loader?limit=10000&mimetype=image/jpg' + }, { + test: /\.png/, + loader: 'url-loader?limit=10000&mimetype=image/png' + }, { + test: /\.svg/, + loader: 'url-loader?limit=10000&mimetype=image/svg+xml' + }, { + test: /\.jsx?$/, + include: [ + path.resolve(__dirname, '../node_modules/react-routing/src'), + path.resolve(__dirname, '../src') + ], + loaders: [...(WATCH ? ['react-hot'] : []), 'babel-loader'] + }] + }, + + postcss: [ + require('postcss-nested')(), + require('cssnext')(), + require('autoprefixer-core')(AUTOPREFIXER_BROWSERS) + ] +}; + +// +// Configuration for the client-side bundle (app.js) +// ----------------------------------------------------------------------------- + +const appConfig = merge({}, config, { + entry: [...(WATCH ? [ + 'webpack/hot/dev-server', + 'webpack-hot-middleware/client'] : []), + './src/app.js' + ], + output: { + path: path.join(__dirname, '../build/public'), + filename: 'app.js' + }, + devtool: DEBUG ? 'source-map' : false, + plugins: [ + ...config.plugins, + new DefinePlugin(merge(GLOBALS, {'__SERVER__': false})), + ...(DEBUG ? [] : [ + new webpack.optimize.DedupePlugin(), + new webpack.optimize.UglifyJsPlugin({compress: {warnings: VERBOSE}}), + new webpack.optimize.AggressiveMergingPlugin() + ]), + ...(WATCH ? [ + new webpack.HotModuleReplacementPlugin(), + new webpack.NoErrorsPlugin() + ] : []) + ], + module: { + loaders: [...config.module.loaders, { + test: /\.css$/, + loader: `${STYLE_LOADER}!${CSS_LOADER}!postcss-loader` + }] + } +}); + +// +// Configuration for the server-side bundle (server.js) +// ----------------------------------------------------------------------------- + +const serverConfig = merge({}, config, { + entry: './src/server.js', + output: { + path: './build', + filename: 'server.js', + libraryTarget: 'commonjs2' + }, + target: 'node', + externals: [ + function (context, request, cb) { + var isExternal = + request.match(/^[a-z][a-z\/\.\-0-9]*$/i) && + !request.match(/^react-routing/) && + !context.match(/[\\/]react-routing/); + cb(null, Boolean(isExternal)); + } + ], + node: { + console: false, + global: false, + process: false, + Buffer: false, + __filename: false, + __dirname: false + }, + devtool: DEBUG ? 'source-map' : 'cheap-module-source-map', + plugins: [ + ...config.plugins, + new DefinePlugin(merge(GLOBALS, {'__SERVER__': true})), + new BannerPlugin('require("source-map-support").install();', + { raw: true, entryOnly: false }) + ], + module: { + loaders: [...config.module.loaders, { + test: /\.css$/, + loader: `${CSS_LOADER}!postcss-loader` + }] + } +}); + +export default [appConfig, serverConfig]; diff --git a/tools/copy.js b/tools/copy.js @@ -0,0 +1,53 @@ +/** + * React Starter Kit (http://www.reactstarterkit.com/) + * + * Copyright © 2014-2015 Kriasoft, LLC. All rights reserved. + * + * This source code is licensed under the MIT license found in the + * LICENSE.txt file in the root directory of this source tree. + */ + +import { ncp as copy } from 'ncp'; + +/** + * Copies static files such as robots.txt, favicon.ico to the + * output (build) folder. + */ +export default () => { + console.log('copy'); + return Promise.all([ + + // Static files + new Promise((resolve, reject) => { + copy('src/public', 'build/public', err => { + if (err) { + reject(err); + } else { + resolve(); + } + }) + }), + + // Files with content (e.g. *.md files) + new Promise((resolve, reject) => { + copy('src/content', 'build/content', err => { + if (err) { + reject(err); + } else { + resolve(); + } + }) + }), + + // Website and email templates + new Promise((resolve, reject) => { + copy('src/templates', 'build/templates', err => { + if (err) { + reject(err); + } else { + resolve(); + } + }) + }) + ]); +}; diff --git a/tools/lib/fs.js b/tools/lib/fs.js @@ -0,0 +1,33 @@ +/** + * React Starter Kit (http://www.reactstarterkit.com/) + * + * Copyright © 2014-2015 Kriasoft, LLC. All rights reserved. + * + * This source code is licensed under the MIT license found in the + * LICENSE.txt file in the root directory of this source tree. + */ + +import fs from 'fs'; +import mkdirp from 'mkdirp'; + +const writeFile = (filename, contents) => new Promise((resolve, reject) => { + fs.writeFile(filename, contents, 'utf8', err => { + if (err) { + reject(err); + } else { + resolve(); + } + }); +}); + +const makeDir = name => new Promise((resolve, reject) => { + mkdirp(name, err => { + if (err) { + reject(err); + } else { + resolve(); + } + }); +}); + +export default { writeFile, makeDir }; diff --git a/tools/serve.js b/tools/serve.js @@ -0,0 +1,28 @@ +/** + * React Starter Kit (http://www.reactstarterkit.com/) + * + * Copyright © 2014-2015 Kriasoft, LLC. All rights reserved. + * + * This source code is licensed under the MIT license found in the + * LICENSE.txt file in the root directory of this source tree. + */ + +import path from 'path'; +import cp from 'child_process'; + +/** + * Launches Node.js/Express web server in a separate (forked) process. + */ +export default () => new Promise((resolve, reject) => { + console.log('serve'); + const server = cp.fork(path.join(__dirname, '../build/server.js'), { + env: Object.assign({NODE_ENV: 'development'}, process.env) + }); + server.once('message', message => { + if (message.match(/^online$/)) { + resolve(); + } + }); + server.once('error', err => reject(error)); + process.on('exit', () => server.kill('SIGTERM')); +}); diff --git a/tools/start.js b/tools/start.js @@ -0,0 +1,61 @@ +/** + * React Starter Kit (http://www.reactstarterkit.com/) + * + * Copyright © 2014-2015 Kriasoft, LLC. All rights reserved. + * + * This source code is licensed under the MIT license found in the + * LICENSE.txt file in the root directory of this source tree. + */ + +import browserSync from 'browser-sync'; +import webpack from 'webpack'; +import webpackDevMiddleware from 'webpack-dev-middleware'; +import webpackHotMiddleware from 'webpack-hot-middleware'; + +global.WATCH = true; +const config = require('./config')[0]; // Client-side bundle configuration +const bundler = webpack(config); + +/** + * Launches a development web server with "live reload" functionality - + * synchronizing URLs, interactions and code changes across multiple devices. + */ +export default async () => { + + await require('./build')(); + await require('./serve')(); + + browserSync({ + proxy: { + + target: 'localhost:5000', + + middleware: [ + webpackDevMiddleware(bundler, { + // IMPORTANT: dev middleware can't access config, so we should + // provide publicPath by ourselves + publicPath: config.output.publicPath, + + // pretty colored output + stats: config.stats, + + hot: true, + historyApiFallback: true + + // for other settings see + // http://webpack.github.io/docs/webpack-dev-middleware.html + }), + + // bundler should be the same as above + webpackHotMiddleware(bundler) + ] + }, + + // no need to watch '*.js' here, webpack will take care of it for us, + // including full page reloads if HMR won't work + files: [ + 'build/public/**/*.css', + 'build/public/**/*.html' + ] + }); +}; diff --git a/webpack.config.js b/webpack.config.js @@ -1,166 +0,0 @@ -/* - * React.js Starter Kit - * Copyright (c) Konstantin Tarkus (@koistya), KriaSoft LLC - * - * This source code is licensed under the MIT license found in the - * LICENSE.txt file in the root directory of this source tree. - */ - -import path from 'path'; -import webpack, { DefinePlugin, BannerPlugin } from 'webpack'; -import merge from 'lodash/object/merge'; -import minimist from 'minimist'; - -const argv = minimist(process.argv.slice(2)); -const DEBUG = !argv.release; -const STYLE_LOADER = 'style-loader/useable'; -const CSS_LOADER = DEBUG ? 'css-loader' : 'css-loader?minimize'; -const AUTOPREFIXER_BROWSERS = [ - 'Android 2.3', - 'Android >= 4', - 'Chrome >= 20', - 'Firefox >= 24', - 'Explorer >= 8', - 'iOS >= 6', - 'Opera >= 12', - 'Safari >= 6' -]; -const GLOBALS = { - 'process.env.NODE_ENV': DEBUG ? '"development"' : '"production"', - '__DEV__': DEBUG -}; - -// -// Common configuration chunk to be used for both -// client-side (app.js) and server-side (server.js) bundles -// ----------------------------------------------------------------------------- - -const config = { - output: { - publicPath: './', - sourcePrefix: ' ' - }, - - cache: DEBUG, - debug: DEBUG, - - stats: { - colors: true, - reasons: DEBUG - }, - - plugins: [ - new webpack.optimize.OccurenceOrderPlugin() - ], - - resolve: { - extensions: ['', '.webpack.js', '.web.js', '.js', '.jsx'] - }, - - module: { - loaders: [ - { - test: /\.css$/, - loader: `${STYLE_LOADER}!${CSS_LOADER}!postcss-loader` - }, - { - test: /\.gif/, - loader: 'url-loader?limit=10000&mimetype=image/gif' - }, - { - test: /\.jpg/, - loader: 'url-loader?limit=10000&mimetype=image/jpg' - }, - { - test: /\.png/, - loader: 'url-loader?limit=10000&mimetype=image/png' - }, - { - test: /\.svg/, - loader: 'url-loader?limit=10000&mimetype=image/svg+xml' - }, - { - test: /\.jsx?$/, - include: [ - path.resolve(__dirname, 'node_modules/react-routing/src'), - path.resolve(__dirname, 'src') - ], - loader: 'babel-loader' - } - ] - }, - - postcss: [ - require('postcss-nested')(), - require('cssnext')(), - require('autoprefixer-core')(AUTOPREFIXER_BROWSERS) - ] -}; - -// -// Configuration for the client-side bundle (app.js) -// ----------------------------------------------------------------------------- - -const appConfig = merge({}, config, { - entry: './src/app.js', - output: { - path: './build/public', - filename: 'app.js' - }, - devtool: DEBUG ? 'source-map' : false, - plugins: config.plugins.concat([ - new DefinePlugin(merge(GLOBALS, {'__SERVER__': false})) - ].concat(DEBUG ? [] : [ - new webpack.optimize.DedupePlugin(), - new webpack.optimize.UglifyJsPlugin(), - new webpack.optimize.AggressiveMergingPlugin() - ]) - ) -}); - -// -// Configuration for the server-side bundle (server.js) -// ----------------------------------------------------------------------------- - -const serverConfig = merge({}, config, { - entry: './src/server.js', - output: { - path: './build', - filename: 'server.js', - libraryTarget: 'commonjs2' - }, - target: 'node', - externals: [ - function (context, request, cb) { - var isExternal = - request.match(/^[a-z][a-z\/\.\-0-9]*$/i) && - !request.match(/^react-routing/) && - !context.match(/[\\/]react-routing/); - cb(null, Boolean(isExternal)); - } - ], - node: { - console: false, - global: false, - process: false, - Buffer: false, - __filename: false, - __dirname: false - }, - devtool: DEBUG ? 'source-map' : 'cheap-module-source-map', - plugins: config.plugins.concat( - new DefinePlugin(merge(GLOBALS, {'__SERVER__': true})), - new BannerPlugin('require("source-map-support").install();', - { raw: true, entryOnly: false }) - ), - module: { - loaders: config.module.loaders.map(function(loader) { - // Remove style-loader - return merge(loader, { - loader: loader.loader = loader.loader.replace(STYLE_LOADER + '!', '') - }); - }) - } -}); - -export default [appConfig, serverConfig];