Allow to customize our babel configuration (#466)

* Add a way to customize babel configurations.

* Add babel configuration docs to README.
This commit is contained in:
Arunoda Susiripala 2016-12-22 07:06:00 +05:30 committed by Guillermo Rauch
parent 9ac79ed1ae
commit 1719738ed1
7 changed files with 155 additions and 15 deletions

View file

@ -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
}
}
```

View file

@ -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
```

View file

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

View file

@ -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"
}
}

View file

@ -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 (<p>Please wait..</p>)
}
// 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 (
<div>
<h3>Your Lucky number is: "{randomNo}"</h3>
<p>{message}</p>
<button onClick={() => this.recalculate()}>Try Again</button>
</div>
)
}
}

View file

@ -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))

View file

@ -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)