mirror of
https://github.com/nuxt/nuxt.git
synced 2025-01-30 23:32:38 +00:00
Spa Meta
This commit is contained in:
parent
b83f897339
commit
866e31d1a6
@ -151,6 +151,17 @@ export function flatRoutes (router, path = '', 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) {
|
||||
let start = -1
|
||||
let routesIndex = []
|
||||
|
58
lib/core/meta.js
Normal file
58
lib/core/meta.js
Normal 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
|
||||
}
|
||||
}
|
@ -10,12 +10,13 @@ import _ from 'lodash'
|
||||
import { join, resolve } from 'path'
|
||||
import fs from 'fs-extra'
|
||||
import { createBundleRenderer } from 'vue-server-renderer'
|
||||
import { getContext, setAnsiColors, isUrl } from 'utils'
|
||||
import { getContext, setAnsiColors, isUrl, attrsStr } from 'utils'
|
||||
import Debug from 'debug'
|
||||
import Youch from '@nuxtjs/youch'
|
||||
import { SourceMapConsumer } from 'source-map'
|
||||
import connect from 'connect'
|
||||
import { Options } from 'common'
|
||||
import MetaRenderer from './meta'
|
||||
|
||||
const debug = Debug('nuxt:render')
|
||||
debug.color = 4 // Force blue color
|
||||
@ -32,6 +33,7 @@ export default class Renderer extends Tapable {
|
||||
|
||||
// Will be set by createRenderer
|
||||
this.bundleRenderer = null
|
||||
this.metaRenderer = null
|
||||
|
||||
// Will be available on dev
|
||||
this.webpackDevMiddleware = null
|
||||
@ -128,7 +130,10 @@ export default class Renderer extends Tapable {
|
||||
}
|
||||
|
||||
createRenderer () {
|
||||
// Skip if SSR is disabled
|
||||
// Create Meta Renderer
|
||||
this.metaRenderer = new MetaRenderer(this.nuxt)
|
||||
|
||||
// Check if SSR is disabled
|
||||
if (this.noSSR) {
|
||||
return
|
||||
}
|
||||
@ -335,16 +340,17 @@ export default class Renderer extends Tapable {
|
||||
|
||||
async readSource (frame) {
|
||||
const serverBundle = this.resources.serverBundle
|
||||
// Initialize smc cache
|
||||
if (!serverBundle.$maps) {
|
||||
serverBundle.$maps = {}
|
||||
}
|
||||
|
||||
// Remove webpack:/// & query string from the end
|
||||
const sanitizeName = name => name ? name.replace('webpack:///', '').split('?')[0] : ''
|
||||
|
||||
// SourceMap Support for SSR Bundle
|
||||
if (serverBundle && serverBundle.maps[frame.fileName]) {
|
||||
// Initialize smc cache
|
||||
if (!serverBundle.$maps) {
|
||||
serverBundle.$maps = {}
|
||||
}
|
||||
|
||||
// Read SourceMap object
|
||||
const smc = serverBundle.$maps[frame.fileName] || new SourceMapConsumer(serverBundle.maps[frame.fileName])
|
||||
serverBundle.$maps[frame.fileName] = smc
|
||||
@ -423,17 +429,17 @@ export default class Renderer extends Tapable {
|
||||
context.isServer = true
|
||||
|
||||
// Basic response if SSR is disabled or spa data provided
|
||||
const SPAData = context.spa || (context.res && context.res.spa)
|
||||
if (this.noSSR || SPAData) {
|
||||
const data = {
|
||||
HTML_ATTRS: '',
|
||||
BODY_ATTRS: '',
|
||||
HEAD: '',
|
||||
APP: `<div id="__nuxt">${this.resources.loadingHTML}</div>`
|
||||
}
|
||||
const spa = context.spa || (context.res && context.res.spa)
|
||||
if (this.noSSR || spa) {
|
||||
const HEAD = this.metaRenderer.render(context)
|
||||
const HTML_ATTRS = attrsStr(this.options.head.htmlAttrs)
|
||||
const APP = `<div id="__nuxt">${this.resources.loadingHTML}</div>`
|
||||
|
||||
if (SPAData) {
|
||||
Object.assign(data, SPAData)
|
||||
const data = {
|
||||
HTML_ATTRS,
|
||||
BODY_ATTRS: '',
|
||||
HEAD,
|
||||
APP
|
||||
}
|
||||
|
||||
const html = this.resources.spaTemplate(data)
|
||||
|
@ -92,6 +92,7 @@
|
||||
"html-minifier": "^3.5.3",
|
||||
"html-webpack-plugin": "^2.30.1",
|
||||
"lodash": "^4.17.4",
|
||||
"lru-cache": "^4.1.1",
|
||||
"memory-fs": "^0.4.1",
|
||||
"minimist": "^1.2.0",
|
||||
"opencollective": "^1.0.3",
|
||||
|
@ -63,7 +63,7 @@
|
||||
"compression": "^1.7.0",
|
||||
"fs-extra": "^4.0.1",
|
||||
"vue-server-renderer": "~2.4.2",
|
||||
"@nuxtjs/youch": "3.0.1",
|
||||
"@nuxtjs/youch": "3.0.2",
|
||||
"source-map": "^0.5.6",
|
||||
"connect": "^3.6.3",
|
||||
"server-destroy": "^1.0.1"
|
||||
|
Loading…
Reference in New Issue
Block a user