Skip to content

Exploration of different config + expose webpack config #222

New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Merged
merged 16 commits into from
Dec 17, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 61 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,66 @@ Then run `now` and enjoy!

Note: we recommend putting `.next` in `.npmignore` or `.gitignore`. Otherwise, use `files` or `now.files` to opt-into a whitelist of files you want to deploy (and obviously exclude `.next`)

## Configuration

While Next.js aims to work without any configuration, sometimes there is a need to add custom behaviour.
You can define custom configuration in a file called `next.config.js` in the project root directory.
An example of a configuration looks like this:

```javascript
// next.config.js
module.exports = {
cdn: true
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't have a cdn option. May be we need to re-phrase this.

}
```

### Customizing webpack config

Sometimes the user needs to have custom configuration for webpack to add a specific behaviour in the build process.
An example of this is using `eslint-loader` to lint the files before compiling. This can be done by defining
`webpack` in the config.

```javascript
module.exports = {
webpack: (webpackConfig, { dev }) => {
webpackConfig.module.preLoaders.push({ test: /\.js$/, loader: 'eslint-loader' })
return webpackConfig
}
}
```

As you can see you need to provide a function which has two parameters `webpackConfig`, which is the config used by Next.js, and `options`, which contains
`dev` (`true` if dev environment). The config you return is the config used by Next.js.
You can also return a `Promise` which will be resolved first.

_NOTE: Use this option with care, because you can potentially break the existing webpack build configuration by using this option._

These are some more examples:

```javascript
const I18nPlugin = require('i18n-webpack-plugin');

module.exports = {
webpack: (webpackConfig, { dev }) => {
// Read image files:
webpackConfig.module.loaders.push({
test: /\.png$/,
loader: 'file'
})

// Adding a plugin
webpackConfig.plugins.push(new I18nPlugin())

// Or adding an alias
// Create webpackConfig.resolve.alias if it doesn't exist yet:
webpackConfig.resolve.alias = webpackConfig.resolve.alias || {}
webpackConfig.resolve.alias.src = './src'

return webpackConfig
}
}
```

## FAQ

<details>
Expand Down Expand Up @@ -423,7 +483,7 @@ For this reason we want to promote a situation where users can share the cache f

We are committed to providing a great uptime and levels of security for our CDN. Even so, we also **automatically fall back** if the CDN script fails to load [with a simple trick](http://www.hanselman.com/blog/CDNsFailButYourScriptsDontHaveToFallbackFromCDNToLocalJQuery.aspx).

To turn the CDN off, just set `{ “next”: { cdn: false } }` in `package.json`.
To turn the CDN off, just set `module.exports = { cdn: false }` in `next.config.js`.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't worry about this one. We'll remove it anyway.

</details>

<details>
Expand Down
30 changes: 24 additions & 6 deletions bin/next
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import { join } from 'path'
import { spawn } from 'cross-spawn'
import { watchFile } from 'fs'

const defaultCommand = 'dev'
const commands = new Set([
Expand All @@ -23,9 +24,26 @@ if (commands.has(cmd)) {

const bin = join(__dirname, 'next-' + cmd)

const proc = spawn(bin, args, { stdio: 'inherit', customFds: [0, 1, 2] })
proc.on('close', (code) => process.exit(code))
proc.on('error', (err) => {
console.error(err)
process.exit(1)
})
const startProcess = () => {
const proc = spawn(bin, args, { stdio: 'inherit', customFds: [0, 1, 2] })
proc.on('close', (code) => process.exit(code))
proc.on('error', (err) => {
console.error(err)
process.exit(1)
})
return proc
}

let proc = startProcess()

if (cmd === 'dev') {
watchFile(join(process.cwd(), 'next.config.js'), (cur, prev) => {
if (cur.size > 0 || prev.size > 0) {
console.log('\n> Found a change in next.config.js, restarting the server...')
// Don't listen to 'close' now since otherwise parent gets killed by listener
proc.removeAllListeners('close')
proc.kill()
proc = startProcess()
}
})
}
11 changes: 9 additions & 2 deletions server/build/webpack.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import WatchPagesPlugin from './plugins/watch-pages-plugin'
import WatchRemoveEventPlugin from './plugins/watch-remove-event-plugin'
import DynamicEntryPlugin from './plugins/dynamic-entry-plugin'
import DetachPlugin from './plugins/detach-plugin'
import getConfig from '../config'

export default async function createCompiler (dir, { dev = false } = {}) {
dir = resolve(dir)
Expand Down Expand Up @@ -166,7 +167,7 @@ export default async function createCompiler (dir, { dev = false } = {}) {
[errorDebugPath, 'dist/pages/_error-debug.js']
])

return webpack({
let webpackConfig = {
context: dir,
entry,
output: {
Expand Down Expand Up @@ -206,5 +207,11 @@ export default async function createCompiler (dir, { dev = false } = {}) {
customInterpolateName: function (url, name, opts) {
return interpolateNames.get(this.resourcePath) || url
}
})
}
const config = getConfig(dir)
if (config.webpack) {
console.log('> Using Webpack config function defined in next.config.js.')
webpackConfig = await config.webpack(webpackConfig, { dev })
}
return webpack(webpackConfig)
}
30 changes: 13 additions & 17 deletions server/config.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { join } from 'path'
import { readFile } from 'mz/fs'
import { existsSync } from 'fs'

const cache = new Map()

const defaultConfig = {}
const defaultConfig = {
webpack: null
}

export default function getConfig (dir) {
if (!cache.has(dir)) {
Expand All @@ -12,22 +14,16 @@ export default function getConfig (dir) {
return cache.get(dir)
}

async function loadConfig (dir) {
const path = join(dir, 'package.json')
function loadConfig (dir) {
const path = join(dir, 'next.config.js')

let data
try {
data = await readFile(path, 'utf8')
} catch (err) {
if (err.code === 'ENOENT') {
data = '{}'
} else {
throw err
}
}
let userConfig = {}

// no try-cache, it must be a valid json
const config = JSON.parse(data).next || {}
const userHasConfig = existsSync(path)
if (userHasConfig) {
const userConfigModule = require(path)
userConfig = userConfigModule.default || userConfigModule
}

return Object.assign({}, defaultConfig, config)
return Object.assign({}, defaultConfig, userConfig)
}