Middleware feature 🔥

This commit is contained in:
Sébastien Chopin 2017-02-03 15:09:27 +01:00
parent 84b8a0de3f
commit 17650c25e0
26 changed files with 296 additions and 116 deletions

View File

@ -99,7 +99,7 @@ Learn more: https://nuxtjs.org/api/nuxt
## Using nuxt.js as a middleware ## Using nuxt.js as a middleware
You might want to use your own server with you configurations, your API and everything awesome your created with. That's why you can use nuxt.js as a middleware. It's recommended to use it at the end of your middlewares since it will handle the rendering of your web application and won't call next(). You might want to use your own server with you configurations, your API and everything awesome your created with. That's why you can use nuxt.js as a middleware. It's recommended to use it at the end of your middleware since it will handle the rendering of your web application and won't call next().
```js ```js
app.use(nuxt.render) app.use(nuxt.render)

View File

@ -17,7 +17,7 @@ if (fs.existsSync(nuxtConfigFile)) {
if (typeof options.rootDir !== 'string') { if (typeof options.rootDir !== 'string') {
options.rootDir = rootDir options.rootDir = rootDir
} }
options.dev = false // Force production mode (no webpack middlewares called) options.dev = false // Force production mode (no webpack middleware called)
console.log('[nuxt] Generating...') // eslint-disable-line no-console console.log('[nuxt] Generating...') // eslint-disable-line no-console
var nuxt = new Nuxt(options) var nuxt = new Nuxt(options)

View File

@ -14,7 +14,7 @@ if (fs.existsSync(nuxtConfigFile)) {
if (typeof options.rootDir !== 'string') { if (typeof options.rootDir !== 'string') {
options.rootDir = rootDir options.rootDir = rootDir
} }
options.dev = false // Force production mode (no webpack middlewares called) options.dev = false // Force production mode (no webpack middleware called)
var nuxt = new Nuxt(options) var nuxt = new Nuxt(options)

View File

@ -0,0 +1,10 @@
export default function ({ store, redirect, error }) {
// If user not connected, redirect to /
if (!store.state.authUser) {
// return redirect('/')
error({
message: 'You are not connected',
statusCode: 403
})
}
}

View File

@ -6,6 +6,5 @@ module.exports = {
{ name: 'viewport', content: 'width=device-width, initial-scale=1' }, { name: 'viewport', content: 'width=device-width, initial-scale=1' },
{ hid: 'description', content: 'Auth Routes example' } { hid: 'description', content: 'Auth Routes example' }
] ]
}, }
loading: { color: '#3B8070' }
} }

View File

@ -2,12 +2,12 @@
"name": "auth-routes", "name": "auth-routes",
"description": "", "description": "",
"dependencies": { "dependencies": {
"axios": "^0.15.3",
"body-parser": "^1.15.2", "body-parser": "^1.15.2",
"cross-env": "^3.1.3", "cross-env": "^3.1.3",
"express": "^4.14.0", "express": "^4.14.0",
"express-session": "^1.14.2", "express-session": "^1.14.2",
"nuxt": "latest", "nuxt": "latest"
"whatwg-fetch": "^2.0.1"
}, },
"scripts": { "scripts": {
"dev": "node server.js", "dev": "node server.js",

View File

@ -8,11 +8,6 @@
<script> <script>
export default { export default {
// we use fetch() because we do not need to set data to this component middleware: 'auth'
fetch ({ store, redirect }) {
if (!store.state.authUser) {
return redirect('/')
}
}
} }
</script> </script>

View File

@ -1,7 +1,9 @@
const Nuxt = require('nuxt') const Nuxt = require('../../')
const bodyParser = require('body-parser') const bodyParser = require('body-parser')
const session = require('express-session') const session = require('express-session')
const app = require('express')() const app = require('express')()
const host = process.env.HOST || '127.0.0.1'
const port = process.env.PORT || '3000'
// Body parser, to access req.body // Body parser, to access req.body
app.use(bodyParser.json()) app.use(bodyParser.json())
@ -20,7 +22,7 @@ app.post('/api/login', function (req, res) {
req.session.authUser = { username: 'demo' } req.session.authUser = { username: 'demo' }
return res.json({ username: 'demo' }) return res.json({ username: 'demo' })
} }
res.status(401).json({ error: 'Bad credentials' }) res.status(401).json({ message: 'Bad credentials' })
}) })
// POST /api/logout to log out the user and remove it from the req.session // POST /api/logout to log out the user and remove it from the req.session
@ -29,19 +31,23 @@ app.post('/api/logout', function (req, res) {
res.json({ ok: true }) res.json({ ok: true })
}) })
// We instantiate Nuxt.js with the options // Import and Set Nuxt.js options
const isProd = process.env.NODE_ENV === 'production'
let config = require('./nuxt.config.js') let config = require('./nuxt.config.js')
config.dev = !isProd config.dev = !(process.env.NODE_ENV === 'production')
// Init Nuxt.js
const nuxt = new Nuxt(config) const nuxt = new Nuxt(config)
// No build in production app.use(nuxt.render)
const promise = (isProd ? Promise.resolve() : nuxt.build())
promise.then(() => { // Build only in dev mode
app.use(nuxt.render) if (config.dev) {
app.listen(3000) nuxt.build()
console.log('Server is listening on http://localhost:3000') // eslint-disable-line no-console .catch((error) => {
}) console.error(error) // eslint-disable-line no-console
.catch((error) => { process.exit(1)
console.error(error) // eslint-disable-line no-console })
process.exit(1) }
})
// Listen the server
app.listen(port, host)
console.log('Server listening on ' + host + ':' + port) // eslint-disable-line no-console

