mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-23 14:15:13 +00:00
many improvements
This commit is contained in:
parent
d68b4f0c00
commit
5722a92c4c
@ -87,12 +87,10 @@ function listenOnConfigChanges(nuxt, server) {
|
||||
options.rootDir = rootDir
|
||||
nuxt.close()
|
||||
.then(() => {
|
||||
nuxt.renderer = null
|
||||
debug('Rebuilding the app...')
|
||||
return new Nuxt(options).build()
|
||||
})
|
||||
.then((nuxt) => {
|
||||
var nuxt = new Nuxt(options)
|
||||
server.nuxt = nuxt
|
||||
return nuxt.ready()
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('Error while rebuild the app:', error) // eslint-disable-line no-console
|
||||
|
107
lib/builder.js
107
lib/builder.js
@ -7,11 +7,11 @@ import webpack from 'webpack'
|
||||
import serialize from 'serialize-javascript'
|
||||
import { join, resolve, basename, dirname } from 'path'
|
||||
import Tapable from 'tappable'
|
||||
import chalk from 'chalk'
|
||||
import MFS from 'memory-fs'
|
||||
import { sequence, parallel } from "./utils"
|
||||
import { r, wp, createRoutes } from './utils'
|
||||
import clientWebpackConfig from './webpack/client.config.js'
|
||||
import serverWebpackConfig from './webpack/server.config.js'
|
||||
import MFS from 'memory-fs'
|
||||
|
||||
const debug = require('debug')('nuxt:build')
|
||||
debug.color = 2 // Force green color
|
||||
@ -23,9 +23,6 @@ const writeFile = pify(fs.writeFile)
|
||||
const mkdirp = pify(fs.mkdirp)
|
||||
const glob = pify(require('glob'))
|
||||
|
||||
const host = process.env.HOST || process.env.npm_package_config_nuxt_host || 'localhost'
|
||||
const port = process.env.PORT || process.env.npm_package_config_nuxt_port || '3000'
|
||||
|
||||
export default class Builder extends Tapable {
|
||||
constructor (nuxt) {
|
||||
super()
|
||||
@ -50,7 +47,7 @@ export default class Builder extends Tapable {
|
||||
_.defaultsDeep(this.options.build, extraDefaults)
|
||||
|
||||
// Mute stats on dev
|
||||
this.webpackStats = this.options.dev ? '' : {
|
||||
this.webpackStats = this.options.dev ? false : {
|
||||
chunks: false,
|
||||
children: false,
|
||||
modules: false,
|
||||
@ -220,7 +217,7 @@ export default class Builder extends Tapable {
|
||||
}))
|
||||
|
||||
// Interpret and move template files to .nuxt/
|
||||
return Promise.all(templatesFiles.map(async ({ src, dst, options, custom }) => {
|
||||
await Promise.all(templatesFiles.map(async ({ src, dst, options, custom }) => {
|
||||
// Add template to watchers
|
||||
this.options.build.watch.push(src)
|
||||
// Render template to dst
|
||||
@ -245,7 +242,7 @@ export default class Builder extends Tapable {
|
||||
// Write file
|
||||
await writeFile(path, content, 'utf8')
|
||||
// Fix webpack loop (https://github.com/webpack/watchpack/issues/25#issuecomment-287789288)
|
||||
const dateFS = Date.now() / 1000 - 30
|
||||
const dateFS = Date.now() / 1000 - 1000
|
||||
return utimes(path, dateFS, dateFS)
|
||||
}))
|
||||
}
|
||||
@ -256,16 +253,23 @@ export default class Builder extends Tapable {
|
||||
|
||||
// Client
|
||||
let clientConfig = clientWebpackConfig.call(this)
|
||||
clientConfig.name = '$client'
|
||||
compilersOptions.push(clientConfig)
|
||||
|
||||
// Server
|
||||
let serverConfig = serverWebpackConfig.call(this)
|
||||
serverConfig.name = '$server'
|
||||
compilersOptions.push(serverConfig)
|
||||
|
||||
// Leverage webpack multi-compiler for faster builds
|
||||
this.compiler = webpack(compilersOptions)
|
||||
// Simulate webpack multi compiler interface
|
||||
// Separate compilers are simpler, safer and faster
|
||||
this.compiler = { cache: {}, compilers: [] }
|
||||
compilersOptions.forEach(compilersOption => {
|
||||
this.compiler.compilers.push(webpack(compilersOption))
|
||||
})
|
||||
this.compiler.plugin = (...args) => {
|
||||
this.compiler.compilers.forEach(compiler => {
|
||||
compiler.plugin(...args)
|
||||
})
|
||||
}
|
||||
|
||||
// Access to compilers with name
|
||||
this.compiler.compilers.forEach(compiler => {
|
||||
@ -274,71 +278,84 @@ export default class Builder extends Tapable {
|
||||
}
|
||||
})
|
||||
|
||||
// Add middleware for dev
|
||||
// Add dev Stuff
|
||||
if (this.options.dev) {
|
||||
this.webpackDev()
|
||||
}
|
||||
|
||||
// Start build
|
||||
return new Promise((resolve, reject) => {
|
||||
const handler = (err, multiStats) => {
|
||||
// Start Builds
|
||||
return parallel(this.compiler.compilers, compiler => new Promise((resolve, reject) => {
|
||||
let _resolved = false
|
||||
const handler = (err, stats) => {
|
||||
if (_resolved) return
|
||||
_resolved = true
|
||||
if (err) {
|
||||
return reject(err)
|
||||
}
|
||||
for (let _stats of multiStats.stats) {
|
||||
console.log(_stats.toString(this.webpackStats)) // eslint-disable-line no-console
|
||||
if (_stats.hasErrors()) {
|
||||
if (!this.options.dev) {
|
||||
// Show build stats for production
|
||||
console.log(stats.toString(this.webpackStats)) // eslint-disable-line no-console
|
||||
if (stats.hasErrors()) {
|
||||
return reject(new Error('Webpack build exited with errors'))
|
||||
}
|
||||
}
|
||||
// Use watch handler instead of compiler.apply('done') to prevent duplicate emits
|
||||
this.applyPlugins('reload', multiStats)
|
||||
resolve()
|
||||
}
|
||||
if (this.options.dev) {
|
||||
this.compiler.watch(this.options.watchers.webpack, handler)
|
||||
if (compiler.options.name === 'client') {
|
||||
// Client watch is started by dev-middleware
|
||||
resolve()
|
||||
} else {
|
||||
// Build and watch for changes
|
||||
compiler.watch(this.options.watchers.webpack, handler)
|
||||
}
|
||||
} else {
|
||||
this.compiler.run(handler)
|
||||
// Production build
|
||||
compiler.run(handler)
|
||||
}
|
||||
})
|
||||
}))
|
||||
}
|
||||
|
||||
webpackDev () {
|
||||
debug('Adding webpack middleware...')
|
||||
|
||||
// Use MFS for faster builds
|
||||
// Use shared MFS + Cache for faster builds
|
||||
let mfs = new MFS()
|
||||
this.compiler.compilers.forEach(compiler => {
|
||||
compiler.outputFileSystem = mfs
|
||||
compiler.cache = this.compiler.cache
|
||||
})
|
||||
|
||||
// Watch
|
||||
this.plugin('reload', () => {
|
||||
// Show open URL
|
||||
let _host = host === '0.0.0.0' ? 'localhost' : host
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(chalk.bold(chalk.bgCyan.black(' OPEN ') + chalk.cyan(` http://${_host}:${port}\n`)))
|
||||
|
||||
// Run after each compile
|
||||
this.compiler.plugin('done', stats => {
|
||||
console.log(stats.toString(this.webpackStats)) // eslint-disable-line no-console
|
||||
// Reload renderer if available
|
||||
if (this.nuxt.renderer) {
|
||||
this.nuxt.renderer.loadResources(mfs)
|
||||
}
|
||||
})
|
||||
|
||||
// Create webpack Dev/Hot middleware
|
||||
this.webpackDevMiddleware = pify(require('webpack-dev-middleware')(this.compiler.$client, {
|
||||
// Add dev Middleware
|
||||
debug('Adding webpack middleware...')
|
||||
|
||||
// Create webpack dev middleware
|
||||
this.webpackDevMiddleware = pify(require('webpack-dev-middleware')(this.compiler.client, {
|
||||
publicPath: this.options.build.publicPath,
|
||||
stats: this.webpackStats,
|
||||
quiet: true,
|
||||
noInfo: true,
|
||||
quiet: true,
|
||||
watchOptions: this.options.watchers.webpack
|
||||
}))
|
||||
|
||||
this.webpackHotMiddleware = pify(require('webpack-hot-middleware')(this.compiler.$client, {
|
||||
this.webpackHotMiddleware = pify(require('webpack-hot-middleware')(this.compiler.client, {
|
||||
log: false,
|
||||
heartbeat: 2500
|
||||
}))
|
||||
|
||||
// Stop webpack middleware on nuxt.close()
|
||||
this.nuxt.plugin('close', () => new Promise(resolve => {
|
||||
this.webpackDevMiddleware.close(() => resolve())
|
||||
}))
|
||||
|
||||
// Start watching files
|
||||
this.watchFiles()
|
||||
}
|
||||
|
||||
@ -360,13 +377,21 @@ export default class Builder extends Tapable {
|
||||
})
|
||||
/* istanbul ignore next */
|
||||
const refreshFiles = _.debounce(this.generateRoutesAndFiles, 200)
|
||||
// Watch for internals
|
||||
this.filesWatcher = chokidar.watch(patterns, options)
|
||||
|
||||
// Watch for src Files
|
||||
let filesWatcher = chokidar.watch(patterns, options)
|
||||
.on('add', refreshFiles)
|
||||
.on('unlink', refreshFiles)
|
||||
|
||||
// Watch for custom provided files
|
||||
this.customFilesWatcher = chokidar.watch(_.uniq(this.options.build.watch), options)
|
||||
let customFilesWatcher = chokidar.watch(_.uniq(this.options.build.watch), options)
|
||||
.on('change', refreshFiles)
|
||||
|
||||
// Stop watching on nuxt.close()
|
||||
this.nuxt.plugin('close', () => {
|
||||
filesWatcher.close()
|
||||
customFilesWatcher.close()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
53
lib/nuxt.js
53
lib/nuxt.js
@ -1,11 +1,14 @@
|
||||
import Tapable from 'tappable'
|
||||
import Builder from './builder'
|
||||
import chalk from 'chalk'
|
||||
import * as Utils from './utils'
|
||||
import Renderer from './renderer'
|
||||
import ModuleContainer from './module-container'
|
||||
import Server from './server'
|
||||
import defaults from './defaults'
|
||||
|
||||
const defaultHost = process.env.HOST || process.env.npm_package_config_nuxt_host || 'localhost'
|
||||
const defaultPort = process.env.PORT || process.env.npm_package_config_nuxt_port || '3000'
|
||||
|
||||
export default class Nuxt extends Tapable {
|
||||
constructor (_options = {}) {
|
||||
super()
|
||||
@ -57,7 +60,7 @@ export default class Nuxt extends Tapable {
|
||||
if (this._builder) {
|
||||
return this._builder
|
||||
}
|
||||
// const Builder = require('./builder').default
|
||||
const Builder = require('./builder').default
|
||||
this._builder = new Builder(this)
|
||||
return this._builder
|
||||
}
|
||||
@ -90,36 +93,28 @@ export default class Nuxt extends Tapable {
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
serverReady ({ host = defaultHost, port = defaultPort } = {}) {
|
||||
let _host = host === '0.0.0.0' ? 'localhost' : host
|
||||
|
||||
// eslint-disable-next-line no-console
|
||||
console.log('\n' + chalk.bold(chalk.bgBlue.black(' OPEN ') + chalk.blue(` http://${_host}:${port}\n`)))
|
||||
|
||||
return this.applyPluginsAsync('serverReady').catch(this.errorHandler)
|
||||
}
|
||||
|
||||
async close (callback) {
|
||||
let promises = []
|
||||
/* istanbul ignore if */
|
||||
if (this.webpackDevMiddleware) {
|
||||
const p = new Promise((resolve, reject) => {
|
||||
this.webpackDevMiddleware.close(() => resolve())
|
||||
})
|
||||
promises.push(p)
|
||||
}
|
||||
/* istanbul ignore if */
|
||||
if (this.webpackServerWatcher) {
|
||||
const p = new Promise((resolve, reject) => {
|
||||
this.webpackServerWatcher.close(() => resolve())
|
||||
})
|
||||
promises.push(p)
|
||||
}
|
||||
/* istanbul ignore if */
|
||||
if (this.filesWatcher) {
|
||||
this.filesWatcher.close()
|
||||
}
|
||||
/* istanbul ignore if */
|
||||
if (this.customFilesWatcher) {
|
||||
this.customFilesWatcher.close()
|
||||
}
|
||||
// Call for close
|
||||
await this.applyPluginsAsync('close')
|
||||
|
||||
promises.push(this.applyPluginsAsync('close'))
|
||||
// Remove all references
|
||||
delete this._generator
|
||||
delete this._builder
|
||||
|
||||
return Promise.all(promises).then(() => {
|
||||
if (typeof callback === 'function') callback()
|
||||
})
|
||||
this.initialized = false
|
||||
|
||||
if (typeof callback === 'function') {
|
||||
callback()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -10,6 +10,7 @@ import _ from 'lodash'
|
||||
import { resolve, join } from 'path'
|
||||
import fs from 'fs-extra'
|
||||
import { createBundleRenderer } from 'vue-server-renderer'
|
||||
import chalk from 'chalk'
|
||||
import { getContext, setAnsiColors, encodeHtml } from './utils'
|
||||
|
||||
const debug = require('debug')('nuxt:render')
|
||||
@ -39,6 +40,7 @@ export default class Renderer extends Tapable {
|
||||
errorTemplate: parseTemplate(fs.readFileSync(resolve(__dirname, 'views', 'error.html'), 'utf8'))
|
||||
}
|
||||
|
||||
// Initialize
|
||||
if (nuxt.initialized) {
|
||||
// If nuxt already initialized
|
||||
this._ready = this.ready().catch(this.nuxt.errorHandler)
|
||||
@ -71,16 +73,18 @@ export default class Renderer extends Tapable {
|
||||
|
||||
// Load resources from fs
|
||||
if (!this.options.dev) {
|
||||
return this.loadResources()
|
||||
await this.loadResources()
|
||||
}
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
async loadResources (_fs = fs, distPath) {
|
||||
distPath = distPath || resolve(this.options.buildDir, 'dist')
|
||||
async loadResources (_fs = fs, isServer) {
|
||||
let distPath = resolve(this.options.buildDir, 'dist')
|
||||
|
||||
const resourceMap = {
|
||||
clientManifest: {
|
||||
path: join(distPath, 'client-manifest.json'),
|
||||
path: join(distPath, 'vue-ssr-client-manifest.json'),
|
||||
transform: JSON.parse
|
||||
},
|
||||
serverBundle: {
|
||||
@ -116,7 +120,7 @@ export default class Renderer extends Tapable {
|
||||
})
|
||||
|
||||
if (updated.length > 0) {
|
||||
// debug('Updated', updated.join(', '))
|
||||
// debug('Updated', updated.join(', '), isServer)
|
||||
this.createRenderer()
|
||||
}
|
||||
}
|
||||
@ -136,6 +140,8 @@ export default class Renderer extends Tapable {
|
||||
|
||||
// Promisify renderToString
|
||||
this.bundleRenderer.renderToString = pify(this.bundleRenderer.renderToString)
|
||||
|
||||
this.nuxt.serverReady()
|
||||
}
|
||||
|
||||
async render (req, res) {
|
||||
|
@ -8,17 +8,33 @@ class Server {
|
||||
this.options = nuxt.options
|
||||
|
||||
// Initialize
|
||||
if (nuxt.initialized) {
|
||||
// If nuxt already initialized
|
||||
this._ready = this.ready().catch(this.nuxt.errorHandler)
|
||||
} else {
|
||||
// Wait for hook
|
||||
this.nuxt.plugin('afterInit', () => {
|
||||
this._ready = this.ready()
|
||||
return this._ready
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
async ready() {
|
||||
if (this._ready) {
|
||||
return this._ready
|
||||
}
|
||||
|
||||
this.app = connect()
|
||||
this.server = http.createServer(this.app)
|
||||
this.nuxt.ready()
|
||||
.then(() => {
|
||||
// Add Middleware
|
||||
this.options.serverMiddleware.forEach(m => {
|
||||
this.useMiddleware(m)
|
||||
})
|
||||
// Add default render middleware
|
||||
this.useMiddleware(this.render.bind(this))
|
||||
})
|
||||
|
||||
// Add Middleware
|
||||
this.options.serverMiddleware.forEach(m => {
|
||||
this.useMiddleware(m)
|
||||
})
|
||||
// Add default render middleware
|
||||
this.useMiddleware(this.render.bind(this))
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
@ -49,12 +65,13 @@ class Server {
|
||||
host = host || 'localhost'
|
||||
port = port || 3000
|
||||
this.nuxt.ready()
|
||||
.then(() => {
|
||||
this.server.listen(port, host, () => {
|
||||
let _host = host === '0.0.0.0' ? 'localhost' : host
|
||||
console.log('Ready on http://%s:%s', _host, port) // eslint-disable-line no-console
|
||||
.then(() => {
|
||||
this.server.listen(port, host, () => {
|
||||
// Renderer calls showURL when server is really ready
|
||||
// this.nuxt.showURL(host, port)
|
||||
})
|
||||
})
|
||||
})
|
||||
.catch(this.nuxt.errorHandler)
|
||||
return this
|
||||
}
|
||||
|
||||
|
@ -63,6 +63,10 @@ export function sequence (tasks, fn) {
|
||||
return tasks.reduce((promise, task) => promise.then(() => fn(task)), Promise.resolve())
|
||||
}
|
||||
|
||||
export function parallel (tasks, fn) {
|
||||
return Promise.all(tasks.map(task => fn(task)))
|
||||
}
|
||||
|
||||
export function chainFn (base, fn) {
|
||||
/* istanbul ignore if */
|
||||
if (!(fn instanceof Function)) {
|
||||
|
@ -1,6 +1,8 @@
|
||||
import ExtractTextPlugin from 'extract-text-webpack-plugin'
|
||||
import { defaults } from 'lodash'
|
||||
import { join } from 'path'
|
||||
import { join, resolve, } from 'path'
|
||||
import webpack from 'webpack'
|
||||
import { cloneDeep } from 'lodash'
|
||||
import { isUrl, urlJoin } from '../utils'
|
||||
import vueLoaderConfig from './vue-loader.config'
|
||||
import { styleLoader, extractStyles } from './helpers'
|
||||
@ -15,12 +17,15 @@ import { styleLoader, extractStyles } from './helpers'
|
||||
*/
|
||||
export default function webpackBaseConfig ({ isClient, isServer }) {
|
||||
const nodeModulesDir = join(__dirname, '..', 'node_modules')
|
||||
let config = {
|
||||
devtool: (this.options.dev ? 'cheap-module-source-map' : false),
|
||||
|
||||
const config = {
|
||||
devtool: this.options.dev ? 'cheap-module-source-map' : false,
|
||||
entry: {
|
||||
vendor: ['vue', 'vue-router', 'vue-meta']
|
||||
},
|
||||
output: {
|
||||
path: resolve(this.options.buildDir, 'dist'),
|
||||
filename: this.options.build.filenames.app,
|
||||
publicPath: (isUrl(this.options.build.publicPath)
|
||||
? this.options.build.publicPath
|
||||
: urlJoin(this.options.router.base, this.options.build.publicPath))
|
||||
@ -28,7 +33,7 @@ export default function webpackBaseConfig ({ isClient, isServer }) {
|
||||
performance: {
|
||||
maxEntrypointSize: 300000,
|
||||
maxAssetSize: 300000,
|
||||
hints: (this.options.dev ? false : 'warning')
|
||||
hints: this.options.dev ? false : 'warning'
|
||||
},
|
||||
resolve: {
|
||||
extensions: ['.js', '.json', '.vue', '.ts'],
|
||||
@ -57,6 +62,7 @@ export default function webpackBaseConfig ({ isClient, isServer }) {
|
||||
]
|
||||
},
|
||||
module: {
|
||||
noParse: /es6-promise\.js$/, // avoid webpack shimming process
|
||||
rules: [
|
||||
{
|
||||
test: /\.vue$/,
|
||||
@ -98,12 +104,33 @@ export default function webpackBaseConfig ({ isClient, isServer }) {
|
||||
},
|
||||
plugins: this.options.build.plugins
|
||||
}
|
||||
|
||||
// CSS extraction
|
||||
if (extractStyles.call(this)) {
|
||||
config.plugins.push(
|
||||
new ExtractTextPlugin({ filename: this.options.build.filenames.css })
|
||||
)
|
||||
}
|
||||
// Return config
|
||||
return config
|
||||
|
||||
// --------------------------------------
|
||||
// Dev specific config
|
||||
// --------------------------------------
|
||||
if (this.options.dev) {
|
||||
//
|
||||
}
|
||||
|
||||
// --------------------------------------
|
||||
// Production specific config
|
||||
// --------------------------------------
|
||||
if (!this.options.dev) {
|
||||
// This is needed in webpack 2 for minify CSS
|
||||
config.plugins.push(
|
||||
new webpack.LoaderOptionsPlugin({
|
||||
minimize: true
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
// Clone deep avoid leaking config between Client and Server
|
||||
return cloneDeep(config)
|
||||
}
|
||||
|
@ -22,89 +22,108 @@ import base from './base.config.js'
|
||||
export default function webpackClientConfig () {
|
||||
let config = base.call(this, { isClient: true })
|
||||
|
||||
config.name = 'client'
|
||||
|
||||
// Entry
|
||||
config.entry.app = resolve(this.options.buildDir, 'client.js')
|
||||
|
||||
// Add vendors
|
||||
if (this.options.store) {
|
||||
config.entry.vendor.push('vuex')
|
||||
if (!this.options.dev) {
|
||||
if (this.options.store) {
|
||||
config.entry.vendor.push('vuex')
|
||||
}
|
||||
config.entry.vendor = config.entry.vendor.concat(this.options.build.vendor)
|
||||
// Extract vendor chunks for better caching
|
||||
config.plugins.push(
|
||||
new webpack.optimize.CommonsChunkPlugin({
|
||||
name: 'vendor',
|
||||
filename: this.options.build.filenames.vendor,
|
||||
minChunks (module) {
|
||||
// A module is extracted into the vendor chunk when...
|
||||
return (
|
||||
// If it's inside node_modules
|
||||
/node_modules/.test(module.context) &&
|
||||
// Do not externalize if the request is a CSS file
|
||||
!/\.(css|less|scss|sass|styl|stylus)$/.test(module.request)
|
||||
)
|
||||
}
|
||||
})
|
||||
)
|
||||
}
|
||||
config.entry.vendor = config.entry.vendor.concat(this.options.build.vendor)
|
||||
|
||||
// Output
|
||||
config.output.path = resolve(this.options.buildDir, 'dist')
|
||||
config.output.filename = this.options.build.filenames.app
|
||||
|
||||
// env object defined in nuxt.config.js
|
||||
// Env object defined in nuxt.config.js
|
||||
let env = {}
|
||||
each(this.options.env, (value, key) => {
|
||||
env['process.env.' + key] = (typeof value === 'string' ? JSON.stringify(value) : value)
|
||||
})
|
||||
// Webpack plugins
|
||||
config.plugins = (config.plugins || []).concat([
|
||||
// Strip comments in Vue code
|
||||
new webpack.DefinePlugin(Object.assign(env, {
|
||||
'process.env.NODE_ENV': JSON.stringify(env.NODE_ENV || (this.options.dev ? 'development' : 'production')),
|
||||
'process.BROWSER_BUILD': true,
|
||||
'process.SERVER_BUILD': false,
|
||||
'process.browser': true,
|
||||
'process.server': true
|
||||
})),
|
||||
// Extract vendor chunks for better caching
|
||||
new webpack.optimize.CommonsChunkPlugin({
|
||||
name: 'vendor',
|
||||
filename: this.options.build.filenames.vendor,
|
||||
minChunks (module) {
|
||||
// A module is extracted into the vendor chunk when...
|
||||
return (
|
||||
// If it's inside node_modules
|
||||
/node_modules/.test(module.context) &&
|
||||
// Do not externalize if the request is a CSS file
|
||||
!/\.(css|less|scss|sass|styl|stylus)$/.test(module.request)
|
||||
)
|
||||
}
|
||||
}),
|
||||
// Extract webpack runtime & manifest
|
||||
|
||||
// Webpack common plugins
|
||||
if (!Array.isArray(config.plugins)) {
|
||||
config.plugins = []
|
||||
}
|
||||
|
||||
// Generate output HTML
|
||||
config.plugins.push(
|
||||
new HTMLPlugin({
|
||||
template: this.options.appTemplatePath,
|
||||
inject: false
|
||||
})
|
||||
)
|
||||
|
||||
// Generate vue-ssr-client-manifest
|
||||
config.plugins.push(
|
||||
new VueSSRClientPlugin({
|
||||
filename: 'vue-ssr-client-manifest.json'
|
||||
})
|
||||
)
|
||||
|
||||
// Extract webpack runtime & manifest
|
||||
config.plugins.push(
|
||||
new webpack.optimize.CommonsChunkPlugin({
|
||||
name: 'manifest',
|
||||
minChunks: Infinity,
|
||||
filename: this.options.build.filenames.manifest
|
||||
}),
|
||||
// Generate output HTML
|
||||
new HTMLPlugin({
|
||||
template: this.options.appTemplatePath,
|
||||
inject: false // <- Resources will be injected using vue server renderer
|
||||
}),
|
||||
// Generate client manifest json
|
||||
new VueSSRClientPlugin({
|
||||
filename: 'client-manifest.json'
|
||||
})
|
||||
])
|
||||
// client bundle progress bar
|
||||
)
|
||||
|
||||
|
||||
// Define Env
|
||||
config.plugins.push(
|
||||
new webpack.DefinePlugin(Object.assign(env, {
|
||||
'process.env.NODE_ENV': JSON.stringify(env.NODE_ENV || (this.options.dev ? 'development' : 'production')),
|
||||
'process.env.VUE_ENV': JSON.stringify('client'),
|
||||
'process.browser': true,
|
||||
'process.server': false
|
||||
}))
|
||||
)
|
||||
|
||||
// Build progress bar
|
||||
config.plugins.push(
|
||||
new ProgressBarPlugin()
|
||||
)
|
||||
// Add friendly error plugin
|
||||
|
||||
// --------------------------------------
|
||||
// Dev specific config
|
||||
// --------------------------------------
|
||||
if (this.options.dev) {
|
||||
// Add friendly error plugin
|
||||
config.plugins.push(new FriendlyErrorsWebpackPlugin())
|
||||
}
|
||||
// Dev client build
|
||||
if (this.options.dev) {
|
||||
|
||||
// Add HMR support
|
||||
config.entry.app = flatten(['webpack-hot-middleware/client?name=$client&reload=true', config.entry.app])
|
||||
config.entry.app = ['webpack-hot-middleware/client?name=$client&reload=true', config.entry.app]
|
||||
config.output.filename = '[name].js'
|
||||
config.plugins.push(
|
||||
new webpack.HotModuleReplacementPlugin(),
|
||||
new webpack.NoEmitOnErrorsPlugin()
|
||||
)
|
||||
}
|
||||
// Production client build
|
||||
|
||||
// --------------------------------------
|
||||
// Production specific config
|
||||
// --------------------------------------
|
||||
if (!this.options.dev) {
|
||||
// Minify JS
|
||||
config.plugins.push(
|
||||
// This is needed in webpack 2 for minifying CSS
|
||||
new webpack.LoaderOptionsPlugin({
|
||||
minimize: true
|
||||
}),
|
||||
// Minify JS
|
||||
new webpack.optimize.UglifyJsPlugin({
|
||||
sourceMap: true,
|
||||
compress: {
|
||||
@ -112,7 +131,15 @@ export default function webpackClientConfig () {
|
||||
}
|
||||
})
|
||||
)
|
||||
|
||||
// Webpack Bundle Analyzer
|
||||
if (this.options.build.analyze) {
|
||||
config.plugins.push(
|
||||
new BundleAnalyzerPlugin(Object.assign({}, this.options.build.analyze))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Extend config
|
||||
if (typeof this.options.build.extend === 'function') {
|
||||
this.options.build.extend.call(this, config, {
|
||||
@ -120,22 +147,6 @@ export default function webpackClientConfig () {
|
||||
isClient: true
|
||||
})
|
||||
}
|
||||
// Offline-plugin integration
|
||||
if (!this.options.dev && this.options.offline) {
|
||||
const offlineOpts = typeof this.options.offline === 'object' ? this.options.offline : {}
|
||||
config.plugins.push(
|
||||
new OfflinePlugin(defaults(offlineOpts, {}))
|
||||
)
|
||||
}
|
||||
// Webpack Bundle Analyzer
|
||||
if (!this.options.dev && this.options.build.analyze) {
|
||||
let options = {}
|
||||
if (typeof this.options.build.analyze === 'object') {
|
||||
options = this.options.build.analyze
|
||||
}
|
||||
config.plugins.push(
|
||||
new BundleAnalyzerPlugin(options)
|
||||
)
|
||||
}
|
||||
|
||||
return config
|
||||
}
|
||||
|
@ -13,6 +13,8 @@ import base from './base.config.js'
|
||||
export default function webpackServerConfig () {
|
||||
let config = base.call(this, { isServer: true })
|
||||
|
||||
config.name = 'server'
|
||||
|
||||
// env object defined in nuxt.config.js
|
||||
let env = {}
|
||||
each(this.options.env, (value, key) => {
|
||||
@ -24,7 +26,6 @@ export default function webpackServerConfig () {
|
||||
devtool: (this.options.dev ? 'source-map' : false),
|
||||
entry: resolve(this.options.buildDir, 'server.js'),
|
||||
output: Object.assign({}, config.output, {
|
||||
path: resolve(this.options.buildDir, 'dist'),
|
||||
filename: 'server-bundle.js',
|
||||
libraryTarget: 'commonjs2'
|
||||
}),
|
||||
@ -32,6 +33,8 @@ export default function webpackServerConfig () {
|
||||
hints: false
|
||||
},
|
||||
externals: [
|
||||
// https://webpack.js.org/configuration/externals/#externals
|
||||
// https://github.com/liady/webpack-node-externals
|
||||
nodeExternals({
|
||||
// load non-javascript files with extensions, presumably via loaders
|
||||
whitelist: [/\.(?!(?:js|json)$).{1,5}$/i]
|
||||
@ -42,21 +45,19 @@ export default function webpackServerConfig () {
|
||||
filename: 'server-bundle.json'
|
||||
}),
|
||||
new webpack.DefinePlugin(Object.assign(env, {
|
||||
'process.env.NODE_ENV': JSON.stringify(this.options.dev ? 'development' : 'production'),
|
||||
'process.BROWSER_BUILD': false, // deprecated
|
||||
'process.SERVER_BUILD': true, // deprecated
|
||||
'process.env.NODE_ENV': JSON.stringify(env.NODE_ENV || (this.options.dev ? 'development' : 'production')),
|
||||
'process.env.VUE_ENV': JSON.stringify('server'),
|
||||
'process.browser': false,
|
||||
'process.server': true
|
||||
}))
|
||||
])
|
||||
})
|
||||
// This is needed in webpack 2 for minifying CSS
|
||||
|
||||
// --------------------------------------
|
||||
// Production specific config
|
||||
// --------------------------------------
|
||||
if (!this.options.dev) {
|
||||
config.plugins.push(
|
||||
new webpack.LoaderOptionsPlugin({
|
||||
minimize: true
|
||||
})
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
// Extend config
|
||||
@ -66,5 +67,6 @@ export default function webpackServerConfig () {
|
||||
isServer: true
|
||||
})
|
||||
}
|
||||
|
||||
return config
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ export default function ({ isClient }) {
|
||||
}))
|
||||
|
||||
// https://github.com/vuejs/vue-loader/blob/master/docs/en/configurations
|
||||
let config = {
|
||||
const config = {
|
||||
postcss: this.options.build.postcss,
|
||||
loaders: {
|
||||
'js': 'babel-loader?' + babelOptions,
|
||||
@ -23,6 +23,7 @@ export default function ({ isClient }) {
|
||||
preserveWhitespace: false,
|
||||
extractCSS: extractStyles.call(this)
|
||||
}
|
||||
|
||||
// Return the config
|
||||
return config
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user