nwb's default setup can get you developing, testing and building production-ready apps and npm-ready components out of the box without any configuration.
If you need to tweak the default setup to suit your project's needs, or you want to use some of the other features the Babel, Karma and Webpack ecosystems have to offer, you can provide a configuration file.
You can also add new functionality by installing a plugin module.
By default, nwb will look for an nwb.config.js
file in the current working directory for configuration.
You can also specify a configuration file using the --config
option:
nwb --config ./config/nwb.js
This file should export either a configuration object...
module.exports = {
// ...
}
...or a function which returns a configuration object when called:
module.exports = function(args) {
return {
// ...
}
}
If a function is exported, it will be passed an object with the following properties:
command
: the name of the command currently being executed, e.g.'build'
or'test'
webpack
: nwb's version of thewebpack
module, giving you access to the other plugins webpack provides
- react-hn's
nwb.config.js
is a simple configuration file with minor tweaks to Babel and Webpack config. - React Yelp Clone's
nwb.config.js
configures Babel, Karma and Webpack to allow nwb to be dropped into an existing app to handle its development tooling, reducing the amount ofdevDependencies
and configuration which need to be managed.
The configuration object can include the following properties:
- nwb Configuration
- Babel Configuration
babel
babel.cherryPick
- enable cherry-picking for destructuredimport
statementsbabel.loose
- enable loose mode for Babel plugins which support itbabel.plugins
- extra Babel plugins to be usedbabel.presets
- extra Babel presets to be usedbabel.runtime
- enable thetransform-runtime
plugin with different configurationsbabel.stage
- control which experimental and upcoming JavaScript features can be used
- Webpack Configuration
webpack
webpack.aliases
- rewrite certain import pathswebpack.autoprefixer
- options for Autoprefixerwebpack.compat
- enable Webpack compatibility tweaks for commonly-used moduleswebpack.define
- options forDefinePlugin
, for replacing certain expressions with valueswebpack.extractText
- options forExtractTextPlugin
webpack.html
- options forHtmlPlugin
webpack.install
- options forNpmInstallPlugin
webpack.loaders
- tweak the configuration of the default Webpack loaderswebpack.postcss
- custom PostCSS pluginswebpack.publicPath
- path to static resourceswebpack.uglify
- options for Webpack'sUglifyJsPlugin
webpack.extra
- an escape hatch for extra Webpack config, which will be merged into the generated config
- Karma Configuration
karma
karma.browsers
- browsers tests are run inkarma.frameworks
- testing frameworkkarma.plugins
- additional Karma pluginskarma.reporters
- test results reporterkarma.testContext
- point to a Webpack context module for your testskarma.testDirs
- directories containing test code which should be ignored in code coveragekarma.testFiles
- patterns for test fileskarma.extra
- an escape hatch for extra Karma config, which will be merged into the generated config
- npm Build Configuration
npm
npm.esModules
- UMD build
npm.umd
- enable a UMD build which exports a global variableumd.global
- global variable name exported by UMD buildumd.externals
- dependencies to use via global variables in UMD build
package.json
fields
nwb uses this field to determine which type of project it's working with when generic build commands like build
are used.
It must be one of:
'react-app'
'react-component'
'web-app'
'web-module'
For apps, nwb will provide polyfills for Promise
, fetch
and Object.assign
by default.
To disable this, set polyfill
to false
:
module.exports = {
polyfill: false
}
Babel configuration can be provided in a babel
object, using the following properties.
For Webpack builds, any Babel config provided will be used to configure
babel-loader
- you can also provide additional configuration inwebpack.loaders
if necessary.
Note: this feature only works if you're using ES6 import
syntax.
Module names to apply import
cherry-picking to.
If you import a module with destructuring, the entire module will normally be included in your build, even though you're only using specific pieces:
import {Col, Grid, Row} from 'react-bootstrap'
The usual workaround for this is to individually import submodules, which is tedious and bloats import sections in your code:
import Col from 'react-bootstrap/lib/Col'
import Grid from 'react-bootstrap/lib/Grid'
import Row from 'react-bootstrap/lib/Row'
If you use cherryPick
config, you can keep writing code like the first example, but transpile to the same code as the second, by specifying the module name(s) to apply a cherry-picking transform to:
module.exports = {
babel: {
cherryPick: 'react-bootstrap'
}
}
This is implemented using babel-plugin-lodash - please check its issues for compatibility problems with modules you're using cherryPick
with and report any new ones you find.
Some Babel plugins have a loose mode in which they output simpler, potentially faster code rather than following the semantics of the ES6 spec closely.
Loose mode is enabled by default with nwb.
If you want to disable loose mode (e.g. to check your code works in the stricter normal mode for forward-compatibility purposes), set it to false
.
e.g. to disable loose mode only when running tests:
module.exports = {
babel {
loose: process.env.NODE_ENV === 'test'
}
}
Additional Babel plugins to use.
nwb commands are run in the current working directory, so if you need to configure additional Babel plugins or presets, you can install them locally, pass their names and let Babel import them for you.
e.g. to install and use the babel-plugin-react-html-attrs plugin:
npm install babel-plugin-react-html-attrs
module.exports = {
babel: {
plugins: ['react-html-attrs']
}
}
Additional Babel presets to use.
Babel's runtime transform does 3 things by default:
- Imports helper modules from
babel-runtime
instead of duplicating helpers in every module which needs them. - Imports a local polyfill for new ES6 builtins (
Promise
) and static methods (e.g.Object.assign
) when they're used in your code. - Imports the regenerator runtime required to use
async
/await
when needed.
nwb's default config turns the regenerator runtime import on so you can use async
/await
and generators by default.
To enable an additional feature, you can name it (either 'helpers'
or 'polyfill'
):
module.exports = {
babel: {
runtime: 'helpers'
}
}
To enable all features, set runtime
to true
.
To disable use of the runtime transform, set runtime
to false
.
nwb implements its own equivalent of Babel 5's
stage
config for Babel 6
Controls which Babel preset will be used to enable use of experimental, proposed and upcoming JavaScript features in your code, grouped by the stage they're at in the TC39 process for proposing new JavaScript features:
Stage | TC39 Category | Features |
---|---|---|
0 | Strawman, just an idea | do {...} expressions, :: function bind operator |
1 | Proposal: this is worth working on | export extensions |
2 | Draft: initial spec | class properties, object rest/spread syntax, @decorator syntax ( using the Babel Legacy Decorator plugin) - enabled by default |
3 | Candidate: complete spec and initial browser implementations | trailing function commas, async /await , ** exponentiation operator |
e.g. if you want to use export extensions in your app, you should set stage
to 1
:
module.exports = {
babel {
stage: 1
}
}
Stage 2 is enabled by default - to disable use of a stage preset entirely, set stage
to false
:
module.exports = {
babel {
stage: false
}
}
Webpack configuration can be provided in a webpack
object, using the following properties:
Configures Webpack aliases, which allow you to control module resolution. Typically aliases are used to make it easier to import certain modules from within any depth of nested directories in an app.
module.exports = {
webpack: {
aliases: {
// Enable use of 'img/file.png' paths in JavaScript and
// "~images/file.png" paths in stylesheets to require an image from
// src/images from anywhere in the the app.
'img': path.resolve('src/images'),
// Enable use of require('src/path/to/module.js') for top-down imports
// from anywhere in the app, to promote writing location-independent
// code by avoiding ../ directory traversal.
'src': path.resolve('src')
}
}
}
You should be careful to avoid creating aliases which conflict with the names of Node.js builtins or npm packages, as you will be unable to import them.
Configures Autoprefixer options for nwb's default PostCSS configuration.
If you just need to configure the range of browsers prefix addition/removal is based on (nwb's default is >1%, last 4 versions, Firefox ESR, not ie < 9
), you can use a String:
module.exports = {
webpack: {
autoprefixer: '> 1%, last 2 versions, Firefox ESR, ios >= 8'
}
}
Use an Object if you need to set any of Autoprefixer's other options.
e.g. if you also want to disable removal of prefixes which aren't required for the configured range of browsers:
module.exports = {
webpack: {
autoprefixer: {
remove: false,
}
}
}
You can check which browsers your Autoprefixer configuration will target using the browserl.ist service.
Certain libraries require specific configuration to play nicely with Webpack - nwb can take care of the details for you if you use a compat
object to tell it when you're using them.
The following libraries are supported:
Set to true
for Enzyme compatibility - this assumes you're using the latest version of React (v15).
Set to true
to prevent a transitive json-schema dependency from breaking your Webpack build. Failure in this case manifests itself something like so:
Error: define cannot be used indirect
webpack:///(webpack)/buildin/amd-define.js
If you use Moment.js in a Webpack build, all the locales it supports will be imported by default and your build will be about 139KB larger than you were expecting!
Provide an object with a locales
Array specifying language codes for the locales you want to load.
Set to true
for Sinon.js 1.x compatibility.
Here's an example config showing the use of every compat
setting:
module.exports = {
webpack: {
compat: {
enzyme: true,
'json-schema': true,
moment: {
locales: ['de', 'en-gb', 'es', 'fr', 'it']
},
sinon: true
}
}
}
By default, nwb will use Webpack's DefinePlugin
to replace all occurances of process.env.NODE_ENV
with a string containing NODE_ENV
's current value.
You can configure a define
object to add your own constant values.
e.g. to replace all occurrences of __VERSION__
with a string containing your app's version from its package.json
:
module.exports = {
webpack: {
define: {
__VERSION__: JSON.stringify(require('./package.json').version)
}
}
}
Configures options for ExtractTextWebpackPlugin
.
This can be used to control whether or not CSS is extracted from all chunks in an app which uses code splitting, or only the initial chunk:
module.exports = {
webpack: {
extractText: {
allChunks: true
}
}
}
Configures options for HtmlWebpackPlugin
.
For apps, nwb will look for a src/index.html
template to inject <link>
and <script>
tags into for each CSS and JavaScript bundle generated by Webpack.
Use template
config if you have an HTML file elsewhere you want to use:
module.exports = {
webpack: {
html: {
template: 'html/index.html'
}
}
}
If you don't have a template at src/index.html
or specify one via template
, nwb will fall back to using a basic template which has the following properties you can configure:
-
title
- contents for<title>
Default: the value of
name
from your app'spackage.json
-
mountId
- theid
for the<div>
provided for your app to mount itself intoDefault:
'app'
module.exports = {
webpack: {
html: {
mountId: 'root',
title: 'Unimaginative documentation example'
}
}
}
Other HtmlWebpackPlugin
options can also be used. e.g. if you have a favicon.ico
in your src/
directory, you can include it in the index.html
generated when your app is built and have it copied to the output directory like so:
module.exports = {
webpack: {
html: {
favicon: 'src/favicon.ico'
}
}
}
Configures options for NpmInstallPlugin
, which will be used if you pass an --install
flag to nwb serve
.
Each Webpack loader used in nwb's default Webpack configuration has a unique id you can use to customise it.
To customise a loader, add a prop to the loaders
object matching its id with a configuration object.
Refer to each loader's documentation (linked to for each default loader documented below) for configuration options which can be set.
Generic loader options such as include
and exclude
can be configured alongside loader-specific query options - you can also use an explicit query
object if necessary to separate this configuration.
e.g. to enable CSS Modules for your app's CSS, the following loader configs are equivalent:
module.exports = {
webpack: {
loaders: {
css: {
modules: true,
localIdentName: '[hash:base64:5]'
}
}
}
}
module.exports = {
webpack: {
loaders: {
css: {
query: {
modules: true,
localIdentName: '[hash:base64:5]'
}
}
}
}
}
If a loader supports configuration via a top-level webpack configuration property, this can be provided as a config
prop. This is primarily for loaders which can't be configured via query parameters as they have configuration which can't be serialised, such as instances of plugins.
e.g. to use the nib
plugin with the Stylus preprocessor provided by nwb-stylus:
var nib = require('nib')
{
webpack: {
loaders: {
stylus: {
config: {
use: [nib()]
}
}
}
}
}
Alternatively, you can also add new properties directly to the top-level Webpack config using extra
config.
Default loaders configured by nwb and the ids it gives them are:
-
babel
- handles.js
files with babel-loaderDefault config:
{exclude: /node_modules/, query: {babelrc: false, cacheDirectory: true}}
-
css-pipeline
- handles your app's own.css
files by chaining together a number of loaders:Default config:
{exclude: /node_modules/}
Chained loaders are:
-
style
- (only when serving) applies styles using style-loader -
css
- handles URLs, minification and CSS Modules using css-loaderDefault config:
{query: {autoprefixer: false, importLoaders: 1}}
-
postcss
- processes CSS with PostCSS plugins using postcss-loader; by default, this is configured to manage vendor prefixes in CSS using Autoprefixer
-
-
vendor-css-pipeline
- handles.css
files required fromnode_modules/
, with the same set of chained loaders ascss-pipeline
but with avendor-
prefix in their id.Default config:
{include: /node_modules/}
-
graphics
- handles.gif
,.png
,.svg
and.webp
files using using url-loader -
jpeg
- handles.jpeg
files using url-loader -
fonts
- handles.eot
,.otf
,.ttf
,.woff
and.woff2
files using url-loader -
video
- handles.mp4
,.ogg
and.webm
files using url-loader
Default config for all url-loaders in production builds is
{query: {limit: 1, name: '[name].[hash:8].[ext]'}}
, otherwise{query: {limit: 1, name: '[name].[ext]'}}
.
Default
limit
config prevents any files being inlined by default, while allowing you to configureurl-loader
to enable inlining if you need it.
json
- handles.json
files using json-loader
By default, nwb configures the postcss-loader
in each style pipeline to automatically manage vendor prefixes for CSS rules.
Use postcss
configuration to provide your own list of PostCSS plugins to be used for each pipeline, which will completely overwrite nwb's default configuration.
If you're only configuring PostCSS plugins for your app's own CSS, you can just provide a list:
module.exports = {
webpack: {
postcss: [
require('precss')(),
require('autoprefixer')()
]
}
}
Use an object if you're configuring other style pipelines. When using an object, PostCSS plugins for the default style pipeline (applied to your app's own CSS) must be configured using a defaults
property:
var autoprefixer = require('autoprefixer')
var precss = require('precss')
module.exports = {
webpack: {
postcss: {
defaults: [
precss(),
autoprefixer()
],
vendor: [
autoprefixer({add: false})
]
}
}
}
Plugins for other style pipelines are configured using their prefix as a property name: vendor
for anything imported out of node_modules/
, sass
if you're using the nwb-sass
preprocessor plugin, etc.
Your app is responsible for managing its own PostCSS plugin dependencies - between the size of the PostCSS ecosystem and the number of different configuration options postcss-loader
supports, PostCSS could do with its own equivalent of nwb to manage dependencies and configuration!
It's recommended to create instances of PostCSS plugins in your config, as opposed to passing a module, in case you ever need to make use of debug output (enabled by setting a DEBUG
environment variable to nwb
) to examine generated config.
This is just Webpack's
output.publicPath
config pulled up a level to make it more convenient to configure.
publicPath
defines the URL static resources will be referenced by in build output, such as <link>
and <src>
tags in generated HTML, url()
in stylesheets and paths to any static resources you require()
into your modules.
The default publicPath
configured for most app builds is /
, which assumes you will be serving your app's static resources from the root of whatever URL it's hosted at:
<script src="/app.12345678.js"></script>
If you're serving static resources from a different path, or from an external URL such as a CDN, set it as the publicPath
:
module.exports = {
webpack: {
publicPath: 'https://cdn.example.com/myapp/'
}
}
The exception is the React component demo app, which doesn't set a publicPath
, generating a build without any root URL paths to static resources. This allows you to serve it at any path without configuration (e.g. on GitHub Project Pages), or open the generated index.html
file directly in a browser, which is ideal for distributing app builds which don't require a server to run.
If you want to create a path-independent build, set publicPath
to blank or null
:
module.exports = {
webpack: {
publicPath: ''
}
}
The trade-off for path-independence is HTML5 history routing won't work, as serving up index.html
at anything but its real path will mean its static resource URLs won't resolve. You will have to fall back on hash-based routing if you need it.
Configures options for Webpack's UglifyJsPlugin
, which will be used when creating production builds.
Any additional options provided will be merged into nwb's defaults, which are:
module.exports = {
compress: {
screw_ie8: true,
warnings: false,
},
mangle: {
screw_ie8: true,
},
output: {
comments: false,
screw_ie8: true,
},
}
Extra configuration to be merged into the generated Webpack configuration using webpack-merge - see the Webpack configuration docs for the available fields.
Note that you must use Webpack's own config structure in this object - e.g. to add an extra loader which isn't managed by nwb's own webpack.loaders
config, you would need to provide a list of loaders at webpack.extra.module.loaders
.
var path = require('path')
function(nwb) {
return {
type: 'react-app',
webpack: {
extra: {
// Example of adding an extra loader which isn't managed by nwb,
// assuming you've installed html-loader in your project.
module: {
loaders: [
{test: /\.html$/, loader: 'html'}
]
},
// Example of adding an extra plugin which isn't managed by nwb
plugins: [
new nwb.webpack.optimize.MinChunkSizePlugin({
minChunkSize: 1024
})
]
}
}
}
}
nwb's default Karma configuration uses the Mocha framework and reporter plugins for it, but you can configure your own preferences.
Karma configuration can be provided in a karma
object, using the following properties:
Default:
['PhantomJS']
A list of browsers to run tests in.
PhantomJS is the default as it's installed by default with nwb and should be able to run in any environment.
The launcher plugin for Chrome is also included, so if you want to run tests in Chrome, you can just name it:
module.exports = {
karma: {
browsers: ['Chrome']
}
}
For other browsers, you will also need to supply a plugin and manage that dependency yourself:
module.exports = {
karma: {
browsers: ['Firefox'],
plugins: [
require('karma-firefox-launcher')
]
}
}
nwb can also use the first browser defined in a launcher plugin if you pass it in browsers
:
module.exports = {
karma: {
browsers: [
'Chrome',
require('karma-firefox-launcher')
]
}
}
Default:
['mocha']
Karma testing framework plugins.
You must provide the plugin for any custom framework you want to use and manage it as a dependency yourself.
e.g. if you're using a testing framework which produces TAP output (such as tape). this is how you would use frameworks
and plugins
props to configure Karma:
npm install --save-dev karma-tap
module.exports = {
karma: {
frameworks: ['tap'],
plugins: [
require('karma-tap')
]
}
}
nwb can also determine the correct framework name given the plugin itself, so the following is functionally identical to the configuration above:
module.exports = {
karma: {
frameworks: [
require('karma-tap')
]
}
}
If a plugin module provides multiple plugins, nwb will only infer the name of the first plugin it provides, so pass it using plugins
instead and list all the frameworks you want to use, for clarity:
module.exports = {
karma: {
frameworks: ['mocha', 'chai', 'chai-as-promised'],
plugins: [
require('karma-chai-plugins') // Provides chai, chai-as-promised, ...
]
}
}
Note: If you're configuring frameworks and you want to use the Mocha framework plugin managed by nwb, just pass its name as in the above example.
Use this configuration to point to a Webpack context module for your tests if you need to run code prior to any tests being run, such as customising the assertion library you're using, or global before and after hooks.
If you provide a context module, it is responsible for including tests via Webpack's require.context()
- see the example in the Testing docs.
If the default testFiles
config wouldn't have picked up your tests, you must also configure it so they can be excluded from code coverage.
Default:
['test/', 'tests/', 'src/**/__tests__/']
Globs for directories containing test code.
These are used to exclude test utility code from code coverage.
Default:
.spec.js
,.test.js
or-test.js
files anywhere undersrc/
,test/
ortests/
Minimatch glob patterns for test files.
If karma.testContext
is not being used, this controls which files Karma will run tests from.
This is also used to exclude tests from code coverage, so if you're using karma.testContext
and the default patterns wouldn't have picked up your tests, configure this as well to exclude then from code coverage.
A list of plugins to be loaded by Karma - this should be used in combination with browsers
, frameworks
and reporters
config as necessary.
Default:
['mocha']
Customising reporters follows the same principle as frameworks, just using the reporters
prop instead.
For built-in reporters, or nwb's versfon of the Mocha reporter, just pass a name:
module.exports = {
karma: {
reporters: ['progress']
}
}
For custom reporters, install and provide the plugin:
npm install --save-dev karma-tape-reporter
module.exports = {
karma: {
reporters: [
require('karma-tape-reporter')
]
}
}
Extra configuration to be merged into the generated Karma configuration using webpack-merge.
Note that you must use Karma's own config structure in this object.
e.g. to tweak the configuration of the default Mocha reporter:
module.exports = {
karma: {
extra: {
mochaReporter: {
divider: '°º¤ø,¸¸,ø¤º°`°º¤ø,¸,ø¤°º¤ø,¸¸,ø¤º°`°º¤ø,¸',
output: 'autowatch'
}
}
}
}
By default, nwb creates ES5 and ES6 modules builds for publishing to npm.
npm build configuration is defined in a npm
object, using the following fields:
Defaults to
true
if not provided.
Determines whether or not nwb will create an ES6 modules build for use by ES6 module bundlers when you run nwb build
for a React component/libary or web module project.
When providing an ES6 modules build, you should also provide the following in package.json
so compatible module bundlers can find it:
"jsnext:main": "es/index.js",
"module": "es/index.js",
These are included automatically if you create a project with an ES6 modules build enabled.
Configures creation of a UMD build when you run nwb build
for a React component/library or web module.
If you just need to configure the global variable the UMD build will export, you can use a String:
module.exports = {
npm: {
umd: 'MyLibrary'
}
}
If you also have some external dependencies to configure, you must use an Object containing the following properties:
The name of the global variable the UMD build will export.
A mapping from peerDependency
module names to the global variables they're expected to be available as for use by the UMD build.
e.g. if you're creating a React component which also depends on React Router, this configuration would ensure they're not included in the UMD build:
module.exports = {
npm: {
umd: {
global: 'MyComponent',
externals: {
'react': 'React',
'react-router': 'ReactRouter'
}
}
}
}
A banner comment added to UMD builds will use as many of the following package.json
fields as are present:
name
version
homepage
license
If all fields are present the banner will be in this format:
/*!
* your-project v1.2.3 - https://github.com/you/your-project
* MIT Licensed
*/