View File

@ -1,69 +1,41 @@
import Vue from 'vue' import axios from 'axios'
import Vuex from 'vuex'
Vue.use(Vuex) export const state = {
authUser: null
}
// Polyfill for window.fetch() export const mutations = {
require('whatwg-fetch') SET_USER: function (state, user) {
state.authUser = user
}
}
const store = new Vuex.Store({ export const actions = {
nuxtServerInit ({ commit }, { req }) {
state: { if (req.session && req.session.authUser) {
authUser: null commit('SET_USER', req.session.authUser)
},
mutations: {
SET_USER: function (state, user) {
state.authUser = user
} }
}, },
login ({ commit }, { username, password }) {
actions: { return axios.post('/api/login', {
username,
nuxtServerInit ({ commit }, { req }) { password
if (req.session && req.session.authUser) { })
commit('SET_USER', req.session.authUser) .then((res) => {
commit('SET_USER', res.data)
})
.catch((error) => {
if (error.response.status === 401) {
throw new Error('Bad credentials')
} }
}, })
},
login ({ commit }, { username, password }) {
return fetch('/api/login', {
// Send the client cookies to the server
credentials: 'same-origin',
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
username,
password
})
})
.then((res) => {
if (res.status === 401) {
throw new Error('Bad credentials')
} else {
return res.json()
}
})
.then((authUser) => {
commit('SET_USER', authUser)
})
},
logout ({ commit }) {
return fetch('/api/logout', {
// Send the client cookies to the server
credentials: 'same-origin',
method: 'POST'
})
.then(() => {
commit('SET_USER', null)
})
}
logout ({ commit }) {
return axios.post('/api/logout')
.then(() => {
commit('SET_USER', null)
})
} }
}) }
export default store

View File

@ -0,0 +1,40 @@
<template>
<ul>
<li v-for="visit in visits"><i>{{ visit.date | hours }}</i> - {{ visit.path }}</li>
</ul>
</template>
<script>
export default {
computed: {
visits () {
return this.$store.state.visits.slice().reverse()
}
},
filters: {
hours (date) {
return date.split('T')[1].split('.')[0]
}
}
}
</script>
<style scoped>
ul {
position: fixed;
top: 20px;
right: 20px;
margin: 0;
padding: 0;
height: 100%;
overflow: auto;
list-style-type: none;
}
ul li {
padding: 2px 0;
}
ul li i {
color: gray;
font-style: normal;
}
</style>

View File

@ -0,0 +1,14 @@
<template>
<div>
<nuxt/>
<visits/>
</div>
</template>
<script>
import Visits from '~components/Visits'
export default {
components: { Visits }
}
</script>

View File

@ -0,0 +1,3 @@
export default function (context) {
context.userAgent = context.isServer ? context.req.headers['user-agent'] : navigator.userAgent
}

View File

@ -0,0 +1,3 @@
export default function ({ store, route }) {
store.commit('ADD_VISIT', route.path)
}

View File

@ -0,0 +1,5 @@
module.exports = {
router: {
middleware: ['visits', 'user-agent']
}
}

View File

