diff --git a/README.md b/README.md index 1136e93785..0861a5bf56 100644 --- a/README.md +++ b/README.md @@ -310,7 +310,7 @@ app.prepare().then(() => { ``` The `next` API is as follows: -- `next(path: string, opts: object)` - `path` is +- `next(path: string, opts: object)` - `path` is - `next(opts: object)` Supported options: @@ -396,10 +396,40 @@ In order to extend our usage of `webpack`, you can define a function that extend The following example shows how you can use [`react-svg-loader`](https://github.com/boopathi/react-svg-loader) to easily import any `.svg` file as a React component, without modification. ```js +// This file is not going through babel transformation. +// So, we write it in vanilla JS +// (But you could use ES2015 features supported by your Node.js version) + module.exports = { - webpack: (cfg, { dev }) => { - cfg.module.rules.push({ test: /\.svg$/, loader: 'babel!react-svg' }) - return cfg + webpack: (config, { dev }) => { + config.module.rules.push({ test: /\.svg$/, loader: 'babel!react-svg' }) + + // Important: return the modified config + return config + } +} +``` + +### Customizing babel config + +In order to extend our usage of `babel`, you can define a function that extends its config via `next.config.js`. + +The following example config shows you how to use `babel-preset-stage-0` with your app. + +```js +// This file is not going through babel transformation. +// So, we write it in vanilla JS +// (But you could use ES2015 features supported by your Node.js version) + +module.exports = { + // config is the set of options we pass to our babel-loaders's query option + babel: function (config, { dev }) { + // Add the stage-0 preset. + // Make sure to use 'require.resolve' otherwise we won't be able to find it. + config.presets.push(require.resolve('babel-preset-stage-0')) + + // Important: return the modified config + return config } } ``` diff --git a/examples/with-custom-babel-config/README.md b/examples/with-custom-babel-config/README.md new file mode 100644 index 0000000000..1d0b15c43f --- /dev/null +++ b/examples/with-custom-babel-config/README.md @@ -0,0 +1,13 @@ +# Example app using custom babel config + +This example features: + +* An app using proposed [do expressions](https://babeljs.io/docs/plugins/transform-do-expressions/). +* It uses babel-preset-stage-0, which allows us to use above JavaScript feature. + +## How to run it + +```sh +npm install +npm run dev +``` diff --git a/examples/with-custom-babel-config/next.config.js b/examples/with-custom-babel-config/next.config.js new file mode 100644 index 0000000000..37f7d1f0ff --- /dev/null +++ b/examples/with-custom-babel-config/next.config.js @@ -0,0 +1,15 @@ +// This file is not going through babel transformation. +// So, we write it in vanilla JS +// (But you could use ES2015 features supported by your Node.js version) + +module.exports = { + // config is the set of options we pass to our babel-loaders's query option + babel: function (config) { + // Add the stage-0 preset. + // Make sure to use 'require.resolve' otherwise we won't be able to find it. + config.presets.push(require.resolve('babel-preset-stage-0')) + + // Important: return the modified config + return config + } +} diff --git a/examples/with-custom-babel-config/package.json b/examples/with-custom-babel-config/package.json new file mode 100644 index 0000000000..768618d096 --- /dev/null +++ b/examples/with-custom-babel-config/package.json @@ -0,0 +1,19 @@ +{ + "name": "with-custom-babel-config", + "version": "1.0.0", + "description": "This example features:", + "main": "index.js", + "scripts": { + "dev": "next", + "build": "next build", + "start": "next start" + }, + "dependencies": { + "next": "^2.0.0-beta" + }, + "author": "", + "license": "ISC", + "devDependencies": { + "babel-preset-stage-0": "^6.16.0" + } +} diff --git a/examples/with-custom-babel-config/pages/index.js b/examples/with-custom-babel-config/pages/index.js new file mode 100644 index 0000000000..8f1b9e867e --- /dev/null +++ b/examples/with-custom-babel-config/pages/index.js @@ -0,0 +1,46 @@ +import React from 'react' + +export default class MyLuckNo extends React.Component { + constructor (...args) { + super(...args) + this.state = { randomNo: null } + } + + componentDidMount () { + this.recalculate() + } + + recalculate () { + this.setState({ + randomNo: Math.ceil(Math.random() * 100) + }) + } + + render () { + const { randomNo } = this.state + + if (randomNo === null) { + return (

Please wait..

) + } + + // This is an experimental JavaScript feature where we can get with + // using babel-preset-stage-0 + const message = do { + if (randomNo < 30) { + 'Do not give up. Try again.' + } else if (randomNo < 60) { + 'You are a lucky guy' + } else { + 'You are soooo lucky!' + } + } + + return ( +
+

