This commit is contained in:
Pooya Parsa 2017-08-18 20:35:01 +04:30
parent b83f897339
commit 866e31d1a6
5 changed files with 93 additions and 17 deletions

View File

@ -151,6 +151,17 @@ export function flatRoutes (router, path = '', routes = []) {
return routes return routes
} }
export function attrsStr (attrObj = {}, exclude = []) {
return Object.keys(attrObj)
.filter(attr => !exclude.includes(attr))
.map(attr => {
if (typeof attrObj[attr] !== 'string') {
return attr
}
return `${attr}="${attrObj[attr].replace('"', '\'')}"`
}).join(' ')
}
export function cleanChildrenRoutes (routes, isChild = false) { export function cleanChildrenRoutes (routes, isChild = false) {
let start = -1 let start = -1
let routesIndex = [] let routesIndex = []

58
lib/core/meta.js Normal file
View File

@ -0,0 +1,58 @@
import { attrsStr } from 'utils'
import LRU from 'lru-cache'
export default class MetaRenderer {
constructor (nuxt) {
this.nuxt = nuxt
this.options = nuxt.options
this.cache = LRU({})
}
render ({ url = '/' }) {
let head = this.cache.get(url)
if (head) {
return head
}
head = ''
// Title
if (typeof this.options.head.title === 'string') {
head += `<title data-n-head="true">${this.options.head.title || ''}</title>`
}
// Meta
if (Array.isArray(this.options.head.meta)) {
this.options.head.meta.forEach(meta => {
head += `<meta data-n-head="true" ${attrsStr(meta)} />`
})
}
// Links
if (Array.isArray(this.options.head.link)) {
this.options.head.link.forEach(link => {
head += `<link data-n-head="true" ${attrsStr(link)} " />`
})
}
// Style
if (Array.isArray(this.options.head.style)) {
this.options.head.link.forEach(style => {
head += `<style data-n-head="true" ${attrsStr(style, ['cssText'])} ">${style.cssText || ''}</style>`
})
}
// Script
if (Array.isArray(this.options.head.script)) {
this.options.head.script.forEach(script => {
head += `<script data-n-head="true" ${attrsStr(script, ['innerHTML'])} ">${script.innerHTML || ''}</script>`
})
}
this.cache.set(url, head)
return head
}
}

View File

@ -10,12 +10,13 @@ import _ from 'lodash'
import { join, resolve } from 'path' import { join, resolve } from 'path'
import fs from 'fs-extra' import fs from 'fs-extra'
import { createBundleRenderer } from 'vue-server-renderer' import { createBundleRenderer } from 'vue-server-renderer'
import { getContext, setAnsiColors, isUrl } from 'utils' import { getContext, setAnsiColors, isUrl, attrsStr } from 'utils'
import Debug from 'debug' import Debug from 'debug'
import Youch from '@nuxtjs/youch' import Youch from '@nuxtjs/youch'
import { SourceMapConsumer } from 'source-map' import { SourceMapConsumer } from 'source-map'
import connect from 'connect' import connect from 'connect'
import { Options } from 'common' import { Options } from 'common'
import MetaRenderer from './meta'
const debug = Debug('nuxt:render') const debug = Debug('nuxt:render')
debug.color = 4 // Force blue color debug.color = 4 // Force blue color
@ -32,6 +33,7 @@ export default class Renderer extends Tapable {
// Will be set by createRenderer // Will be set by createRenderer
this.bundleRenderer = null this.bundleRenderer = null
this.metaRenderer = null
// Will be available on dev // Will be available on dev
this.webpackDevMiddleware = null this.webpackDevMiddleware = null
@ -128,7 +130,10 @@ export default class Renderer extends Tapable {
} }
createRenderer () { createRenderer () {
// Skip if SSR is disabled // Create Meta Renderer
this.metaRenderer = new MetaRenderer(this.nuxt)
// Check if SSR is disabled
if (this.noSSR) { if (this.noSSR) {
return return
} }
@ -335,16 +340,17 @@ export default class Renderer extends Tapable {
async readSource (frame) { async readSource (frame) {
const serverBundle = this.resources.serverBundle const serverBundle = this.resources.serverBundle
// Initialize smc cache
if (!serverBundle.$maps) {
serverBundle.$maps = {}
}
// Remove webpack:/// & query string from the end // Remove webpack:/// & query string from the end
const sanitizeName = name => name ? name.replace('webpack:///', '').split('?')[0] : '' const sanitizeName = name => name ? name.replace('webpack:///', '').split('?')[0] : ''
// SourceMap Support for SSR Bundle // SourceMap Support for SSR Bundle
if (serverBundle && serverBundle.maps[frame.fileName]) { if (serverBundle && serverBundle.maps[frame.fileName]) {
// Initialize smc cache
if (!serverBundle.$maps) {
serverBundle.$maps = {}
}
// Read SourceMap object // Read SourceMap object
const smc = serverBundle.$maps[frame.fileName] || new SourceMapConsumer(serverBundle.maps[frame.fileName]) const smc = serverBundle.$maps[frame.fileName] || new SourceMapConsumer(serverBundle.maps[frame.fileName])
serverBundle.$maps[frame.fileName] = smc serverBundle.$maps[frame.fileName] = smc
@ -423,17 +429,17 @@ export default class Renderer extends Tapable {
context.isServer = true context.isServer = true
// Basic response if SSR is disabled or spa data provided // Basic response if SSR is disabled or spa data provided
const SPAData = context.spa || (context.res && context.res.spa) const spa = context.spa || (context.res && context.res.spa)
if (this.noSSR || SPAData) { if (this.noSSR || spa) {
const data = { const HEAD = this.metaRenderer.render(context)
HTML_ATTRS: '', const HTML_ATTRS = attrsStr(this.options.head.htmlAttrs)
BODY_ATTRS: '', const APP = `<div id="__nuxt">${this.resources.loadingHTML}</div>`
HEAD: '',
APP: `<div id="__nuxt">${this.resources.loadingHTML}</div>`
}
if (SPAData) { const data = {
Object.assign(data, SPAData) HTML_ATTRS,
BODY_ATTRS: '',
HEAD,
APP
} }
const html = this.resources.spaTemplate(data) const html = this.resources.spaTemplate(data)

View File

@ -92,6 +92,7 @@
"html-minifier": "^3.5.3", "html-minifier": "^3.5.3",
"html-webpack-plugin": "^2.30.1", "html-webpack-plugin": "^2.30.1",
"lodash": "^4.17.4", "lodash": "^4.17.4",
"lru-cache": "^4.1.1",
"memory-fs": "^0.4.1", "memory-fs": "^0.4.1",
"minimist": "^1.2.0", "minimist": "^1.2.0",
"opencollective": "^1.0.3", "opencollective": "^1.0.3",

View File

@ -63,7 +63,7 @@
"compression": "^1.7.0", "compression": "^1.7.0",
"fs-extra": "^4.0.1", "fs-extra": "^4.0.1",
"vue-server-renderer": "~2.4.2", "vue-server-renderer": "~2.4.2",
"@nuxtjs/youch": "3.0.1", "@nuxtjs/youch": "3.0.2",
"source-map": "^0.5.6", "source-map": "^0.5.6",
"connect": "^3.6.3", "connect": "^3.6.3",
"server-destroy": "^1.0.1" "server-destroy": "^1.0.1"