fix(app): lint all templates (#4175)

This commit is contained in:
Pim 2018-10-24 15:46:06 +02:00 committed by Pooya Parsa
parent 81b25ee2e2
commit 96bdcaba01
25 changed files with 304 additions and 220 deletions

View File

@ -6,5 +6,32 @@ module.exports = {
}, },
extends: [ extends: [
'@nuxtjs' '@nuxtjs'
] ],
overrides: [{
files: [ 'test/fixtures/*/.nuxt*/**' ],
rules: {
'vue/name-property-casing': ['error', 'kebab-case']
}
}, {
files: [ 'test/fixtures/*/.nuxt*/**/+(App|index).js' ],
rules: {
'import/order': 'ignore'
}
}, {
files: [ 'test/fixtures/*/.nuxt*/**/client.js' ],
rules: {
'no-console': ['error', { allow: ['error'] }]
}
}, {
files: [ 'test/fixtures/*/.nuxt*/**/router.js' ],
rules: {
'no-console': ['error', { allow: ['warn'] }]
}
}, {
files: [ 'test/fixtures/*/.nuxt*/**/*.html' ],
rules: {
'semi': ['error', 'always', { 'omitLastInOneLineBlock': true }],
'no-var': 'warn'
}
}]
} }

View File

@ -13,7 +13,7 @@
"dev": "yarn build --watch", "dev": "yarn build --watch",
"coverage": "codecov", "coverage": "codecov",
"lint": "eslint --ext .js,.mjs,.vue .", "lint": "eslint --ext .js,.mjs,.vue .",
"lint:app": "eslint-multiplexer eslint --ignore-path lib/app/.eslintignore 'test/fixtures/!(missing-plugin)/.nuxt!(-dev)/**' | eslint-multiplexer -b", "lint:app": "eslint-multiplexer eslint --ignore-path packages/app/template/.eslintignore 'test/fixtures/!(missing-plugin)/.nuxt!(-dev)/**' | eslint-multiplexer -b",
"nuxt": "node -r esm ./packages/cli/bin/nuxt.js", "nuxt": "node -r esm ./packages/cli/bin/nuxt.js",
"test": "yarn test:fixtures && yarn test:unit", "test": "yarn test:fixtures && yarn test:unit",
"test:fixtures": "jest test/fixtures", "test:fixtures": "jest test/fixtures",

View File

