2016-10-15 16:17:27 +00:00
|
|
|
import { resolve, join } from 'path'
|
2016-12-02 01:43:38 +00:00
|
|
|
import { createHash } from 'crypto'
|
2016-10-14 15:05:08 +00:00
|
|
|
import webpack from 'webpack'
|
|
|
|
import glob from 'glob-promise'
|
2016-10-15 19:49:42 +00:00
|
|
|
import WriteFilePlugin from 'write-file-webpack-plugin'
|
2016-12-03 22:01:15 +00:00
|
|
|
import FriendlyErrorsWebpackPlugin from 'friendly-errors-webpack-plugin'
|
2016-10-23 16:42:13 +00:00
|
|
|
import UnlinkFilePlugin from './plugins/unlink-file-plugin'
|
|
|
|
import WatchPagesPlugin from './plugins/watch-pages-plugin'
|
|
|
|
import WatchRemoveEventPlugin from './plugins/watch-remove-event-plugin'
|
|
|
|
import DynamicEntryPlugin from './plugins/dynamic-entry-plugin'
|
2016-11-03 15:12:37 +00:00
|
|
|
import DetachPlugin from './plugins/detach-plugin'
|
2016-10-14 15:05:08 +00:00
|
|
|
|
2016-12-16 20:33:08 +00:00
|
|
|
export default async function createCompiler (dir, { dev = false } = {}) {
|
2016-10-15 16:17:27 +00:00
|
|
|
dir = resolve(dir)
|
|
|
|
|
2016-12-16 18:42:40 +00:00
|
|
|
const pages = await glob('pages/**/*.js', {
|
|
|
|
cwd: dir,
|
|
|
|
ignore: 'pages/_document.js'
|
|
|
|
})
|
2016-10-14 15:05:08 +00:00
|
|
|
|
|
|
|
const entry = {}
|
2016-12-16 20:33:08 +00:00
|
|
|
const defaultEntries = dev
|
|
|
|
? [join(__dirname, '..', '..', 'client/webpack-hot-middleware-client')] : []
|
2016-10-14 15:05:08 +00:00
|
|
|
for (const p of pages) {
|
2016-12-06 09:24:42 +00:00
|
|
|
entry[join('bundles', p)] = defaultEntries.concat([`./${p}?entry`])
|
2016-10-14 15:05:08 +00:00
|
|
|
}
|
|
|
|
|
2016-10-19 12:58:08 +00:00
|
|
|
const nextPagesDir = join(__dirname, '..', '..', 'pages')
|
2016-10-19 12:41:45 +00:00
|
|
|
|
2016-10-17 03:55:09 +00:00
|
|
|
const errorEntry = join('bundles', 'pages', '_error.js')
|
2016-10-19 12:58:08 +00:00
|
|
|
const defaultErrorPath = join(nextPagesDir, '_error.js')
|
2016-11-03 15:12:37 +00:00
|
|
|
if (!entry[errorEntry]) {
|
2016-12-06 09:24:42 +00:00
|
|
|
entry[errorEntry] = defaultEntries.concat([defaultErrorPath + '?entry'])
|
2016-11-03 15:12:37 +00:00
|
|
|
}
|
2016-10-14 15:05:08 +00:00
|
|
|
|
2016-10-19 12:41:45 +00:00
|
|
|
const errorDebugEntry = join('bundles', 'pages', '_error-debug.js')
|
2016-10-19 12:58:08 +00:00
|
|
|
const errorDebugPath = join(nextPagesDir, '_error-debug.js')
|
2016-10-19 12:41:45 +00:00
|
|
|
entry[errorDebugEntry] = errorDebugPath
|
|
|
|
|
2016-10-19 12:58:08 +00:00
|
|
|
const nodeModulesDir = join(__dirname, '..', '..', '..', 'node_modules')
|
2016-10-14 15:05:08 +00:00
|
|
|
|
2016-10-16 02:49:09 +00:00
|
|
|
const plugins = [
|
2016-10-18 14:14:00 +00:00
|
|
|
new WriteFilePlugin({
|
|
|
|
exitOnErrors: false,
|
2016-10-23 16:42:13 +00:00
|
|
|
log: false,
|
|
|
|
// required not to cache removed files
|
|
|
|
useHashIndex: false
|
2016-11-28 00:15:56 +00:00
|
|
|
}),
|
|
|
|
new webpack.optimize.CommonsChunkPlugin({
|
|
|
|
name: 'commons',
|
2016-12-06 09:25:01 +00:00
|
|
|
filename: 'commons.js',
|
2016-12-15 22:29:59 +00:00
|
|
|
minChunks: Math.max(2, pages.length)
|
2016-10-23 16:42:13 +00:00
|
|
|
})
|
2016-11-18 07:26:17 +00:00
|
|
|
]
|
|
|
|
|
2016-12-16 20:33:08 +00:00
|
|
|
if (dev) {
|
2016-11-18 07:26:17 +00:00
|
|
|
plugins.push(
|
2016-11-23 18:32:49 +00:00
|
|
|
new webpack.optimize.OccurrenceOrderPlugin(),
|
2016-11-18 07:26:17 +00:00
|
|
|
new webpack.HotModuleReplacementPlugin(),
|
2016-11-23 18:32:49 +00:00
|
|
|
new webpack.NoErrorsPlugin(),
|
2016-11-18 07:26:17 +00:00
|
|
|
new DetachPlugin(),
|
|
|
|
new DynamicEntryPlugin(),
|
|
|
|
new UnlinkFilePlugin(),
|
|
|
|
new WatchRemoveEventPlugin(),
|
2016-12-02 01:21:21 +00:00
|
|
|
new WatchPagesPlugin(dir),
|
2016-12-03 22:01:15 +00:00
|
|
|
new FriendlyErrorsWebpackPlugin()
|
2016-11-18 07:26:17 +00:00
|
|
|
)
|
2016-12-16 20:33:08 +00:00
|
|
|
} else {
|
|
|
|
plugins.push(
|
|
|
|
new webpack.DefinePlugin({
|
|
|
|
'process.env.NODE_ENV': JSON.stringify('production')
|
|
|
|
}),
|
|
|
|
new webpack.optimize.UglifyJsPlugin({
|
|
|
|
compress: { warnings: false },
|
|
|
|
sourceMap: false
|
|
|
|
})
|
|
|
|
)
|
2016-11-18 07:26:17 +00:00
|
|
|
}
|
2016-10-15 19:49:42 +00:00
|
|
|
|
2016-10-14 15:05:08 +00:00
|
|
|
const babelRuntimePath = require.resolve('babel-runtime/package')
|
2016-12-01 11:54:17 +00:00
|
|
|
.replace(/[\\/]package\.json$/, '')
|
2016-10-14 15:05:08 +00:00
|
|
|
|
2016-12-16 20:33:08 +00:00
|
|
|
const loaders = (dev ? [{
|
2016-12-06 09:24:42 +00:00
|
|
|
test: /\.js(\?[^?]*)?$/,
|
2016-12-01 22:46:49 +00:00
|
|
|
loader: 'hot-self-accept-loader',
|
|
|
|
include: [
|
|
|
|
join(dir, 'pages'),
|
|
|
|
nextPagesDir
|
|
|
|
]
|
2016-12-05 17:09:38 +00:00
|
|
|
}, {
|
2016-12-06 09:24:42 +00:00
|
|
|
test: /\.js(\?[^?]*)?$/,
|
2016-12-05 17:09:38 +00:00
|
|
|
loader: 'react-hot-loader/webpack',
|
|
|
|
exclude: /node_modules/
|
2016-12-01 22:46:49 +00:00
|
|
|
}] : [])
|
|
|
|
.concat([{
|
|
|
|
test: /\.json$/,
|
|
|
|
loader: 'json-loader'
|
|
|
|
}, {
|
2016-12-06 09:24:42 +00:00
|
|
|
test: /\.(js|json)(\?[^?]*)?$/,
|
2016-10-15 16:17:27 +00:00
|
|
|
loader: 'emit-file-loader',
|
2016-10-19 12:41:45 +00:00
|
|
|
include: [dir, nextPagesDir],
|
2016-10-25 09:11:39 +00:00
|
|
|
exclude (str) {
|
|
|
|
return /node_modules/.test(str) && str.indexOf(nextPagesDir) !== 0
|
|
|
|
},
|
2016-10-15 16:17:27 +00:00
|
|
|
query: {
|
2016-10-17 03:55:09 +00:00
|
|
|
name: 'dist/[path][name].[ext]'
|
2016-10-15 16:17:27 +00:00
|
|
|
}
|
2016-12-01 22:46:49 +00:00
|
|
|
}, {
|
2016-11-05 16:12:21 +00:00
|
|
|
loader: 'babel',
|
|
|
|
include: nextPagesDir,
|
|
|
|
query: {
|
2016-12-11 09:09:54 +00:00
|
|
|
babelrc: false,
|
2016-12-02 01:43:38 +00:00
|
|
|
sourceMaps: dev ? 'both' : false,
|
2016-11-05 16:12:21 +00:00
|
|
|
plugins: [
|
|
|
|
[
|
|
|
|
require.resolve('babel-plugin-module-resolver'),
|
|
|
|
{
|
|
|
|
alias: {
|
|
|
|
'ansi-html': require.resolve('ansi-html')
|
|
|
|
}
|
|
|
|
}
|
|
|
|
]
|
|
|
|
]
|
|
|
|
}
|
|
|
|
}, {
|
2016-12-06 09:24:42 +00:00
|
|
|
test: /\.js(\?[^?]*)?$/,
|
2016-10-14 15:05:08 +00:00
|
|
|
loader: 'babel',
|
2016-10-19 12:41:45 +00:00
|
|
|
include: [dir, nextPagesDir],
|
2016-10-25 09:11:39 +00:00
|
|
|
exclude (str) {
|
2016-12-02 07:58:08 +00:00
|
|
|
return /node_modules/.test(str) && str.indexOf(nextPagesDir) !== 0
|
2016-10-25 09:11:39 +00:00
|
|
|
},
|
2016-10-14 15:05:08 +00:00
|
|
|
query: {
|
2016-12-11 09:09:54 +00:00
|
|
|
babelrc: false,
|
2016-12-02 01:43:38 +00:00
|
|
|
sourceMaps: dev ? 'both' : false,
|
2016-10-14 15:05:08 +00:00
|
|
|
presets: ['es2015', 'react'],
|
|
|
|
plugins: [
|
2016-11-28 11:46:42 +00:00
|
|
|
require.resolve('babel-plugin-react-require'),
|
2016-10-28 15:50:31 +00:00
|
|
|
require.resolve('babel-plugin-transform-async-to-generator'),
|
|
|
|
require.resolve('babel-plugin-transform-object-rest-spread'),
|
|
|
|
require.resolve('babel-plugin-transform-class-properties'),
|
|
|
|
require.resolve('babel-plugin-transform-runtime'),
|
2016-10-14 15:05:08 +00:00
|
|
|
[
|
2016-10-28 15:50:31 +00:00
|
|
|
require.resolve('babel-plugin-module-resolver'),
|
2016-10-28 15:48:14 +00:00
|
|
|
{
|
|
|
|
alias: {
|
|
|
|
'babel-runtime': babelRuntimePath,
|
|
|
|
react: require.resolve('react'),
|
|
|
|
'next/link': require.resolve('../../lib/link'),
|
2016-12-15 19:13:40 +00:00
|
|
|
'next/prefetch': require.resolve('../../lib/prefetch'),
|
2016-10-28 15:48:14 +00:00
|
|
|
'next/css': require.resolve('../../lib/css'),
|
2016-12-16 18:42:40 +00:00
|
|
|
'next/head': require.resolve('../../lib/head'),
|
|
|
|
'next/document': require.resolve('../../server/document')
|
2016-10-28 15:48:14 +00:00
|
|
|
}
|
|
|
|
}
|
2016-10-14 15:05:08 +00:00
|
|
|
]
|
|
|
|
]
|
|
|
|
}
|
2016-10-19 12:41:45 +00:00
|
|
|
}])
|
|
|
|
|
|
|
|
const interpolateNames = new Map([
|
|
|
|
[defaultErrorPath, 'dist/pages/_error.js'],
|
|
|
|
[errorDebugPath, 'dist/pages/_error-debug.js']
|
|
|
|
])
|
2016-10-14 15:05:08 +00:00
|
|
|
|
|
|
|
return webpack({
|
|
|
|
context: dir,
|
|
|
|
entry,
|
|
|
|
output: {
|
2016-10-19 12:58:08 +00:00
|
|
|
path: join(dir, '.next'),
|
2016-10-14 15:05:08 +00:00
|
|
|
filename: '[name]',
|
|
|
|
libraryTarget: 'commonjs2',
|
2016-12-16 20:33:08 +00:00
|
|
|
publicPath: dev ? '/_webpack/' : null,
|
2016-12-02 01:43:38 +00:00
|
|
|
devtoolModuleFilenameTemplate ({ resourcePath }) {
|
|
|
|
const hash = createHash('sha1')
|
|
|
|
hash.update(Date.now() + '')
|
|
|
|
const id = hash.digest('hex').slice(0, 7)
|
|
|
|
|
|
|
|
// append hash id for cache busting
|
|
|
|
return `webpack:///${resourcePath}?${id}`
|
|
|
|
}
|
2016-10-14 15:05:08 +00:00
|
|
|
},
|
|
|
|
externals: [
|
|
|
|
'react',
|
|
|
|
'react-dom',
|
|
|
|
{
|
|
|
|
[require.resolve('react')]: 'react',
|
|
|
|
[require.resolve('../../lib/link')]: 'next/link',
|
2016-12-15 19:13:40 +00:00
|
|
|
[require.resolve('../../lib/prefetch')]: 'next/prefetch',
|
2016-10-14 15:05:08 +00:00
|
|
|
[require.resolve('../../lib/css')]: 'next/css',
|
2016-12-16 01:45:58 +00:00
|
|
|
[require.resolve('../../lib/head')]: 'next/head',
|
|
|
|
// React addons ask for React like this.
|
|
|
|
// That causes webpack to push react into the app's bundle.
|
|
|
|
// This fix simply prevents that and ask to use React from the next-bundle
|
|
|
|
'./React': 'react',
|
|
|
|
'./ReactDOM': 'react-dom'
|
2016-10-14 15:05:08 +00:00
|
|
|
}
|
|
|
|
],
|
|
|
|
resolve: {
|
|
|
|
root: [
|
|
|
|
nodeModulesDir,
|
2016-10-19 12:58:08 +00:00
|
|
|
join(dir, 'node_modules')
|
2016-11-14 04:43:31 +00:00
|
|
|
].concat(
|
|
|
|
(process.env.NODE_PATH || '')
|
|
|
|
.split(process.platform === 'win32' ? ';' : ':')
|
|
|
|
)
|
2016-10-14 15:05:08 +00:00
|
|
|
},
|
|
|
|
resolveLoader: {
|
|
|
|
root: [
|
|
|
|
nodeModulesDir,
|
2016-10-19 12:58:08 +00:00
|
|
|
join(__dirname, 'loaders')
|
2016-10-14 15:05:08 +00:00
|
|
|
]
|
|
|
|
},
|
2016-10-15 19:49:42 +00:00
|
|
|
plugins,
|
2016-10-14 15:05:08 +00:00
|
|
|
module: {
|
|
|
|
loaders
|
2016-10-16 04:01:17 +00:00
|
|
|
},
|
2016-12-02 01:43:38 +00:00
|
|
|
devtool: dev ? 'inline-source-map' : false,
|
2016-10-16 04:01:17 +00:00
|
|
|
customInterpolateName: function (url, name, opts) {
|
2016-10-19 12:41:45 +00:00
|
|
|
return interpolateNames.get(this.resourcePath) || url
|
2016-10-14 15:05:08 +00:00
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|