@ -0,0 +1,11 @@
{
"name": "nuxt-middleware",
"dependencies": {
"nuxt": "latest"
},
"scripts": {
"dev": "nuxt",
"build": "nuxt build",
"start": "nuxt start"
}
}

View File

@ -0,0 +1,25 @@
<template>
<div>
<h1>{{ $route.params.slug || 'Home' }}</h1>
<pre>{{ userAgent }}</pre>
<ul>
<li><nuxt-link to="/">Home</nuxt-link></li>
<li v-for="slug in slugs"><nuxt-link :to="{ name: 'slug', params: { slug } }">{{ slug }}</nuxt-link></li>
</ul>
</div>
</template>
<script>
export default {
data ({ store, route, userAgent }) {
return {
userAgent,
slugs: [
'foo',
'bar',
'baz'
]
}
}
}
</script>

View File

@ -0,0 +1,12 @@
export const state = {
visits: []
}
export const mutations = {
ADD_VISIT (state, path) {
state.visits.push({
path,
date: new Date().toJSON()
})
}
}

View File

@ -1,8 +1,9 @@
'use strict' 'use strict'
import Vue from 'vue' import Vue from 'vue'
import middleware from './middleware'
import { app, router<%= (store ? ', store' : '') %> } from './index' import { app, router<%= (store ? ', store' : '') %> } from './index'
import { getMatchedComponents, getMatchedComponentsInstances, flatMapComponents, getContext, promisify, getLocation, compile } from './utils' import { getMatchedComponents, getMatchedComponentsInstances, flatMapComponents, getContext, promiseSeries, promisify, getLocation, compile } from './utils'
const noopData = () => { return {} } const noopData = () => { return {} }
const noopFetch = () => {} const noopFetch = () => {}
let _lastPaths = [] let _lastPaths = []
@ -51,16 +52,44 @@ function loadAsyncComponents (to, from, next) {
}) })
} }
function callMiddleware (Components, context, layout) {
// Call middleware
let midd = <%= serialize(router.middleware, { isJSON: true }) %>
if (layout.middleware) {
midd = midd.concat(layout.middleware)
}
Components.forEach((Component) => {
if (Component.options.middleware) {
midd = midd.concat(Component.options.middleware)
}
})
midd = midd.map((name) => {
if (typeof middleware[name] !== 'function') {
this.error({ statusCode: 500, message: 'Unknown middleware ' + name })
}
return middleware[name]
})
if (this.$options._nuxt.err) return
return promiseSeries(midd, context)
}
function render (to, from, next) { function render (to, from, next) {
if (this._hashChanged) return next() if (this._hashChanged) return next()
const _next = function (path) {
<%= (loading ? 'this.$loading.finish && this.$loading.finish()' : '') %>
nextCalled = true
next(path)
}
const context = getContext({ to<%= (store ? ', store' : '') %>, isClient: true, next: _next.bind(this), error: this.error.bind(this) })
let Components = getMatchedComponents(to) let Components = getMatchedComponents(to)
this._dateLastError = this.$options._nuxt.dateErr this._dateLastError = this.$options._nuxt.dateErr
this._hadError = !!this.$options._nuxt.err this._hadError = !!this.$options._nuxt.err
if (!Components.length) { if (!Components.length) {
// Default layout // Default layout
this.setLayout() this.setLayout()
.then(callMiddleware.bind(this, Components, context))
.then(() => { .then(() => {
this.error({ statusCode: 404, message: 'This page could not be found.', url: to.path }) this.error({ statusCode: 404, message: 'This page could not be found.' })
return next() return next()
}) })
return return
@ -87,6 +116,7 @@ function render (to, from, next) {
let nextCalled = false let nextCalled = false
// Set layout // Set layout
this.setLayout(Components[0].options.layout) this.setLayout(Components[0].options.layout)
.then(callMiddleware.bind(this, Components, context))
.then(() => { .then(() => {
// Pass validation? // Pass validation?
let isValid = true let isValid = true
@ -99,7 +129,7 @@ function render (to, from, next) {
}) })
}) })
if (!isValid) { if (!isValid) {
this.error({ statusCode: 404, message: 'This page could not be found.', url: to.path }) this.error({ statusCode: 404, message: 'This page could not be found.' })
return next() return next()
} }
return Promise.all(Components.map((Component, i) => { return Promise.all(Components.map((Component, i) => {
@ -109,12 +139,6 @@ function render (to, from, next) {
return Promise.resolve() return Promise.resolve()
} }
let promises = [] let promises = []
const _next = function (path) {
<%= (loading ? 'this.$loading.finish && this.$loading.finish()' : '') %>
nextCalled = true
next(path)
}
const context = getContext({ to<%= (store ? ', store' : '') %>, isClient: true, next: _next.bind(this), error: this.error.bind(this) })
// Validate method // Validate method
if (Component._data && typeof Component._data === 'function') { if (Component._data && typeof Component._data === 'function') {
var promise = promisify(Component._data, context) var promise = promisify(Component._data, context)

20
lib/app/middleware.js Normal file
View File

@ -0,0 +1,20 @@
<% if (middleware) { %>
let files = require.context('~/middleware', false, /^\.\/.*\.js$/)
let filenames = files.keys()
function getModule (filename) {
let file = files(filename)
return file.default
? file.default
: file
}
let middleware = {}
// Generate the middleware
for (let filename of filenames) {
let name = filename.replace(/^\.\//, '').replace(/\.js$/, '')
middleware[name] = getModule(filename)
}
export default middleware
<% } else { %>export default {}<% } %>

View File

@ -5,8 +5,9 @@ debug.color = 4 // force blue color
import Vue from 'vue' import Vue from 'vue'
import { stringify } from 'querystring' import { stringify } from 'querystring'
import { omit } from 'lodash' import { omit } from 'lodash'
import middleware from './middleware'
import { app, router<%= (store ? ', store' : '') %> } from './index' import { app, router<%= (store ? ', store' : '') %> } from './index'
import { getMatchedComponents, getContext, promisify, urlJoin } from './utils' import { getMatchedComponents, getContext, promiseSeries, promisify, urlJoin } from './utils'
const isDev = <%= isDev %> const isDev = <%= isDev %>
const _app = new Vue(app) const _app = new Vue(app)
@ -47,6 +48,7 @@ export default context => {
context.error = _app.$options._nuxt.error.bind(_app) context.error = _app.$options._nuxt.error.bind(_app)
<%= (isDev ? 'const s = isDev && Date.now()' : '') %> <%= (isDev ? 'const s = isDev && Date.now()' : '') %>
const ctx = getContext(context)
let Components = getMatchedComponents(context.route) let Components = getMatchedComponents(context.route)
<% if (store) { %> <% if (store) { %>
let promise = (store._actions && store._actions.nuxtServerInit ? store.dispatch('nuxtServerInit', omit(getContext(context), 'redirect', 'error')) : null) let promise = (store._actions && store._actions.nuxtServerInit ? store.dispatch('nuxtServerInit', omit(getContext(context), 'redirect', 'error')) : null)
@ -71,6 +73,26 @@ export default context => {
// Set layout // Set layout
return _app.setLayout(Components.length ? Components[0].options.layout : '') return _app.setLayout(Components.length ? Components[0].options.layout : '')
}) })
.then((layout) => {
// Call middleware
let midd = <%= serialize(router.middleware, { isJSON: true }) %>
if (layout.middleware) {
midd = midd.concat(layout.middleware)
}
Components.forEach((Component) => {
if (Component.options.middleware) {
midd = midd.concat(Component.options.middleware)
}
})
midd = midd.map((name) => {
if (typeof middleware[name] !== 'function') {
context.nuxt.error = context.error({ statusCode: 500, message: 'Unknown middleware ' + name })
}
return middleware[name]
})
if (context.nuxt.error) return
return promiseSeries(midd, ctx)
})
.then(() => { .then(() => {
// Call .validate() // Call .validate()
let isValid = true let isValid = true
@ -94,7 +116,6 @@ export default context => {
// Call data & fetch hooks on components matched by the route. // Call data & fetch hooks on components matched by the route.
return Promise.all(Components.map((Component) => { return Promise.all(Components.map((Component) => {
let promises = [] let promises = []
const ctx = getContext(context)
if (Component.options.data && typeof Component.options.data === 'function') { if (Component.options.data && typeof Component.options.data === 'function') {
Component._data = Component.options.data Component._data = Component.options.data
let promise = promisify(Component._data, ctx) let promise = promisify(Component._data, ctx)
@ -114,7 +135,7 @@ export default context => {
}) })
.then((res) => { .then((res) => {
if (!Components.length) { if (!Components.length) {
context.nuxt.error = context.error({ statusCode: 404, message: 'This page could not be found.', url: context.route.path }) context.nuxt.error = context.error({ statusCode: 404, message: 'This page could not be found.' })
<%= (store ? 'context.nuxt.state = store.state' : '') %> <%= (store ? 'context.nuxt.state = store.state' : '') %>
return _app return _app
} }

View File

@ -2,15 +2,8 @@ import Vue from 'vue'
import Vuex from 'vuex' import Vuex from 'vuex'
Vue.use(Vuex) Vue.use(Vuex)
let files let files = require.context('~/store', false, /^\.\/.*\.js$/)
let filenames = [] let filenames = files.keys()
try {
files = require.context('~store', false, /^\.\/.*\.js$/)
filenames = files.keys()
} catch (e) {
console.warn('Nuxt.js store:', e.message)
}
function getModule (filename) { function getModule (filename) {
let file = files(filename) let file = files(filename)

View File

@ -40,6 +40,7 @@ export function getContext (context) {
ctx.query = ctx.route.query || {} ctx.query = ctx.route.query || {}
ctx.redirect = function (status, path, query) { ctx.redirect = function (status, path, query) {
if (!status) return if (!status) return
ctx._redirected = true
// if only 1 or 2 arguments: redirect('/') or redirect('/', { foo: 'bar' }) // if only 1 or 2 arguments: redirect('/') or redirect('/', { foo: 'bar' })
if (typeof status === 'string' && (typeof path === 'undefined' || typeof path === 'object')) { if (typeof status === 'string' && (typeof path === 'undefined' || typeof path === 'object')) {
query = path || {} query = path || {}
@ -57,6 +58,16 @@ export function getContext (context) {
return ctx return ctx
} }
export function promiseSeries (promises, context) {
if (!promises.length || context._redirected) {
return Promise.resolve()
}
return promisify(promises[0], context)
.then(() => {
return promiseSeries(promises.slice(1), context)
})
}
export function promisify (fn, context) { export function promisify (fn, context) {
let promise let promise
if (fn.length === 2) { if (fn.length === 2) {

View File

@ -120,8 +120,8 @@ export function * build () {
function * buildFiles () { function * buildFiles () {
if (this.dev) { if (this.dev) {
debug('Adding webpack middlewares...') debug('Adding webpack middleware...')
createWebpackMiddlewares.call(this) createWebpackMiddleware.call(this)
webpackWatchAndUpdate.call(this) webpackWatchAndUpdate.call(this)
watchPages.call(this) watchPages.call(this)
} else { } else {
@ -148,12 +148,17 @@ function * generateRoutesAndFiles () {
this.routes = _.uniq(_.map(files, (file) => { this.routes = _.uniq(_.map(files, (file) => {
return file.replace(/^pages/, '').replace(/\.vue$/, '').replace(/\/index/g, '').replace(/_/g, ':').replace('', '/').replace(/\/{2,}/g, '/') return file.replace(/^pages/, '').replace(/\.vue$/, '').replace(/\/index/g, '').replace(/_/g, ':').replace('', '/').replace(/\/{2,}/g, '/')
})) }))
if (typeof this.options.router.extendRoutes === 'function') {
// let the user extend the routes
this.options.router.extendRoutes(this.routes)
}
// Interpret and move template files to .nuxt/ // Interpret and move template files to .nuxt/
debug('Generating files...') debug('Generating files...')
let templatesFiles = [ let templatesFiles = [
'App.vue', 'App.vue',
'client.js', 'client.js',
'index.js', 'index.js',
'middleware.js',
'router.js', 'router.js',
'server.js', 'server.js',
'utils.js', 'utils.js',
@ -168,11 +173,13 @@ function * generateRoutesAndFiles () {
isDev: this.dev, isDev: this.dev,
router: { router: {
base: this.options.router.base, base: this.options.router.base,
middleware: this.options.router.middleware,
linkActiveClass: this.options.router.linkActiveClass, linkActiveClass: this.options.router.linkActiveClass,
scrollBehavior: this.options.router.scrollBehavior scrollBehavior: this.options.router.scrollBehavior
}, },
env: this.options.env, env: this.options.env,
head: this.options.head, head: this.options.head,
middleware: this.options.middleware,
store: this.options.store, store: this.options.store,
css: this.options.css, css: this.options.css,
plugins: this.options.plugins.map((p) => r(this.srcDir, p)), plugins: this.options.plugins.map((p) => r(this.srcDir, p)),
@ -294,7 +301,7 @@ function getWebpackServerConfig () {
return serverWebpackConfig.call(this) return serverWebpackConfig.call(this)
} }
function createWebpackMiddlewares () { function createWebpackMiddleware () {
const clientConfig = getWebpackClientConfig.call(this) const clientConfig = getWebpackClientConfig.call(this)
// setup on the fly compilation + hot-reload // setup on the fly compilation + hot-reload
clientConfig.entry.app = _.flatten(['webpack-hot-middleware/client?reload=true', clientConfig.entry.app]) clientConfig.entry.app = _.flatten(['webpack-hot-middleware/client?reload=true', clientConfig.entry.app])
@ -303,7 +310,7 @@ function createWebpackMiddlewares () {
new webpack.NoEmitOnErrorsPlugin() new webpack.NoEmitOnErrorsPlugin()
) )
const clientCompiler = webpack(clientConfig) const clientCompiler = webpack(clientConfig)
// Add the middlewares to the instance context // Add the middleware to the instance context
this.webpackDevMiddleware = pify(require('webpack-dev-middleware')(clientCompiler, { this.webpackDevMiddleware = pify(require('webpack-dev-middleware')(clientCompiler, {
publicPath: clientConfig.output.publicPath, publicPath: clientConfig.output.publicPath,
stats: { stats: {

View File

@ -76,6 +76,7 @@ export default function () {
console.error(`Could not generate the dynamic route ${route}, please add the mapping params in nuxt.config.js (generate.routeParams).`) // eslint-disable-line no-console console.error(`Could not generate the dynamic route ${route}, please add the mapping params in nuxt.config.js (generate.routeParams).`) // eslint-disable-line no-console
return process.exit(1) return process.exit(1)
} }
route = route + '?'
const toPath = pathToRegexp.compile(route) const toPath = pathToRegexp.compile(route)
routes = routes.concat(routeParams.map((params) => { routes = routes.concat(routeParams.map((params) => {
return toPath(params) return toPath(params)

View File

@ -37,13 +37,16 @@ class Nuxt {
}, },
router: { router: {
base: '/', base: '/',
middleware: [],
linkActiveClass: 'nuxt-link-active', linkActiveClass: 'nuxt-link-active',
extendRoutes: null, extendRoutes: null,
scrollBehavior: null scrollBehavior: null
}, },
build: {} build: {}
} }
// Sanitization
if (options.loading === true) delete options.loading if (options.loading === true) delete options.loading
if (options.router && typeof options.router.middleware === 'string') options.router.middleware = [ options.router.middleware ]
if (typeof options.transition === 'string') options.transition = { name: options.transition } if (typeof options.transition === 'string') options.transition = { name: options.transition }
this.options = _.defaultsDeep(options, defaults) this.options = _.defaultsDeep(options, defaults)
// Env variables // Env variables
@ -54,6 +57,11 @@ class Nuxt {
if (fs.existsSync(join(this.srcDir, 'store'))) { if (fs.existsSync(join(this.srcDir, 'store'))) {
this.options.store = true this.options.store = true
} }
// If middleware defined, update middleware option to true
this.options.middleware = false
if (fs.existsSync(join(this.srcDir, 'middleware'))) {
this.options.middleware = true
}
// Template // Template
this.appTemplate = _.template(fs.readFileSync(resolve(__dirname, 'views', 'app.html'), 'utf8'), { this.appTemplate = _.template(fs.readFileSync(resolve(__dirname, 'views', 'app.html'), 'utf8'), {
imports: { serialize } imports: { serialize }

View File

@ -22,11 +22,11 @@ export function render (req, res) {
const context = getContext(req, res) const context = getContext(req, res)
return co(function * () { return co(function * () {
if (self.dev) { if (self.dev) {
// Call webpack middlewares only in development // Call webpack middleware only in development
yield self.webpackDevMiddleware(req, res) yield self.webpackDevMiddleware(req, res)
yield self.webpackHotMiddleware(req, res) yield self.webpackHotMiddleware(req, res)
} }
// If base in req.url, remove it for the middlewares and vue-router // If base in req.url, remove it for the middleware and vue-router
if (self.options.router.base !== '/' && req.url.indexOf(self.options.router.base) === 0) { if (self.options.router.base !== '/' && req.url.indexOf(self.options.router.base) === 0) {
// Compatibility with base url for dev server // Compatibility with base url for dev server
req.url = req.url.replace(self.options.router.base, '/') req.url = req.url.replace(self.options.router.base, '/')