@ -12,12 +12,14 @@ import '<%= relativeToBuild(resolvePath(c.src || c)) %>'
} }
}).join('\n') %> }).join('\n') %>
const layouts = { <%= Object.keys(layouts).map(key => `"_${key}": _${hash(key)}`).join(',') %> } const layouts = { <%= Object.keys(layouts).map(key => `"_${key}": _${hash(key)}`).join(',') %> }<%= isTest ? '// eslint-disable-line' : '' %>
<% if (splitChunks.layouts) { %>let resolvedLayouts = {}<% } %> <% if (splitChunks.layouts) { %>let resolvedLayouts = {}<% } %>
export default { export default {
<%= isTest ? '/* eslint-disable quotes, semi, indent, comma-spacing, key-spacing, object-curly-spacing, object-property-newline, arrow-parens */' : '' %>
head: <%= serialize(head).replace(/:\w+\(/gm, ':function(') %>, head: <%= serialize(head).replace(/:\w+\(/gm, ':function(') %>,
<%= isTest ? '/* eslint-enable quotes, semi, indent, comma-spacing, key-spacing, object-curly-spacing, object-property-newline, arrow-parens */' : '' %>
render(h, props) { render(h, props) {
<% if (loading) { %>const loadingEl = h('nuxt-loading', { ref: 'loading' })<% } %> <% if (loading) { %>const loadingEl = h('nuxt-loading', { ref: 'loading' })<% } %>
const layoutEl = h(this.layout || 'nuxt') const layoutEl = h(this.layout || 'nuxt')
@ -35,7 +37,7 @@ export default {
} }
}, [ templateEl ]) }, [ templateEl ])
return h('div',{ return h('div', {
domProps: { domProps: {
id: '<%= globals.id %>' id: '<%= globals.id %>'
} }
@ -48,10 +50,10 @@ export default {
layout: null, layout: null,
layoutName: '' layoutName: ''
}), }),
beforeCreate () { beforeCreate() {
Vue.util.defineReactive(this, 'nuxt', this.$options.nuxt) Vue.util.defineReactive(this, 'nuxt', this.$options.nuxt)
}, },
created () { created() {
// Add this.$nuxt in child instances // Add this.$nuxt in child instances
Vue.prototype.<%= globals.nuxt %> = this Vue.prototype.<%= globals.nuxt %> = this
// add to window so we can listen when ready // add to window so we can listen when ready
@ -65,7 +67,7 @@ export default {
this.error = this.nuxt.error this.error = this.nuxt.error
}, },
<% if (loading) { %> <% if (loading) { %>
mounted () { mounted() {
this.$loading = this.$refs.loading this.$loading = this.$refs.loading
}, },
watch: { watch: {
@ -74,7 +76,7 @@ export default {
<% } %> <% } %>
methods: { methods: {
<% if (loading) { %> <% if (loading) { %>
errorChanged () { errorChanged() {
if (this.nuxt.err && this.$loading) { if (this.nuxt.err && this.$loading) {
if (this.$loading.fail) this.$loading.fail() if (this.$loading.fail) this.$loading.fail()
if (this.$loading.finish) this.$loading.finish() if (this.$loading.finish) this.$loading.finish()
@ -82,7 +84,7 @@ export default {
}, },
<% } %> <% } %>
<% if (splitChunks.layouts) { %> <% if (splitChunks.layouts) { %>
setLayout (layout) { setLayout(layout) {
<% if (debug) { %> <% if (debug) { %>
if(layout && typeof layout !== 'string') throw new Error('[nuxt] Avoid using non-string value as layout property.') if(layout && typeof layout !== 'string') throw new Error('[nuxt] Avoid using non-string value as layout property.')
<% } %> <% } %>
@ -92,7 +94,7 @@ export default {
this.layout = resolvedLayouts[_layout] this.layout = resolvedLayouts[_layout]
return this.layout return this.layout
}, },
loadLayout (layout) { loadLayout(layout) {
const undef = !layout const undef = !layout
const inexisting = !(layouts['_' + layout] || resolvedLayouts['_' + layout]) const inexisting = !(layouts['_' + layout] || resolvedLayouts['_' + layout])
let _layout = '_' + ((undef || inexisting) ? 'default' : layout) let _layout = '_' + ((undef || inexisting) ? 'default' : layout)

View File

@ -1,6 +1,5 @@
import Vue from 'vue' import Vue from 'vue'
import middleware from './middleware' import middleware from './middleware'
import { createApp, NuxtError } from './index'
import { import {
applyAsyncData, applyAsyncData,
sanitizeComponent, sanitizeComponent,
@ -16,6 +15,7 @@ import {
getQueryDiff, getQueryDiff,
globalHandleError globalHandleError
} from './utils' } from './utils'
import { createApp, NuxtError } from './index'
const noopData = () => { return {} } const noopData = () => { return {} }
const noopFetch = () => {} const noopFetch = () => {}
@ -29,7 +29,7 @@ let router
// Try to rehydrate SSR data from window // Try to rehydrate SSR data from window
const NUXT = window.<%= globals.context %> || {} const NUXT = window.<%= globals.context %> || {}
Object.assign(Vue.config, <%= serialize(vue.config) %>) Object.assign(Vue.config, <%= serialize(vue.config) %>)<%= isTest ? '// eslint-disable-line' : '' %>
<% if (debug || mode === 'spa') { %> <% if (debug || mode === 'spa') { %>
// Setup global Vue error handler // Setup global Vue error handler
@ -46,7 +46,7 @@ if (!Vue.config.$nuxt) {
if (typeof defaultErrorHandler === 'function') { if (typeof defaultErrorHandler === 'function') {
handled = defaultErrorHandler(err, vm, info, ...rest) handled = defaultErrorHandler(err, vm, info, ...rest)
} }
if (handled === true){ if (handled === true) {
return handled return handled
} }
@ -79,10 +79,10 @@ Vue.config.$nuxt.<%= globals.nuxt %> = true
// Create and mount App // Create and mount App
createApp() createApp()
.then(mountApp) .then(mountApp)
.catch((err) => { .catch((err) => {
console.error('[nuxt] Error while initializing app', err) console.error('[nuxt] Error while initializing app', err)
}) })
function componentOption(component, key, ...args) { function componentOption(component, key, ...args) {
if (!component || !component.options || !component.options[key]) { if (!component || !component.options || !component.options[key]) {
@ -107,17 +107,17 @@ function mapTransitions(Components, to, from) {
// Combine transitions & prefer `leave` transitions of 'from' route // Combine transitions & prefer `leave` transitions of 'from' route
if (from && from.matched.length && from.matched[0].components.default) { if (from && from.matched.length && from.matched[0].components.default) {
const from_transitions = componentTransitions(from.matched[0].components.default) const fromTransitions = componentTransitions(from.matched[0].components.default)
Object.keys(from_transitions) Object.keys(fromTransitions)
.filter((key) => from_transitions[key] && key.toLowerCase().includes('leave')) .filter(key => fromTransitions[key] && key.toLowerCase().includes('leave'))
.forEach((key) => { transitions[key] = from_transitions[key] }) .forEach((key) => { transitions[key] = fromTransitions[key] })
} }
return transitions return transitions
}) })
} }
async function loadAsyncComponents (to, from, next) { async function loadAsyncComponents(to, from, next) {
// Check if route path changed (this._pathChanged), only if the page is not an error (for validate()) // Check if route path changed (this._pathChanged), only if the page is not an error (for validate())
this._pathChanged = !!app.nuxt.err || from.path !== to.path this._pathChanged = !!app.nuxt.err || from.path !== to.path
this._queryChanged = JSON.stringify(to.query) !== JSON.stringify(from.query) this._queryChanged = JSON.stringify(to.query) !== JSON.stringify(from.query)
@ -138,7 +138,7 @@ async function loadAsyncComponents (to, from, next) {
const watchQuery = Component.options.watchQuery const watchQuery = Component.options.watchQuery
if (watchQuery === true) return true if (watchQuery === true) return true
if (Array.isArray(watchQuery)) { if (Array.isArray(watchQuery)) {
return watchQuery.some((key) => this._diffQuery[key]) return watchQuery.some(key => this._diffQuery[key])
} }
return false return false
}) })
@ -150,10 +150,10 @@ async function loadAsyncComponents (to, from, next) {
// Call next() // Call next()
next() next()
} catch (err) { } catch (err) {
err = err || {} const error = err || {}
const statusCode = (err.statusCode || err.status || (err.response && err.response.status) || 500) const statusCode = (error.statusCode || error.status || (error.response && error.response.status) || 500)
this.error({ statusCode, message: err.message }) this.error({ statusCode, message: error.message })
this.<%= globals.nuxt %>.$emit('routeChanged', to, from, err) this.<%= globals.nuxt %>.$emit('routeChanged', to, from, error)
next(false) next(false)
} }
} }
@ -182,8 +182,8 @@ function resolveComponents(router) {
}) })
} }
function callMiddleware (Components, context, layout) { function callMiddleware(Components, context, layout) {
let midd = <%= devalue(router.middleware) %> let midd = <%= devalue(router.middleware) %><%= isTest ? '// eslint-disable-line' : '' %>
let unknownMiddleware = false let unknownMiddleware = false
// If layout is undefined, only call global middleware // If layout is undefined, only call global middleware
@ -212,7 +212,7 @@ function callMiddleware (Components, context, layout) {
return middlewareSeries(midd, context) return middlewareSeries(midd, context)
} }
async function render (to, from, next) { async function render(to, from, next) {
if (this._pathChanged === false && this._queryChanged === false) return next() if (this._pathChanged === false && this._queryChanged === false) return next()
// Handle first render on SPA mode // Handle first render on SPA mode
if (to === from) _lastPaths = [] if (to === from) _lastPaths = []
@ -337,21 +337,21 @@ async function render (to, from, next) {
Component._dataRefresh = false Component._dataRefresh = false
// Check if Component need to be refreshed (call asyncData & fetch) // Check if Component need to be refreshed (call asyncData & fetch)
// Only if its slug has changed or is watch query changes // Only if its slug has changed or is watch query changes
if (this._pathChanged && this._queryChanged || Component._path !== _lastPaths[i]) { if ((this._pathChanged && this._queryChanged) || Component._path !== _lastPaths[i]) {
Component._dataRefresh = true Component._dataRefresh = true
} else if (!this._pathChanged && this._queryChanged) { } else if (!this._pathChanged && this._queryChanged) {
const watchQuery = Component.options.watchQuery const watchQuery = Component.options.watchQuery
if (watchQuery === true) { if (watchQuery === true) {
Component._dataRefresh = true Component._dataRefresh = true
} else if (Array.isArray(watchQuery)) { } else if (Array.isArray(watchQuery)) {
Component._dataRefresh = watchQuery.some((key) => this._diffQuery[key]) Component._dataRefresh = watchQuery.some(key => this._diffQuery[key])
} }
} }
if (!this._hadError && this._isMounted && !Component._dataRefresh) { if (!this._hadError && this._isMounted && !Component._dataRefresh) {
return Promise.resolve() return Promise.resolve()
} }
let promises = [] const promises = []
const hasAsyncData = ( const hasAsyncData = (
Component.options.asyncData && Component.options.asyncData &&
@ -368,7 +368,7 @@ async function render (to, from, next) {
.then((asyncDataResult) => { .then((asyncDataResult) => {
applyAsyncData(Component, asyncDataResult) applyAsyncData(Component, asyncDataResult)
<% if (loading) { %> <% if (loading) { %>
if(this.$loading.increase) { if (this.$loading.increase) {
this.$loading.increase(loadingIncrease) this.$loading.increase(loadingIncrease)
} }
<% } %> <% } %>
@ -408,10 +408,9 @@ async function render (to, from, next) {
next() next()
} }
} catch (error) { } catch (err) {
if (!error) { const error = err || {}
error = {} if (error.message === 'ERR_REDIRECT') {
} else if (error.message === 'ERR_REDIRECT') {
return this.<%= globals.nuxt %>.$emit('routeChanged', to, from, error) return this.<%= globals.nuxt %>.$emit('routeChanged', to, from, error)
} }
_lastPaths = [] _lastPaths = []
@ -434,7 +433,7 @@ async function render (to, from, next) {
} }
// Fix components format in matched, it's due to code-splitting of vue-router // Fix components format in matched, it's due to code-splitting of vue-router
function normalizeComponents (to, ___) { function normalizeComponents(to, ___) {
flatMapComponents(to, (Component, _, match, key) => { flatMapComponents(to, (Component, _, match, key) => {
if (typeof Component === 'object' && !Component.options) { if (typeof Component === 'object' && !Component.options) {
// Updated via vue-router resolveAsyncComponents() // Updated via vue-router resolveAsyncComponents()
@ -486,7 +485,7 @@ function fixPrepatch(to, ___) {
typeof instance.constructor.options.data === 'function' typeof instance.constructor.options.data === 'function'
) { ) {
const newData = instance.constructor.options.data.call(instance) const newData = instance.constructor.options.data.call(instance)
for (let key in newData) { for (const key in newData) {
Vue.set(instance.$data, key, newData[key]) Vue.set(instance.$data, key, newData[key])
} }
} }
@ -499,7 +498,7 @@ function fixPrepatch(to, ___) {
}) })
} }
function nuxtReady (_app) { function nuxtReady(_app) {
window.<%= globals.readyCallback %>Cbs.forEach((cb) => { window.<%= globals.readyCallback %>Cbs.forEach((cb) => {
if (typeof cb === 'function') { if (typeof cb === 'function') {
cb(_app) cb(_app)
@ -531,7 +530,7 @@ function getNuxtChildComponents($parent, $components = []) {
return $components return $components
} }
function hotReloadAPI (_app) { function hotReloadAPI(_app) {
if (!module.hot) return if (!module.hot) return
let $components = getNuxtChildComponents(_app.<%= globals.nuxt %>, []) let $components = getNuxtChildComponents(_app.<%= globals.nuxt %>, [])
@ -539,7 +538,7 @@ function hotReloadAPI (_app) {
$components.forEach(addHotReload.bind(_app)) $components.forEach(addHotReload.bind(_app))
} }
function addHotReload ($component, depth) { function addHotReload($component, depth) {
if ($component.$vnode.data._hasHotReload) return if ($component.$vnode.data._hasHotReload) return
$component.$vnode.data._hasHotReload = true $component.$vnode.data._hasHotReload = true
@ -617,7 +616,7 @@ async function mountApp(__app) {
// Set global variables // Set global variables
app = __app.app app = __app.app
router = __app.router router = __app.router
<% if (store) { %>store = __app.store <% } %> <% if (store) { %>store = __app.store<% } %>
// Resolve route components // Resolve route components
const Components = await Promise.all(resolveComponents(router)) const Components = await Promise.all(resolveComponents(router))

View File

@ -1,4 +1,4 @@
/* /*<%= isTest ? ' @vue/component' : '' %>
** From https://github.com/egoist/vue-no-ssr ** From https://github.com/egoist/vue-no-ssr
** With the authorization of @egoist ** With the authorization of @egoist
*/ */

View File

@ -1,8 +1,15 @@
<%= isTest ? '// @vue/component' : '' %>
export default { export default {
name: 'nuxt-child', name: 'nuxt-child',
functional: true, functional: true,
props: ['keepAlive', 'keepAliveProps'], props: {
render (h, { parent, data, props }) { nuxtChildKey: {
type: String,
default: ''
},
keepAlive: Boolean
},
render(h, { parent, data, props }) {
data.nuxtChild = true data.nuxtChild = true
const _parent = parent const _parent = parent
const transitions = parent.<%= globals.nuxt %>.nuxt.transitions const transitions = parent.<%= globals.nuxt %>.nuxt.transitions
@ -17,14 +24,14 @@ export default {
} }
data.nuxtChildDepth = depth data.nuxtChildDepth = depth
const transition = transitions[depth] || defaultTransition const transition = transitions[depth] || defaultTransition
let transitionProps = {} const transitionProps = {}
transitionsKeys.forEach((key) => { transitionsKeys.forEach((key) => {
if (typeof transition[key] !== 'undefined') { if (typeof transition[key] !== 'undefined') {
transitionProps[key] = transition[key] transitionProps[key] = transition[key]
} }
}) })
let listeners = {} const listeners = {}
listenersKeys.forEach((key) => { listenersKeys.forEach((key) => {
if (typeof transition[key] === 'function') { if (typeof transition[key] === 'function') {
listeners[key] = transition[key].bind(_parent) listeners[key] = transition[key].bind(_parent)
@ -43,7 +50,7 @@ export default {
let routerView = [ let routerView = [
h('router-view', data) h('router-view', data)
] ]
if (typeof props.keepAlive !== 'undefined') { if (props.keepAlive) {
routerView = [ routerView = [
h('keep-alive', { props: props.keepAliveProps }, routerView) h('keep-alive', { props: props.keepAliveProps }, routerView)
] ]

View File

@ -1,10 +1,10 @@
<template> <template>
<div class="__nuxt-error-page"> <div class="__nuxt-error-page">
<div class="error"> <div class="error">
<svg xmlns="http://www.w3.org/2000/svg" width="90" height="90" fill="#DBE1EC" viewBox="0 0 48 48"><path d="M22 30h4v4h-4zm0-16h4v12h-4zm1.99-10C12.94 4 4 12.95 4 24s8.94 20 19.99 20S44 35.05 44 24 35.04 4 23.99 4zM24 40c-8.84 0-16-7.16-16-16S15.16 8 24 8s16 7.16 16 16-7.16 16-16 16z"/></svg> <svg xmlns="http://www.w3.org/2000/svg" width="90" height="90" fill="#DBE1EC" viewBox="0 0 48 48"><path d="M22 30h4v4h-4zm0-16h4v12h-4zm1.99-10C12.94 4 4 12.95 4 24s8.94 20 19.99 20S44 35.05 44 24 35.04 4 23.99 4zM24 40c-8.84 0-16-7.16-16-16S15.16 8 24 8s16 7.16 16 16-7.16 16-16 16z" /></svg>
<div class="title">{{ message }}</div> <div class="title">{{ message }}</div>
<p class="description" v-if="statusCode === 404"> <p v-if="statusCode === 404" class="description">
<nuxt-link class="error-link" to="/"><%= messages.back_to_home %></nuxt-link> <nuxt-link class="error-link" to="/"><%= messages.back_to_home %></nuxt-link>
</p> </p>
<% if(debug) { %> <% if(debug) { %>
@ -14,15 +14,20 @@
<div class="logo"> <div class="logo">
<a href="https://nuxtjs.org" target="_blank" rel="noopener"><%= messages.nuxtjs %></a> <a href="https://nuxtjs.org" target="_blank" rel="noopener"><%= messages.nuxtjs %></a>
</div> </div>
</div> </div>
</div> </div>
</template> </template>
<script> <script>
export default { export default {
name: 'nuxt-error', name: 'nuxt-error',
props: ['error'], props: {
head () { error: {
type: Object,
default: null
}
},
head() {
return { return {
title: this.message, title: this.message,
meta: [ meta: [
@ -34,10 +39,10 @@ export default {
} }
}, },
computed: { computed: {
statusCode () { statusCode() {
return (this.error && this.error.statusCode) || 500 return (this.error && this.error.statusCode) || 500
}, },
message () { message() {
return this.error.message || `<%= messages.client_error %>` return this.error.message || `<%= messages.client_error %>`
} }
} }

View File

@ -1,7 +1,8 @@
<%= isTest ? '// @vue/component' : '' %>
export default { export default {
name: 'nuxt-link', name: 'nuxt-link',
functional: true, functional: true,
render (h, { data, children }) { render(h, { data, children }) {
return h('router-link', data, children) return h('router-link', data, children)
} }
} }

View File

@ -1,10 +1,13 @@
<template> <template>
<div class="nuxt-progress" :style="{ <div
class="nuxt-progress"
:style="{
'width': percent + '%', 'width': percent + '%',
'height': height, 'height': height,
'background-color': canSuccess ? color : failedColor, 'background-color': canSuccess ? color : failedColor,
'opacity': show ? 1 : 0 'opacity': show ? 1 : 0
}"></div> }"
/>
</template> </template>
<script> <script>
@ -12,20 +15,20 @@ import Vue from 'vue'
export default { export default {
name: 'nuxt-loading', name: 'nuxt-loading',
data () { data() {
return { return {
percent: 0, percent: 0,
show: false, show: false,
canSuccess: true, canSuccess: true,
throttle: <%= loading.throttle %>, throttle: <%= loading.throttle || 200 %>,
duration: <%= loading.duration %>, duration: <%= loading.duration || 1000 %>,
height: '<%= loading.height %>', height: '<%= loading.height %>',
color: '<%= loading.color %>', color: '<%= loading.color %>',
failedColor: '<%= loading.failedColor %>', failedColor: '<%= loading.failedColor %>'
} }
}, },
methods: { methods: {
start () { start() {
this.canSuccess = true this.canSuccess = true
if (this._throttle) { if (this._throttle) {
clearTimeout(this._throttle) clearTimeout(this._throttle)
@ -47,33 +50,33 @@ export default {
}, this.throttle) }, this.throttle)
return this return this
}, },
set (num) { set(num) {
this.show = true this.show = true
this.canSuccess = true this.canSuccess = true
this.percent = Math.floor(num) this.percent = Math.floor(num)
return this return this
}, },
get () { get() {
return Math.floor(this.percent) return Math.floor(this.percent)
}, },
increase (num) { increase(num) {
this.percent = this.percent + Math.floor(num) this.percent = this.percent + Math.floor(num)
return this return this
}, },
decrease (num) { decrease(num) {
this.percent = this.percent - Math.floor(num) this.percent = this.percent - Math.floor(num)
return this return this
}, },
finish () { finish() {
this.percent = 100 this.percent = 100
this.hide() this.hide()
return this return this
}, },
pause () { pause() {
clearInterval(this._timer) clearInterval(this._timer)
return this return this
}, },
hide () { hide() {
clearInterval(this._timer) clearInterval(this._timer)
this._timer = null this._timer = null
clearTimeout(this._throttle) clearTimeout(this._throttle)
@ -88,7 +91,7 @@ export default {
}, 500) }, 500)
return this return this
}, },
fail () { fail() {
this.canSuccess = false this.canSuccess = false
return this return this
} }

View File

@ -1,5 +1,6 @@
<%= isTest ? '// @vue/component' : '' %>
import Vue from 'vue' import Vue from 'vue'
import NuxtChild from './nuxt-child' import { compile } from '../utils'
<% if (components.ErrorPage) { %> <% if (components.ErrorPage) { %>
<% if (('~@').includes(components.ErrorPage.charAt(0))) { %> <% if (('~@').includes(components.ErrorPage.charAt(0))) { %>
@ -10,12 +11,14 @@ import NuxtError from '<%= "../" + components.ErrorPage %>'
<% } else { %> <% } else { %>
import NuxtError from './nuxt-error.vue' import NuxtError from './nuxt-error.vue'
<% } %> <% } %>
import NuxtChild from './nuxt-child'
import { compile } from '../utils'
export default { export default {
name: 'nuxt', name: 'nuxt',
props: ['nuxtChildKey', 'keepAlive'], props: {
nuxtChildKey: String,
keepAlive: Boolean
},
render(h) { render(h) {
// If there is some error // If there is some error
if (this.nuxt.err) { if (this.nuxt.err) {
@ -31,11 +34,11 @@ export default {
props: this.$props props: this.$props
}) })
}, },
beforeCreate () { beforeCreate() {
Vue.util.defineReactive(this, 'nuxt', this.$root.$options.nuxt) Vue.util.defineReactive(this, 'nuxt', this.$root.$options.nuxt)
}, },
computed: { computed: {
routerViewKey () { routerViewKey() {
// If nuxtChildKey prop is given or current route has children // If nuxtChildKey prop is given or current route has children
if (typeof this.nuxtChildKey !== 'undefined' || this.$route.matched.length > 1) { if (typeof this.nuxtChildKey !== 'undefined' || this.$route.matched.length > 1) {
return this.nuxtChildKey || compile(this.$route.matched[0].path)(this.$route.params) return this.nuxtChildKey || compile(this.$route.matched[0].path)(this.$route.params)

View File

@ -11,8 +11,10 @@ import { setContext, getLocation, getRouteData } from './utils'
<% if (store) { %>import { createStore } from './store.js'<% } %> <% if (store) { %>import { createStore } from './store.js'<% } %>
/* Plugins */ /* Plugins */
<%= isTest ? '/* eslint-disable camelcase */' : '' %>
<% plugins.forEach((plugin) => { %>import <%= plugin.name %> from '<%= plugin.name %>' // Source: <%= relativeToBuild(plugin.src) %><%= (plugin.ssr===false) ? ' (ssr: false)' : '' %> <% plugins.forEach((plugin) => { %>import <%= plugin.name %> from '<%= plugin.name %>' // Source: <%= relativeToBuild(plugin.src) %><%= (plugin.ssr===false) ? ' (ssr: false)' : '' %>
<% }) %> <% }) %>
<%= isTest ? '/* eslint-enable camelcase */' : '' %>
// Component: <no-ssr> // Component: <no-ssr>
Vue.component(NoSSR.name, NoSSR) Vue.component(NoSSR.name, NoSSR)
@ -40,9 +42,9 @@ const defaultTransition = <%=
.replace('enterCancelled(', 'function(').replace('beforeLeave(', 'function(').replace('leave(', 'function(') .replace('enterCancelled(', 'function(').replace('beforeLeave(', 'function(').replace('leave(', 'function(')
.replace('afterLeave(', 'function(').replace('leaveCancelled(', 'function(').replace('beforeAppear(', 'function(') .replace('afterLeave(', 'function(').replace('leaveCancelled(', 'function(').replace('beforeAppear(', 'function(')
.replace('appear(', 'function(').replace('afterAppear(', 'function(').replace('appearCancelled(', 'function(') .replace('appear(', 'function(').replace('afterAppear(', 'function(').replace('appearCancelled(', 'function(')
%> %><%= isTest ? '// eslint-disable-line' : '' %>
async function createApp (ssrContext) { async function createApp(ssrContext) {
const router = await createRouter(ssrContext) const router = await createRouter(ssrContext)
<% if (store) { %> <% if (store) { %>
@ -56,7 +58,8 @@ async function createApp (ssrContext) {
<% } %> <% } %>
<% } %> <% } %>
// Create Root instance // Create Root instance13:14:29: Error: can't open file '.eslintrc.js' (error 2: No such file or directory)
// here we inject the router and store to all child components, // here we inject the router and store to all child components,
// making them available everywhere as `this.$router` and `this.$store`. // making them available everywhere as `this.$router` and `this.$store`.
const app = { const app = {
@ -65,7 +68,7 @@ async function createApp (ssrContext) {
nuxt: { nuxt: {
defaultTransition, defaultTransition,
transitions: [ defaultTransition ], transitions: [ defaultTransition ],
setTransitions (transitions) { setTransitions(transitions) {
if (!Array.isArray(transitions)) { if (!Array.isArray(transitions)) {
transitions = [ transitions ] transitions = [ transitions ]
} }
@ -84,7 +87,7 @@ async function createApp (ssrContext) {
}, },
err: null, err: null,
dateErr: null, dateErr: null,
error (err) { error(err) {
err = err || null err = err || null
app.context._errored = !!err app.context._errored = !!err
if (typeof err === 'string') err = { statusCode: 500, message: err } if (typeof err === 'string') err = { statusCode: 500, message: err }
@ -124,6 +127,7 @@ async function createApp (ssrContext) {
beforeRenderFns: ssrContext ? ssrContext.beforeRenderFns : undefined beforeRenderFns: ssrContext ? ssrContext.beforeRenderFns : undefined
}) })
<% if (plugins.length) { %>
const inject = function (key, value) { const inject = function (key, value) {
if (!key) throw new Error('inject(key, value) has no key provided') if (!key) throw new Error('inject(key, value) has no key provided')
if (!value) throw new Error('inject(key, value) has no value provided') if (!value) throw new Error('inject(key, value) has no value provided')
@ -142,13 +146,14 @@ async function createApp (ssrContext) {
Vue.use(() => { Vue.use(() => {
if (!Vue.prototype.hasOwnProperty(key)) { if (!Vue.prototype.hasOwnProperty(key)) {
Object.defineProperty(Vue.prototype, key, { Object.defineProperty(Vue.prototype, key, {
get () { get() {
return this.$root.$options[key] return this.$root.$options[key]
} }
}) })
} }
}) })
} }
<% } %>
<% if (store) { %> <% if (store) { %>
if (process.client) { if (process.client) {
@ -160,12 +165,14 @@ async function createApp (ssrContext) {
<% } %> <% } %>
// Plugin execution // Plugin execution
<%= isTest ? '/* eslint-disable camelcase */' : '' %>
<% plugins.filter(p => p.ssr).forEach((plugin) => { %> <% plugins.filter(p => p.ssr).forEach((plugin) => { %>
if (typeof <%= plugin.name %> === 'function') await <%= plugin.name %>(app.context, inject)<% }) %> if (typeof <%= plugin.name %> === 'function') await <%= plugin.name %>(app.context, inject)<% }) %>
<% if (plugins.filter(p => !p.ssr).length) { %> <% if (plugins.filter(p => !p.ssr).length) { %>
if (process.client) { <% plugins.filter((p) => !p.ssr).forEach((plugin) => { %> if (process.client) { <% plugins.filter((p) => !p.ssr).forEach((plugin) => { %>
if (typeof <%= plugin.name %> === 'function') await <%= plugin.name %>(app.context, inject)<% }) %> if (typeof <%= plugin.name %> === 'function') await <%= plugin.name %>(app.context, inject)<% }) %>
}<% } %> }<% } %>
<%= isTest ? '/* eslint-enable camelcase */' : '' %>
// If server-side, wait for async component to be resolved first // If server-side, wait for async component to be resolved first
if (process.server && ssrContext && ssrContext.url) { if (process.server && ssrContext && ssrContext.url) {
@ -186,8 +193,8 @@ async function createApp (ssrContext) {
return { return {
app, app,
router, <% if(store) { %>store,<% } %>
<% if(store) { %>store<% } %> router
} }
} }

View File

@ -1,3 +1,3 @@
<template> <template>
<nuxt/> <nuxt />
</template> </template>

View File

@ -2,7 +2,7 @@
const files = require.context('@/<%= dir.middleware %>', false, /^\.\/(?!<%= ignorePrefix %>)[^.]+\.(<%= extensions %>)$/) const files = require.context('@/<%= dir.middleware %>', false, /^\.\/(?!<%= ignorePrefix %>)[^.]+\.(<%= extensions %>)$/)
const filenames = files.keys() const filenames = files.keys()
function getModule (filename) { function getModule(filename) {
const file = files(filename) const file = files(filename)
return file.default || file return file.default || file
} }

View File

@ -1,32 +1,39 @@
import Vue from 'vue' import Vue from 'vue'
import Router from 'vue-router' import Router from 'vue-router'
import { interopDefault } from './utils'; import { interopDefault } from './utils'
<% function recursiveRoutes(routes, tab, components) { <% function recursiveRoutes(routes, tab, components, indentCount) {
let res = '' let res = ''
const baseIndent = tab.repeat(indentCount)
const firstIndent = '\n' + tab.repeat(indentCount + 1)
const nextIndent = ',' + firstIndent
routes.forEach((route, i) => { routes.forEach((route, i) => {
route._name = '_' + hash(route.component) route._name = '_' + hash(route.component)
components.push({ _name: route._name, component: route.component, name: route.name, chunkName: route.chunkName }) components.push({ _name: route._name, component: route.component, name: route.name, chunkName: route.chunkName })
// @see: https://router.vuejs.org/api/#router-construction-options // @see: https://router.vuejs.org/api/#router-construction-options
res += tab + '{\n' res += '{'
res += tab + '\tpath: ' + JSON.stringify(route.path) res += firstIndent + 'path: ' + JSON.stringify(route.path)
res += (route.component) ? ',\n\t' + tab + 'component: ' + (splitChunks.pages ? route._name : `() => ${route._name}.default || ${route._name}`) : '' res += (route.component) ? nextIndent + 'component: ' + (splitChunks.pages ? route._name : `() => ${route._name}.default || ${route._name}`) : ''
res += (route.redirect) ? ',\n\t' + tab + 'redirect: ' + JSON.stringify(route.redirect) : '' res += (route.redirect) ? nextIndent + 'redirect: ' + JSON.stringify(route.redirect) : ''
res += (route.meta) ? ',\n\t' + tab + 'meta: ' + JSON.stringify(route.meta) : '' res += (route.meta) ? nextIndent + 'meta: ' + JSON.stringify(route.meta) : ''
res += (typeof route.props !== 'undefined') ? ',\n\t' + tab + 'props: ' + (typeof route.props === 'function' ? serialize(route.props) : JSON.stringify(route.props)) : '' res += (typeof route.props !== 'undefined') ? nextIndent + 'props: ' + (typeof route.props === 'function' ? serialize(route.props) : JSON.stringify(route.props)) : ''
res += (typeof route.caseSensitive !== 'undefined') ? ',\n\t' + tab + 'caseSensitive: ' + JSON.stringify(route.caseSensitive) : '' res += (typeof route.caseSensitive !== 'undefined') ? nextIndent + 'caseSensitive: ' + JSON.stringify(route.caseSensitive) : ''
res += (route.alias) ? ',\n\t' + tab + 'alias: ' + JSON.stringify(route.alias) : '' res += (route.alias) ? nextIndent + 'alias: ' + JSON.stringify(route.alias) : ''
res += (route.pathToRegexpOptions) ? ',\n\t' + tab + 'pathToRegexpOptions: ' + JSON.stringify(route.pathToRegexpOptions) : '' res += (route.pathToRegexpOptions) ? nextIndent + 'pathToRegexpOptions: ' + JSON.stringify(route.pathToRegexpOptions) : ''
res += (route.name) ? ',\n\t' + tab + 'name: ' + JSON.stringify(route.name) : '' res += (route.name) ? nextIndent + 'name: ' + JSON.stringify(route.name) : ''
res += (route.beforeEnter) ? ',\n\t' + tab + 'beforeEnter: ' + serialize(route.beforeEnter) : '' if (route.beforeEnter) {
res += (route.children) ? ',\n\t' + tab + 'children: [\n' + recursiveRoutes(routes[i].children, tab + '\t\t', components) + '\n\t' + tab + ']' : '' if(isTest) { res += ',\n/* eslint-disable indent, semi */' }
res += '\n' + tab + '}' + (i + 1 === routes.length ? '' : ',\n') res += (isTest ? firstIndent : nextIndent) + 'beforeEnter: ' + serialize(route.beforeEnter)
if(isTest) { res += firstIndent + '/* eslint-enable indent, semi */' }
}
res += (route.children) ? nextIndent + 'children: [' + recursiveRoutes(routes[i].children, tab, components, indentCount + 1) + ']' : ''
res += '\n' + baseIndent + '}' + (i + 1 === routes.length ? '' : ', ')
}) })
return res return res
} }
const _components = [] const _components = []
const _routes = recursiveRoutes(router.routes, '\t\t', _components) const _routes = recursiveRoutes(router.routes, ' ', _components, 2)
%> <%= uniqBy(_components, '_name').map((route) => { %><%= uniqBy(_components, '_name').map((route) => {
if (!route.component) return '' if (!route.component) return ''
const path = relativeToBuild(route.component) const path = relativeToBuild(route.component)
const chunkName = wChunk(route.chunkName) const chunkName = wChunk(route.chunkName)
@ -56,7 +63,7 @@ const scrollBehavior = function (to, from, savedPosition) {
if (to.matched.length < 2) { if (to.matched.length < 2) {
// scroll to the top of the page // scroll to the top of the page
position = { x: 0, y: 0 } position = { x: 0, y: 0 }
} else if (to.matched.some((r) => r.components.default.options.scrollToTop)) { } else if (to.matched.some(r => r.components.default.options.scrollToTop)) {
// if one of the children has scrollToTop option set to true // if one of the children has scrollToTop option set to true
position = { x: 0, y: 0 } position = { x: 0, y: 0 }
} }
@ -92,16 +99,16 @@ const scrollBehavior = function (to, from, savedPosition) {
} }
<% } %> <% } %>
export function createRouter () { export function createRouter() {
return new Router({ return new Router({
mode: '<%= router.mode %>', mode: '<%= router.mode %>',
base: '<%= router.base %>', base: '<%= router.base %>',
linkActiveClass: '<%= router.linkActiveClass %>', linkActiveClass: '<%= router.linkActiveClass %>',
linkExactActiveClass: '<%= router.linkExactActiveClass %>', linkExactActiveClass: '<%= router.linkExactActiveClass %>',
scrollBehavior, scrollBehavior,
routes: [ <%= isTest ? '/* eslint-disable quotes */' : '' %>
<%= _routes %> routes: [<%= _routes %>],
], <%= isTest ? '/* eslint-enable quotes */' : '' %>
<% if (router.parseQuery) { %>parseQuery: <%= serialize(router.parseQuery).replace('parseQuery(', 'function(') %>,<% } %> <% if (router.parseQuery) { %>parseQuery: <%= serialize(router.parseQuery).replace('parseQuery(', 'function(') %>,<% } %>
<% if (router.stringifyQuery) { %>stringifyQuery: <%= serialize(router.stringifyQuery).replace('stringifyQuery(', 'function(') %>,<% } %> <% if (router.stringifyQuery) { %>stringifyQuery: <%= serialize(router.stringifyQuery).replace('stringifyQuery(', 'function(') %>,<% } %>
fallback: <%= router.fallback %> fallback: <%= router.fallback %>

View File

@ -1,18 +1,18 @@
import Vue from 'vue'
import { stringify } from 'querystring' import { stringify } from 'querystring'
import Vue from 'vue'
import omit from 'lodash/omit' import omit from 'lodash/omit'
import middleware from './middleware' import middleware from './middleware'
import { createApp, NuxtError } from './index'
import { applyAsyncData, sanitizeComponent, getMatchedComponents, getContext, middlewareSeries, promisify, urlJoin } from './utils' import { applyAsyncData, sanitizeComponent, getMatchedComponents, getContext, middlewareSeries, promisify, urlJoin } from './utils'
import { createApp, NuxtError } from './index'
const debug = require('debug')('nuxt:render') const debug = require('debug')('nuxt:render')
debug.color = 4 // force blue color debug.color = 4 // force blue color
const isDev = <%= isDev %> const isDev = <%= isDev %>
const noopApp = () => new Vue({ render: (h) => h('div') }) const noopApp = () => new Vue({ render: h => h('div') })
const createNext = (ssrContext) => (opts) => { const createNext = ssrContext => (opts) => {
ssrContext.redirected = opts ssrContext.redirected = opts
// If nuxt generate // If nuxt generate
if (!ssrContext.res) { if (!ssrContext.res) {
@ -21,8 +21,9 @@ const createNext = (ssrContext) => (opts) => {
} }
opts.query = stringify(opts.query) opts.query = stringify(opts.query)
opts.path = opts.path + (opts.query ? '?' + opts.query : '') opts.path = opts.path + (opts.query ? '?' + opts.query : '')
if (!opts.path.startsWith('http') && ('<%= router.base %>' !== '/' && !opts.path.startsWith('<%= router.base %>'))) { const routerBase = '<%= router.base %>'
opts.path = urlJoin('<%= router.base %>', opts.path) if (!opts.path.startsWith('http') && (routerBase !== '/' && !opts.path.startsWith(routerBase))) {
opts.path = urlJoin(routerBase, opts.path)
} }
// Avoid loop redirect // Avoid loop redirect
if (opts.path === ssrContext.url) { if (opts.path === ssrContext.url) {
@ -59,7 +60,7 @@ export default async (ssrContext) => {
const beforeRender = async () => { const beforeRender = async () => {
// Call beforeNuxtRender() methods // Call beforeNuxtRender() methods
await Promise.all(ssrContext.beforeRenderFns.map((fn) => promisify(fn, { Components, nuxtState: ssrContext.nuxt }))) await Promise.all(ssrContext.beforeRenderFns.map(fn => promisify(fn, { Components, nuxtState: ssrContext.nuxt })))
<% if (store) { %> <% if (store) { %>
// Add the state from the vuex store // Add the state from the vuex store
ssrContext.nuxt.state = store.state ssrContext.nuxt.state = store.state
@ -67,7 +68,7 @@ export default async (ssrContext) => {
} }
const renderErrorPage = async () => { const renderErrorPage = async () => {
// Load layout for error page // Load layout for error page
let errLayout = (typeof NuxtError.layout === 'function' ? NuxtError.layout(app.context) : NuxtError.layout) const errLayout = (typeof NuxtError.layout === 'function' ? NuxtError.layout(app.context) : NuxtError.layout)
ssrContext.nuxt.layout = errLayout || 'default' ssrContext.nuxt.layout = errLayout || 'default'
await _app.loadLayout(errLayout) await _app.loadLayout(errLayout)
_app.setLayout(errLayout) _app.setLayout(errLayout)
@ -104,7 +105,7 @@ export default async (ssrContext) => {
/* /*
** Call global middleware (nuxt.config.js) ** Call global middleware (nuxt.config.js)
*/ */
let midd = <%= serialize(router.middleware).replace('middleware(', 'function(') %> let midd = <%= serialize(router.middleware).replace('middleware(', 'function(') %><%= isTest ? '// eslint-disable-line' : '' %>
midd = midd.map((name) => { midd = midd.map((name) => {
if (typeof name === 'function') return name if (typeof name === 'function') return name
if (typeof middleware[name] !== 'function') { if (typeof middleware[name] !== 'function') {
@ -186,12 +187,12 @@ export default async (ssrContext) => {
if (!Components.length) return render404Page() if (!Components.length) return render404Page()
// Call asyncData & fetch hooks on components matched by the route. // Call asyncData & fetch hooks on components matched by the route.
let asyncDatas = await Promise.all(Components.map((Component) => { const asyncDatas = await Promise.all(Components.map((Component) => {
let promises = [] const promises = []
// Call asyncData(context) // Call asyncData(context)
if (Component.options.asyncData && typeof Component.options.asyncData === 'function') { if (Component.options.asyncData && typeof Component.options.asyncData === 'function') {
let promise = promisify(Component.options.asyncData, app.context) const promise = promisify(Component.options.asyncData, app.context)
promise.then((asyncDataResult) => { promise.then((asyncDataResult) => {
ssrContext.asyncData[Component.cid] = asyncDataResult ssrContext.asyncData[Component.cid] = asyncDataResult
applyAsyncData(Component) applyAsyncData(Component)
@ -205,8 +206,7 @@ export default async (ssrContext) => {
// Call fetch(context) // Call fetch(context)
if (Component.options.fetch) { if (Component.options.fetch) {
promises.push(Component.options.fetch(app.context)) promises.push(Component.options.fetch(app.context))
} } else {
else {
promises.push(null) promises.push(null)
} }

View File

@ -81,7 +81,7 @@ export const createStore = storeData instanceof Function ? storeData : () => {
} }
// Dynamically require module // Dynamically require module
function getModule (filename) { function getModule(filename) {
const file = files(filename) const file = files(filename)
const module = file.default || file const module = file.default || file
if (module.commit) { if (module.commit) {
@ -93,7 +93,7 @@ function getModule (filename) {
return module return module
} }
function getModuleNamespace (storeData, namePath, forAppend = false) { function getModuleNamespace(storeData, namePath, forAppend = false) {
if (namePath.length === 1) { if (namePath.length === 1) {
if (forAppend) { if (forAppend) {
return storeData return storeData
@ -107,7 +107,7 @@ function getModuleNamespace (storeData, namePath, forAppend = false) {
return getModuleNamespace(storeData.modules[namespace], namePath, forAppend) return getModuleNamespace(storeData.modules[namespace], namePath, forAppend)
} }
function appendModule (module, filename, name) { function appendModule(module, filename, name) {
const file = files(filename) const file = files(filename)
module.appends = module.appends || [] module.appends = module.appends || []
module.appends.push(name) module.appends.push(name)

View File

@ -20,7 +20,7 @@ export function globalHandleError(error) {
} }
export function interopDefault(promise) { export function interopDefault(promise) {
return promise.then(m => m.default || m); return promise.then(m => m.default || m)
} }
export function applyAsyncData(Component, asyncData) { export function applyAsyncData(Component, asyncData) {
@ -99,7 +99,8 @@ export function resolveRouteComponents(route) {
if (typeof Component === 'function' && !Component.options) { if (typeof Component === 'function' && !Component.options) {
Component = await Component() Component = await Component()
} }
return match.components[key] = sanitizeComponent(Component) match.components[key] = sanitizeComponent(Component)
return match.components[key]
}) })
) )
} }
@ -117,7 +118,6 @@ export async function getRouteData(route) {
} }
export async function setContext(app, context) { export async function setContext(app, context) {
const route = (context.to ? context.to : context.route)
// If context not defined, create it // If context not defined, create it
if (!app.context) { if (!app.context) {
app.context = { app.context = {
@ -129,7 +129,7 @@ export async function setContext(app, context) {
payload: context.payload, payload: context.payload,
error: context.error, error: context.error,
base: '<%= router.base %>', base: '<%= router.base %>',
env: <%= JSON.stringify(env) %> env: <%= JSON.stringify(env) %><%= isTest ? '// eslint-disable-line' : '' %>
} }
// Only set once // Only set once
if (context.req) app.context.req = context.req if (context.req) app.context.req = context.req
@ -230,7 +230,7 @@ export function promisify(fn, context) {
// Imported from vue-router // Imported from vue-router
export function getLocation(base, mode) { export function getLocation(base, mode) {
var path = window.location.pathname let path = window.location.pathname
if (mode === 'hash') { if (mode === 'hash') {
return window.location.hash.replace(/^#\//, '') return window.location.hash.replace(/^#\//, '')
} }
@ -294,17 +294,17 @@ const PATH_REGEXP = new RegExp([
* @return {!Array} * @return {!Array}
*/ */
function parse(str, options) { function parse(str, options) {
var tokens = [] const tokens = []
var key = 0 let key = 0
var index = 0 let index = 0
var path = '' let path = ''
var defaultDelimiter = options && options.delimiter || '/' const defaultDelimiter = (options && options.delimiter) || '/'
var res let res
while ((res = PATH_REGEXP.exec(str)) != null) { while ((res = PATH_REGEXP.exec(str)) != null) {
var m = res[0] const m = res[0]
var escaped = res[1] const escaped = res[1]
var offset = res.index const offset = res.index
path += str.slice(index, offset) path += str.slice(index, offset)
index = offset + m.length index = offset + m.length
@ -314,13 +314,13 @@ function parse(str, options) {
continue continue
} }
var next = str[index] const next = str[index]
var prefix = res[2] const prefix = res[2]
var name = res[3] const name = res[3]
var capture = res[4] const capture = res[4]
var group = res[5] const group = res[5]
var modifier = res[6] const modifier = res[6]
var asterisk = res[7] const asterisk = res[7]
// Push the current path onto the tokens. // Push the current path onto the tokens.
if (path) { if (path) {
@ -328,11 +328,11 @@ function parse(str, options) {
path = '' path = ''
} }
var partial = prefix != null && next != null && next !== prefix const partial = prefix != null && next != null && next !== prefix
var repeat = modifier === '+' || modifier === '*' const repeat = modifier === '+' || modifier === '*'
var optional = modifier === '?' || modifier === '*' const optional = modifier === '?' || modifier === '*'
var delimiter = res[2] || defaultDelimiter const delimiter = res[2] || defaultDelimiter
var pattern = capture || group const pattern = capture || group
tokens.push({ tokens.push({
name: name || key++, name: name || key++,
@ -366,7 +366,7 @@ function parse(str, options) {
* @return {string} * @return {string}
*/ */
function encodeURIComponentPretty(str) { function encodeURIComponentPretty(str) {
return encodeURI(str).replace(/[\/?#]/g, (c) => { return encodeURI(str).replace(/[/?#]/g, (c) => {
return '%' + c.charCodeAt(0).toString(16).toUpperCase() return '%' + c.charCodeAt(0).toString(16).toUpperCase()
}) })
} }
@ -388,23 +388,23 @@ function encodeAsterisk(str) {
*/ */
function tokensToFunction(tokens) { function tokensToFunction(tokens) {
// Compile all the tokens into regexps. // Compile all the tokens into regexps.
var matches = new Array(tokens.length) const matches = new Array(tokens.length)
// Compile all the patterns before compilation. // Compile all the patterns before compilation.
for (var i = 0; i < tokens.length; i++) { for (let i = 0; i < tokens.length; i++) {
if (typeof tokens[i] === 'object') { if (typeof tokens[i] === 'object') {
matches[i] = new RegExp('^(?:' + tokens[i].pattern + ')$') matches[i] = new RegExp('^(?:' + tokens[i].pattern + ')$')
} }
} }
return function(obj, opts) { return function (obj, opts) {
var path = '' let path = ''
var data = obj || {} const data = obj || {}
var options = opts || {} const options = opts || {}
var encode = options.pretty ? encodeURIComponentPretty : encodeURIComponent const encode = options.pretty ? encodeURIComponentPretty : encodeURIComponent
for (var i = 0; i < tokens.length; i++) { for (let i = 0; i < tokens.length; i++) {
var token = tokens[i] const token = tokens[i]
if (typeof token === 'string') { if (typeof token === 'string') {
path += token path += token
@ -412,8 +412,8 @@ function tokensToFunction(tokens) {
continue continue
} }
var value = data[token.name] const value = data[token.name]
var segment let segment
if (value == null) { if (value == null) {
if (token.optional) { if (token.optional) {
@ -441,7 +441,7 @@ function tokensToFunction(tokens) {
} }
} }
for (var j = 0; j < value.length; j++) { for (let j = 0; j < value.length; j++) {
segment = encode(value[j]) segment = encode(value[j])
if (!matches[i].test(segment)) { if (!matches[i].test(segment)) {
@ -474,7 +474,7 @@ function tokensToFunction(tokens) {
* @return {string} * @return {string}
*/ */
function escapeString(str) { function escapeString(str) {
return str.replace(/([.+*?=^!:${}()[\]|\/\\])/g, '\\$1') return str.replace(/([.+*?=^!:${}()[\]|/\\])/g, '\\$1')
} }
/** /**
@ -484,7 +484,7 @@ function escapeString(str) {
* @return {string} * @return {string}
*/ */
function escapeGroup(group) { function escapeGroup(group) {
return group.replace(/([=!:$\/()])/g, '\\$1') return group.replace(/([=!:$/()])/g, '\\$1')
} }
/** /**
@ -494,9 +494,9 @@ function escapeGroup(group) {
* @param {string} query * @param {string} query
* @return {string} * @return {string}
*/ */
function formatUrl (url, query) { function formatUrl(url, query) {
let protocol let protocol
let index = url.indexOf('://') const index = url.indexOf('://')
if (index !== -1) { if (index !== -1) {
protocol = url.substring(0, index) protocol = url.substring(0, index)
url = url.substring(index + 3) url = url.substring(index + 3)
@ -531,9 +531,9 @@ function formatUrl (url, query) {
* @param {object} query * @param {object} query
* @return {string} * @return {string}
*/ */
function formatQuery (query) { function formatQuery(query) {
return Object.keys(query).sort().map((key) => { return Object.keys(query).sort().map((key) => {
var val = query[key] const val = query[key]
if (val == null) { if (val == null) {
return '' return ''
} }

View File

@ -96,9 +96,9 @@
</style> </style>
<script> <script>
window.addEventListener('error', function() { window.addEventListener('error', function () {
var e = document.getElementById("nuxt-loading"); var e = document.getElementById('nuxt-loading');
if (e) e.className += " error"; if (e) e.className += ' error';
}); });
</script> </script>

View File

@ -33,7 +33,8 @@ import {
sequence, sequence,
relativeTo, relativeTo,
waitFor, waitFor,
determineGlobals determineGlobals,
stripWhitespace
} from '@nuxt/common' } from '@nuxt/common'
import PerfLoader from './webpack/utils/perf-loader' import PerfLoader from './webpack/utils/perf-loader'
@ -214,6 +215,7 @@ export default class Builder {
splitChunks: this.options.build.splitChunks, splitChunks: this.options.build.splitChunks,
uniqBy, uniqBy,
isDev: this.options.dev, isDev: this.options.dev,
isTest: this.options.test,
debug: this.options.debug, debug: this.options.debug,
vue: { config: this.options.vue.config }, vue: { config: this.options.vue.config },
mode: this.options.mode, mode: this.options.mode,
@ -432,7 +434,8 @@ export default class Builder {
}, },
interpolate: /<%=([\s\S]+?)%>/g interpolate: /<%=([\s\S]+?)%>/g
}) })
content = templateFunction( content = stripWhitespace(
templateFunction(
Object.assign({}, templateVars, { Object.assign({}, templateVars, {
options: options || {}, options: options || {},
custom, custom,
@ -440,6 +443,7 @@ export default class Builder {
dst dst
}) })
) )
)
} catch (err) { } catch (err) {
/* istanbul ignore next */ /* istanbul ignore next */
throw new Error(`Could not compile template ${src}: ${err.message}`) throw new Error(`Could not compile template ${src}: ${err.message}`)

View File

@ -10,6 +10,7 @@ const nuxtDir = fs.existsSync(path.resolve(__dirname, '..', '..', 'package.js'))
export default { export default {
// Information about running environment // Information about running environment
dev: Boolean(env.dev), dev: Boolean(env.dev),
test: Boolean(env.test),
debug: undefined, // = dev debug: undefined, // = dev
// Mode // Mode

View File

@ -389,3 +389,18 @@ const DYNAMIC_ROUTE_REGEX = /^\/(:|\*)/
* @return {array} * @return {array}
*/ */
export const wrapArray = value => Array.isArray(value) ? value : [value] export const wrapArray = value => Array.isArray(value) ? value : [value]
const WHITESPACE_REPLACEMENTS = [
[/[ \t\f\r]+\n/g, '\n'], // strip empty indents
[/{\n{2,}/g, '{\n'], // strip start padding from blocks
[/\n{2,}([ \t\f\r]*})/g, '\n$1'], // strip end padding from blocks
[/\n{3,}/g, '\n\n'], // strip multiple blank lines (1 allowed)
[/\n{2,}$/g, '\n'] // strip blank lines EOF (0 allowed)
]
export const stripWhitespace = function stripWhitespace(string) {
WHITESPACE_REPLACEMENTS.forEach(([regex, newSubstr]) => {
string = string.replace(regex, newSubstr)
})
return string
}

View File

@ -1,4 +1,5 @@
export default { export default {
test: true,
hooks(hook) { hooks(hook) {
hook('build:done', () => { hook('build:done', () => {
process.stdout.write('Compiled successfully') process.stdout.write('Compiled successfully')

View File

@ -1,7 +1,8 @@
export default { export default {
buildDir: '.nuxt-generate/.build', test: true,
buildDir: '.nuxt-generate/build',
generate: { generate: {
dir: '.nuxt-generate/.generate' dir: '.nuxt-generate/generate'
}, },
hooks(hook) { hooks(hook) {
hook('generate:done', (generator, errors) => { hook('generate:done', (generator, errors) => {

View File

@ -30,6 +30,7 @@ export const loadFixture = async function (fixture, overrides) {
config.rootDir = rootDir config.rootDir = rootDir
config.dev = false config.dev = false
config.test = true
return defaultsDeep({}, overrides, config) return defaultsDeep({}, overrides, config)
} }