improvements

This commit is contained in:
Pooya Parsa 2017-06-15 19:23:00 +04:30
parent 15bc36afb0
commit d882b1ac77
4 changed files with 64 additions and 42 deletions

View File

@ -5,10 +5,9 @@ import hash from 'hash-sum'
import pify from 'pify' import pify from 'pify'
import webpack from 'webpack' import webpack from 'webpack'
import serialize from 'serialize-javascript' import serialize from 'serialize-javascript'
import webpackDevMiddleware from 'webpack-dev-middleware'
import webpackHotMiddleware from 'webpack-hot-middleware'
import { join, resolve, basename, dirname } from 'path' import { join, resolve, basename, dirname } from 'path'
import Tapable from 'tappable' import Tapable from 'tappable'
import chalk from 'chalk'
import { r, wp, createRoutes } from './utils' import { r, wp, createRoutes } from './utils'
import clientWebpackConfig from './webpack/client.config.js' import clientWebpackConfig from './webpack/client.config.js'
import serverWebpackConfig from './webpack/server.config.js' import serverWebpackConfig from './webpack/server.config.js'
@ -282,7 +281,7 @@ export default class Builder extends Tapable {
// Start build // Start build
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
this.compiler.run((err, multiStats) => { const handler = (err, multiStats) => {
if (err) { if (err) {
return reject(err) return reject(err)
} }
@ -292,8 +291,15 @@ export default class Builder extends Tapable {
return reject(new Error('Webpack build exited with errors')) 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() resolve()
}) }
if (this.options.dev) {
this.compiler.watch(this.options.watchers.webpack, handler)
} else {
this.compiler.run(handler)
}
}) })
} }
@ -306,42 +312,33 @@ export default class Builder extends Tapable {
compiler.outputFileSystem = mfs compiler.outputFileSystem = mfs
}) })
let clientConfig = this.compiler.$client.options // 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`)))
// Setup on the fly compilation + hot-reload // Reload renderer if available
clientConfig.entry.app = _.flatten(['webpack-hot-middleware/client?reload=true', clientConfig.entry.app]) if (this.nuxt.renderer) {
clientConfig.plugins.push( this.nuxt.renderer.loadResources(mfs)
new webpack.HotModuleReplacementPlugin(), }
new webpack.NoEmitOnErrorsPlugin() })
)
// Create webpack dev middleware // Create webpack Dev/Hot middleware
this.webpackDevMiddleware = pify(webpackDevMiddleware(this.compiler.$client, { this.webpackDevMiddleware = pify(require('webpack-dev-middleware')(this.compiler.$client, {
publicPath: clientConfig.output.publicPath, publicPath: this.options.build.publicPath,
stats: this.webpackStats, stats: this.webpackStats,
quiet: true, quiet: true,
noInfo: true, noInfo: true,
watchOptions: this.options.watchers.webpack watchOptions: this.options.watchers.webpack
})) }))
this.webpackHotMiddleware = pify(webpackHotMiddleware(this.compiler.$client, { this.webpackHotMiddleware = pify(require('webpack-hot-middleware')(this.compiler.$client, {
log: false, log: false,
heartbeat: 2500 heartbeat: 2500
})) }))
// Run after compilation is done
this.compiler.plugin('done', async stats => {
// Reload renderer if available
if (this.nuxt.renderer) {
await this.nuxt.renderer.loadResources(mfs)
}
// Show open URL
if (!stats.hasErrors() && !stats.hasWarnings()) {
let _host = host === '0.0.0.0' ? 'localhost' : host
console.log(`> Open http://${_host}:${port}\n`) // eslint-disable-line no-console
}
})
this.watchFiles() this.watchFiles()
} }

View File

@ -1,4 +1,5 @@
import Tapable from 'tappable' import Tapable from 'tappable'
import Builder from './builder'
import * as Utils from './utils' import * as Utils from './utils'
import Renderer from './renderer' import Renderer from './renderer'
import ModuleContainer from './module-container' import ModuleContainer from './module-container'
@ -56,7 +57,7 @@ export default class Nuxt extends Tapable {
if (this._builder) { if (this._builder) {
return this._builder return this._builder
} }
const Builder = require('./builder').default // const Builder = require('./builder').default
this._builder = new Builder(this) this._builder = new Builder(this)
return this._builder return this._builder
} }

View File

@ -69,9 +69,11 @@ export default class Renderer extends Tapable {
this.gzipMiddleware = pify(compression(this.options.render.gzip)) this.gzipMiddleware = pify(compression(this.options.render.gzip))
} }
// Try to load resources from fs // Load resources from fs
if (!this.options.dev) {
return this.loadResources() return this.loadResources()
} }
}
async loadResources (_fs = fs, distPath) { async loadResources (_fs = fs, distPath) {
distPath = distPath || resolve(this.options.buildDir, 'dist') distPath = distPath || resolve(this.options.buildDir, 'dist')
@ -91,22 +93,33 @@ export default class Renderer extends Tapable {
} }
} }
let updated = []
Object.keys(resourceMap).forEach(resourceKey => { Object.keys(resourceMap).forEach(resourceKey => {
let { path, transform } = resourceMap[resourceKey] let { path, transform } = resourceMap[resourceKey]
let data let rawKey = '$$' + resourceKey
if (_fs.existsSync(path)) { let rawData, data
data = _fs.readFileSync(path, 'utf8') if (!_fs.existsSync(path)) {
if (typeof transform === 'function') { return // Resource not exists
data = transform(data)
} }
rawData = _fs.readFileSync(path, 'utf8')
if (!rawData || rawData === this.resources[rawKey]) {
return // No changes
}
this.resources[rawKey] = rawData
data = transform(rawData)
if (!data) {
return // Invalid data ?
} }
if (data) {
this.resources[resourceKey] = data this.resources[resourceKey] = data
} updated.push(resourceKey)
}) })
if (updated.length > 0) {
// debug('Updated', updated.join(', '))
this.createRenderer() this.createRenderer()
} }
}
createRenderer () { createRenderer () {
// If resources are not yet provided // If resources are not yet provided
@ -232,7 +245,9 @@ export default class Renderer extends Tapable {
async renderRoute (url, context = {}) { async renderRoute (url, context = {}) {
/* istanbul ignore if */ /* istanbul ignore if */
if (!this.bundleRenderer || !this.resources.appTemplate) { if (!this.bundleRenderer || !this.resources.appTemplate) {
return Promise.reject(new Error('bundleRenderer is not available')) return new Promise(resolve => {
setTimeout(() => resolve(this.renderRoute(url, context)), 1000)
})
} }
// Log rendered url // Log rendered url

View File

@ -1,4 +1,4 @@
import { each, defaults } from 'lodash' import { each, defaults, flatten } from 'lodash'
import webpack from 'webpack' import webpack from 'webpack'
import VueSSRClientPlugin from 'vue-server-renderer/client-plugin' import VueSSRClientPlugin from 'vue-server-renderer/client-plugin'
import HTMLPlugin from 'html-webpack-plugin' import HTMLPlugin from 'html-webpack-plugin'
@ -88,6 +88,15 @@ export default function webpackClientConfig () {
if (this.options.dev) { if (this.options.dev) {
config.plugins.push(new FriendlyErrorsWebpackPlugin()) 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.plugins.push(
new webpack.HotModuleReplacementPlugin(),
new webpack.NoEmitOnErrorsPlugin()
)
}
// Production client build // Production client build
if (!this.options.dev) { if (!this.options.dev) {
config.plugins.push( config.plugins.push(