Your Lucky number is: "{randomNo}"

+

{message}

+ +
+ ) + } +} diff --git a/server/build/babel/index.js b/server/build/babel/index.js index 70ebfb2a83..c6472d3393 100644 --- a/server/build/babel/index.js +++ b/server/build/babel/index.js @@ -3,11 +3,13 @@ import { readFile, writeFile } from 'mz/fs' import { transform } from 'babel-core' import chokidar from 'chokidar' import mkdirp from 'mkdirp-then' +import getConfig from '../../config' export default babel async function babel (dir, { dev = false } = {}) { dir = resolve(dir) + const config = getConfig('../') let src try { @@ -20,11 +22,18 @@ async function babel (dir, { dev = false } = {}) { } } - const { code } = transform(src, { + let babelOptions = { babelrc: false, sourceMaps: dev ? 'inline' : false, presets: [require.resolve('./preset')] - }) + } + + if (config.babel) { + console.log('> Using "babel" config function defined in next.config.js.') + babelOptions = await config.babel(babelOptions, { dev }) + } + + const { code } = transform(src, babelOptions) const file = join(dir, '.next', 'dist', 'pages', '_document.js') await mkdirp(dirname(file)) diff --git a/server/build/webpack.js b/server/build/webpack.js index cc6aa0e986..3b5b8d4d3d 100644 --- a/server/build/webpack.js +++ b/server/build/webpack.js @@ -13,6 +13,7 @@ import getConfig from '../config' export default async function createCompiler (dir, { dev = false, quiet = false } = {}) { dir = resolve(dir) + const config = getConfig(dir) const pages = await glob('pages/**/*.js', { cwd: dir, @@ -83,6 +84,19 @@ export default async function createCompiler (dir, { dev = false, quiet = false ) } + let mainBabelOptions = { + babelrc: false, + sourceMaps: dev ? 'both' : false, + presets: [ + require.resolve('./babel/preset') + ] + } + + if (config.babel) { + console.log('> Using "babel" config function defined in next.config.js.') + mainBabelOptions = await config.babel(mainBabelOptions, { dev }) + } + const loaders = (dev ? [{ test: /\.js(\?[^?]*)?$/, loader: 'hot-self-accept-loader', @@ -133,13 +147,7 @@ export default async function createCompiler (dir, { dev = false, quiet = false exclude (str) { return /node_modules/.test(str) && str.indexOf(nextPagesDir) !== 0 }, - query: { - babelrc: false, - sourceMaps: dev ? 'both' : false, - presets: [ - require.resolve('./babel/preset') - ] - } + query: mainBabelOptions }]) const interpolateNames = new Map([ @@ -188,9 +196,9 @@ export default async function createCompiler (dir, { dev = false, quiet = false return interpolateNames.get(this.resourcePath) || url } } - const config = getConfig(dir) + if (config.webpack) { - console.log('> Using Webpack config function defined in next.config.js.') + console.log('> Using "webpack" config function defined in next.config.js.') webpackConfig = await config.webpack(webpackConfig, { dev }) } return webpack(webpackConfig)