Skip to content

Commit

Permalink
refactor(project): simplify config files
Browse files Browse the repository at this point in the history
  • Loading branch information
David Zukowski committed Dec 2, 2016
1 parent c135b61 commit ad5924a
Show file tree
Hide file tree
Showing 11 changed files with 86 additions and 100 deletions.
12 changes: 5 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,9 +91,7 @@ The application structure presented in this boilerplate is **fractal**, where fu
```
.
├── bin # Build/Start scripts
├── build # All build-related configuration
│ └── webpack # Environment-specific configuration files for webpack
├── config # Project configuration settings
├── config # Project and build configurations
├── server # Express application that provides webpack middleware
│ └── main.js # Server application entry point
├── src # Application source code
Expand Down Expand Up @@ -144,7 +142,7 @@ Then follow the [manual integration walkthrough](https://github.com/gaearon/redu
We use `react-router` [route definitions](https://github.com/reactjs/react-router/blob/master/docs/API.md#plainroute) (`<route>/index.js`) to define units of logic within our application. See the [application structure](#application-structure) section for more information.

## Testing
To add a unit test, simply create a `.spec.js` file anywhere in `~/tests`. Karma will pick up on these files automatically, and Mocha and Chai will be available within your test without the need to import them. Coverage reports will be compiled to `~/coverage` by default. If you wish to change what reporters are used and where reports are compiled, you can do so by modifying `coverage_reporters` in `~/config/index.js`.
To add a unit test, simply create a `.spec.js` file anywhere in `~/tests`. Karma will pick up on these files automatically, and Mocha and Chai will be available within your test without the need to import them. Coverage reports will be compiled to `~/coverage` by default. If you wish to change what reporters are used and where reports are compiled, you can do so by modifying `coverage_reporters` in `~/config/project.config.js`.

## Deployment
Out of the box, this starter kit is deployable by serving the `~/dist` folder generated by `npm run deploy` (make sure to specify your target `NODE_ENV` as well). This project does not concern itself with the details of server-side rendering or API structure, since that demands an opinionated structure that makes it difficult to extend the starter kit. However, if you do need help with more advanced deployment strategies, here are a few tips:
Expand All @@ -156,9 +154,9 @@ If you are serving the application via a web server such as nginx, make sure to

### Configuration

Default project configuration can be found in `~/config/index.js`. Here you'll be able to redefine your `src` and `dist` directories, adjust compilation settings, tweak your vendor dependencies, and more. For the most part, you should be able to make changes in here **without ever having to touch the actual webpack build configuration**.
Default project configuration can be found in `~/config/project.config.js`. Here you'll be able to redefine your `src` and `dist` directories, adjust compilation settings, tweak your vendor dependencies, and more. For the most part, you should be able to make changes in here **without ever having to touch the actual webpack build configuration**.

If you need environment-specific overrides (useful for dynamically setting API endpoints, for example), you can edit `~/config/environments.js` and define overrides on a per-NODE_ENV basis. There are examples for both `development` and `production`, so use those as guidelines. Here are some common configuration options:
If you need environment-specific overrides (useful for dynamically setting API endpoints, for example), you can edit `~/config/environments.config.js` and define overrides on a per-NODE_ENV basis. There are examples for both `development` and `production`, so use those as guidelines. Here are some common configuration options:

|Key|Description|
|---|-----------|
Expand All @@ -182,7 +180,7 @@ import SomeComponent from 'components/SomeComponent' // Hooray!

### Globals

These are global variables available to you anywhere in your source code. If you wish to modify them, they can be found as the `globals` key in `~/config/index.js`. When adding new globals, make sure you also add them to `~/.eslintrc`.
These are global variables available to you anywhere in your source code. If you wish to modify them, they can be found as the `globals` key in `~/config/project.config.js`. When adding new globals, make sure you also add them to `~/.eslintrc`.

|Variable|Description|
|---|---|
Expand Down
39 changes: 33 additions & 6 deletions bin/compile.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,48 @@
const fs = require('fs-extra')
const webpack = require('webpack')
const debug = require('debug')('app:bin:compile')
const webpackCompiler = require('../build/webpack-compiler')
const webpackConfig = require('../build/webpack.config')
const config = require('../config')
const webpackConfig = require('../configs/webpack.config')
const project = require('../project')

const paths = config.utils_paths
// Wrapper around webpack to promisify its compiler and supply friendly logging
const webpackCompiler = (webpackConfig) =>
Promise((resolve, reject) => {
const compiler = webpack(webpackConfig)

compiler.run((err, stats) => {
if (err) {
debug('Webpack compiler encountered a fatal error.', err)
return reject(err)
}

const jsonStats = stats.toJson()
debug('Webpack compile completed.')
debug(stats.toString(project.compiler_stats))

if (jsonStats.errors.length > 0) {
debug('Webpack compiler encountered errors.')
debug(jsonStats.errors.join('\n'))
return reject(new Error('Webpack compiler encountered errors'))
} else if (jsonStats.warnings.length > 0) {
debug('Webpack compiler encountered warnings.')
debug(jsonStats.warnings.join('\n'))
} else {
debug('No errors or warnings encountered.')
}
resolve(jsonStats)
})
})

const compile = () => {
debug('Starting compiler.')
return Promise.resolve()
.then(() => webpackCompiler(webpackConfig))
.then(stats => {
if (stats.warnings.length && config.compiler_fail_on_warning) {
if (stats.warnings.length && project.compiler_fail_on_warning) {
throw new Error('Config set to fail on warning, exiting with status code "1".')
}
debug('Copying static assets to dist folder.')
fs.copySync(paths.client('static'), paths.dist())
fs.copySync(project.paths.client('static'), project.paths.dist())
})
.then(() => {
debug('Compilation completed successfully.')
Expand Down
6 changes: 6 additions & 0 deletions bin/dev-server.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
const project = require('../config/project.config')
const server = require('../server/main')
const debug = require('debug')('app:bin:dev-server')

server.listen(project.server_port)
debug(`Server is now running at http://localhost:${project.server_port}.`)
7 changes: 0 additions & 7 deletions bin/server.js

