mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-30 09:27:13 +00:00
Merge branch 'nested-dynamic-routes'
This commit is contained in:
commit
004e21b929
13
.editorconfig
Normal file
13
.editorconfig
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
# editorconfig.org
|
||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
indent_size = 2
|
||||||
|
indent_style = space
|
||||||
|
end_of_line = lf
|
||||||
|
charset = utf-8
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
insert_final_newline = true
|
||||||
|
|
||||||
|
[*.md]
|
||||||
|
trim_trailing_whitespace = false
|
@ -4,6 +4,8 @@ node_js:
|
|||||||
- "6.9"
|
- "6.9"
|
||||||
- "5.12"
|
- "5.12"
|
||||||
- "4.7"
|
- "4.7"
|
||||||
|
before_install:
|
||||||
|
- if [[ `npm -v` != 3* ]]; then npm i -g npm@3; fi
|
||||||
install:
|
install:
|
||||||
- npm install
|
- npm install
|
||||||
- npm run build
|
- npm run build
|
||||||
|
@ -5,6 +5,7 @@ process.env.DEBUG = 'nuxt:*'
|
|||||||
|
|
||||||
var _ = require('lodash')
|
var _ = require('lodash')
|
||||||
var debug = require('debug')('nuxt:build')
|
var debug = require('debug')('nuxt:build')
|
||||||
|
debug.color = 2 // force green color
|
||||||
var fs = require('fs')
|
var fs = require('fs')
|
||||||
var Nuxt = require('../')
|
var Nuxt = require('../')
|
||||||
var chokidar = require('chokidar')
|
var chokidar = require('chokidar')
|
||||||
@ -37,7 +38,7 @@ nuxt.build()
|
|||||||
function listenOnConfigChanges (nuxt, server) {
|
function listenOnConfigChanges (nuxt, server) {
|
||||||
// Listen on nuxt.config.js changes
|
// Listen on nuxt.config.js changes
|
||||||
var build = _.debounce(() => {
|
var build = _.debounce(() => {
|
||||||
debug('[nuxt.config.js] changed, rebuilding the app...')
|
debug('[nuxt.config.js] changed')
|
||||||
delete require.cache[nuxtConfigFile]
|
delete require.cache[nuxtConfigFile]
|
||||||
var options = {}
|
var options = {}
|
||||||
if (fs.existsSync(nuxtConfigFile)) {
|
if (fs.existsSync(nuxtConfigFile)) {
|
||||||
@ -50,6 +51,8 @@ function listenOnConfigChanges (nuxt, server) {
|
|||||||
options.rootDir = rootDir
|
options.rootDir = rootDir
|
||||||
nuxt.close()
|
nuxt.close()
|
||||||
.then(() => {
|
.then(() => {
|
||||||
|
nuxt.renderer = null
|
||||||
|
debug('Rebuilding the app...')
|
||||||
return new Nuxt(options).build()
|
return new Nuxt(options).build()
|
||||||
})
|
})
|
||||||
.then((nuxt) => {
|
.then((nuxt) => {
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<p>{{ userAgent }}</p>
|
<p>{{ userAgent }}</p>
|
||||||
<p><router-link to="/post">See a post (http request / Ajax)</router-link></p>
|
<p><nuxt-link to="/post">See a post (http request / Ajax)</nuxt-link></p>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<p>{{ post.title }}!</p>
|
<p>{{ post.title }}!</p>
|
||||||
<p><router-link to="/">Back home</router-link></p>
|
<p><nuxt-link to="/">Back home</nuxt-link></p>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -183,7 +183,7 @@ Let's add a `/secret` route where only the connected user can see its content:
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<h1>Super secret page</h1>
|
<h1>Super secret page</h1>
|
||||||
<router-link to="/">Back to the home page</router-link>
|
<nuxt-link to="/">Back to the home page</nuxt-link>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@
|
|||||||
<p><i>You can also refresh this page, you'll still be connected!</i></p>
|
<p><i>You can also refresh this page, you'll still be connected!</i></p>
|
||||||
<button @click="logout">Logout</button>
|
<button @click="logout">Logout</button>
|
||||||
</div>
|
</div>
|
||||||
<p><router-link to="/secret">Super secret page</router-link></p>
|
<p><nuxt-link to="/secret">Super secret page</nuxt-link></p>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<div>
|
<div>
|
||||||
<h1>Super secret page</h1>
|
<h1>Super secret page</h1>
|
||||||
<p>If you try to access this URL not connected, you will be redirected to the home page (server-side or client-side)</p>
|
<p>If you try to access this URL not connected, you will be redirected to the home page (server-side or client-side)</p>
|
||||||
<router-link to="/">Back to the home page</router-link>
|
<nuxt-link to="/">Back to the home page</nuxt-link>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<p>About Page</p>
|
<p>About Page</p>
|
||||||
<router-link to="/">Go to /</router-link>
|
<nuxt-link to="/">Go to /</nuxt-link>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<p>Hello {{ name }}!</p>
|
<p>Hello {{ name }}!</p>
|
||||||
<router-link to="/about">Go to /about</router-link>
|
<nuxt-link to="/about">Go to /about</nuxt-link>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -2,38 +2,177 @@
|
|||||||
|
|
||||||
> Nuxt.js is based on vue-router and allows you to defined custom routes :rocket:
|
> Nuxt.js is based on vue-router and allows you to defined custom routes :rocket:
|
||||||
|
|
||||||
## Usage
|
## Concept
|
||||||
|
|
||||||
|
Nuxt.js detect and generate automatically the vue-router config according to your file tree of .vue files inside the `pages` directory.
|
||||||
|
|
||||||
|
## Basic routes
|
||||||
|
|
||||||
|
This file tree:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
/pages
|
||||||
|
|-> /team
|
||||||
|
|-> index.vue
|
||||||
|
|-> about.vue
|
||||||
|
|-> index.vue
|
||||||
|
```
|
||||||
|
|
||||||
|
will automatically generate:
|
||||||
|
|
||||||
Add your custom routes inside `nuxt.config.js`:
|
|
||||||
```js
|
```js
|
||||||
module.exports = {
|
|
||||||
router: {
|
router: {
|
||||||
routes: [
|
routes: [
|
||||||
{ name: 'user', path: '/users/:id', component: 'pages/user' }
|
{
|
||||||
]
|
name: 'index',
|
||||||
|
path: '/',
|
||||||
|
component: 'pages/index'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'team',
|
||||||
|
path: '/team',
|
||||||
|
component: 'pages/team/index'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'team-about',
|
||||||
|
path: '/team/about',
|
||||||
|
component: 'pages/team/about'
|
||||||
}
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
| key | Optional? | definition |
|
## Dynamic routes
|
||||||
|------|------------|-----------|
|
|
||||||
| `path` | **Required** | Route path, it can have dynamic mapping, look at [vue-router documentation](https://router.vuejs.org/en/essentials/dynamic-matching.html) about it. |
|
|
||||||
| `component` | **Required** | Path to the `.vue` component, if relative, it has to be from the app folder. |
|
|
||||||
| `name` | Optional | Route name, useful for linking to it with `<router-link>`, see [vue-router documentation](https://router.vuejs.org/en/essentials/named-routes.html) about it. |
|
|
||||||
| `meta` | Optional | Let you add custom fields to get back inside your component (available in the context via `route.meta` inside `data` and `fetch` methods). See [vue-router documentation](https://router.vuejs.org/en/advanced/meta.html) about it. |
|
|
||||||
| `children` | Optional | *Not supported* |
|
|
||||||
|
|
||||||
## Hidden pages
|
To define a dynamic route with a param, you need to define a .vue file prefixed by an underscore.
|
||||||
|
|
||||||
>If you want don't want nuxt.js to generate a route for a specific page, you just have to **rename it with _ at the beginning**.
|
This file tree:
|
||||||
|
|
||||||
Let's say I have a component `pages/user.vue` and I don't want nuxt.js to create the `/user`. I can rename it to `pages/_user.vue` and voilà!
|
```bash
|
||||||
|
/pages
|
||||||
|
|-> /projects
|
||||||
|
|-> index.vue
|
||||||
|
|-> _slug.vue
|
||||||
|
```
|
||||||
|
|
||||||
|
will automatically generate:
|
||||||
|
|
||||||
You can then change the component path in the `nuxt.config.js`:
|
|
||||||
```js
|
```js
|
||||||
// ...
|
router: {
|
||||||
{ name: 'user', path: '/users/:id', component: 'pages/_user' }
|
routes: [
|
||||||
// ...
|
{
|
||||||
|
name: 'projects',
|
||||||
|
path: '/projects',
|
||||||
|
component: 'pages/projects/index'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'projects-slug',
|
||||||
|
path: '/projects/:slug',
|
||||||
|
component: 'pages/projects/_slug'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Additional feature : validate (optional)
|
||||||
|
|
||||||
|
Nuxt.js allows you to define a validator function inside your dynamic route component (In this example: `pages/projects/_slug.vue`).
|
||||||
|
|
||||||
|
If validate function fails, Nuxt.js will automatically load the 404 error page.
|
||||||
|
|
||||||
|
```js
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
validate ({ params }) {
|
||||||
|
return /^[A-z]+$/.test(params.slug)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Nested Routes (children)
|
||||||
|
|
||||||
|
To define a nested route, you need to define a .vue file with the same name as the directory which contain your children views.
|
||||||
|
> Don't forget to put `<nuxt-child></nuxt-child>` inside your parent .vue file.
|
||||||
|
|
||||||
|
This file tree:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
/pages
|
||||||
|
|-> /users
|
||||||
|
|-> _id.vue
|
||||||
|
|-> users.vue
|
||||||
|
```
|
||||||
|
|
||||||
|
will automatically generate:
|
||||||
|
|
||||||
|
```js
|
||||||
|
router: {
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
path: '/users',
|
||||||
|
component: 'pages/users',
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: ':id',
|
||||||
|
component: 'pages/users/_id',
|
||||||
|
name: 'users-id'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Dynamic Nested Routes
|
||||||
|
|
||||||
|
This file tree:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
/pages
|
||||||
|
|-> /posts
|
||||||
|
|-> /_slug
|
||||||
|
|-> _name.vue
|
||||||
|
|-> comments.vue
|
||||||
|
|-> _slug.vue
|
||||||
|
|-> index.vue
|
||||||
|
|-> posts.vue
|
||||||
|
```
|
||||||
|
|
||||||
|
will automatically generate:
|
||||||
|
|
||||||
|
```js
|
||||||
|
router: {
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
path: '/posts',
|
||||||
|
component: 'pages/posts',
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: "",
|
||||||
|
component: 'pages/posts/index',
|
||||||
|
name: 'posts'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: ':slug',
|
||||||
|
component: 'pages/posts/_slug',
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
path: 'comments',
|
||||||
|
component: 'pages/posts/_slug/comments',
|
||||||
|
name: 'posts-slug-comments'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: ':name',
|
||||||
|
component: 'pages/posts/_slug/_name',
|
||||||
|
name: 'posts-slug-name'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## Demo
|
## Demo
|
||||||
|
@ -1,9 +1,4 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
router: {
|
|
||||||
routes: [
|
|
||||||
{ name: 'user', path: '/users/:id(\\d+)', component: 'pages/_user' }
|
|
||||||
]
|
|
||||||
},
|
|
||||||
build: {
|
build: {
|
||||||
vendor: ['axios']
|
vendor: ['axios']
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
<h2>Users</h2>
|
<h2>Users</h2>
|
||||||
<ul class="users">
|
<ul class="users">
|
||||||
<li v-for="user in users">
|
<li v-for="user in users">
|
||||||
<router-link :to="{ name: 'user', params: { id: user.id } }">{{ user.name }}</router-link>
|
<nuxt-link :to="'/users/'+user.id">{{ user.name }}</nuxt-link>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
<h3>{{ name }}</h3>
|
<h3>{{ name }}</h3>
|
||||||
<h4>@{{ username }}</h4>
|
<h4>@{{ username }}</h4>
|
||||||
<p>Email : {{ email }}</p>
|
<p>Email : {{ email }}</p>
|
||||||
<p><router-link to="/">List of users</router-link></p>
|
<p><nuxt-link to="/">List of users</nuxt-link></p>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -11,8 +11,11 @@
|
|||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
validate ({ params }) {
|
||||||
|
return !isNaN(+params.id)
|
||||||
|
},
|
||||||
data ({ params, error }) {
|
data ({ params, error }) {
|
||||||
return axios.get(`https://jsonplaceholder.typicode.com/users/${params.id}`)
|
return axios.get(`https://jsonplaceholder.typicode.com/users/${+params.id}`)
|
||||||
.then((res) => res.data)
|
.then((res) => res.data)
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
error({ message: 'User not found', statusCode: 404 })
|
error({ message: 'User not found', statusCode: 404 })
|
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<p>Hi from {{ name }}</p>
|
<p>Hi from {{ name }}</p>
|
||||||
<router-link to="/">Home page</router-link>
|
<nuxt-link to="/">Home page</nuxt-link>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<h1>Welcome!</h1>
|
<h1>Welcome!</h1>
|
||||||
<router-link to="/about">About page</router-link>
|
<nuxt-link to="/about">About page</nuxt-link>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<h1 class="title">Another Page</h1>
|
<h1 class="title">Another Page</h1>
|
||||||
<p><router-link to="/" class="button is-medium is-info hvr-wobble-vertical">Another button</router-link></p>
|
<p><nuxt-link to="/" class="button is-medium is-info hvr-wobble-vertical">Another button</nuxt-link></p>
|
||||||
<p><router-link to="/">Back home</router-link></p>
|
<p><nuxt-link to="/">Back home</nuxt-link></p>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<h1 class="title">Custom CSS!</h1>
|
<h1 class="title">Custom CSS!</h1>
|
||||||
<p><router-link to="/about" class="button is-medium is-primary hvr-float-shadow">I am a button</router-link></p>
|
<p><nuxt-link to="/about" class="button is-medium is-primary hvr-float-shadow">I am a button</nuxt-link></p>
|
||||||
<p><router-link to="/about">About page</router-link></p>
|
<p><nuxt-link to="/about">About page</nuxt-link></p>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
<h1>About page</h1>
|
<h1>About page</h1>
|
||||||
<p>Click below to see the custom meta tags added with our custom component <code>twitter-head-card</code></p>
|
<p>Click below to see the custom meta tags added with our custom component <code>twitter-head-card</code></p>
|
||||||
<twitter-head-card></twitter-head-card>
|
<twitter-head-card></twitter-head-card>
|
||||||
<p><router-link to="/">Home page</router-link></p>
|
<p><nuxt-link to="/">Home page</nuxt-link></p>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<h1>Home page 🚀</h1>
|
<h1>Home page 🚀</h1>
|
||||||
<router-link to="/about">About page</router-link>
|
<nuxt-link to="/about">About page</nuxt-link>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<h1>Welcome!</h1>
|
<h1>Welcome!</h1>
|
||||||
<router-link to="/about">About page</router-link>
|
<nuxt-link to="/about">About page</nuxt-link>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<img :src="thumbnailUrl" />
|
<img :src="thumbnailUrl" />
|
||||||
<p><router-link to="/">Home</router-link> - About</p>
|
<p><nuxt-link to="/">Home</nuxt-link> - About</p>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<p><button @click="showLoginError">Notif me!</button></p>
|
<p><button @click="showLoginError">Notif me!</button></p>
|
||||||
<p>Home - <router-link to="/about">About</router-link></p>
|
<p>Home - <nuxt-link to="/about">About</nuxt-link></p>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -71,7 +71,7 @@ To define a custom transition for a specific route, simply add the `transition`
|
|||||||
<template>
|
<template>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<h1>About page</h1>
|
<h1>About page</h1>
|
||||||
<router-link to="/">Home page</router-link>
|
<nuxt-link to="/">Home page</nuxt-link>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<h1>About page</h1>
|
<h1>About page</h1>
|
||||||
<router-link to="/">Home page</router-link>
|
<nuxt-link to="/">Home page</nuxt-link>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<h1>Home page</h1>
|
<h1>Home page</h1>
|
||||||
<router-link to="/about">About page</router-link>
|
<nuxt-link to="/about">About page</nuxt-link>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
<img src="~static/nuxt-black.png" />
|
<img src="~static/nuxt-black.png" />
|
||||||
<h2>Thank you for testing nuxt.js</h2>
|
<h2>Thank you for testing nuxt.js</h2>
|
||||||
<p>Loaded from the {{ name }}</p>
|
<p>Loaded from the {{ name }}</p>
|
||||||
<p><router-link to="/">Back home</router-link></p>
|
<p><nuxt-link to="/">Back home</nuxt-link></p>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<div class="container">
|
<div class="container">
|
||||||
<img src="nuxt.png" />
|
<img src="nuxt.png" />
|
||||||
<h2>Hello World.</h2>
|
<h2>Hello World.</h2>
|
||||||
<p><router-link to="/about">About</router-link></p>
|
<p><nuxt-link to="/about">About</nuxt-link></p>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<div>
|
<div>
|
||||||
<p>
|
<p>
|
||||||
<button @click="$store.commit('increment')">{{ $store.state.counter }}</button><br>
|
<button @click="$store.commit('increment')">{{ $store.state.counter }}</button><br>
|
||||||
<router-link to="/">Home</router-link>
|
<nuxt-link to="/">Home</nuxt-link>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
<div>
|
<div>
|
||||||
<p>
|
<p>
|
||||||
<button @click="increment">{{ counter }}</button><br>
|
<button @click="increment">{{ counter }}</button><br>
|
||||||
<router-link to="/about">About</router-link>
|
<nuxt-link to="/about">About</nuxt-link>
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
@ -4,16 +4,26 @@ require('es6-object-assign').polyfill()
|
|||||||
import 'es6-promise/auto'
|
import 'es6-promise/auto'
|
||||||
import Vue from 'vue'
|
import Vue from 'vue'
|
||||||
import { app, router<%= (store ? ', store' : '') %> } from './index'
|
import { app, router<%= (store ? ', store' : '') %> } from './index'
|
||||||
import { getMatchedComponents, getMatchedComponentsInstances, flatMapComponents, getContext, promisify, getLocation } from './utils'
|
import { getMatchedComponents, getMatchedComponentsInstances, flatMapComponents, getContext, promisify, getLocation, compile } from './utils'
|
||||||
const noopData = () => { return {} }
|
const noopData = () => { return {} }
|
||||||
const noopFetch = () => {}
|
const noopFetch = () => {}
|
||||||
|
let _lastPaths = []
|
||||||
|
|
||||||
|
function mapTransitions(Components, to, from) {
|
||||||
|
return Components.map((Component) => {
|
||||||
|
let transition = Component.options.transition
|
||||||
|
if (typeof transition === 'function') {
|
||||||
|
return transition(to, from)
|
||||||
|
}
|
||||||
|
return transition
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
function loadAsyncComponents (to, ___, next) {
|
function loadAsyncComponents (to, ___, next) {
|
||||||
const resolveComponents = flatMapComponents(to, (Component, _, match, key) => {
|
const resolveComponents = flatMapComponents(to, (Component, _, match, key) => {
|
||||||
if (typeof Component === 'function' && !Component.options) {
|
if (typeof Component === 'function' && !Component.options) {
|
||||||
return new Promise(function (resolve, reject) {
|
return new Promise(function (resolve, reject) {
|
||||||
const _resolve = (Component) => {
|
const _resolve = (Component) => {
|
||||||
// console.log('Component loaded', Component, match.path, key)
|
|
||||||
if (!Component.options) {
|
if (!Component.options) {
|
||||||
Component = Vue.extend(Component) // fix issue #6
|
Component = Vue.extend(Component) // fix issue #6
|
||||||
Component._Ctor = Component
|
Component._Ctor = Component
|
||||||
@ -44,13 +54,12 @@ function loadAsyncComponents (to, ___, next) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function render (to, ___, next) {
|
function render (to, from, next) {
|
||||||
let Components = getMatchedComponents(to)
|
let Components = getMatchedComponents(to)
|
||||||
if (!Components.length) {
|
if (!Components.length) {
|
||||||
this.error({ statusCode: 404, message: 'This page could not be found.', url: to.path })
|
this.error({ statusCode: 404, message: 'This page could not be found.', url: to.path })
|
||||||
return next()
|
return next()
|
||||||
}
|
}
|
||||||
// console.log('Load components', Components, to.path)
|
|
||||||
// Update ._data and other properties if hot reloaded
|
// Update ._data and other properties if hot reloaded
|
||||||
Components.forEach(function (Component) {
|
Components.forEach(function (Component) {
|
||||||
if (!Component._data) {
|
if (!Component._data) {
|
||||||
@ -67,10 +76,26 @@ function render (to, ___, next) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
this.setTransition(Components[0].options.transition)
|
this.setTransitions(mapTransitions(Components, to, from))
|
||||||
this.error()
|
this.error()
|
||||||
let nextCalled = false
|
let nextCalled = false
|
||||||
Promise.all(Components.map((Component) => {
|
let isValid = Components.some((Component) => {
|
||||||
|
if (typeof Component.options.validate !== 'function') return true
|
||||||
|
return Component.options.validate({
|
||||||
|
params: to.params || {},
|
||||||
|
query: to.query || {}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
if (!isValid) {
|
||||||
|
this.error({ statusCode: 404, message: 'This page could not be found.', url: to.path })
|
||||||
|
return next()
|
||||||
|
}
|
||||||
|
Promise.all(Components.map((Component, i) => {
|
||||||
|
// Check if only children route changed
|
||||||
|
Component._path = compile(to.matched[i].path)(to.params)
|
||||||
|
if (Component._path === _lastPaths[i] && (i + 1) !== Components.length) {
|
||||||
|
return Promise.resolve()
|
||||||
|
}
|
||||||
let promises = []
|
let promises = []
|
||||||
const _next = function (path) {
|
const _next = function (path) {
|
||||||
<%= (loading ? 'this.$loading.finish && this.$loading.finish()' : '') %>
|
<%= (loading ? 'this.$loading.finish && this.$loading.finish()' : '') %>
|
||||||
@ -78,6 +103,7 @@ function render (to, ___, next) {
|
|||||||
next(path)
|
next(path)
|
||||||
}
|
}
|
||||||
const context = getContext({ to<%= (store ? ', store' : '') %>, isClient: true, next: _next.bind(this), error: this.error.bind(this) })
|
const context = getContext({ to<%= (store ? ', store' : '') %>, isClient: true, next: _next.bind(this), error: this.error.bind(this) })
|
||||||
|
// Validate method
|
||||||
if (Component._data && typeof Component._data === 'function') {
|
if (Component._data && typeof Component._data === 'function') {
|
||||||
var promise = promisify(Component._data, context)
|
var promise = promisify(Component._data, context)
|
||||||
promise.then((data) => {
|
promise.then((data) => {
|
||||||
@ -99,6 +125,7 @@ function render (to, ___, next) {
|
|||||||
return Promise.all(promises)
|
return Promise.all(promises)
|
||||||
}))
|
}))
|
||||||
.then(() => {
|
.then(() => {
|
||||||
|
_lastPaths = Components.map((Component, i) => compile(to.matched[i].path)(to.params))
|
||||||
<%= (loading ? 'this.$loading.finish && this.$loading.finish()' : '') %>
|
<%= (loading ? 'this.$loading.finish && this.$loading.finish()' : '') %>
|
||||||
// If not redirected
|
// If not redirected
|
||||||
if (!nextCalled) {
|
if (!nextCalled) {
|
||||||
@ -106,6 +133,7 @@ function render (to, ___, next) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
|
_lastPaths = []
|
||||||
this.error(error)
|
this.error(error)
|
||||||
next(false)
|
next(false)
|
||||||
})
|
})
|
||||||
@ -118,12 +146,14 @@ function fixPrepatch (to, ___) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
Vue.nextTick(() => {
|
Vue.nextTick(() => {
|
||||||
let RouterViewComponentFile = this.$nuxt._routerViewCache.default.__file
|
|
||||||
if (typeof this.$nuxt._routerViewCache.default === 'function') RouterViewComponentFile = this.$nuxt._routerViewCache.default.options.__file
|
|
||||||
let instances = getMatchedComponentsInstances(to)
|
let instances = getMatchedComponentsInstances(to)
|
||||||
instances.forEach((instance, i) => {
|
instances.forEach((instance) => {
|
||||||
if (!instance) return;
|
if (!instance) return;
|
||||||
if (instance.constructor.options.__file === RouterViewComponentFile) {
|
let file = instance.$parent._routerViewCache.default.__file
|
||||||
|
if (typeof instance.$parent._routerViewCache.default === 'function') {
|
||||||
|
file = instance.$parent._routerViewCache.default.options.__file
|
||||||
|
}
|
||||||
|
if (instance.constructor.options.__file === file) {
|
||||||
let newData = instance.constructor.options.data()
|
let newData = instance.constructor.options.data()
|
||||||
for (let key in newData) {
|
for (let key in newData) {
|
||||||
Vue.set(instance.$data, key, newData[key])
|
Vue.set(instance.$data, key, newData[key])
|
||||||
@ -254,8 +284,11 @@ Promise.all(resolveComponents)
|
|||||||
store.replaceState(NUXT.state)
|
store.replaceState(NUXT.state)
|
||||||
}
|
}
|
||||||
<% } %>
|
<% } %>
|
||||||
_app.setTransition = _app.$options._nuxt.setTransition.bind(_app)
|
_app.setTransitions = _app.$options._nuxt.setTransitions.bind(_app)
|
||||||
if (Components.length) _app.setTransition(Components[0].options.transition)
|
if (Components.length) {
|
||||||
|
_app.setTransitions(mapTransitions(Components, router.currentRoute))
|
||||||
|
_lastPaths = router.currentRoute.matched.map((route) => compile(route.path)(router.currentRoute.params))
|
||||||
|
}
|
||||||
_app.error = _app.$options._nuxt.error.bind(_app)
|
_app.error = _app.$options._nuxt.error.bind(_app)
|
||||||
_app.$loading = {} // to avoid error while _app.$nuxt does not exist
|
_app.$loading = {} // to avoid error while _app.$nuxt does not exist
|
||||||
if (NUXT.error) _app.error(NUXT.error)
|
if (NUXT.error) _app.error(NUXT.error)
|
||||||
|
60
lib/app/components/nuxt-child.js
Normal file
60
lib/app/components/nuxt-child.js
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
import Vue from 'vue'
|
||||||
|
|
||||||
|
const transitionsKeys = [
|
||||||
|
'name',
|
||||||
|
'mode',
|
||||||
|
'css',
|
||||||
|
'type',
|
||||||
|
'enterClass',
|
||||||
|
'leaveClass',
|
||||||
|
'enterActiveClass',
|
||||||
|
'leaveActiveClass'
|
||||||
|
]
|
||||||
|
const listenersKeys = [
|
||||||
|
'beforeEnter',
|
||||||
|
'enter',
|
||||||
|
'afterEnter',
|
||||||
|
'enterCancelled',
|
||||||
|
'beforeLeave',
|
||||||
|
'leave',
|
||||||
|
'afterLeave',
|
||||||
|
'leaveCancelled'
|
||||||
|
]
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'nuxt-child',
|
||||||
|
functional: true,
|
||||||
|
render (h, { parent, data }) {
|
||||||
|
data.nuxtChild = true
|
||||||
|
|
||||||
|
const transitions = parent.$nuxt.nuxt.transitions
|
||||||
|
const defaultTransition = parent.$nuxt.nuxt.defaultTransition
|
||||||
|
let depth = 0
|
||||||
|
while (parent) {
|
||||||
|
if (parent.$vnode && parent.$vnode.data.nuxtChild) {
|
||||||
|
depth++
|
||||||
|
}
|
||||||
|
parent = parent.$parent
|
||||||
|
}
|
||||||
|
data.nuxtChildDepth = depth
|
||||||
|
const transition = transitions[depth] || defaultTransition
|
||||||
|
let transitionProps = {}
|
||||||
|
transitionsKeys.forEach((key) => {
|
||||||
|
if (typeof transition[key] !== 'undefined') {
|
||||||
|
transitionProps[key] = transition[key]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
let listeners = {}
|
||||||
|
listenersKeys.forEach((key) => {
|
||||||
|
if (typeof transition[key] === 'function') {
|
||||||
|
listeners[key] = transition[key]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return h('transition', {
|
||||||
|
props: transitionProps,
|
||||||
|
on: listeners
|
||||||
|
}, [
|
||||||
|
h('router-view', data)
|
||||||
|
])
|
||||||
|
}
|
||||||
|
}
|
@ -5,7 +5,7 @@
|
|||||||
<div class="error-wrapper-message">
|
<div class="error-wrapper-message">
|
||||||
<h2 class="error-message">{{ error.message }}</h2>
|
<h2 class="error-message">{{ error.message }}</h2>
|
||||||
</div>
|
</div>
|
||||||
<p v-if="error.statusCode === 404"><router-link class="error-link" to="/">Back to the home page</router-link></p>
|
<p v-if="error.statusCode === 404"><nuxt-link class="error-link" to="/">Back to the home page</nuxt-link></p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
9
lib/app/components/nuxt-link.js
Normal file
9
lib/app/components/nuxt-link.js
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import Vue from 'vue'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'nuxt-link',
|
||||||
|
functional: true,
|
||||||
|
render (h, { data, children }) {
|
||||||
|
return h('router-link', data, children)
|
||||||
|
}
|
||||||
|
}
|
@ -1,15 +1,14 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<% if (loading) { %><nuxt-loading ref="loading"></nuxt-loading><% } %>
|
<% if (loading) { %><nuxt-loading ref="loading"></nuxt-loading><% } %>
|
||||||
<transition :name="nuxt.transition.name" :mode="nuxt.transition.mode">
|
<nuxt-child v-if="!nuxt.err"></nuxt-child>
|
||||||
<router-view v-if="!nuxt.err"></router-view>
|
|
||||||
<nuxt-error v-if="nuxt.err" :error="nuxt.err"></nuxt-error>
|
<nuxt-error v-if="nuxt.err" :error="nuxt.err"></nuxt-error>
|
||||||
</transition>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import Vue from 'vue'
|
import Vue from 'vue'
|
||||||
|
import NuxtChild from './nuxt-child'
|
||||||
import NuxtError from '<%= components.ErrorPage %>'
|
import NuxtError from '<%= components.ErrorPage %>'
|
||||||
<% if (loading) { %>import NuxtLoading from '<%= (typeof loading === "string" ? loading : "./nuxt-loading.vue") %>'<% } %>
|
<% if (loading) { %>import NuxtLoading from '<%= (typeof loading === "string" ? loading : "./nuxt-loading.vue") %>'<% } %>
|
||||||
|
|
||||||
@ -47,6 +46,7 @@ export default {
|
|||||||
},
|
},
|
||||||
<% } %>
|
<% } %>
|
||||||
components: {
|
components: {
|
||||||
|
NuxtChild,
|
||||||
NuxtError<%= (loading ? ',\n NuxtLoading' : '') %>
|
NuxtError<%= (loading ? ',\n NuxtLoading' : '') %>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,11 +5,17 @@ import Meta from 'vue-meta'
|
|||||||
import router from './router.js'
|
import router from './router.js'
|
||||||
<% if (store) { %>import store from '~store/index.js'<% } %>
|
<% if (store) { %>import store from '~store/index.js'<% } %>
|
||||||
import NuxtContainer from './components/nuxt-container.vue'
|
import NuxtContainer from './components/nuxt-container.vue'
|
||||||
|
import NuxtChild from './components/nuxt-child.js'
|
||||||
|
import NuxtLink from './components/nuxt-link.js'
|
||||||
import Nuxt from './components/nuxt.vue'
|
import Nuxt from './components/nuxt.vue'
|
||||||
import App from '<%= appPath %>'
|
import App from '<%= appPath %>'
|
||||||
|
|
||||||
// Component: <nuxt-container>
|
// Component: <nuxt-container>
|
||||||
Vue.component(NuxtContainer.name, NuxtContainer)
|
Vue.component(NuxtContainer.name, NuxtContainer)
|
||||||
|
// Component: <nuxt-child>
|
||||||
|
Vue.component(NuxtChild.name, NuxtChild)
|
||||||
|
// Component: <nuxt-link>
|
||||||
|
Vue.component(NuxtLink.name, NuxtLink)
|
||||||
// Component: <nuxt>
|
// Component: <nuxt>
|
||||||
Vue.component(Nuxt.name, Nuxt)
|
Vue.component(Nuxt.name, Nuxt)
|
||||||
|
|
||||||
@ -43,16 +49,24 @@ const app = {
|
|||||||
router,
|
router,
|
||||||
<%= (store ? 'store,' : '') %>
|
<%= (store ? 'store,' : '') %>
|
||||||
_nuxt: {
|
_nuxt: {
|
||||||
transition: Object.assign({}, defaultTransition),
|
defaultTransition: defaultTransition,
|
||||||
setTransition (transition) {
|
transitions: [ defaultTransition ],
|
||||||
|
setTransitions (transitions) {
|
||||||
|
if (!Array.isArray(transitions)) {
|
||||||
|
transitions = [ transitions ]
|
||||||
|
}
|
||||||
|
transitions = transitions.map((transition) => {
|
||||||
if (!transition) {
|
if (!transition) {
|
||||||
transition = defaultTransition
|
transition = defaultTransition
|
||||||
} else if (typeof transition === 'string') {
|
} else if (typeof transition === 'string') {
|
||||||
transition = Object.assign({}, defaultTransition, { name: transition })
|
transition = Object.assign({}, defaultTransition, { name: transition })
|
||||||
|
} else {
|
||||||
|
transition = Object.assign({}, defaultTransition, transition)
|
||||||
}
|
}
|
||||||
this.$options._nuxt.transition.name = transition.name
|
|
||||||
this.$options._nuxt.transition.mode = transition.mode
|
|
||||||
return transition
|
return transition
|
||||||
|
})
|
||||||
|
this.$options._nuxt.transitions = transitions
|
||||||
|
return transitions
|
||||||
},
|
},
|
||||||
err: null,
|
err: null,
|
||||||
error (err) {
|
error (err) {
|
||||||
|
@ -5,8 +5,24 @@ import Router from 'vue-router'
|
|||||||
|
|
||||||
Vue.use(Router)
|
Vue.use(Router)
|
||||||
|
|
||||||
<% uniqBy(router.routes, '_name').forEach((route) => { %>
|
<%
|
||||||
const <%= route._name %> = process.BROWSER_BUILD ? () => System.import('<%= route._component %>') : require('<%= route._component %>')
|
function recursiveRoutes(routes, tab, components) {
|
||||||
|
var res = ''
|
||||||
|
routes.forEach((route, i) => {
|
||||||
|
components.push({ _name: route._name, component: route.component })
|
||||||
|
res += tab + '{\n'
|
||||||
|
res += tab + '\tpath: ' + JSON.stringify(route.path) + ',\n'
|
||||||
|
res += tab + '\tcomponent: ' + route._name
|
||||||
|
res += (route.name) ? ',\n\t' + tab + 'name: ' + JSON.stringify(route.name) : ''
|
||||||
|
res += (route.children) ? ',\n\t' + tab + 'children: [\n' + recursiveRoutes(routes[i].children, tab + '\t\t', components) + '\n\t' + tab + ']' : ''
|
||||||
|
res += '\n' + tab + '}' + (i + 1 === routes.length ? '' : ',\n')
|
||||||
|
})
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
var _components = []
|
||||||
|
var _routes = recursiveRoutes(router.routes, '\t\t', _components)
|
||||||
|
uniqBy(_components, '_name').forEach((route) => { %>
|
||||||
|
const <%= route._name %> = process.BROWSER_BUILD ? () => System.import('<%= route.component %>') : require('<%= route.component %>')
|
||||||
<% }) %>
|
<% }) %>
|
||||||
|
|
||||||
const scrollBehavior = (to, from, savedPosition) => {
|
const scrollBehavior = (to, from, savedPosition) => {
|
||||||
@ -14,8 +30,11 @@ const scrollBehavior = (to, from, savedPosition) => {
|
|||||||
// savedPosition is only available for popstate navigations.
|
// savedPosition is only available for popstate navigations.
|
||||||
return savedPosition
|
return savedPosition
|
||||||
} else {
|
} else {
|
||||||
// Scroll to the top by default
|
let position = {}
|
||||||
let position = { x: 0, y: 0 }
|
// if no children detected
|
||||||
|
if (to.matched.length < 2) {
|
||||||
|
position = { x: 0, y: 0 }
|
||||||
|
}
|
||||||
// if link has anchor, scroll to anchor by returning the selector
|
// if link has anchor, scroll to anchor by returning the selector
|
||||||
if (to.hash) {
|
if (to.hash) {
|
||||||
position = { selector: to.hash }
|
position = { selector: to.hash }
|
||||||
@ -30,13 +49,6 @@ export default new Router({
|
|||||||
linkActiveClass: '<%= router.linkActiveClass %>',
|
linkActiveClass: '<%= router.linkActiveClass %>',
|
||||||
scrollBehavior,
|
scrollBehavior,
|
||||||
routes: [
|
routes: [
|
||||||
<% router.routes.forEach((route, i) => { %>
|
<%= _routes %>
|
||||||
{
|
|
||||||
path: '<%= route.path %>',
|
|
||||||
component: <%= route._name %><% if (route.name) { %>,
|
|
||||||
name: '<%= route.name %>'<% } %><% if (route.meta) { %>,
|
|
||||||
meta: <%= JSON.stringify(route.meta) %><% } %>
|
|
||||||
}<%= (i + 1 === router.routes.length ? '' : ',') %>
|
|
||||||
<% }) %>
|
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
'use strict'
|
'use strict'
|
||||||
|
|
||||||
const debug = require('debug')('nuxt:render')
|
const debug = require('debug')('nuxt:render')
|
||||||
|
debug.color = 4 // force blue color
|
||||||
import Vue from 'vue'
|
import Vue from 'vue'
|
||||||
import { stringify } from 'querystring'
|
import { stringify } from 'querystring'
|
||||||
import { omit } from 'lodash'
|
import { omit } from 'lodash'
|
||||||
@ -60,8 +61,8 @@ export default context => {
|
|||||||
<% } %>
|
<% } %>
|
||||||
return promise
|
return promise
|
||||||
.then(() => {
|
.then(() => {
|
||||||
// Call data & fetch hooks on components matched by the route.
|
// Sanitize Components
|
||||||
return Promise.all(Components.map((Component) => {
|
Components = Components.map((Component) => {
|
||||||
let promises = []
|
let promises = []
|
||||||
if (!Component.options) {
|
if (!Component.options) {
|
||||||
Component = Vue.extend(Component)
|
Component = Vue.extend(Component)
|
||||||
@ -70,6 +71,24 @@ export default context => {
|
|||||||
Component._Ctor = Component
|
Component._Ctor = Component
|
||||||
Component.extendOptions = Component.options
|
Component.extendOptions = Component.options
|
||||||
}
|
}
|
||||||
|
return Component
|
||||||
|
})
|
||||||
|
// Call .validate()
|
||||||
|
let isValid = Components.some((Component) => {
|
||||||
|
if (typeof Component.options.validate !== 'function') return true
|
||||||
|
return Component.options.validate({
|
||||||
|
params: context.route.params || {},
|
||||||
|
query: context.route.query || {}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
if (!isValid) {
|
||||||
|
// Call the 404 error by making the Components array empty
|
||||||
|
Components = []
|
||||||
|
return _app
|
||||||
|
}
|
||||||
|
// Call data & fetch hooks on components matched by the route.
|
||||||
|
return Promise.all(Components.map((Component) => {
|
||||||
|
let promises = []
|
||||||
const ctx = getContext(context)
|
const ctx = getContext(context)
|
||||||
if (Component.options.data && typeof Component.options.data === 'function') {
|
if (Component.options.data && typeof Component.options.data === 'function') {
|
||||||
Component._data = Component.options.data
|
Component._data = Component.options.data
|
||||||
|
232
lib/app/utils.js
232
lib/app/utils.js
@ -91,3 +91,235 @@ export function getLocation (base) {
|
|||||||
export function urlJoin () {
|
export function urlJoin () {
|
||||||
return [].slice.call(arguments).join('/').replace(/\/+/g, '/')
|
return [].slice.call(arguments).join('/').replace(/\/+/g, '/')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Imported from path-to-regexp
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compile a string to a template function for the path.
|
||||||
|
*
|
||||||
|
* @param {string} str
|
||||||
|
* @param {Object=} options
|
||||||
|
* @return {!function(Object=, Object=)}
|
||||||
|
*/
|
||||||
|
export function compile (str, options) {
|
||||||
|
return tokensToFunction(parse(str, options))
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The main path matching regexp utility.
|
||||||
|
*
|
||||||
|
* @type {RegExp}
|
||||||
|
*/
|
||||||
|
const PATH_REGEXP = new RegExp([
|
||||||
|
// Match escaped characters that would otherwise appear in future matches.
|
||||||
|
// This allows the user to escape special characters that won't transform.
|
||||||
|
'(\\\\.)',
|
||||||
|
// Match Express-style parameters and un-named parameters with a prefix
|
||||||
|
// and optional suffixes. Matches appear as:
|
||||||
|
//
|
||||||
|
// "/:test(\\d+)?" => ["/", "test", "\d+", undefined, "?", undefined]
|
||||||
|
// "/route(\\d+)" => [undefined, undefined, undefined, "\d+", undefined, undefined]
|
||||||
|
// "/*" => ["/", undefined, undefined, undefined, undefined, "*"]
|
||||||
|
'([\\/.])?(?:(?:\\:(\\w+)(?:\\(((?:\\\\.|[^\\\\()])+)\\))?|\\(((?:\\\\.|[^\\\\()])+)\\))([+*?])?|(\\*))'
|
||||||
|
].join('|'), 'g')
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse a string for the raw tokens.
|
||||||
|
*
|
||||||
|
* @param {string} str
|
||||||
|
* @param {Object=} options
|
||||||
|
* @return {!Array}
|
||||||
|
*/
|
||||||
|
function parse (str, options) {
|
||||||
|
var tokens = []
|
||||||
|
var key = 0
|
||||||
|
var index = 0
|
||||||
|
var path = ''
|
||||||
|
var defaultDelimiter = options && options.delimiter || '/'
|
||||||
|
var res
|
||||||
|
|
||||||
|
while ((res = PATH_REGEXP.exec(str)) != null) {
|
||||||
|
var m = res[0]
|
||||||
|
var escaped = res[1]
|
||||||
|
var offset = res.index
|
||||||
|
path += str.slice(index, offset)
|
||||||
|
index = offset + m.length
|
||||||
|
|
||||||
|
// Ignore already escaped sequences.
|
||||||
|
if (escaped) {
|
||||||
|
path += escaped[1]
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
var next = str[index]
|
||||||
|
var prefix = res[2]
|
||||||
|
var name = res[3]
|
||||||
|
var capture = res[4]
|
||||||
|
var group = res[5]
|
||||||
|
var modifier = res[6]
|
||||||
|
var asterisk = res[7]
|
||||||
|
|
||||||
|
// Push the current path onto the tokens.
|
||||||
|
if (path) {
|
||||||
|
tokens.push(path)
|
||||||
|
path = ''
|
||||||
|
}
|
||||||
|
|
||||||
|
var partial = prefix != null && next != null && next !== prefix
|
||||||
|
var repeat = modifier === '+' || modifier === '*'
|
||||||
|
var optional = modifier === '?' || modifier === '*'
|
||||||
|
var delimiter = res[2] || defaultDelimiter
|
||||||
|
var pattern = capture || group
|
||||||
|
|
||||||
|
tokens.push({
|
||||||
|
name: name || key++,
|
||||||
|
prefix: prefix || '',
|
||||||
|
delimiter: delimiter,
|
||||||
|
optional: optional,
|
||||||
|
repeat: repeat,
|
||||||
|
partial: partial,
|
||||||
|
asterisk: !!asterisk,
|
||||||
|
pattern: pattern ? escapeGroup(pattern) : (asterisk ? '.*' : '[^' + escapeString(delimiter) + ']+?')
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Match any characters still remaining.
|
||||||
|
if (index < str.length) {
|
||||||
|
path += str.substr(index)
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the path exists, push it onto the end.
|
||||||
|
if (path) {
|
||||||
|
tokens.push(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
return tokens
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prettier encoding of URI path segments.
|
||||||
|
*
|
||||||
|
* @param {string}
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
function encodeURIComponentPretty (str) {
|
||||||
|
return encodeURI(str).replace(/[\/?#]/g, function (c) {
|
||||||
|
return '%' + c.charCodeAt(0).toString(16).toUpperCase()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encode the asterisk parameter. Similar to `pretty`, but allows slashes.
|
||||||
|
*
|
||||||
|
* @param {string}
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
function encodeAsterisk (str) {
|
||||||
|
return encodeURI(str).replace(/[?#]/g, function (c) {
|
||||||
|
return '%' + c.charCodeAt(0).toString(16).toUpperCase()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Expose a method for transforming tokens into the path function.
|
||||||
|
*/
|
||||||
|
function tokensToFunction (tokens) {
|
||||||
|
// Compile all the tokens into regexps.
|
||||||
|
var matches = new Array(tokens.length)
|
||||||
|
|
||||||
|
// Compile all the patterns before compilation.
|
||||||
|
for (var i = 0; i < tokens.length; i++) {
|
||||||
|
if (typeof tokens[i] === 'object') {
|
||||||
|
matches[i] = new RegExp('^(?:' + tokens[i].pattern + ')$')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return function (obj, opts) {
|
||||||
|
var path = ''
|
||||||
|
var data = obj || {}
|
||||||
|
var options = opts || {}
|
||||||
|
var encode = options.pretty ? encodeURIComponentPretty : encodeURIComponent
|
||||||
|
|
||||||
|
for (var i = 0; i < tokens.length; i++) {
|
||||||
|
var token = tokens[i]
|
||||||
|
|
||||||
|
if (typeof token === 'string') {
|
||||||
|
path += token
|
||||||
|
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
var value = data[token.name]
|
||||||
|
var segment
|
||||||
|
|
||||||
|
if (value == null) {
|
||||||
|
if (token.optional) {
|
||||||
|
// Prepend partial segment prefixes.
|
||||||
|
if (token.partial) {
|
||||||
|
path += token.prefix
|
||||||
|
}
|
||||||
|
|
||||||
|
continue
|
||||||
|
} else {
|
||||||
|
throw new TypeError('Expected "' + token.name + '" to be defined')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Array.isArray(value)) {
|
||||||
|
if (!token.repeat) {
|
||||||
|
throw new TypeError('Expected "' + token.name + '" to not repeat, but received `' + JSON.stringify(value) + '`')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value.length === 0) {
|
||||||
|
if (token.optional) {
|
||||||
|
continue
|
||||||
|
} else {
|
||||||
|
throw new TypeError('Expected "' + token.name + '" to not be empty')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (var j = 0; j < value.length; j++) {
|
||||||
|
segment = encode(value[j])
|
||||||
|
|
||||||
|
if (!matches[i].test(segment)) {
|
||||||
|
throw new TypeError('Expected all "' + token.name + '" to match "' + token.pattern + '", but received `' + JSON.stringify(segment) + '`')
|
||||||
|
}
|
||||||
|
|
||||||
|
path += (j === 0 ? token.prefix : token.delimiter) + segment
|
||||||
|
}
|
||||||
|
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
segment = token.asterisk ? encodeAsterisk(value) : encode(value)
|
||||||
|
|
||||||
|
if (!matches[i].test(segment)) {
|
||||||
|
throw new TypeError('Expected "' + token.name + '" to match "' + token.pattern + '", but received "' + segment + '"')
|
||||||
|
}
|
||||||
|
|
||||||
|
path += token.prefix + segment
|
||||||
|
}
|
||||||
|
|
||||||
|
return path
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Escape a regular expression string.
|
||||||
|
*
|
||||||
|
* @param {string} str
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
function escapeString (str) {
|
||||||
|
return str.replace(/([.+*?=^!:${}()[\]|\/\\])/g, '\\$1')
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Escape the capturing group by escaping special characters and meaning.
|
||||||
|
*
|
||||||
|
* @param {string} group
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
function escapeGroup (group) {
|
||||||
|
return group.replace(/([=!:$\/()])/g, '\\$1')
|
||||||
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
'use strict'
|
'use strict'
|
||||||
|
|
||||||
const debug = require('debug')('nuxt:build')
|
const debug = require('debug')('nuxt:build')
|
||||||
|
debug.color = 2 // force green color
|
||||||
const _ = require('lodash')
|
const _ = require('lodash')
|
||||||
const co = require('co')
|
const co = require('co')
|
||||||
const chokidar = require('chokidar')
|
const chokidar = require('chokidar')
|
||||||
@ -9,10 +10,9 @@ const hash = require('hash-sum')
|
|||||||
const pify = require('pify')
|
const pify = require('pify')
|
||||||
const webpack = require('webpack')
|
const webpack = require('webpack')
|
||||||
const { createBundleRenderer } = require('vue-server-renderer')
|
const { createBundleRenderer } = require('vue-server-renderer')
|
||||||
const { join, resolve, sep, posix } = require('path')
|
const { join, resolve, sep } = require('path')
|
||||||
const clientWebpackConfig = require('./webpack/client.config.js')
|
const clientWebpackConfig = require('./webpack/client.config.js')
|
||||||
const serverWebpackConfig = require('./webpack/server.config.js')
|
const serverWebpackConfig = require('./webpack/server.config.js')
|
||||||
const basename = posix.basename
|
|
||||||
const remove = pify(fs.remove)
|
const remove = pify(fs.remove)
|
||||||
const readFile = pify(fs.readFile)
|
const readFile = pify(fs.readFile)
|
||||||
const writeFile = pify(fs.writeFile)
|
const writeFile = pify(fs.writeFile)
|
||||||
@ -111,13 +111,6 @@ exports.build = function * () {
|
|||||||
if (!this.dev) {
|
if (!this.dev) {
|
||||||
yield mkdirp(r(this.dir, '.nuxt/dist'))
|
yield mkdirp(r(this.dir, '.nuxt/dist'))
|
||||||
}
|
}
|
||||||
// Resolve custom routes component path
|
|
||||||
this.options.router.routes.forEach((route) => {
|
|
||||||
if (route.component.slice(-4) !== '.vue') {
|
|
||||||
route.component = route.component + '.vue'
|
|
||||||
}
|
|
||||||
route.component = r(this.srcDir, route.component)
|
|
||||||
})
|
|
||||||
// Generate routes and interpret the template files
|
// Generate routes and interpret the template files
|
||||||
yield generateRoutesAndFiles.call(this)
|
yield generateRoutesAndFiles.call(this)
|
||||||
/*
|
/*
|
||||||
@ -144,15 +137,9 @@ function * generateRoutesAndFiles () {
|
|||||||
** Generate routes based on files
|
** Generate routes based on files
|
||||||
*/
|
*/
|
||||||
const files = yield glob('pages/**/*.vue', { cwd: this.srcDir })
|
const files = yield glob('pages/**/*.vue', { cwd: this.srcDir })
|
||||||
let routes = []
|
this.routes = _.uniq(_.map(files, (file) => {
|
||||||
files.forEach((file) => {
|
return file.replace(/^pages/, '').replace(/\.vue$/, '').replace(/\/index/g, '').replace(/_/g, ':').replace('', '/').replace(/\/{2,}/g, '/')
|
||||||
let path = file.replace(/^pages/, '').replace(/index\.vue$/, '/').replace(/\.vue$/, '').replace(/\/{2,}/g, '/')
|
}))
|
||||||
let name = file.replace(/^pages/, '').replace(/\.vue$/, '').replace(/\/{2,}/g, '/').split('/').slice(1).join('-')
|
|
||||||
if (basename(path)[0] === '_') return
|
|
||||||
routes.push({ path: path, component: r(this.srcDir, file), name: name })
|
|
||||||
})
|
|
||||||
// Concat pages routes and custom routes in this.routes
|
|
||||||
this.routes = routes.concat(this.options.router.routes)
|
|
||||||
/*
|
/*
|
||||||
** Interpret and move template files to .nuxt/
|
** Interpret and move template files to .nuxt/
|
||||||
*/
|
*/
|
||||||
@ -165,8 +152,10 @@ function * generateRoutesAndFiles () {
|
|||||||
'server.js',
|
'server.js',
|
||||||
'utils.js',
|
'utils.js',
|
||||||
'components/nuxt-container.vue',
|
'components/nuxt-container.vue',
|
||||||
'components/nuxt.vue',
|
'components/nuxt-loading.vue',
|
||||||
'components/nuxt-loading.vue'
|
'components/nuxt-child.js',
|
||||||
|
'components/nuxt-link.js',
|
||||||
|
'components/nuxt.vue'
|
||||||
]
|
]
|
||||||
let templateVars = {
|
let templateVars = {
|
||||||
uniqBy: _.uniqBy,
|
uniqBy: _.uniqBy,
|
||||||
@ -192,23 +181,10 @@ function * generateRoutesAndFiles () {
|
|||||||
templateVars.loading = templateVars.loading + '.vue'
|
templateVars.loading = templateVars.loading + '.vue'
|
||||||
}
|
}
|
||||||
// Format routes for the lib/app/router.js template
|
// Format routes for the lib/app/router.js template
|
||||||
templateVars.router.routes = this.routes.map((route) => {
|
templateVars.router.routes = createRoutes(files, this.srcDir)
|
||||||
const r = Object.assign({}, route)
|
|
||||||
r._component = r.component
|
|
||||||
r._name = '_' + hash(r._component)
|
|
||||||
r.component = r._name
|
|
||||||
r.path = r.path.replace(/\\/g, '\\\\') // regex expression in route path escaping for lodash templating
|
|
||||||
return r
|
|
||||||
})
|
|
||||||
if (files.includes('pages/_app.vue')) {
|
|
||||||
templateVars.appPath = r(this.srcDir, 'pages/_app.vue')
|
|
||||||
}
|
|
||||||
if (fs.existsSync(join(this.srcDir, 'layouts', 'app.vue'))) {
|
if (fs.existsSync(join(this.srcDir, 'layouts', 'app.vue'))) {
|
||||||
templateVars.appPath = r(this.srcDir, 'layouts/app.vue')
|
templateVars.appPath = r(this.srcDir, 'layouts/app.vue')
|
||||||
}
|
}
|
||||||
if (files.includes('pages/_error.vue')) {
|
|
||||||
templateVars.components.ErrorPage = r(this.srcDir, 'pages/_error.vue')
|
|
||||||
}
|
|
||||||
if (fs.existsSync(join(this.srcDir, 'layouts', 'error.vue'))) {
|
if (fs.existsSync(join(this.srcDir, 'layouts', 'error.vue'))) {
|
||||||
templateVars.components.ErrorPage = r(this.srcDir, 'layouts/error.vue')
|
templateVars.components.ErrorPage = r(this.srcDir, 'layouts/error.vue')
|
||||||
}
|
}
|
||||||
@ -223,6 +199,46 @@ function * generateRoutesAndFiles () {
|
|||||||
yield moveTemplates
|
yield moveTemplates
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function createRoutes (files, srcDir) {
|
||||||
|
let routes = []
|
||||||
|
files.forEach((file) => {
|
||||||
|
let keys = file.replace(/^pages/, '').replace(/\.vue$/, '').replace(/\/{2,}/g, '/').split('/').slice(1)
|
||||||
|
let route = { name: '', path: '', component: r(srcDir, file), _name: null }
|
||||||
|
let parent = routes
|
||||||
|
keys.forEach((key, i) => {
|
||||||
|
route.name = route.name ? route.name + (key === 'index' ? '' : '-' + key.replace('_', '')) : key.replace('_', '')
|
||||||
|
let child = _.find(parent, { name: route.name })
|
||||||
|
if (child) {
|
||||||
|
if (!child.children) {
|
||||||
|
child.children = []
|
||||||
|
}
|
||||||
|
parent = child.children
|
||||||
|
} else {
|
||||||
|
route.path = route.path + (key === 'index' ? (i > 0 ? '' : '/') : '/' + key.replace('_', ':'))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
route._name = '_' + hash(route.component)
|
||||||
|
// Order Routes path
|
||||||
|
if (_.last(keys)[0] === '_') {
|
||||||
|
parent.push(route)
|
||||||
|
} else {
|
||||||
|
parent.unshift(route)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return cleanChildrenRoutes(routes)
|
||||||
|
}
|
||||||
|
|
||||||
|
function cleanChildrenRoutes (routes, isChild = false) {
|
||||||
|
routes.forEach((route) => {
|
||||||
|
route.path = (isChild) ? route.path.replace('/', '') : route.path
|
||||||
|
if (route.children) {
|
||||||
|
delete route.name
|
||||||
|
route.children = cleanChildrenRoutes(route.children, true)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return routes
|
||||||
|
}
|
||||||
|
|
||||||
function getWebpackClientConfig () {
|
function getWebpackClientConfig () {
|
||||||
return clientWebpackConfig.call(this)
|
return clientWebpackConfig.call(this)
|
||||||
}
|
}
|
||||||
|
@ -23,8 +23,11 @@ module.exports = function () {
|
|||||||
output: {
|
output: {
|
||||||
publicPath: urlJoin(this.options.router.base, '/_nuxt/')
|
publicPath: urlJoin(this.options.router.base, '/_nuxt/')
|
||||||
},
|
},
|
||||||
|
performance: {
|
||||||
|
hints: (this.dev ? false : 'warning')
|
||||||
|
},
|
||||||
resolve: {
|
resolve: {
|
||||||
extensions: ['.js', '.vue'],
|
extensions: ['.js', '.json', '.vue'],
|
||||||
// Disable for now
|
// Disable for now
|
||||||
alias: {
|
alias: {
|
||||||
'~': join(this.srcDir),
|
'~': join(this.srcDir),
|
||||||
|
@ -1,10 +1,18 @@
|
|||||||
'use strict'
|
'use strict'
|
||||||
|
|
||||||
|
const { defaults } = require('lodash')
|
||||||
|
|
||||||
module.exports = function () {
|
module.exports = function () {
|
||||||
|
let babelOptions = JSON.stringify(defaults(this.options.build.babel, {
|
||||||
|
presets: [
|
||||||
|
['es2015', { modules: false }],
|
||||||
|
'stage-2'
|
||||||
|
]
|
||||||
|
}))
|
||||||
let config = {
|
let config = {
|
||||||
postcss: this.options.build.postcss,
|
postcss: this.options.build.postcss,
|
||||||
loaders: {
|
loaders: {
|
||||||
'js': 'babel-loader?presets[]=es2015&presets[]=stage-2',
|
'js': 'babel-loader?' + babelOptions,
|
||||||
'less': 'vue-style-loader!css-loader!less-loader',
|
'less': 'vue-style-loader!css-loader!less-loader',
|
||||||
'sass': 'vue-style-loader!css-loader!sass-loader?indentedSyntax',
|
'sass': 'vue-style-loader!css-loader!sass-loader?indentedSyntax',
|
||||||
'scss': 'vue-style-loader!css-loader!sass-loader',
|
'scss': 'vue-style-loader!css-loader!sass-loader',
|
||||||
|
@ -8,6 +8,7 @@ const pathToRegexp = require('path-to-regexp')
|
|||||||
const _ = require('lodash')
|
const _ = require('lodash')
|
||||||
const { resolve, join, dirname, sep } = require('path')
|
const { resolve, join, dirname, sep } = require('path')
|
||||||
const { promisifyRouteParams } = require('./utils')
|
const { promisifyRouteParams } = require('./utils')
|
||||||
|
const { minify } = require('html-minifier')
|
||||||
const copy = pify(fs.copy)
|
const copy = pify(fs.copy)
|
||||||
const remove = pify(fs.remove)
|
const remove = pify(fs.remove)
|
||||||
const writeFile = pify(fs.writeFile)
|
const writeFile = pify(fs.writeFile)
|
||||||
@ -69,15 +70,15 @@ module.exports = function () {
|
|||||||
*/
|
*/
|
||||||
let routes = []
|
let routes = []
|
||||||
this.routes.forEach((route) => {
|
this.routes.forEach((route) => {
|
||||||
if (route.path.includes(':') || route.path.includes('*')) {
|
if (route.includes(':') || route.includes('*')) {
|
||||||
const routeParams = this.options.generate.routeParams[route.path]
|
const routeParams = this.options.generate.routeParams[route]
|
||||||
if (!routeParams) {
|
if (!routeParams) {
|
||||||
console.error(`Could not generate the dynamic route ${route.path}, please add the mapping params in nuxt.config.js (generate.routeParams).`) // eslint-disable-line no-console
|
console.error(`Could not generate the dynamic route ${route}, please add the mapping params in nuxt.config.js (generate.routeParams).`) // eslint-disable-line no-console
|
||||||
return process.exit(1)
|
return process.exit(1)
|
||||||
}
|
}
|
||||||
const toPath = pathToRegexp.compile(route.path)
|
const toPath = pathToRegexp.compile(route)
|
||||||
routes = routes.concat(routeParams.map((params) => {
|
routes = routes.concat(routeParams.map((params) => {
|
||||||
return Object.assign({}, route, { path: toPath(params) })
|
return toPath(params)
|
||||||
}))
|
}))
|
||||||
} else {
|
} else {
|
||||||
routes.push(route)
|
routes.push(route)
|
||||||
@ -87,8 +88,28 @@ module.exports = function () {
|
|||||||
while (routes.length) {
|
while (routes.length) {
|
||||||
yield routes.splice(0, 500).map((route) => {
|
yield routes.splice(0, 500).map((route) => {
|
||||||
return co(function * () {
|
return co(function * () {
|
||||||
const { html } = yield self.renderRoute(route.path)
|
var { html } = yield self.renderRoute(route)
|
||||||
var path = join(route.path, sep, 'index.html') // /about -> /about/index.html
|
html = minify(html, {
|
||||||
|
collapseBooleanAttributes: true,
|
||||||
|
collapseWhitespace: true,
|
||||||
|
decodeEntities: true,
|
||||||
|
minifyCSS: true,
|
||||||
|
minifyJS: true,
|
||||||
|
processConditionalComments: true,
|
||||||
|
removeAttributeQuotes: true,
|
||||||
|
removeComments: true,
|
||||||
|
removeEmptyAttributes: true,
|
||||||
|
removeOptionalTags: true,
|
||||||
|
removeRedundantAttributes: true,
|
||||||
|
removeScriptTypeAttributes: true,
|
||||||
|
removeStyleLinkTypeAttributes: true,
|
||||||
|
removeTagWhitespace: true,
|
||||||
|
sortAttributes: true,
|
||||||
|
sortClassName: true,
|
||||||
|
trimCustomFragments: true,
|
||||||
|
useShortDoctype: true
|
||||||
|
})
|
||||||
|
var path = join(route, sep, 'index.html') // /about -> /about/index.html
|
||||||
debug('Generate file: ' + path)
|
debug('Generate file: ' + path)
|
||||||
path = join(distPath, path)
|
path = join(distPath, path)
|
||||||
// Make sure the sub folders are created
|
// Make sure the sub folders are created
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
'use strict'
|
|
||||||
|
|
||||||
const _ = require('lodash')
|
const _ = require('lodash')
|
||||||
const co = require('co')
|
const co = require('co')
|
||||||
const fs = require('fs-extra')
|
const fs = require('fs-extra')
|
||||||
@ -41,8 +39,7 @@ class Nuxt {
|
|||||||
},
|
},
|
||||||
router: {
|
router: {
|
||||||
base: '/',
|
base: '/',
|
||||||
linkActiveClass: 'router-link-active',
|
linkActiveClass: 'nuxt-link-active'
|
||||||
routes: []
|
|
||||||
},
|
},
|
||||||
build: {}
|
build: {}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
const debug = require('debug')('nuxt:render')
|
const debug = require('debug')('nuxt:render')
|
||||||
|
debug.color = 4 // force blue color
|
||||||
const co = require('co')
|
const co = require('co')
|
||||||
const { urlJoin } = require('./utils')
|
const { urlJoin } = require('./utils')
|
||||||
const { getContext } = require('./utils')
|
const { getContext } = require('./utils')
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "nuxt",
|
"name": "nuxt",
|
||||||
"version": "0.8.8",
|
"version": "0.9.0",
|
||||||
"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": [
|
||||||
{
|
{
|
||||||
@ -63,6 +63,7 @@
|
|||||||
"fs-extra": "^1.0.0",
|
"fs-extra": "^1.0.0",
|
||||||
"glob": "^7.1.1",
|
"glob": "^7.1.1",
|
||||||
"hash-sum": "^1.0.2",
|
"hash-sum": "^1.0.2",
|
||||||
|
"html-minifier": "^3.2.3",
|
||||||
"lodash": "^4.17.2",
|
"lodash": "^4.17.2",
|
||||||
"lru-cache": "^4.0.2",
|
"lru-cache": "^4.0.2",
|
||||||
"memory-fs": "^0.4.1",
|
"memory-fs": "^0.4.1",
|
||||||
@ -78,7 +79,7 @@
|
|||||||
"vue-server-renderer": "^2.1.3",
|
"vue-server-renderer": "^2.1.3",
|
||||||
"vue-template-compiler": "^2.1.3",
|
"vue-template-compiler": "^2.1.3",
|
||||||
"vuex": "^2.0.0",
|
"vuex": "^2.0.0",
|
||||||
"webpack": "2.1.0-beta.27",
|
"webpack": "2.2.0-rc.0",
|
||||||
"webpack-dev-middleware": "^1.8.4",
|
"webpack-dev-middleware": "^1.8.4",
|
||||||
"webpack-hot-middleware": "^2.13.2"
|
"webpack-hot-middleware": "^2.13.2"
|
||||||
},
|
},
|
||||||
|
Loading…
Reference in New Issue
Block a user