Merge branch 'dev' of github.com:Atinux/nuxt.js into dev

This commit is contained in:
Sébastien Chopin 2017-09-21 22:35:48 +02:00
commit 27b80739bc
47 changed files with 563 additions and 277 deletions

View File

@ -81,7 +81,12 @@ function genConfig (opts) {
'external-helpers' 'external-helpers'
], ],
presets: [ presets: [
['es2015', { modules: false }] ['env', {
targets: {
node: '6.11.0'
},
modules: false
}]
], ],
'env': { 'env': {
'test': { 'test': {

View File

@ -15,7 +15,8 @@ const packageJSON = readJSONSync(resolve(rootDir, 'package.json'))
// Required and Excluded packages for start // Required and Excluded packages for start
let requires = [ let requires = [
'source-map-support', 'source-map-support',
'pretty-error' 'pretty-error',
'minimist'
] ]
const excludes = [ const excludes = [

View File

@ -1,15 +1,15 @@
module.exports = { module.exports = {
build: { build: {
filenames: { filenames: {
css: 'styles.[chunkhash].css', // default: common.[chunkhash].css css: 'styles.[chunkhash].css', // default: common.[chunkhash].css
manifest: 'manifest.[hash].js', // default: manifest.[hash].js manifest: 'manifest.[hash].js', // default: manifest.[hash].js
vendor: 'vendor.[hash].js', // default: vendor.bundle.[hash].js vendor: 'vendor.[hash].js', // default: vendor.bundle.[hash].js
app: 'app.[chunkhash].js' // default: nuxt.bundle.[chunkhash].js app: 'app.[chunkhash].js' // default: nuxt.bundle.[chunkhash].js
}, },
vendor: ['lodash'], vendor: ['lodash'],
extend (config, { dev }) { extend (config, { dev }) {
if (dev) { if (dev) {
config.devtool = (dev ? 'eval-source-map' : false) config.devtool = 'eval-source-map'
} }
const urlLoader = config.module.rules.find((loader) => loader.loader === 'url-loader') const urlLoader = config.module.rules.find((loader) => loader.loader === 'url-loader')
// Increase limit to 100KO // Increase limit to 100KO

View File

@ -45,7 +45,7 @@ ul {
list-style: none; list-style: none;
margin: 0; margin: 0;
padding: 0; padding: 0;
with: 100%; width: 100%;
max-width: 300px; max-width: 300px;
margin: auto; margin: auto;
} }

Binary file not shown.

View File

@ -1,3 +1,11 @@
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 400;
src: local('Roboto'), local('Roboto-Regular'), url(../assets/roboto.woff2) format('woff2');
unicode-range: U+0460-052F, U+20B4, U+2DE0-2DFF, U+A640-A69F;
}
body { body {
background: #eee; background: #eee;
text-align: center; text-align: center;
@ -7,6 +15,7 @@ body {
position: absolute; position: absolute;
top: 0; top: 0;
left: 0; left: 0;
font-family: 'Roboto';
} }
.content { .content {
margin-top: 100px; margin-top: 100px;

View File

@ -9,5 +9,12 @@ module.exports = {
css: [ css: [
'bulma/css/bulma.css', 'bulma/css/bulma.css',
'~/css/main.css' '~/css/main.css'
] ],
render: {
bundleRenderer: {
shouldPreload: (file, type) => {
return ['script', 'style', 'font'].includes(type)
}
}
}
} }

View File

@ -1,7 +1,7 @@
{ {
"name": "nuxt-global-css", "name": "nuxt-global-css",
"dependencies": { "dependencies": {
"bulma": "^0.4.3", "bulma": "^0.5.1",
"nuxt": "latest" "nuxt": "latest"
}, },
"scripts": { "scripts": {

View File

@ -1,7 +1,7 @@
{ {
"name": "nuxt-i18n", "name": "nuxt-i18n",
"dependencies": { "dependencies": {
"nuxt": "latest", "nuxt": "^1.0.0-rc9",
"vue-i18n": "^7.0.5" "vue-i18n": "^7.0.5"
}, },
"scripts": { "scripts": {

View File

@ -3,7 +3,7 @@ import VueI18n from 'vue-i18n'
Vue.use(VueI18n) Vue.use(VueI18n)
export default ({ app, store }) => { export default ({ app, isClient, store }) => {
// Set i18n instance on app // Set i18n instance on app
// This way we can use it in middleware and pages asyncData/fetch // This way we can use it in middleware and pages asyncData/fetch
app.i18n = new VueI18n({ app.i18n = new VueI18n({

View File

@ -0,0 +1,3 @@
# Layout transitions with Nuxt.js
https://nuxtjs.org/examples/layout-transitions

View File

@ -0,0 +1,52 @@
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;
}
.container {
text-align: center;
padding-top: 200px;
font-size: 20px;
transition: all .5s cubic-bezier(.55,0,.1,1);
}
.page-enter-active, .page-leave-active {
transition: opacity .5s
}
.page-enter, .page-leave-active {
opacity: 0
}
.layout-enter-active, .layout-leave-active {
transition: opacity .5s
}
.layout-enter, .layout-leave-active {
opacity: 0
}
.bounce-enter-active {
animation: bounce-in .8s;
}
.bounce-leave-active {
animation: bounce-out .5s;
}
@keyframes bounce-in {
0% { transform: scale(0) }
50% { transform: scale(1.5) }
100% { transform: scale(1) }
}
@keyframes bounce-out {
0% { transform: scale(1) }
50% { transform: scale(1.5) }
100% { transform: scale(0) }
}
.slide-left-enter,
.slide-right-leave-active {
opacity: 0;
transform: translate(30px, 0);
}
.slide-left-leave-active,
.slide-right-enter {
opacity: 0;
transform: translate(-30px, 0);
}

View File

@ -0,0 +1,11 @@
<template>
<div>
<menu>
<ul>
<li>Option 1</li>
<li>Option 2</li>
</ul>
</menu>
<nuxt/>
</div>
</template>

View File

@ -0,0 +1,10 @@
module.exports = {
build: {
vendor: ['axios']
},
css: ['~/assets/main.css'],
layoutTransition: {
name: 'layout',
mode: 'out-in'
}
}

View File

@ -0,0 +1,12 @@
{
"name": "nuxt-layout-transitions",
"dependencies": {
"axios": "^0.15.3",
"nuxt": "latest"
},
"scripts": {
"dev": "../../bin/nuxt",
"build": "nuxt build",
"start": "nuxt start"
}
}

View File

@ -0,0 +1,13 @@
<template>
<div class="container">
<h1>About page</h1>
<nuxt-link to="/">Home page</nuxt-link>
</div>
</template>
<script>
export default {
layout: 'secondary',
transition: 'bounce'
}
</script>

View File

@ -0,0 +1,7 @@
<template>
<div class="container">
<h1>Home page</h1>
<p><nuxt-link to="/about">About page</nuxt-link></p>
<p><nuxt-link to="/users">Lists of users</nuxt-link></p>
</div>
</template>

View File

@ -0,0 +1,71 @@
<template>
<div class="container">
<nuxt-link v-if="page > 1" :to="'?page=' + (page - 1)">&lt; Prev</nuxt-link>
<a v-else class="disabled">&lt; Prev</a>
<span>{{ page }}/{{ totalPages }}</span>
<nuxt-link v-if="page < totalPages" :to="'?page=' + (page + 1)">Next &gt;</nuxt-link>
<a v-else class="disabled">Next &gt;</a>
<ul>
<li v-for="user in users">
<img :src="user.avatar" class="avatar" />
<span>{{ user.first_name }} {{ user.last_name }}</span>
</li>
</ul>
<p><nuxt-link to="/">Back home</nuxt-link></p>
</div>
</template>
<script>
import axios from 'axios'
export default {
transition (to, from) {
if (!from) return 'slide-left'
return +to.query.page < +from.query.page ? 'slide-right' : 'slide-left'
},
async asyncData ({ query }) {
const page = query.page || 1
const { data } = await axios.get(`https://reqres.in/api/users?page=${page}`)
return {
page: +data.page,
totalPages: data.total_pages,
users: data.data
}
}
}
</script>
<style scoped>
a {
display: inline-block;
margin: 0 1em;
color: #34495e;
text-decoration: none;
}
a.disabled {
color: #ccc;
}
ul {
margin: auto;
padding: 0;
width: 100%;
max-width: 400px;
padding-top: 40px;
}
li {
list-style-type: none;
width: 400px;
border: 1px #ddd solid;
overflow: hidden;
}
li img {
float: left;
width: 100px;
height: 100px;
}
li span {
display: inline-block;
padding-top: 40px;
text-transform: uppercase;
}
</style>

View File

@ -23,23 +23,19 @@ module.exports = {
*/ */
css: ['~/assets/main.css'], css: ['~/assets/main.css'],
/* /*
** Cutomize loading indicator ** Customize loading indicator
*/ */
loadingIndicator: { loadingIndicator: {
/* /*
** See https://github.com/nuxt/nuxt.js/tree/dev/lib/app/views/loading for available loading indicators ** See https://github.com/nuxt/nuxt.js/tree/dev/lib/app/views/loading for available loading indicators
** You can add a custom indicator by giving a path ** You can add a custom indicator by giving a path
** Default: 'circle'
*/ */
name: 'folding-cube', // name: 'folding-cube',
/* /*
** You can give custom options given to the template ** You can give custom options given to the template
** See https://github.com/nuxt/nuxt.js/blob/dev/lib/app/views/loading/folding-cube.html ** See https://github.com/nuxt/nuxt.js/blob/dev/lib/app/views/loading/folding-cube.html
** Default:
** - color: '#3B8070'
** - background: 'white'
*/ */
color: '#222', // color: '#DBE1EC'
background: 'white' // background: 'white'
} }
} }

View File

@ -7,7 +7,7 @@ module.exports = function (options) {
loader: 'ts-loader' loader: 'ts-loader'
}) })
// Add TypeScript loader for vue files // Add TypeScript loader for vue files
for (rule of config.module.rules) { for (let rule of config.module.rules) {
if (rule.loader === 'vue-loader') { if (rule.loader === 'vue-loader') {
rule.query.loaders.ts = 'ts-loader?{"appendTsSuffixTo":["\\\\.vue$"]}' rule.query.loaders.ts = 'ts-loader?{"appendTsSuffixTo":["\\\\.vue$"]}'
} }

View File

@ -1,8 +1,8 @@
{ {
"name": "nuxt-vue-apollo", "name": "nuxt-vue-apollo",
"dependencies": { "dependencies": {
"@nuxtjs/apollo": "^2.0.0", "@nuxtjs/apollo": "^2.1.1",
"nuxt": "^1.0.0-rc6" "nuxt": "^1.0.0-rc9"
}, },
"scripts": { "scripts": {
"dev": "nuxt", "dev": "nuxt",

View File

@ -1,7 +1,9 @@
<template> <template>
<div id="__nuxt"> <div id="__nuxt">
<% if (loading) { %><nuxt-loading ref="loading"></nuxt-loading><% } %> <% if (loading) { %><nuxt-loading ref="loading"></nuxt-loading><% } %>
<component v-if="layout" :is="nuxt.err ? 'nuxt' : layout"></component> <% if (layoutTransition) { %><transition name="<%= layoutTransition.name %>" mode="<%= layoutTransition.mode %>"><% } %>
<component v-if="layout" :is="nuxt.err ? 'nuxt' : layout" :key="layoutName"></component>
<% if (layoutTransition) { %></transition><% } %>
</div> </div>
</template> </template>

View File

@ -26,18 +26,19 @@ let router
// Try to rehydrate SSR data from window // Try to rehydrate SSR data from window
const NUXT = window.__NUXT__ || {} const NUXT = window.__NUXT__ || {}
NUXT.components = window.__COMPONENTS__ || null
<% if (debug || mode === 'spa') { %> <% if (debug || mode === 'spa') { %>
// Setup global Vue error handler // Setup global Vue error handler
const defaultErrorHandler = Vue.config.errorHandler const defaultErrorHandler = Vue.config.errorHandler
Vue.config.errorHandler = function (err, vm, info) { Vue.config.errorHandler = function (err, vm, info) {
err.statusCode = err.statusCode || err.name || 'Whoops!' const nuxtError = {
err.message = err.message || err.toString() statusCode: err.statusCode || err.name || 'Whoops!',
message: err.message || err.toString()
}
// Show Nuxt Error Page // Show Nuxt Error Page
if(vm && vm.$root && vm.$root.$nuxt && vm.$root.$nuxt.error && info !== 'render function') { if(vm && vm.$root && vm.$root.$nuxt && vm.$root.$nuxt.error && info !== 'render function') {
vm.$root.$nuxt.error(err) vm.$root.$nuxt.error(nuxtError)
} }
// Call other handler if exist // Call other handler if exist
@ -49,7 +50,7 @@ Vue.config.errorHandler = function (err, vm, info) {
if (process.env.NODE_ENV !== 'production') { if (process.env.NODE_ENV !== 'production') {
console.error(err) console.error(err)
} else { } else {
console.error(err.message) console.error(err.message || nuxtError.message)
} }
} }
<% } %> <% } %>
@ -132,30 +133,31 @@ async function loadAsyncComponents (to, from, next) {
} }
} }
function applySSRData(Component, ssrData) {
if (NUXT.serverRendered && ssrData) {
applyAsyncData(Component, ssrData)
}
Component._Ctor = Component
return Component
}
// Get matched components // Get matched components
function resolveComponents(router) { function resolveComponents(router) {
const path = getLocation(router.options.base) const path = getLocation(router.options.base, router.options.mode)
return flatMapComponents(router.match(path), (Component, _, match, key, index) => { return flatMapComponents(router.match(path), (Component, _, match, key, index) => {
// If component already resolved // If component already resolved
if (typeof Component !== 'function' || Component.options) { if (typeof Component !== 'function' || Component.options) {
const _Component = sanitizeComponent(Component) const _Component = applySSRData(sanitizeComponent(Component), NUXT.data ? NUXT.data[index] : null)
match.components[key] = _Component match.components[key] = _Component
return _Component return _Component
} }
// Resolve component // Resolve component
return Component().then(Component => { return Component().then(Component => {
const _Component = sanitizeComponent(Component) const _Component = applySSRData(sanitizeComponent(Component), NUXT.data ? NUXT.data[index] : null)
if (NUXT.serverRendered) { match.components[key] = _Component
applyAsyncData(_Component, NUXT.data[index]) return _Component
if (NUXT.components) {
Component.options.components = Object.assign(_Component.options.components, NUXT.components[index])
}
_Component._Ctor = _Component
}
match.components[key] = _Component
return _Component
}) })
}) })
} }
@ -228,7 +230,7 @@ async function render (to, from, next) {
await callMiddleware.call(this, Components, context, layout) await callMiddleware.call(this, Components, context, layout)
if (context._redirected) return if (context._redirected) return
this.error({ statusCode: 404, message: 'This page could not be found.' }) this.error({ statusCode: 404, message: '<%= messages.error_404 %>' })
return next() return next()
} }
@ -272,7 +274,7 @@ async function render (to, from, next) {
}) })
// ...If .validate() returned false // ...If .validate() returned false
if (!isValid) { if (!isValid) {
this.error({ statusCode: 404, message: 'This page could not be found.' }) this.error({ statusCode: 404, message: '<%= messages.error_404 %>' })
return next() return next()
} }

View File

@ -37,6 +37,19 @@ export default {
name: 'nuxt-child', name: 'nuxt-child',
functional: true, functional: true,
render (h, { parent, data }) { render (h, { parent, data }) {
const nuxt = parent.$root.nuxt
const component = parent.$route.matched[0].components.default
const layoutUid = parent._uid
const layoutName = component.options ? component.options.layout : null
// If we're changing layout render the stored vnode
if (nuxt._layoutUid === layoutUid &&
nuxt._layoutName !== layoutName) return nuxt._childVnode
nuxt._layoutUid = layoutUid
nuxt._layoutName = layoutName
data.nuxtChild = true data.nuxtChild = true
const _parent = parent const _parent = parent
const transitions = parent.$nuxt.nuxt.transitions const transitions = parent.$nuxt.nuxt.transitions
@ -62,11 +75,14 @@ export default {
listeners[key] = transition[key].bind(_parent) listeners[key] = transition[key].bind(_parent)
} }
}) })
return h('transition', {
nuxt._childVnode = h('transition', {
props: transitionProps, props: transitionProps,
on: listeners on: listeners
}, [ }, [
h('router-view', data) h('router-view', data)
]) ])
return nuxt._childVnode
} }
} }

View File

@ -1,32 +1,21 @@
<template> <template>
<div class="__nuxt-error-page"> <div class="__nuxt-error-page">
<div class="container"> <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>
<div class="row"> <div class="title">{{ message }}</div>
<div class="column"> <p class="description" v-if="statusCode === 404">
<h1>{{ statusCode }} </h1> <nuxt-link class="error-link" to="/"><%= messages.back_to_home %></nuxt-link>
<h3> {{ message }} </h3> </p>
<p v-if="statusCode === 404"> <% if(debug) { %>
<nuxt-link class="error-link" to="/">Back to the home page</nuxt-link> <p class="description" v-else><%= messages.client_error_details %></p>
</p> <% } %>
<% if(debug) { %>
<small v-else>
Open developer tools to view stack trace
</small>
<% } %>
</div>
</div>
<div class="row"> <div class="logo">
<div class="column"> <a href="https://nuxtjs.org" target="_blank" rel="noopener"><%= messages.nuxtjs %></a>
<div class="poweredby">
<small> Powered by <a href="https://nuxtjs.org" target="_blank" rel="noopener">Nuxt.js</a> </small>
</div>
</div>
</div>
</div>
</div> </div>
</div>
</div>
</template> </template>
<script> <script>
@ -35,14 +24,17 @@ export default {
props: ['error'], props: ['error'],
head () { head () {
return { return {
title: this.statusCode + ' - ' + this.message, title: this.message,
link: [ meta: [
{ rel: 'stylesheet', href: 'https://cdnjs.cloudflare.com/ajax/libs/normalize/7.0.0/normalize.min.css', type: 'text/css', media: 'all' }, {
{ rel: 'stylesheet', href: 'https://cdnjs.cloudflare.com/ajax/libs/milligram/1.3.0/milligram.min.css', type: 'text/css', media: 'all' } name: 'viewport',
content: 'width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no'
}
] ]
} }
}, },
<% if(debug) { %> <% if(debug) { %>
// Only on debug mode
data () { data () {
return { return {
mounted: false mounted: false
@ -51,13 +43,23 @@ export default {
mounted () { mounted () {
this.mounted = true this.mounted = true
}, },
created () {
console.error(this.error)
},
watch: {
error(newErr) {
if(newErr) {
console.error(newErr)
}
}
},
<% } %> <% } %>
computed: { computed: {
statusCode () { statusCode () {
return (this.error && this.error.statusCode) || 500 return (this.error && this.error.statusCode) || 500
}, },
message () { message () {
return this.error.message || 'Nuxt Server Error' return this.error.message || '<%= messages.client_error %>'
} }
} }
} }
@ -65,29 +67,46 @@ export default {
<style> <style>
.__nuxt-error-page { .__nuxt-error-page {
background: #F5F7FA; padding: 1rem;
font-size: 14px; background: #F7F8FB;
word-spacing: 1px; color: #47494E;
-ms-text-size-adjust: 100%;
-webkit-text-size-adjust: 100%;
-moz-osx-font-smoothing: grayscale;
-webkit-font-smoothing: antialiased;
text-align: center; text-align: center;
}
.__nuxt-error-page .container {
display: flex; display: flex;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
flex-direction: column; flex-direction: column;
height: 100vh; font-family: sans-serif;
margin: 0 auto; font-weight: 100 !important;
max-width: 70%; -ms-text-size-adjust: 100%;
-webkit-text-size-adjust: 100%;
-webkit-font-smoothing: antialiased;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
} }
.__nuxt-error-page .poweredby { .__nuxt-error-page .error {
text-align: center; max-width: 450px;
margin-top: 10%; }
.__nuxt-error-page .title {
font-size: 1.5rem;
margin-top: 15px;
color: #47494E;
margin-bottom: 8px;
}
.__nuxt-error-page .description {
color: #7F828B;
line-height: 21px;
margin-bottom: 10px;
} }
.__nuxt-error-page a { .__nuxt-error-page a {
color: #42b983 !important; color: #7F828B !important;
text-decoration: none;
}
.__nuxt-error-page .logo {
position: fixed;
left: 12px;
bottom: 12px;
} }
</style> </style>

View File

@ -1,6 +1,8 @@
<template> <template>
<nuxt-error v-if="nuxt.err" :error="nuxt.err"></nuxt-error> <div class="nuxt">
<nuxt-child :key="routerViewKey" v-else></nuxt-child> <nuxt-error v-if="nuxt.err" :error="nuxt.err"></nuxt-error>
<nuxt-child :key="routerViewKey" v-else></nuxt-child>
</div>
</template> </template>
<script> <script>

View File

@ -43,7 +43,11 @@ const defaultTransition = <%=
async function createApp (ssrContext) { async function createApp (ssrContext) {
const router = createRouter() const router = createRouter()
<% if (store) { %>const store = createStore()<% } %> <% if (store) { %>
const store = createStore()
// Add this.$router into store actions/mutations
store.$router = router
<% } %>
// Create Root instance // Create Root instance
// here we inject the router and store to all child components, // here we inject the router and store to all child components,
@ -135,6 +139,15 @@ async function createApp (ssrContext) {
<% } %> <% } %>
} }
<% if (store) { %>
if (process.browser) {
// Replace store state before plugins execution
if (window.__NUXT__ && window.__NUXT__.state) {
store.replaceState(window.__NUXT__.state)
}
}
<% } %>
<% plugins.filter(p => p.ssr).forEach(plugin => { %> <% plugins.filter(p => p.ssr).forEach(plugin => { %>
if (typeof <%= plugin.name %> === 'function') await <%= plugin.name %>(ctx, inject)<% }) %> if (typeof <%= plugin.name %> === 'function') await <%= plugin.name %>(ctx, inject)<% }) %>
<% if (plugins.filter(p => !p.ssr).length) { %> <% if (plugins.filter(p => !p.ssr).length) { %>
@ -142,14 +155,8 @@ async function createApp (ssrContext) {
if (typeof <%= plugin.name %> === 'function') await <%= plugin.name %>(ctx, inject)<% }) %> if (typeof <%= plugin.name %> === 'function') await <%= plugin.name %>(ctx, inject)<% }) %>
}<% } %> }<% } %>
<% if (store) { %> // Inject context
if (process.browser) { inject('ctx', ctx)
// Replace store state before calling plugins
if (window.__NUXT__ && window.__NUXT__.state) {
store.replaceState(window.__NUXT__.state)
}
}
<% } %>
if (process.server && ssrContext && ssrContext.url) { if (process.server && ssrContext && ssrContext.url) {
await new Promise((resolve, reject) => { await new Promise((resolve, reject) => {

View File

@ -193,7 +193,7 @@ export default async context => {
// If no Components found, returns 404 // If no Components found, returns 404
if (!Components.length) { if (!Components.length) {
context.nuxt.error = context.error({ statusCode: 404, message: 'This page could not be found.' }) context.nuxt.error = context.error({ statusCode: 404, message: '<%= messages.error_404 %>' })
} }
<% if (isDev) { %>if (asyncDatas.length) debug('Data fetching ' + context.url + ': ' + (Date.now() - s) + 'ms')<% } %> <% if (isDev) { %>if (asyncDatas.length) debug('Data fetching ' + context.url + ': ' + (Date.now() - s) + 'ms')<% } %>

View File

@ -108,6 +108,9 @@ export function getContext (context, app) {
if (ctx.isServer && context.beforeRenderFns) { if (ctx.isServer && context.beforeRenderFns) {
ctx.beforeNuxtRender = (fn) => context.beforeRenderFns.push(fn) ctx.beforeNuxtRender = (fn) => context.beforeRenderFns.push(fn)
} }
if (ctx.isClient && window.__NUXT__) {
ctx.nuxtState = window.__NUXT__
}
return ctx return ctx
} }
@ -144,8 +147,11 @@ export function promisify (fn, context) {
} }
// Imported from vue-router // Imported from vue-router
export function getLocation (base) { export function getLocation (base, mode) {
var path = window.location.pathname var path = window.location.pathname
if (mode === 'hash') {
return window.location.hash.replace(/^#\//, '')
}
if (base && path.indexOf(base) === 0) { if (base && path.indexOf(base) === 0) {
path = path.slice(base.length) path = path.slice(base.length)
} }

File diff suppressed because one or more lines are too long

View File

@ -203,6 +203,7 @@ export default class Builder extends Tapable {
] ]
const templateVars = { const templateVars = {
options: this.options, options: this.options,
messages: this.options.messages,
uniqBy: _.uniqBy, uniqBy: _.uniqBy,
isDev: this.options.dev, isDev: this.options.dev,
debug: this.options.debug, debug: this.options.debug,
@ -218,6 +219,7 @@ export default class Builder extends Tapable {
layouts: Object.assign({}, this.options.layouts), layouts: Object.assign({}, this.options.layouts),
loading: typeof this.options.loading === 'string' ? this.relativeToBuild(this.options.srcDir, this.options.loading) : this.options.loading, loading: typeof this.options.loading === 'string' ? this.relativeToBuild(this.options.srcDir, this.options.loading) : this.options.loading,
transition: this.options.transition, transition: this.options.transition,
layoutTransition: this.options.layoutTransition,
components: { components: {
ErrorPage: this.options.ErrorPage ? this.relativeToBuild(this.options.ErrorPage) : null ErrorPage: this.options.ErrorPage ? this.relativeToBuild(this.options.ErrorPage) : null
} }
@ -485,9 +487,9 @@ export default class Builder extends Tapable {
compiler.run((err, stats) => { compiler.run((err, stats) => {
/* istanbul ignore if */ /* istanbul ignore if */
if (err) { if (err) {
console.error(err) // eslint-disable-line no-console
return reject(err) return reject(err)
} }
if (err) return console.error(err) // eslint-disable-line no-console
// Show build stats for production // Show build stats for production
console.log(stats.toString(this.webpackStats)) // eslint-disable-line no-console console.log(stats.toString(this.webpackStats)) // eslint-disable-line no-console
@ -518,7 +520,7 @@ export default class Builder extends Tapable {
this.webpackHotMiddleware = pify(webpackHotMiddleware(this.compiler.client, Object.assign({ this.webpackHotMiddleware = pify(webpackHotMiddleware(this.compiler.client, Object.assign({
log: false, log: false,
heartbeat: 1000 heartbeat: 10000
}, this.options.build.hotMiddleware))) }, this.options.build.hotMiddleware)))
// Inject to renderer instance // Inject to renderer instance

View File

@ -5,7 +5,6 @@ import HTMLPlugin from 'html-webpack-plugin'
import FriendlyErrorsWebpackPlugin from 'friendly-errors-webpack-plugin' import FriendlyErrorsWebpackPlugin from 'friendly-errors-webpack-plugin'
import ProgressBarPlugin from 'progress-bar-webpack-plugin' import ProgressBarPlugin from 'progress-bar-webpack-plugin'
import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer' import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer'
// import MinifyPlugin from 'babel-minify-webpack-plugin'
import { resolve } from 'path' import { resolve } from 'path'
import { existsSync } from 'fs' import { existsSync } from 'fs'
import Debug from 'debug' import Debug from 'debug'
@ -77,7 +76,7 @@ export default function webpackClientConfig () {
// Env object defined in nuxt.config.js // Env object defined in nuxt.config.js
let env = {} let env = {}
each(this.options.env, (value, key) => { each(this.options.env, (value, key) => {
env['process.env.' + key] = (typeof value === 'string' ? JSON.stringify(value) : value) env['process.env.' + key] = (['boolean', 'number'].indexOf(typeof value) !== -1 ? value : JSON.stringify(value))
}) })
// Webpack common plugins // Webpack common plugins
@ -153,7 +152,7 @@ export default function webpackClientConfig () {
// Add HMR support // Add HMR support
config.entry.app = [ config.entry.app = [
// https://github.com/glenjamin/webpack-hot-middleware#config // https://github.com/glenjamin/webpack-hot-middleware#config
`webpack-hot-middleware/client?name=client&reload=true&timeout=3000&path=${this.options.router.base}/__webpack_hmr`.replace(/\/\//g, '/'), `webpack-hot-middleware/client?name=client&reload=true&timeout=30000&path=${this.options.router.base}/__webpack_hmr`.replace(/\/\//g, '/'),
config.entry.app config.entry.app
] ]
config.plugins.push( config.plugins.push(
@ -191,17 +190,13 @@ export default function webpackClientConfig () {
if (!this.options.dev) { if (!this.options.dev) {
// Scope Hoisting // Scope Hoisting
config.plugins.push( config.plugins.push(
new webpack.optimize.ModuleConcatenationPlugin() // new webpack.optimize.ModuleConcatenationPlugin()
) )
// https://webpack.js.org/plugins/hashed-module-ids-plugin // https://webpack.js.org/plugins/hashed-module-ids-plugin
config.plugins.push(new webpack.HashedModuleIdsPlugin()) config.plugins.push(new webpack.HashedModuleIdsPlugin())
// Minify JS // Minify JS
// https://github.com/webpack-contrib/babel-minify-webpack-plugin
// config.plugins.push(new MinifyPlugin())
// https://github.com/webpack-contrib/uglifyjs-webpack-plugin // https://github.com/webpack-contrib/uglifyjs-webpack-plugin
config.plugins.push( config.plugins.push(
new webpack.optimize.UglifyJsPlugin({ new webpack.optimize.UglifyJsPlugin({

View File

@ -17,7 +17,7 @@ export default function webpackServerConfig () {
// env object defined in nuxt.config.js // env object defined in nuxt.config.js
let env = {} let env = {}
each(this.options.env, (value, key) => { each(this.options.env, (value, key) => {
env['process.env.' + key] = (typeof value === 'string' ? JSON.stringify(value) : value) env['process.env.' + key] = (['boolean', 'number'].indexOf(typeof value) !== -1 ? value : JSON.stringify(value))
}) })
config = Object.assign(config, { config = Object.assign(config, {

View File

@ -24,6 +24,9 @@ Options.from = function (_options) {
if (typeof options.transition === 'string') { if (typeof options.transition === 'string') {
options.transition = { name: options.transition } options.transition = { name: options.transition }
} }
if (typeof options.layoutTransition === 'string') {
options.layoutTransition = { name: options.layoutTransition }
}
// Apply defaults // Apply defaults
_.defaultsDeep(options, Options.defaults) _.defaultsDeep(options, Options.defaults)
@ -60,8 +63,8 @@ Options.from = function (_options) {
// Apply defaults to loadingIndicator // Apply defaults to loadingIndicator
options.loadingIndicator = Object.assign({ options.loadingIndicator = Object.assign({
name: 'circle', name: 'pulse',
color: '#3B8070', color: '#dbe1ec',
background: 'white' background: 'white'
}, options.loadingIndicator) }, options.loadingIndicator)
@ -243,6 +246,10 @@ Options.defaults = {
appearActiveClass: 'appear-active', appearActiveClass: 'appear-active',
appearToClass: 'appear-to' appearToClass: 'appear-to'
}, },
layoutTransition: {
name: 'layout',
mode: 'out-in'
},
router: { router: {
mode: 'history', mode: 'history',
base: '/', base: '/',
@ -274,5 +281,17 @@ Options.defaults = {
ignored: /-dll/ ignored: /-dll/
}, },
chokidar: {} chokidar: {}
},
editor: {
editor: 'code'
},
messages: {
error_404: 'This page could not be found',
server_error: 'Server error',
nuxtjs: 'Nuxt.js',
back_to_home: 'Back to the home page',
server_error_details: 'An error occurred in the application and your page could not be served. If you are the application owner, check your logs for details.',
client_error: 'Error',
client_error_details: 'An error occurred while rendering the page. Check developer tools console for details.'
} }
} }

View File

@ -50,23 +50,28 @@ export default class MetaRenderer {
// Get vue-meta context // Get vue-meta context
const m = await this.getMeta(url) const m = await this.getMeta(url)
// HTML_ATTRS // HTML_ATTRS
meta.HTML_ATTRS = 'data-n-head-ssr ' + m.htmlAttrs.text() meta.HTML_ATTRS = m.htmlAttrs.text()
// BODY_ATTRS // BODY_ATTRS
meta.BODY_ATTRS = m.bodyAttrs.text() meta.BODY_ATTRS = m.bodyAttrs.text()
// HEAD tags // HEAD tags
meta.HEAD = m.meta.text() + m.title.text() + m.link.text() + m.style.text() + m.script.text() + m.noscript.text() meta.HEAD = m.meta.text() + m.title.text() + m.link.text() + m.style.text() + m.script.text() + m.noscript.text()
// Resources Hints
meta.resourceHints = ''
// Resource Hints // Resource Hints
const clientManifest = this.renderer.resources.clientManifest const clientManifest = this.renderer.resources.clientManifest
if (this.options.render.resourceHints && clientManifest) { if (this.options.render.resourceHints && clientManifest) {
const publicPath = clientManifest.publicPath || '/_nuxt/' const publicPath = clientManifest.publicPath || '/_nuxt/'
// Pre-Load initial resources // Pre-Load initial resources
if (Array.isArray(clientManifest.initial)) { if (Array.isArray(clientManifest.initial)) {
meta.HEAD += clientManifest.initial.map(r => `<link rel="preload" href="${publicPath}${r}" as="script" />`).join('') meta.resourceHints += clientManifest.initial.map(r => `<link rel="preload" href="${publicPath}${r}" as="script" />`).join('')
} }
// Pre-Fetch async resources // Pre-Fetch async resources
if (Array.isArray(clientManifest.async)) { if (Array.isArray(clientManifest.async)) {
meta.HEAD += clientManifest.async.map(r => `<link rel="prefetch" href="${publicPath}${r}" />`).join('') meta.resourceHints += clientManifest.async.map(r => `<link rel="prefetch" href="${publicPath}${r}" />`).join('')
}
// Add them to HEAD
if (meta.resourceHints) {
meta.HEAD += meta.resourceHints
} }
} }

View File

@ -108,6 +108,9 @@ export default class Renderer extends Tapable {
this.resources.loadingHTML = '' this.resources.loadingHTML = ''
} }
// Call resourcesLoaded plugin
await this.applyPluginsAsync('resourcesLoaded', this.resources)
if (updated.length > 0) { if (updated.length > 0) {
// debug('Updated', updated.join(', '), isServer) // debug('Updated', updated.join(', '), isServer)
this.createRenderer() this.createRenderer()
@ -183,7 +186,7 @@ export default class Renderer extends Tapable {
} }
const handler = m.handler || m const handler = m.handler || m
const path = (this.options.router.base + (m.path ? m.path : '')).replace(/\/\//g, '/') const path = (((m.prefix !== false) ? this.options.router.base : '') + (m.path ? m.path : '')).replace(/\/\//g, '/')
// Inject $src and $m to final handler // Inject $src and $m to final handler
if (src) handler.$src = src if (src) handler.$src = src
@ -193,6 +196,10 @@ export default class Renderer extends Tapable {
this.app.use(path, handler) this.app.use(path, handler)
} }
get publicPath () {
return isUrl(this.options.build.publicPath) ? Options.defaults.build.publicPath : this.options.build.publicPath
}
async setupMiddleware () { async setupMiddleware () {
// Apply setupMiddleware from modules first // Apply setupMiddleware from modules first
await this.applyPluginsAsync('setupMiddleware', this.app) await this.applyPluginsAsync('setupMiddleware', this.app)
@ -225,6 +232,32 @@ export default class Renderer extends Tapable {
}) })
} }
// open in editor for debug mode only
const _this = this
if (this.options.debug) {
this.useMiddleware({
path: '_open',
handler (req, res) {
// Lazy load open-in-editor
const openInEditor = require('open-in-editor')
const editor = openInEditor.configure(_this.options.editor)
// Parse Query
const query = req.url.split('?')[1].split('&').reduce((q, part) => {
const s = part.split('=')
q[s[0]] = decodeURIComponent(s[1])
return q
}, {})
// eslint-disable-next-line no-console
console.log('[open in editor]', query.file)
editor.open(query.file).then(() => {
res.end('opened in editor!')
}).catch(err => {
res.end(err)
})
}
})
}
// For serving static/ files to / // For serving static/ files to /
this.useMiddleware(serveStatic(resolve(this.options.srcDir, 'static'), this.options.render.static)) this.useMiddleware(serveStatic(resolve(this.options.srcDir, 'static'), this.options.render.static))
@ -233,10 +266,10 @@ export default class Renderer extends Tapable {
if (!this.options.dev) { if (!this.options.dev) {
const distDir = resolve(this.options.buildDir, 'dist') const distDir = resolve(this.options.buildDir, 'dist')
this.useMiddleware({ this.useMiddleware({
path: isUrl(this.options.build.publicPath) ? Options.defaults.build.publicPath : this.options.build.publicPath, path: this.publicPath,
handler: serveStatic(distDir, { handler: serveStatic(distDir, {
index: false, // Don't serve index.html template index: false, // Don't serve index.html template
maxAge: (this.options.dev ? 0 : '1y') // 1 year in production maxAge: '1y' // 1 year in production
}) })
}) })
} }
@ -319,6 +352,11 @@ export default class Renderer extends Tapable {
err.message = err.message || 'Nuxt Server Error' err.message = err.message || 'Nuxt Server Error'
err.name = (!err.name || err.name === 'Error') ? 'NuxtServerError' : err.name err.name = (!err.name || err.name === 'Error') ? 'NuxtServerError' : err.name
// We hide actual errors from end users, so show them on server logs
if (err.statusCode !== 404) {
console.error(err) // eslint-disable-line no-console
}
const sendResponse = (content, type = 'text/html') => { const sendResponse = (content, type = 'text/html') => {
// Set Headers // Set Headers
res.statusCode = err.statusCode res.statusCode = err.statusCode
@ -398,7 +436,6 @@ export default class Renderer extends Tapable {
const contents = smc.sourceContentFor(source) const contents = smc.sourceContentFor(source)
if (contents) { if (contents) {
frame.contents = contents frame.contents = contents
return
} }
} }
} }
@ -424,12 +461,15 @@ export default class Renderer extends Tapable {
this.options.buildDir this.options.buildDir
] ]
// Scan filesystem // Scan filesystem for real path
for (let pathDir of searchPath) { for (let pathDir of searchPath) {
let fullPath = resolve(pathDir, frame.fileName) let fullPath = resolve(pathDir, frame.fileName)
let source = await fs.readFile(fullPath, 'utf-8').catch(() => null) let source = await fs.readFile(fullPath, 'utf-8').catch(() => null)
if (source) { if (source) {
frame.contents = source if (!frame.contents) {
frame.contents = source
}
frame.fullPath = fullPath
return return
} }
} }
@ -453,9 +493,15 @@ export default class Renderer extends Tapable {
// Basic response if SSR is disabled or spa data provided // Basic response if SSR is disabled or spa data provided
const spa = context.spa || (context.res && context.res.spa) const spa = context.spa || (context.res && context.res.spa)
if (this.noSSR || spa) { if (this.noSSR || spa) {
const { HTML_ATTRS, BODY_ATTRS, HEAD } = await this.metaRenderer.render(context) const { HTML_ATTRS, BODY_ATTRS, HEAD, resourceHints } = await this.metaRenderer.render(context)
const APP = `<div id="__nuxt">${this.resources.loadingHTML}</div>` const APP = `<div id="__nuxt">${this.resources.loadingHTML}</div>`
// Detect 404 errors
if (url.includes(this.options.build.publicPath) || url.includes('__webpack')) {
const err = { statusCode: 404, message: this.options.messages.error_404, name: 'ResourceNotFound' }
throw err
}
const data = { const data = {
HTML_ATTRS, HTML_ATTRS,
BODY_ATTRS, BODY_ATTRS,
@ -465,7 +511,7 @@ export default class Renderer extends Tapable {
const html = this.resources.spaTemplate(data) const html = this.resources.spaTemplate(data)
return { html } return { html, resourceHints }
} }
// Call renderToString from the bundleRenderer and generate the HTML (will update the context as well) // Call renderToString from the bundleRenderer and generate the HTML (will update the context as well)

View File

@ -1,6 +1,6 @@
{ {
"name": "nuxt", "name": "nuxt",
"version": "1.0.0-rc7", "version": "1.0.0-rc11",
"description": "A minimalistic framework for server-rendered Vue.js applications (inspired by Next.js)", "description": "A minimalistic framework for server-rendered Vue.js applications (inspired by Next.js)",
"contributors": [ "contributors": [
{ {
@ -64,20 +64,18 @@
"npm": ">=3.10.0" "npm": ">=3.10.0"
}, },
"dependencies": { "dependencies": {
"@nuxtjs/youch": "3.0.2", "@nuxtjs/youch": "3.1.0",
"ansi-html": "^0.0.7", "ansi-html": "^0.0.7",
"autoprefixer": "^7.1.3", "autoprefixer": "^7.1.3",
"babel-core": "^6.26.0", "babel-core": "^6.26.0",
"babel-loader": "^7.1.2", "babel-loader": "^7.1.2",
"babel-preset-es2015": "^6.24.1", "babel-preset-vue-app": "^1.3.0",
"babel-preset-vue-app": "^1.2.1",
"bulma": "^0.5.1",
"chalk": "^2.1.0", "chalk": "^2.1.0",
"chokidar": "^1.7.0", "chokidar": "^1.7.0",
"clone": "^2.1.1", "clone": "^2.1.1",
"compression": "^1.7.0", "compression": "^1.7.0",
"connect": "^3.6.3", "connect": "^3.6.3",
"css-loader": "https://github.com/nuxt/css-loader.git", "css-loader": "^0.28.7",
"debug": "^3.0.1", "debug": "^3.0.1",
"es6-promise": "^4.1.1", "es6-promise": "^4.1.1",
"etag": "^1.8.0", "etag": "^1.8.0",
@ -94,6 +92,7 @@
"lru-cache": "^4.1.1", "lru-cache": "^4.1.1",
"memory-fs": "^0.4.1", "memory-fs": "^0.4.1",
"minimist": "^1.2.0", "minimist": "^1.2.0",
"open-in-editor": "^2.2.0",
"opencollective": "^1.0.3", "opencollective": "^1.0.3",
"pify": "^3.0.0", "pify": "^3.0.0",
"postcss": "^6.0.10", "postcss": "^6.0.10",
@ -107,7 +106,7 @@
"serve-static": "^1.12.4", "serve-static": "^1.12.4",
"server-destroy": "^1.0.1", "server-destroy": "^1.0.1",
"source-map": "^0.5.7", "source-map": "^0.5.7",
"source-map-support": "^0.4.16", "source-map-support": "^0.4.17",
"tappable": "^1.1.0", "tappable": "^1.1.0",
"url-loader": "^0.5.9", "url-loader": "^0.5.9",
"vue": "~2.4.2", "vue": "~2.4.2",
@ -129,13 +128,12 @@
"babel-plugin-array-includes": "^2.0.3", "babel-plugin-array-includes": "^2.0.3",
"babel-plugin-external-helpers": "^6.22.0", "babel-plugin-external-helpers": "^6.22.0",
"babel-plugin-istanbul": "^4.1.4", "babel-plugin-istanbul": "^4.1.4",
"babel-preset-es2015": "^6.24.1",
"codecov": "^2.3.0", "codecov": "^2.3.0",
"copy-webpack-plugin": "^4.0.1", "copy-webpack-plugin": "^4.0.1",
"cross-env": "^5.0.5", "cross-env": "^5.0.5",
"eslint": "^4.5.0", "eslint": "^4.6.1",
"eslint-config-standard": "^10.2.1", "eslint-config-standard": "^10.2.1",
"eslint-plugin-html": "^3.2.0", "eslint-plugin-html": "^3.2.1",
"eslint-plugin-import": "^2.7.0", "eslint-plugin-import": "^2.7.0",
"eslint-plugin-node": "^5.1.1", "eslint-plugin-node": "^5.1.1",
"eslint-plugin-promise": "^3.5.0", "eslint-plugin-promise": "^3.5.0",

View File

@ -1,6 +1,6 @@
{ {
"name": "nuxt-start", "name": "nuxt-start",
"version": "1.0.0-rc7", "version": "1.0.0-rc11",
"description": "runtime-only build for nuxt", "description": "runtime-only build for nuxt",
"contributors": [ "contributors": [
{ {
@ -46,8 +46,9 @@
"npm": ">=3.10.0" "npm": ">=3.10.0"
}, },
"dependencies": { "dependencies": {
"source-map-support": "^0.4.16", "source-map-support": "^0.4.17",
"pretty-error": "^2.1.1", "pretty-error": "^2.1.1",
"minimist": "^1.2.0",
"lodash": "^4.17.4", "lodash": "^4.17.4",
"hash-sum": "^1.0.2", "hash-sum": "^1.0.2",
"tappable": "^1.1.0", "tappable": "^1.1.0",

View File

@ -119,7 +119,7 @@ test('/error status code', async t => {
await rp(url('/error')) await rp(url('/error'))
} catch (err) { } catch (err) {
t.true(err.statusCode === 500) t.true(err.statusCode === 500)
t.true(err.response.body.includes('Error mouahahah')) t.true(err.response.body.includes('An error occurred in the application and your page could not be served'))
} }
}) })

View File

@ -29,7 +29,7 @@ test('/ should display an error', async t => {
test('/404 should display an error too', async t => { test('/404 should display an error too', async t => {
let { error } = await nuxt.renderRoute('/404') let { error } = await nuxt.renderRoute('/404')
t.true(error.message.includes('This page could not be found.')) t.true(error.message.includes('This page could not be found'))
}) })
test('/ with renderAndGetWindow()', async t => { test('/ with renderAndGetWindow()', async t => {

View File

@ -1,3 +1,10 @@
.global-css-selector { .global-css-selector {
color: red; color: red;
} }
.test-enter-active, .test-leave-active {
transition: opacity .5s
}
.test-enter, .test-leave-active {
opacity: 0
}

Binary file not shown.

View File

@ -4,3 +4,17 @@
<nuxt/> <nuxt/>
</div> </div>
</template> </template>
<style>
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 400;
src: local('Roboto'), local('Roboto-Regular'), url(~/assets/roboto.woff2) format('woff2');
unicode-range: U+0460-052F, U+20B4, U+2DE0-2DFF, U+A640-A69F;
}
body {
font-family: 'Roboto';
}
</style>

View File

@ -15,6 +15,7 @@ module.exports = {
} }
}, },
transition: 'test', transition: 'test',
layoutTransition: 'test',
offline: true, offline: true,
plugins: [ plugins: [
'~/plugins/test.js', '~/plugins/test.js',
@ -24,10 +25,18 @@ module.exports = {
env: { env: {
bool: true, bool: true,
num: 23, num: 23,
string: 'Nuxt.js' string: 'Nuxt.js',
object: {
bool: false,
string: 'ok',
num2: 8.23,
obj: {
again: true
}
}
}, },
build: { build: {
extractCSS: true, // extractCSS: true,
publicPath: '/orion/', publicPath: '/orion/',
analyze: { analyze: {
analyzerMode: 'disabled', analyzerMode: 'disabled',
@ -46,6 +55,11 @@ module.exports = {
http2: { http2: {
push: true push: true
}, },
bundleRenderer: {
shouldPreload: (file, type) => {
return ['script', 'style', 'font'].includes(type)
}
},
static: { static: {
maxAge: '1y' maxAge: '1y'
} }

View File

@ -1,11 +1,20 @@
<template> <template>
<pre>{{ env }}</pre> <div>
<pre>{{ env }}</pre>
<p>object:</p>
<pre>{{ processEnv }}</pre>
<nuxt-link to="/">Home</nuxt-link>
</div>
</template> </template>
<script> <script>
export default { export default {
layout: 'custom-env', layout: 'custom-env',
data() {
return { processEnv: process.env.object }
},
asyncData ({ env }) { asyncData ({ env }) {
delete env.object
return { env } return { env }
} }
} }

View File

@ -26,9 +26,13 @@ test('/', async t => {
}) })
test('/ (global styles inlined)', async t => { test('/ (global styles inlined)', async t => {
// const { html } = await nuxt.renderRoute('/') const { html } = await nuxt.renderRoute('/')
// t.true(html.includes('.global-css-selector')) t.true(html.includes('.global-css-selector'))
t.pass() })
test('/ (preload fonts)', async t => {
const { html } = await nuxt.renderRoute('/')
t.true(html.includes('<link rel="preload" href="/test/orion/fonts/roboto.7cf5d7c.woff2" as="font" type="font/woff2" crossorigin'))
}) })
test('/ (custom app.html)', async t => { test('/ (custom app.html)', async t => {
@ -64,6 +68,10 @@ test('/test/env', async t => {
t.true(html.includes('"bool": true')) t.true(html.includes('"bool": true'))
t.true(html.includes('"num": 23')) t.true(html.includes('"num": 23'))
t.true(html.includes('"string": "Nuxt.js"')) t.true(html.includes('"string": "Nuxt.js"'))
t.true(html.includes('"bool": false'))
t.true(html.includes('"string": "ok"'))
t.true(html.includes('"num2": 8.23'))
t.true(html.includes('"obj": {'))
}) })
test('/test/error', async t => { test('/test/error', async t => {
@ -87,7 +95,7 @@ test('/test/about-bis (added with extendRoutes)', async t => {
test('Check stats.json generated by build.analyze', t => { test('Check stats.json generated by build.analyze', t => {
const stats = require(resolve(__dirname, 'fixtures/with-config/.nuxt/dist/stats.json')) const stats = require(resolve(__dirname, 'fixtures/with-config/.nuxt/dist/stats.json'))
t.is(stats.assets.length, 28) t.is(stats.assets.length, 27)
}) })
test('Check /test/test.txt with custom serve-static options', async t => { test('Check /test/test.txt with custom serve-static options', async t => {

100
yarn.lock
View File

@ -961,9 +961,9 @@ babel-preset-es2015@^6.24.1:
babel-plugin-transform-es2015-unicode-regex "^6.24.1" babel-plugin-transform-es2015-unicode-regex "^6.24.1"
babel-plugin-transform-regenerator "^6.24.1" babel-plugin-transform-regenerator "^6.24.1"
babel-preset-vue-app@^1.2.1: babel-preset-vue-app@^1.3.0:
version "1.2.1" version "1.3.0"
resolved "https://registry.yarnpkg.com/babel-preset-vue-app/-/babel-preset-vue-app-1.2.1.tgz#2f6b71890a21a675019ca1db8d0da15bf017ba24" resolved "https://registry.yarnpkg.com/babel-preset-vue-app/-/babel-preset-vue-app-1.3.0.tgz#4b31f690a353c8735963e06927a072a0bb82126f"
dependencies: dependencies:
babel-plugin-syntax-dynamic-import "^6.18.0" babel-plugin-syntax-dynamic-import "^6.18.0"
babel-plugin-transform-object-rest-spread "^6.26.0" babel-plugin-transform-object-rest-spread "^6.26.0"
@ -1220,10 +1220,6 @@ builtin-status-codes@^3.0.0:
version "3.0.0" version "3.0.0"
resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8" resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8"
bulma@^0.5.1:
version "0.5.1"
resolved "https://registry.yarnpkg.com/bulma/-/bulma-0.5.1.tgz#db2831c94afe732250c7b12527a7b792a4dc9ef8"
bytes@2.5.0: bytes@2.5.0:
version "2.5.0" version "2.5.0"
resolved "https://registry.yarnpkg.com/bytes/-/bytes-2.5.0.tgz#4c9423ea2d252c270c41b2bdefeff9bb6b62c06a" resolved "https://registry.yarnpkg.com/bytes/-/bytes-2.5.0.tgz#4c9423ea2d252c270c41b2bdefeff9bb6b62c06a"
@ -1308,12 +1304,12 @@ caniuse-api@^2.0.0:
lodash.uniq "^4.5.0" lodash.uniq "^4.5.0"
caniuse-db@^1.0.30000529, caniuse-db@^1.0.30000634, caniuse-db@^1.0.30000639: caniuse-db@^1.0.30000529, caniuse-db@^1.0.30000634, caniuse-db@^1.0.30000639:
version "1.0.30000718" version "1.0.30000721"
resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000718.tgz#86cdd97987302554934c61e106f4e470f16f993c" resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000721.tgz#cdc52efe8f82dd13916615b78e86f704ece61802"
caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000718: caniuse-lite@^1.0.0, caniuse-lite@^1.0.30000718:
version "1.0.30000718" version "1.0.30000721"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000718.tgz#0dd24290beb11310b2d80f6b70a823c2a65a6fad" resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000721.tgz#931a21a7bd85016300328d21f126d84b73437d35"
capture-stack-trace@^1.0.0: capture-stack-trace@^1.0.0:
version "1.0.0" version "1.0.0"
@ -1348,7 +1344,7 @@ chalk@^0.4.0:
has-color "~0.1.0" has-color "~0.1.0"
strip-ansi "~0.1.0" strip-ansi "~0.1.0"
chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0: chalk@^2.0.1, chalk@^2.1.0:
version "2.1.0" version "2.1.0"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.1.0.tgz#ac5becf14fa21b99c6c92ca7a7d7cfd5b17e743e" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.1.0.tgz#ac5becf14fa21b99c6c92ca7a7d7cfd5b17e743e"
dependencies: dependencies:
@ -1815,9 +1811,9 @@ css-color-names@0.0.4:
version "0.0.4" version "0.0.4"
resolved "https://registry.yarnpkg.com/css-color-names/-/css-color-names-0.0.4.tgz#808adc2e79cf84738069b646cb20ec27beb629e0" resolved "https://registry.yarnpkg.com/css-color-names/-/css-color-names-0.0.4.tgz#808adc2e79cf84738069b646cb20ec27beb629e0"
"css-loader@https://github.com/nuxt/css-loader.git": css-loader@^0.28.7:
version "0.28.5" version "0.28.7"
resolved "https://github.com/nuxt/css-loader.git#43674428e42dd208f6192cfc0b1679935a0bae4b" resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-0.28.7.tgz#5f2ee989dd32edd907717f953317656160999c1b"
dependencies: dependencies:
babel-code-frame "^6.11.0" babel-code-frame "^6.11.0"
css-selector-tokenizer "^0.7.0" css-selector-tokenizer "^0.7.0"
@ -2354,11 +2350,12 @@ eslint-module-utils@^2.1.1:
debug "^2.6.8" debug "^2.6.8"
pkg-dir "^1.0.0" pkg-dir "^1.0.0"
eslint-plugin-html@^3.2.0: eslint-plugin-html@^3.2.1:
version "3.2.0" version "3.2.1"
resolved "https://registry.yarnpkg.com/eslint-plugin-html/-/eslint-plugin-html-3.2.0.tgz#fb64c2789e9582b97f580a38814a57966f91a7b2" resolved "https://registry.yarnpkg.com/eslint-plugin-html/-/eslint-plugin-html-3.2.1.tgz#4289d38245f3d95134d22c17b1894d78db92c572"
dependencies: dependencies:
htmlparser2 "^3.8.2" htmlparser2 "^3.8.2"
semver "^5.4.1"
eslint-plugin-import@^2.7.0: eslint-plugin-import@^2.7.0:
version "2.7.0" version "2.7.0"
@ -2399,9 +2396,9 @@ eslint-scope@^3.7.1:
esrecurse "^4.1.0" esrecurse "^4.1.0"
estraverse "^4.1.1" estraverse "^4.1.1"
eslint@^4.5.0: eslint@^4.6.1:
version "4.5.0" version "4.6.1"
resolved "https://registry.yarnpkg.com/eslint/-/eslint-4.5.0.tgz#bb75d3b8bde97fb5e13efcd539744677feb019c3" resolved "https://registry.yarnpkg.com/eslint/-/eslint-4.6.1.tgz#ddc7fc7fd70bf93205b0b3449bb16a1e9e7d4950"
dependencies: dependencies:
ajv "^5.2.0" ajv "^5.2.0"
babel-code-frame "^6.22.0" babel-code-frame "^6.22.0"
@ -2591,7 +2588,7 @@ extend@~3.0.0:
version "3.0.1" version "3.0.1"
resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444" resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444"
external-editor@^2.0.1, external-editor@^2.0.4: external-editor@^2.0.1:
version "2.0.4" version "2.0.4"
resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-2.0.4.tgz#1ed9199da9cbfe2ef2f7a31b2fde8b0d12368972" resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-2.0.4.tgz#1ed9199da9cbfe2ef2f7a31b2fde8b0d12368972"
dependencies: dependencies:
@ -3249,7 +3246,7 @@ ini@^1.3.4, ini@~1.3.0:
version "1.3.4" version "1.3.4"
resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.4.tgz#0537cb79daf59b59a1a517dff706c86ec039162e" resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.4.tgz#0537cb79daf59b59a1a517dff706c86ec039162e"
inquirer@3.0.6: inquirer@3.0.6, inquirer@^3.0.6:
version "3.0.6" version "3.0.6"
resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-3.0.6.tgz#e04aaa9d05b7a3cb9b0f407d04375f0447190347" resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-3.0.6.tgz#e04aaa9d05b7a3cb9b0f407d04375f0447190347"
dependencies: dependencies:
@ -3267,25 +3264,6 @@ inquirer@3.0.6:
strip-ansi "^3.0.0" strip-ansi "^3.0.0"
through "^2.3.6" through "^2.3.6"
inquirer@^3.0.6:
version "3.2.2"
resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-3.2.2.tgz#c2aaede1507cc54d826818737742d621bef2e823"
dependencies:
ansi-escapes "^2.0.0"
chalk "^2.0.0"
cli-cursor "^2.1.0"
cli-width "^2.0.0"
external-editor "^2.0.4"
figures "^2.0.0"
lodash "^4.3.0"
mute-stream "0.0.7"
run-async "^2.2.0"
rx-lite "^4.0.8"
rx-lite-aggregates "^4.0.8"
string-width "^2.1.0"
strip-ansi "^4.0.0"
through "^2.3.6"
interpret@^1.0.0: interpret@^1.0.0:
version "1.0.3" version "1.0.3"
resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.0.3.tgz#cbc35c62eeee73f19ab7b10a801511401afc0f90" resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.0.3.tgz#cbc35c62eeee73f19ab7b10a801511401afc0f90"
@ -4090,7 +4068,7 @@ minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1:
dependencies: dependencies:
brace-expansion "^1.1.7" brace-expansion "^1.1.7"
minimist@0.0.8: minimist@0.0.8, minimist@~0.0.1:
version "0.0.8" version "0.0.8"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d"
@ -4098,10 +4076,6 @@ minimist@1.2.0, minimist@^1.1.3, minimist@^1.2.0:
version "1.2.0" version "1.2.0"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284"
minimist@~0.0.1:
version "0.0.10"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf"
"mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0, mkdirp@~0.5.1: "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0, mkdirp@~0.5.1:
version "0.5.1" version "0.5.1"
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903"
@ -4130,8 +4104,8 @@ mute-stream@0.0.7:
resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab"
nan@^2.3.0: nan@^2.3.0:
version "2.6.2" version "2.7.0"
resolved "https://registry.yarnpkg.com/nan/-/nan-2.6.2.tgz#e4ff34e6c95fdfb5aecc08de6596f43605a7db45" resolved "https://registry.yarnpkg.com/nan/-/nan-2.7.0.tgz#d95bf721ec877e08db276ed3fc6eb78f9083ad46"
natural-compare@^1.4.0: natural-compare@^1.4.0:
version "1.4.0" version "1.4.0"
@ -5748,16 +5722,6 @@ run-async@^2.2.0:
dependencies: dependencies:
is-promise "^2.1.0" is-promise "^2.1.0"
rx-lite-aggregates@^4.0.8:
version "4.0.8"
resolved "https://registry.yarnpkg.com/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz#753b87a89a11c95467c4ac1626c4efc4e05c67be"
dependencies:
rx-lite "*"
rx-lite@*, rx-lite@^4.0.8:
version "4.0.8"
resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-4.0.8.tgz#0b1e11af8bc44836f04a6407e92da42467b79444"
rx@^4.1.0: rx@^4.1.0:
version "4.1.0" version "4.1.0"
resolved "https://registry.yarnpkg.com/rx/-/rx-4.1.0.tgz#a5f13ff79ef3b740fe30aa803fb09f98805d4782" resolved "https://registry.yarnpkg.com/rx/-/rx-4.1.0.tgz#a5f13ff79ef3b740fe30aa803fb09f98805d4782"
@ -5786,7 +5750,7 @@ semver-diff@^2.0.0:
dependencies: dependencies:
semver "^5.0.3" semver "^5.0.3"
"semver@2 || 3 || 4 || 5", semver@^5.0.3, semver@^5.1.0, semver@^5.3.0: "semver@2 || 3 || 4 || 5", semver@^5.0.3, semver@^5.1.0, semver@^5.3.0, semver@^5.4.1:
version "5.4.1" version "5.4.1"
resolved "https://registry.yarnpkg.com/semver/-/semver-5.4.1.tgz#e059c09d8571f0540823733433505d3a2f00b18e" resolved "https://registry.yarnpkg.com/semver/-/semver-5.4.1.tgz#e059c09d8571f0540823733433505d3a2f00b18e"
@ -5915,12 +5879,18 @@ source-list-map@^2.0.0:
version "2.0.0" version "2.0.0"
resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.0.tgz#aaa47403f7b245a92fbc97ea08f250d6087ed085" resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.0.tgz#aaa47403f7b245a92fbc97ea08f250d6087ed085"
source-map-support@^0.4.0, source-map-support@^0.4.15, source-map-support@^0.4.16: source-map-support@^0.4.0, source-map-support@^0.4.15:
version "0.4.16" version "0.4.16"
resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.16.tgz#16fecf98212467d017d586a2af68d628b9421cd8" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.16.tgz#16fecf98212467d017d586a2af68d628b9421cd8"
dependencies: dependencies:
source-map "^0.5.6" source-map "^0.5.6"
source-map-support@^0.4.17:
version "0.4.17"
resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.17.tgz#6f2150553e6375375d0ccb3180502b78c18ba430"
dependencies:
source-map "^0.5.6"
source-map@0.5.6: source-map@0.5.6:
version "0.5.6" version "0.5.6"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412"
@ -6045,7 +6015,7 @@ string-width@^1.0.1, string-width@^1.0.2:
is-fullwidth-code-point "^1.0.0" is-fullwidth-code-point "^1.0.0"
strip-ansi "^3.0.0" strip-ansi "^3.0.0"
string-width@^2.0.0, string-width@^2.1.0: string-width@^2.0.0:
version "2.1.1" version "2.1.1"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e"
dependencies: dependencies:
@ -6725,14 +6695,10 @@ window-size@0.1.0:
version "0.1.0" version "0.1.0"
resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d" resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d"
wordwrap@0.0.2: wordwrap@0.0.2, wordwrap@~0.0.2:
version "0.0.2" version "0.0.2"
resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f" resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f"
wordwrap@~0.0.2:
version "0.0.3"
resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107"
wordwrap@~1.0.0: wordwrap@~1.0.0:
version "1.0.0" version "1.0.0"
resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb"