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

This commit is contained in:
Sébastien Chopin 2017-07-12 08:41:47 +02:00
commit fdc84d2a4a
29 changed files with 695 additions and 114 deletions

View File

@ -0,0 +1,69 @@
body {
font-family: "Roboto", "Helvetica Neue", "Hiragino Sans GB", "LiHei Pro", Arial, serif;
text-rendering: optimizelegibility;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
font-weight: 400;
font-size: 16px;
word-spacing: 1px;
color: #666;
margin: 0;
}
img {
border: none;
}
a {
color: #666;
text-decoration: none;
transition: color 0.2s ease, border-color 0.2s ease;
}
.header {
letter-spacing: 5px;
margin: 50px auto 15px;
text-align: center;
}
.header a {
font-size: 15px;
color: #444;
}
.links {
text-align: center;
font-family: "Roboto", "Helvetica Neue", "Hiragino Sans GB", "LiHei Pro", Arial, serif;
color: #999;
font-size: 24px;
margin: 0;
}
.links a {
cursor: pointer;
padding: 2px;
margin: 0 3px;
}
.links img {
width: 15px;
height: 15px;
}
.header,
h1,
h2,
h3,
h4,
h5,
h6 {
font-family: "Montserrat", "Helvetica Neue", "Hiragino Sans GB", "LiHei Pro", Arial, sans-serif;
font-weight: 400;
color: #444;
}
.main {
max-width: 600px;
margin: 50px auto;
padding: 0 30px 50px;
position: relative;
}
@media screen and (max-width: 420px) {
.header {
margin: 40px auto 10px;
}
.header a {
font-size: 14px;
}
}

View File

@ -0,0 +1,57 @@
.main > ul {
list-style-type: none;
padding: 0;
padding-top: 4px;
}
.main > ul > li {
position: relative;
padding: 30px 0 30px;
border-bottom: 1px solid #e6e6e6;
}
.main > ul > li:first-child {
margin-top: -30px;
}
.main h2,
.main h3 {
letter-spacing: 1px;
margin: 0;
text-transform: uppercase;
}
.main h2 {
font-size: 20px;
letter-spacing: 1px;
margin-left: 120px;
}
.main h2 a {
color: #444;
}
.main h2 a:hover {
color: #f33;
}
.main h3 {
font-size: 13px;
color: #999;
position: absolute;
left: 0;
top: 33px;
}
@media screen and (max-width: 420px) {
.main h2 {
font-size: 16px;
margin-left: 0;
}
.main h2 a:hover {
color: #f66;
}
.main h3 {
font-size: 11px;
position: static;
margin-bottom: 10px;
}
.main ul li {
padding: 18px 0 20px;
}
.main ul li:first-child {
margin-top: -35px;
}
}

View File

