Skip to content

Latest commit

 

History

History
966 lines (700 loc) · 32.9 KB

Configuration.md

File metadata and controls

966 lines (700 loc) · 32.9 KB

Configuration

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.

Configuration File

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 the webpack module, giving you access to the other plugins webpack provides

Example Configuration Files

Configuration Object

The configuration object can include the following properties:

type: String (required for generic build commands)

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'

polyfill: Boolean

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

babel: Object

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 in webpack.loaders if necessary.

cherryPick: String | Array<String>

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.

loose: Boolean

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'
  }
}
plugins: Array<String | Array>

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']
  }
}
presets: Array<String>

Additional Babel presets to use.

runtime: String | Boolean

Babel's runtime transform does 3 things by default:

  1. Imports helper modules from babel-runtime instead of duplicating helpers in every module which needs them.
  2. Imports a local polyfill for new ES6 builtins (Promise) and static methods (e.g. Object.assign) when they're used in your code.
  3. 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.

stage: Number | 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

webpack: Object

Webpack configuration can be provided in a webpack object, using the following properties:

aliases: Object

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.

autoprefixer: String | Object

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.

compat: Object

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:

enzyme: Boolean

Set to true for Enzyme compatibility - this assumes you're using the latest version of React (v15).

json-schema: Boolean

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
moment: Object

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.

sinon: Boolean

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
    }
  }
}
define: Object

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)
    }
  }
}
extractText: Object

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
    }
  }
}
html: Object

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 templateconfig 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's package.json

  • mountId - the id for the <div> provided for your app to mount itself into

    Default: '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'
    }
  }
}
install: Object

Configures options for NpmInstallPlugin, which will be used if you pass an --install flag to nwb serve.

loaders: Object

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

Default loaders configured by nwb and the ids it gives them are:

  • babel - handles .js files with babel-loader

    Default 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-loader

      Default 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 from node_modules/, with the same set of chained loaders as css-pipeline but with a vendor- 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 configure url-loader to enable inlining if you need it.

postcss: Array<Plugin> | Object<String, Array<Plugin>>

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.

publicPath: String

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.

uglify: Object

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: Object

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
          })
        ]
      }
    }
  }
}

Karma Configuration

nwb's default Karma configuration uses the Mocha framework and reporter plugins for it, but you can configure your own preferences.

karma: Object

Karma configuration can be provided in a karma object, using the following properties:

browsers: Array<String | Plugin>

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')
    ]
  }
}
frameworks: Array<String | Plugin>

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.

testContext: String

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.

testDirs: String | Array<String>

Default: ['test/', 'tests/', 'src/**/__tests__/']

Globs for directories containing test code.

These are used to exclude test utility code from code coverage.

testFiles: String | Array<String>

Default: .spec.js, .test.js or -test.js files anywhere under src/, test/ or tests/

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.

plugins: Array<Plugin>

A list of plugins to be loaded by Karma - this should be used in combination with browsers, frameworks and reporters config as necessary.

reporters: Array<String | Plugin>

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: Object

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'
      }
    }
  }
}

npm Build Configuration

By default, nwb creates ES5 and ES6 modules builds for publishing to npm.

npm: Object

npm build configuration is defined in a npm object, using the following fields:

esModules: Boolean

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.

umd: String | Object

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:

global: String

The name of the global variable the UMD build will export.

externals: Object

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'
      }
    }
  }
}

package.json UMD Banner Configuration

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
 */