From 866e31d1a6d0b921d2d4bddffac094427e529f13 Mon Sep 17 00:00:00 2001 From: Pooya Parsa Date: Fri, 18 Aug 2017 20:35:01 +0430 Subject: [PATCH] Spa Meta --- lib/common/utils.js | 11 +++++++++ lib/core/meta.js | 58 ++++++++++++++++++++++++++++++++++++++++++++ lib/core/renderer.js | 38 +++++++++++++++++------------ package.json | 1 + start/package.json | 2 +- 5 files changed, 93 insertions(+), 17 deletions(-) create mode 100644 lib/core/meta.js diff --git a/lib/common/utils.js b/lib/common/utils.js index 54a13cbaa1..c61c20b6b4 100644 --- a/lib/common/utils.js +++ b/lib/common/utils.js @@ -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 = [] diff --git a/lib/core/meta.js b/lib/core/meta.js new file mode 100644 index 0000000000..436cb05a2a --- /dev/null +++ b/lib/core/meta.js @@ -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 += `${this.options.head.title || ''}` + } + + // Meta + if (Array.isArray(this.options.head.meta)) { + this.options.head.meta.forEach(meta => { + head += `` + }) + } + + // Links + if (Array.isArray(this.options.head.link)) { + this.options.head.link.forEach(link => { + head += `` + }) + } + + // Style + if (Array.isArray(this.options.head.style)) { + this.options.head.link.forEach(style => { + head += `` + }) + } + + // Script + if (Array.isArray(this.options.head.script)) { + this.options.head.script.forEach(script => { + head += `` + }) + } + + this.cache.set(url, head) + + return head + } +} diff --git a/lib/core/renderer.js b/lib/core/renderer.js index 4604271d65..87c4c6b311 100644 --- a/lib/core/renderer.js +++ b/lib/core/renderer.js @@ -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: `
${this.resources.loadingHTML}
` - } + 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 = `
${this.resources.loadingHTML}
` - if (SPAData) { - Object.assign(data, SPAData) + const data = { + HTML_ATTRS, + BODY_ATTRS: '', + HEAD, + APP } const html = this.resources.spaTemplate(data) diff --git a/package.json b/package.json index f9b470a626..7b32760f02 100644 --- a/package.json +++ b/package.json @@ -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", diff --git a/start/package.json b/start/package.json index 1d0983566b..543558b56f 100644 --- a/start/package.json +++ b/start/package.json @@ -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"