@ -0,0 +1,307 @@
.gutter pre {
color: #999;
}
pre {
color: #525252;
}
pre .function .keyword,
pre .constant {
color: #0092db;
}
pre .keyword,
pre .attribute {
color: #e96900;
}
pre .number,
pre .literal {
color: #ae81ff;
}
pre .tag,
pre .tag .title,
pre .change,
pre .winutils,
pre .flow,
pre .lisp .title,
pre .clojure .built_in,
pre .nginx .title,
pre .tex .special {
color: #2973b7;
}
pre .class .title {
color: #fff;
}
pre .symbol,
pre .symbol .string,
pre .value,
pre .regexp {
color: #42b983;
}
pre .title {
color: #a6e22e;
}
pre .tag .value,
pre .string,
pre .subst,
pre .haskell .type,
pre .preprocessor,
pre .ruby .class .parent,
pre .built_in,
pre .sql .aggregate,
pre .django .template_tag,
pre .django .variable,
pre .smalltalk .class,
pre .javadoc,
pre .django .filter .argument,
pre .smalltalk .localvars,
pre .smalltalk .array,
pre .attr_selector,
pre .pseudo,
pre .addition,
pre .stream,
pre .envvar,
pre .apache .tag,
pre .apache .cbracket,
pre .tex .command,
pre .prompt {
color: #42b983;
}
pre .comment,
pre .java .annotation,
pre .python .decorator,
pre .template_comment,
pre .pi,
pre .doctype,
pre .deletion,
pre .shebang,
pre .apache .sqbracket,
pre .tex .formula {
color: #b3b3b3;
}
pre .coffeescript .javascript,
pre .javascript .xml,
pre .tex .formula,
pre .xml .javascript,
pre .xml .vbscript,
pre .xml .css,
pre .xml .cdata {
opacity: 0.5;
}
.main .post {
position: relative;
padding-bottom: 30px;
margin-bottom: 30px;
border-bottom: 1px solid #e6e6e6;
}
.main .post h1,
.main .post h2 {
text-transform: uppercase;
letter-spacing: 0px;
}
.main .post h1 a:hover,
.main .post h2 a:hover {
border-bottom: 3px solid #666;
}
.main .post h1 {
font-size: 32px;
margin: 0 0 45px;
letter-spacing: 1px;
}
.main .post h2 {
font-size: 24px;
margin: 60px 0 30px;
position: relative;
}
.main .post h2:before {
content: '';
border-left: 5px solid #41b883;
position: absolute;
left: -15px;
height: 75%;
top: 12%;
}
.main .post h3 {
margin: 30px 0 15px;
}
.main .post .date {
font-family: "Montserrat", "Helvetica Neue", "Hiragino Sans GB", "LiHei Pro", Arial, sans-serif;
font-size: 13px;
color: #999;
margin: 0 0 30px;
letter-spacing: 1px;
position: initial;
text-transform: none;
}
.main .post .content {
text-align: left;
line-height: 1.8em;
}
.main .post .content p,
.main .post .content ul,
.main .post .content ol {
margin: 1em 0 1.5em;
}
.main .post .content strong {
font-weight: 600;
color: #444;
}
.main .post .content ol {
padding-left: 1.6em;
}
.main .post .content ul {
padding-left: 15px;
list-style-type: none;
}
.main .post .content ul li:before {
position: absolute;
font-weight: 600;
content: " · ";
margin: 0;
left: 0;
}
.main .post .content a {
color: #41b883;
border-bottom: 2px solid transparent;
}
.main .post .content a:hover {
color: #41b883;
border-bottom-color: #41b883;
}
.main .post .content .highlight,
.main .post .content .highlight table {
margin: 0;
width: 100%;
}
.main .post .content .highlight {
overflow-x: auto;
}
.main .post .content .highlight table,
.main .post .content .highlight tr,
.main .post .content .highlight td {
padding: 0;
border-collapse: collapse;
}
.main .post .content code {
font-family: "Roboto Mono", "Menlo", "Consolas", monospace;
font-size: 13px;
background-color: #f6f6f6;
padding: 3px 10px;
margin: 0 5px;
border-radius: 2px;
}
.main .post .content pre {
font-family: "Roboto Mono", "Menlo", "Consolas", monospace;
font-size: 13px;
overflow-x: auto;
text-align: left;
padding: 15px 25px;
background-color: #f6f6f6;
line-height: 1.5em;
}
.main .post .content .code pre {
border-top-right-radius: 2px;
border-bottom-right-radius: 2px;
}
.main .post .content .gutter pre {
padding: 15px 0 15px 15px;
color: #75715e;
border-top-left-radius: 2px;
border-bottom-left-radius: 2px;
}
.main .post .content blockquote {
margin: 2em 0;
padding-left: 30px;
border-left: 5px solid #e6e6e6;
}
.main .post .content blockquote p {
font-size: 17px;
font-style: italic;
line-height: 1.8em;
color: #999;
}
.main .post img {
display: block;
max-width: 100%;
}
.blog-nav {
position: fixed;
bottom: 20px;
height: 20px;
line-height: 20px;
font-family: "Montserrat", "Helvetica Neue", "Hiragino Sans GB", "LiHei Pro", Arial, sans-serif;
font-size: 15px;
color: #999;
text-decoration: none;
cursor: pointer;
letter-spacing: 1px;
border-bottom: 3px solid transparent;
}
.blog-nav:hover {
color: #333;
border-bottom-color: #333;
}
#newer {
left: 40px;
}
#older {
right: 40px;
}
.show-comments {
font-family: "Montserrat", "Helvetica Neue", "Hiragino Sans GB", "LiHei Pro", Arial, sans-serif;
text-align: center;
}
.show-comments a {
color: #999;
cursor: pointer;
}
.show-comments a:hover {
color: #666;
}
@media screen and (max-width: 900px) {
.main .post {
padding-bottom: 80px;
}
.blog-nav {
position: absolute;
bottom: 30px;
}
#newer {
left: 0;
}
#older {
right: 0;
}
}
@media screen and (max-width: 420px) {
.main {
margin-top: 32px;
}
.main .post h1 {
font-size: 24px;
margin: 0 0 30px;
}
.main .post h2 {
font-size: 20px;
margin: 30px 0 15px;
}
.main .post h3 {
font-size: 16px;
line-height: 1.3em;
}
.main .post .date {
font-size: 12px;
margin: 0 0 20px;
}
.main .post .content {
font-size: 15px;
}
.main .post .content pre {
font-size: 12px;
}
.main .post .content blockquote p {
font-size: 16px;
}
.blog-nav {
font-size: 14px;
color: #444;
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 139 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -0,0 +1,15 @@
<template>
<div class="wrapper">
<div class="header">
<nuxt-link to="/">NUXT BLOG</nuxt-link>
</div>
<p class="links">
<a href="https://twitter.com/nuxt_js" target="_blank"><img src="~assets/img/twitter.png"></a>
<a href="https://github.com/nuxt/nuxt.js/tree/dev/examples/async-component-injection" target="_blank"><img src="~assets/img/github.png"></a>
</p>
<div class="main">
<nuxt/>
</div>
</div>
</template>

View File

@ -0,0 +1,22 @@
module.exports = {
head: {
title: 'Nuxt Blog',
meta: [
{ charset: 'utf-8' },
{ name: 'viewport', content: 'width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no' }
],
link: [
{ rel: 'icon', href: '/favicon.ico', type: 'image/x-icon' },
{ rel: 'stylesheet', href: 'http://fonts.googleapis.com/css?family=Montserrat|Roboto:400,400italic,600|Roboto+Mono', type: 'text/css' }
]
},
css: [
'@/assets/css/common.css'
],
generate: {
routes: [
'/deep-dive-into-ocean',
'/welcome-to-my-blog'
]
}
}

View File

@ -0,0 +1,21 @@
<template>
<div class="post">
<component :is="component"/>
</div>
</template>
<script>
// See https://vuejs.org/v2/guide/components.html#Advanced-Async-Components
const getPost = (slug) => ({
component: import(`@/posts/${slug}`),
error: require('@/posts/404')
})
export default {
beforeCreate () {
this.component = () => getPost(this.$route.params.slug)
}
}
</script>
<style src="@/assets/css/post.css"/>

View File

@ -0,0 +1,22 @@
<template>
<ul>
<li v-for="(post, index) in posts" :key="index">
<h3>{{ post.date }}</h3>
<h2><nuxt-link :to="post.link">{{ post.title }}</nuxt-link></h2>
</li>
<li style="border:none;text-align: center;font-size: 14px;">Design from <a href="http://blog.evanyou.me" target="_blank">EvanYou.me</a></li>
</ul>
</template>
<script>
export default {
data: () => ({
posts: [
{ date: 'Jul 10, 2017', title: 'Deep dive into the Ocean', link: '/deep-dive-into-ocean' },
{ date: 'Jul 08, 2017', title: 'Welcome to my blog', link: '/welcome-to-my-blog' }
]
})
}
</script>
<style src="@/assets/css/index.css"/>

View File

@ -0,0 +1,3 @@
<template>
<h1 style="text-align: center;">Article not found</h1>
</template>

View File

@ -0,0 +1,17 @@
<template>
<div>
<h3 class="date">Jul 10, 2017</h3>
<h1>Deep dive into the Ocean</h1>
<div class="content">
<img src="~assets/img/swimmer.jpg">
<h2>Subtitle #1</h2>
<p>Far far away, behind the word mountains, far from the countries Vokalia and Consonantia, there live the blind texts. Separated they live in Bookmarksgrove right at the coast of the Semantics, a large language ocean. A small river named Duden flows by their place and supplies it with the necessary regelialia. It is a paradisematic country, in which roasted parts of sentences fly into your mouth. Even the all-powerful Pointing has no control about the blind texts it is an almost unorthographic life One day however a small line of blind text by the name of Lorem Ipsum decided to leave for the far World of Grammar.</p>
<h2>Another subtitle</h2>
<ul>
<li>Vue.js</li>
<li>Nuxt.js</li>
<li>= <3</li>
</ul>
</div>
</div>
</template>

View File

@ -0,0 +1,10 @@
<template>
<div>
<h3 class="date">Jul 08, 2017</h3>
<h1>Welcome to my blog</h1>
<div class="content">
<h2>What is Lorem Ipsum?</h2>
<p><b>Lorem Ipsum</b> is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.</p>
</div>
</div>
</template>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -1,7 +0,0 @@
<template>
<div>
<h1>Article 1</h1>
<p>Hello I am the first article :)</p>
<nuxt-link to="/">Home</nuxt-link>
</div>
</template>

View File

@ -1,7 +0,0 @@
<template>
<div>
<h1>Article 2</h1>
<p>Hello I am the second article!</p>
<nuxt-link to="/">Home</nuxt-link>
</div>
</template>

View File

@ -1,19 +0,0 @@
<template>
<component :is="comp"/>
</template>
<script>
const components = {}
const files = require.context('@/articles', false, /\.vue$/)
files.keys().forEach((filename) => {
const name = filename.replace('./', '').replace('.vue', '')
components[name] = () => import('@/articles/' + name + '.vue').then((m) => m.default || m)
})
export default {
async asyncData({ params, error }) {
return { comp: params.slug }
},
components
}
</script>

View File

@ -1,9 +0,0 @@
<template>
<div>
<h1>Articles</h1>
<ul>
<li><nuxt-link to="/article-1">Article #1</nuxt-link></li>
<li><nuxt-link to="/article-2">Article #2</nuxt-link></li>
</ul>
</div>
</template>

1
lib/app/empty.js Normal file
View File

@ -0,0 +1 @@
// This file is intentially left empty for noop aliases

View File

@ -9,40 +9,16 @@ import Nuxt from './components/nuxt.vue'
import App from '<%= appPath %>'
import { getContext } from './utils'
<% if (store) { %>import { createStore } from './store.js'<% } %>
if (process.browser) {
// window.onNuxtReady(() => console.log('Ready')) hook
// Useful for jsdom testing or plugins (https://github.com/tmpvar/jsdom#dealing-with-asynchronous-script-loading)
window._nuxtReadyCbs = []
window.onNuxtReady = function (cb) {
window._nuxtReadyCbs.push(cb)
}
}
<% if (plugins.filter(p => p.ssr).length) { %>
// Require plugins
<% plugins.filter(p => p.ssr).forEach(plugin => { %>
let <%= plugin.name %> = require('<%= relativeToBuild(plugin.src) %>')
<%= plugin.name %> = <%= plugin.name %>.default || <%= plugin.name %>
<% plugins.forEach(plugin => { %>import <%= plugin.name %> from '<%= plugin.name %>'
<% }) %>
<% } %>
<% if (plugins.filter(p => !p.ssr).length) { %>
// Require browser-only plugins
if (process.browser) {
<% plugins.filter(p => !p.ssr).forEach(plugin => { %>
let <%= plugin.name %> = require('<%= relativeToBuild(plugin.src) %>')
<%= plugin.name %> = <%= plugin.name %>.default || <%= plugin.name %>
<% }) %>
}
<% } %>
// 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-meta configuration
@ -132,24 +108,17 @@ async function createApp (ssrContext) {
route: router.currentRoute,
next,
error: app._nuxt.error.bind(app),
<% if(store) { %> store,<% } %>
<% if(store) { %>store,<% } %>
req: ssrContext ? ssrContext.req : undefined,
res: ssrContext ? ssrContext.res : undefined,
}, app)
<% if (plugins.filter(p => p.ssr).length) { %>
<% plugins.filter(p => p.ssr).forEach(plugin => { %>
if (typeof <%= plugin.name %> === 'function') await <%= plugin.name %>(ctx)
<% }) %>
<% } %>
if (typeof <%= plugin.name %> === 'function') await <%= plugin.name %>(ctx)<% }) %>
<% if (plugins.filter(p => !p.ssr).length) { %>
if (process.browser) {
<% plugins.filter(p => !p.ssr).forEach(plugin => { %>
if (typeof <%= plugin.name %> === 'function') await <%= plugin.name %>(ctx)
<% }) %>
}
<% } %>
if (process.browser) { <% plugins.filter(p => !p.ssr).forEach(plugin => { %>
if (typeof <%= plugin.name %> === 'function') await <%= plugin.name %>(ctx)<% }) %>
}<% } %>
return {
app,

View File

@ -2,6 +2,15 @@ import Vue from 'vue'
const noopData = () => ({})
// window.onNuxtReady(() => console.log('Ready')) hook
// Useful for jsdom testing or plugins (https://github.com/tmpvar/jsdom#dealing-with-asynchronous-script-loading)
if (process.browser) {
window._nuxtReadyCbs = []
window.onNuxtReady = function (cb) {
window._nuxtReadyCbs.push(cb)
}
}
export function applyAsyncData (Component, asyncData = {}) {
const ComponentData = Component.options.data || noopData
// Prevent calling this method for each request on SSR context

View File

@ -49,6 +49,14 @@ export default class Builder extends Tapable {
this._buildStatus = STATUS.INITIAL
}
get plugins () {
return this.options.plugins.map((p, i) => {
if (typeof p === 'string') p = { src: p }
p.src = r(this.options.srcDir, p.src)
return { src: p.src, ssr: (p.ssr !== false), name: `plugin${i}` }
})
}
async build () {
// Avoid calling build() method multiple times when dev:true
/* istanbul ignore if */
@ -119,6 +127,7 @@ export default class Builder extends Tapable {
'router.js',
'server.js',
'utils.js',
'empty.js',
'components/nuxt-error.vue',
'components/nuxt-loading.vue',
'components/nuxt-child.js',
@ -137,11 +146,7 @@ export default class Builder extends Tapable {
middleware: fs.existsSync(join(this.options.srcDir, 'middleware')),
store: this.options.store,
css: this.options.css,
plugins: this.options.plugins.map((p, i) => {
if (typeof p === 'string') p = { src: p }
p.src = r(this.options.srcDir, p.src)
return { src: p.src, ssr: (p.ssr !== false), name: `plugin${i}` }
}),
plugins: this.plugins,
appPath: './App.vue',
layouts: Object.assign({}, this.options.layouts),
loading: typeof this.options.loading === 'string' ? this.relativeToBuild(this.options.srcDir, this.options.loading) : this.options.loading,
@ -264,15 +269,33 @@ export default class Builder extends Tapable {
async webpackBuild () {
debug('Building files...')
let compilersOptions = []
const compilersOptions = []
// Client
let clientConfig = clientWebpackConfig.call(this)
const clientConfig = clientWebpackConfig.call(this)
compilersOptions.push(clientConfig)
// Server
let serverConfig = serverWebpackConfig.call(this)
compilersOptions.push(serverConfig)
const serverConfig = serverWebpackConfig.call(this)
if (this.options.build.ssr) {
compilersOptions.push(serverConfig)
}
// Alias plugins to their real path
this.plugins.forEach(p => {
const src = this.relativeToBuild(p.src)
// Client config
if (!clientConfig.resolve.alias[p.name]) {
clientConfig.resolve.alias[p.name] = src
}
// Server config
if (!serverConfig.resolve.alias[p.name]) {
// Alias to noop for ssr:false plugins
serverConfig.resolve.alias[p.name] = p.ssr ? src : './empty.js'
}
})
// Simulate webpack multi compiler interface
// Separate compilers are simpler, safer and faster

View File

@ -60,11 +60,23 @@ export default function webpackClientConfig () {
config.plugins = []
}
// Generate output HTML
// Generate output HTML for SSR
if (this.options.build.ssr) {
config.plugins.push(
new HTMLPlugin({
filename: 'index.ssr.html',
template: this.options.appTemplatePath,
inject: false // Resources will be injected using bundleRenderer
})
)
}
// Generate output HTML for SPA
config.plugins.push(
new HTMLPlugin({
filename: 'index.spa.html',
template: this.options.appTemplatePath,
inject: this.options.ssr === false,
inject: true,
chunksSortMode: 'dependency'
})
)

View File

@ -46,16 +46,57 @@ export default function Options (_options) {
options.store = true
}
// Resolve mode
let mode = options.mode
if (typeof mode === 'function') {
mode = mode()
}
if (typeof mode === 'string') {
mode = Modes[mode]
}
// Apply mode
_.defaultsDeep(options, mode)
return options
}
const Modes = {
universal: {
build: {
ssr: true
},
render: {
ssr: true
}
},
spa: {
build: {
ssr: false
},
render: {
ssr: false
}
},
static: {
build: {
ssr: true
},
render: {
ssr: 'static'
}
}
}
export const defaultOptions = {
dev: (process.env.NODE_ENV !== 'production'),
mode: 'universal',
dev: process.env.NODE_ENV !== 'production',
buildDir: '.nuxt',
nuxtAppDir: resolve(__dirname, '../lib/app/'), // Relative to dist
build: {
analyze: false,
extractCSS: false,
ssr: undefined,
publicPath: '/_nuxt/',
filenames: {
css: 'common.[chunkhash].css',
@ -64,7 +105,6 @@ export const defaultOptions = {
app: 'nuxt.bundle.[chunkhash].js'
},
vendor: [],
loaders: [],
plugins: [],
babel: {},
postcss: [],
@ -133,10 +173,10 @@ export const defaultOptions = {
scrollBehavior: null,
fallback: false
},
ssr: true,
render: {
bundleRenderer: {},
resourceHints: true,
ssr: undefined,
http2: {
push: false
},

View File

@ -42,7 +42,8 @@ export default class Renderer extends Tapable {
this.resources = {
clientManifest: null,
serverBundle: null,
appTemplate: null,
ssrTemplate: null,
spaTemplate: null,
errorTemplate: parseTemplate('<pre>{{ stack }}</pre>') // Will be loaded on ready
}
@ -121,7 +122,18 @@ export default class Renderer extends Tapable {
}
get noSSR () {
return this.options.ssr === false
return this.options.render.ssr === false
}
get staticSSR () {
return this.options.render.ssr === 'static'
}
get isReady () {
if (this.noSSR) {
return this.resources.spaTemplate
}
return this.bundleRenderer && this.resources.ssrTemplate
}
createRenderer () {
@ -297,7 +309,7 @@ export default class Renderer extends Tapable {
async renderRoute (url, context = {}) {
/* istanbul ignore if */
if (!(this.noSSR || this.bundleRenderer) || !this.resources.appTemplate) {
if (!this.isReady) {
return new Promise(resolve => {
setTimeout(() => resolve(this.renderRoute(url, context)), 1000)
})
@ -315,7 +327,7 @@ export default class Renderer extends Tapable {
let APP = '<div id="__nuxt"></div>'
let HEAD = ''
let html = this.resources.appTemplate({
let html = this.resources.spaTemplate({
HTML_ATTRS: '',
BODY_ATTRS: '',
HEAD,
@ -340,15 +352,19 @@ export default class Renderer extends Tapable {
}
let resourceHints = ''
if (this.options.render.resourceHints) {
resourceHints = context.renderResourceHints()
HEAD += resourceHints
}
HEAD += context.renderStyles()
APP += `<script type="text/javascript">window.__NUXT__=${serialize(context.nuxt, { isJSON: true })};</script>`
APP += context.renderScripts()
let html = this.resources.appTemplate({
if (!this.staticSSR) {
if (this.options.render.resourceHints) {
resourceHints = context.renderResourceHints()
HEAD += resourceHints
}
APP += `<script type="text/javascript">window.__NUXT__=${serialize(context.nuxt, { isJSON: true })};</script>`
APP += context.renderScripts()
}
HEAD += context.renderStyles()
let html = this.resources.ssrTemplate({
HTML_ATTRS: 'data-n-head-ssr ' + m.htmlAttrs.text(),
BODY_ATTRS: m.bodyAttrs.text(),
HEAD,
@ -422,8 +438,13 @@ const resourceMap = [
transform: JSON.parse
},
{
key: 'appTemplate',
fileName: 'index.html',
key: 'ssrTemplate',
fileName: 'index.ssr.html',
transform: parseTemplate
},
{
key: 'spaTemplate',
fileName: 'index.spa.html',
transform: parseTemplate
}
]

View File

@ -7,3 +7,5 @@ function $reverseStr (str) {
}
Vue.prototype.$reverseStr = $reverseStr
export default undefined

View File

@ -3,18 +3,21 @@ import Router from 'vue-router'
Vue.use(Router)
const indexPage = () => import('~/views/index.vue').then(m => m.default || m)
const aboutPage = () => import('~/views/about.vue').then(m => m.default || m)
export function createRouter () {
return new Router({
mode: 'history',
routes: [
{
path: '/',
component: require('~/views/index.vue').default,
component: indexPage,
name: 'index'
},
{
path: '/about',
component: require('~/views/about.vue').default,
component: aboutPage,
name: 'about'
}
]

View File

@ -90,7 +90,7 @@ test('/test/about-bis (added with extendRoutes)', async t => {
test('Check stats.json generated by build.analyze', t => {
const stats = require(resolve(__dirname, 'fixtures/with-config/.nuxt/dist/stats.json'))
t.is(stats.assets.length, 26)
t.is(stats.assets.length, 27)
})
test('Check /test.txt with custom serve-static options', async t => {