This file was deleted.

36 changes: 0 additions & 36 deletions build/webpack-compiler.js

This file was deleted.

File renamed without changes.
18 changes: 9 additions & 9 deletions build/karma.conf.js → config/karma.config.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
const argv = require('yargs').argv
const config = require('../config')
const project = require('./project.config')
const webpackConfig = require('./webpack.config')
const debug = require('debug')('app:karma')
const debug = require('debug')('app:config:karma')

debug('Creating configuration.')
const karmaConfig = {
basePath : '../', // project root in relation to bin/karma.js
files : [
{
pattern : `./${config.dir_test}/test-bundler.js`,
pattern : `./${project.dir_test}/test-bundler.js`,
watched : false,
served : true,
included : true
Expand All @@ -18,7 +18,7 @@ const karmaConfig = {
frameworks : ['mocha'],
reporters : ['mocha'],
preprocessors : {
[`${config.dir_test}/test-bundler.js`] : ['webpack']
[`${project.dir_test}/test-bundler.js`] : ['webpack']
},
browsers : ['PhantomJS'],
webpack : {
Expand Down Expand Up @@ -53,19 +53,19 @@ const karmaConfig = {
noInfo : true
},
coverageReporter : {
reporters : config.coverage_reporters
reporters : project.coverage_reporters
}
}

if (config.globals.__COVERAGE__) {
if (project.globals.__COVERAGE__) {
karmaConfig.reporters.push('coverage')
karmaConfig.webpack.module.preLoaders = [{
test : /\.(js|jsx)$/,
include : new RegExp(config.dir_client),
include : new RegExp(project.dir_client),
exclude : /node_modules/,
loader : 'babel',
query : Object.assign({}, config.compiler_babel, {
plugins : (config.compiler_babel.plugins || []).concat('istanbul')
query : Object.assign({}, project.compiler_babel, {
plugins : (project.compiler_babel.plugins || []).concat('istanbul')
})
}]
}
Expand Down
6 changes: 3 additions & 3 deletions config/index.js → config/project.config.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* eslint key-spacing:0 spaced-comment:0 */
const path = require('path')
const debug = require('debug')('app:config')
const debug = require('debug')('app:config:project')
const argv = require('yargs').argv
const ip = require('ip')

Expand Down Expand Up @@ -109,7 +109,7 @@ function base () {
return path.resolve.apply(path, args)
}

config.utils_paths = {
config.paths = {
base : base,
client : base.bind(null, config.dir_client),
dist : base.bind(null, config.dir_dist)
Expand All @@ -119,7 +119,7 @@ config.utils_paths = {
// Environment Configuration
// ========================================================
debug(`Looking for environment overrides for NODE_ENV "${config.env}".`)
const environments = require('./environments')
const environments = require('./environments.config')
const overrides = environments[config.env]
if (overrides) {
debug('Found overrides, applying to default configuration.')
Expand Down
37 changes: 18 additions & 19 deletions build/webpack.config.js → config/webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,44 +3,43 @@ const webpack = require('webpack')
const cssnano = require('cssnano')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const ExtractTextPlugin = require('extract-text-webpack-plugin')
const config = require('../config')
const debug = require('debug')('app:webpack:config')
const project = require('./project.config')
const debug = require('debug')('app:config:webpack')

const paths = config.utils_paths
const __DEV__ = config.globals.__DEV__
const __PROD__ = config.globals.__PROD__
const __TEST__ = config.globals.__TEST__
const __DEV__ = project.globals.__DEV__
const __PROD__ = project.globals.__PROD__
const __TEST__ = project.globals.__TEST__

debug('Creating configuration.')
const webpackConfig = {
name : 'client',
target : 'web',
devtool : config.compiler_devtool,
devtool : project.compiler_devtool,
resolve : {
root : paths.client(),
root : project.paths.client(),
extensions : ['', '.js', '.jsx', '.json']
},
module : {}
}
// ------------------------------------
// Entry Points
// ------------------------------------
const APP_ENTRY = paths.client('main.js')
const APP_ENTRY = project.paths.client('main.js')

webpackConfig.entry = {
app : __DEV__
? [APP_ENTRY].concat(`webpack-hot-middleware/client?path=${config.compiler_public_path}__webpack_hmr`)
? [APP_ENTRY].concat(`webpack-hot-middleware/client?path=${project.compiler_public_path}__webpack_hmr`)
: [APP_ENTRY],
vendor : config.compiler_vendors
vendor : project.compiler_vendors
}

// ------------------------------------
// Bundle Output
// ------------------------------------
webpackConfig.output = {
filename : `[name].[${config.compiler_hash_type}].js`,
path : paths.dist(),
publicPath : config.compiler_public_path
filename : `[name].[${project.compiler_hash_type}].js`,
path : project.paths.dist(),
publicPath : project.compiler_public_path
}

// ------------------------------------
Expand All @@ -55,11 +54,11 @@ webpackConfig.externals['react/addons'] = true
// Plugins
// ------------------------------------
webpackConfig.plugins = [
new webpack.DefinePlugin(config.globals),
new webpack.DefinePlugin(project.globals),
new HtmlWebpackPlugin({
template : paths.client('index.html'),
template : project.paths.client('index.html'),
hash : false,
favicon : paths.client('static/favicon.ico'),
favicon : project.paths.client('static/favicon.ico'),
filename : 'index.html',
inject : 'body',
minify : {
Expand Down Expand Up @@ -122,7 +121,7 @@ webpackConfig.module.loaders = [{
test : /\.(js|jsx)$/,
exclude : /node_modules/,
loader : 'babel',
query : config.compiler_babel
query : project.compiler_babel
}, {
test : /\.json$/,
loader : 'json'
Expand Down Expand Up @@ -156,7 +155,7 @@ webpackConfig.module.loaders.push({
})

webpackConfig.sassLoader = {
includePaths : paths.client('styles')
includePaths : project.paths.client('styles')
}

webpackConfig.postcss = [
Expand Down
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
}
},
"dev": {
"command": "nodemon bin/server --ignore dist --ignore coverage --ignore tests --ignore src",
"command": "nodemon bin/dev-server --ignore dist --ignore coverage --ignore tests --ignore src",
"env": {
"NODE_ENV": "development",
"DEBUG": "app:*"
Expand All @@ -56,13 +56,13 @@
}
},
"start": {
"command": "node bin/server",
"command": "node bin/dev-server",
"env": {
"DEBUG": "app:*"
}
},
"test": {
"command": "node ./node_modules/karma/bin/karma start build/karma.conf",
"command": "node ./node_modules/karma/bin/karma start config/karma.config",
"env": {
"NODE_ENV": "test",
"DEBUG": "app:*"
Expand Down
19 changes: 9 additions & 10 deletions server/main.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
const express = require('express')
const debug = require('debug')('app:server')
const webpack = require('webpack')
const webpackConfig = require('../build/webpack.config')
const config = require('../config')
const webpackConfig = require('../config/webpack.config')
const project = require('../config/project.config')
const compress = require('compression')

const app = express()
const paths = config.utils_paths

// This rewrites all routes requests to the root /index.html file
// (ignoring file requests). If you want to implement universal
Expand All @@ -19,26 +18,26 @@ app.use(compress())
// ------------------------------------
// Apply Webpack HMR Middleware
// ------------------------------------
if (config.env === 'development') {
if (project.env === 'development') {
const compiler = webpack(webpackConfig)

debug('Enable webpack dev and HMR middleware')
app.use(require('webpack-dev-middleware')(compiler, {
publicPath : webpackConfig.output.publicPath,
contentBase : paths.client(),
contentBase : project.paths.client(),
hot : true,
quiet : config.compiler_quiet,
noInfo : config.compiler_quiet,
quiet : project.compiler_quiet,
noInfo : project.compiler_quiet,
lazy : false,
stats : config.compiler_stats
stats : project.compiler_stats
}))
app.use(require('webpack-hot-middleware')(compiler))

// Serve static assets from ~/src/static since Webpack is unaware of
// these files. This middleware doesn't need to be enabled outside
// of development since this directory will be copied into ~/dist
// when the application is compiled.
app.use(express.static(paths.client('static')))
app.use(express.static(project.paths.client('static')))
} else {
debug(
'Server is being run outside of live development mode, meaning it will ' +
Expand All @@ -51,7 +50,7 @@ if (config.env === 'development') {
// Serving ~/dist by default. Ideally these files should be served by
// the web server and not the app server, but this helps to demo the
// server in production.
app.use(express.static(paths.dist()))
app.use(express.static(project.paths.dist()))
}

module.exports = app

0 comments on commit ad5924a

Please sign in to comment.