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:
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];