mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-11 08:33:53 +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
|
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
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 { 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)
|
||||||
|
@ -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",
|
||||||
|
@ -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"
|
||||||
|
Loading…
Reference in New Issue
Block a user