mirror of
https://github.com/nuxt/nuxt.git
synced 2025-02-18 14:41:25 +00:00
feat: configurable global name (#4012)
Co-authored-by: JuliaNeumann <jn.julianeumann@gmail.com>
This commit is contained in:
parent
c2fde1958a
commit
a3dd7dad6b
@ -37,7 +37,7 @@ export default {
|
|||||||
|
|
||||||
return h('div',{
|
return h('div',{
|
||||||
domProps: {
|
domProps: {
|
||||||
id: '__nuxt'
|
id: '<%= globals.id %>'
|
||||||
}
|
}
|
||||||
}, [
|
}, [
|
||||||
<% if (loading) { %>loadingEl,<% } %>
|
<% if (loading) { %>loadingEl,<% } %>
|
||||||
@ -53,10 +53,13 @@ export default {
|
|||||||
},
|
},
|
||||||
created () {
|
created () {
|
||||||
// Add this.$nuxt in child instances
|
// Add this.$nuxt in child instances
|
||||||
Vue.prototype.$nuxt = this
|
Vue.prototype.<%= globals.nuxt %> = this
|
||||||
// add to window so we can listen when ready
|
// add to window so we can listen when ready
|
||||||
if (typeof window !== 'undefined') {
|
if (typeof window !== 'undefined') {
|
||||||
window.$nuxt = this
|
window.<%= globals.nuxt %> = this
|
||||||
|
<% if (globals.nuxt !== '$nuxt') { %>
|
||||||
|
window.$nuxt = true
|
||||||
|
<% } %>
|
||||||
}
|
}
|
||||||
// Add $nuxt.error()
|
// Add $nuxt.error()
|
||||||
this.error = this.nuxt.error
|
this.error = this.nuxt.error
|
||||||
@ -100,8 +103,8 @@ export default {
|
|||||||
return resolvedLayouts[_layout]
|
return resolvedLayouts[_layout]
|
||||||
})
|
})
|
||||||
.catch((e) => {
|
.catch((e) => {
|
||||||
if (this.$nuxt) {
|
if (this.<%= globals.nuxt %>) {
|
||||||
return this.$nuxt.error({ statusCode: 500, message: e.message })
|
return this.<%= globals.nuxt %>.error({ statusCode: 500, message: e.message })
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -27,14 +27,15 @@ let router
|
|||||||
<% if (store) { %>let store<% } %>
|
<% if (store) { %>let store<% } %>
|
||||||
|
|
||||||
// Try to rehydrate SSR data from window
|
// Try to rehydrate SSR data from window
|
||||||
const NUXT = window.__NUXT__ || {}
|
const NUXT = window.<%= globals.context %> || {}
|
||||||
|
|
||||||
Object.assign(Vue.config, <%= serialize(vue.config) %>)
|
Object.assign(Vue.config, <%= serialize(vue.config) %>)
|
||||||
|
|
||||||
<% if (debug || mode === 'spa') { %>
|
<% if (debug || mode === 'spa') { %>
|
||||||
// Setup global Vue error handler
|
// Setup global Vue error handler
|
||||||
const defaultErrorHandler = Vue.config.errorHandler
|
if (!Vue.config.$nuxt) {
|
||||||
Vue.config.errorHandler = (err, vm, info, ...rest) => {
|
const defaultErrorHandler = Vue.config.errorHandler
|
||||||
|
Vue.config.errorHandler = (err, vm, info, ...rest) => {
|
||||||
const nuxtError = {
|
const nuxtError = {
|
||||||
statusCode: err.statusCode || err.name || 'Whoops!',
|
statusCode: err.statusCode || err.name || 'Whoops!',
|
||||||
message: err.message || err.toString()
|
message: err.message || err.toString()
|
||||||
@ -49,10 +50,16 @@ Vue.config.errorHandler = (err, vm, info, ...rest) => {
|
|||||||
return handled
|
return handled
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (vm && vm.$root) {
|
||||||
|
const nuxtApp = Object.keys(Vue.config.$nuxt)
|
||||||
|
.find(nuxtInstance => vm.$root[nuxtInstance])
|
||||||
|
|
||||||
// Show Nuxt Error Page
|
// Show Nuxt Error Page
|
||||||
if (vm && vm.$root && vm.$root.$nuxt && vm.$root.$nuxt.error && info !== 'render function') {
|
if (nuxtApp && vm.$root[nuxtApp].error && info !== 'render function') {
|
||||||
vm.$root.$nuxt.error(nuxtError)
|
vm.$root[nuxtApp].error(nuxtError)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (typeof defaultErrorHandler === 'function') {
|
if (typeof defaultErrorHandler === 'function') {
|
||||||
return handled
|
return handled
|
||||||
}
|
}
|
||||||
@ -63,7 +70,11 @@ Vue.config.errorHandler = (err, vm, info, ...rest) => {
|
|||||||
} else {
|
} else {
|
||||||
console.error(err.message || nuxtError.message)
|
console.error(err.message || nuxtError.message)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
Vue.config.$nuxt = {}
|
||||||
}
|
}
|
||||||
|
Vue.config.$nuxt.<%= globals.nuxt %> = true
|
||||||
|
|
||||||
<% } %>
|
<% } %>
|
||||||
|
|
||||||
// Create and mount App
|
// Create and mount App
|
||||||
@ -142,7 +153,7 @@ async function loadAsyncComponents (to, from, next) {
|
|||||||
err = err || {}
|
err = err || {}
|
||||||
const statusCode = (err.statusCode || err.status || (err.response && err.response.status) || 500)
|
const statusCode = (err.statusCode || err.status || (err.response && err.response.status) || 500)
|
||||||
this.error({ statusCode, message: err.message })
|
this.error({ statusCode, message: err.message })
|
||||||
this.$nuxt.$emit('routeChanged', to, from, err)
|
this.<%= globals.nuxt %>.$emit('routeChanged', to, from, err)
|
||||||
next(false)
|
next(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -401,7 +412,7 @@ async function render (to, from, next) {
|
|||||||
if (!error) {
|
if (!error) {
|
||||||
error = {}
|
error = {}
|
||||||
} else if (error.message === 'ERR_REDIRECT') {
|
} else if (error.message === 'ERR_REDIRECT') {
|
||||||
return this.$nuxt.$emit('routeChanged', to, from, error)
|
return this.<%= globals.nuxt %>.$emit('routeChanged', to, from, error)
|
||||||
}
|
}
|
||||||
_lastPaths = []
|
_lastPaths = []
|
||||||
const errorResponseStatus = (error.response && error.response.status)
|
const errorResponseStatus = (error.response && error.response.status)
|
||||||
@ -417,7 +428,7 @@ async function render (to, from, next) {
|
|||||||
await this.loadLayout(layout)
|
await this.loadLayout(layout)
|
||||||
|
|
||||||
this.error(error)
|
this.error(error)
|
||||||
this.$nuxt.$emit('routeChanged', to, from, error)
|
this.<%= globals.nuxt %>.$emit('routeChanged', to, from, error)
|
||||||
next(false)
|
next(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -489,19 +500,19 @@ function fixPrepatch(to, ___) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function nuxtReady (_app) {
|
function nuxtReady (_app) {
|
||||||
window._nuxtReadyCbs.forEach((cb) => {
|
window.<%= globals.readyCallback %>Cbs.forEach((cb) => {
|
||||||
if (typeof cb === 'function') {
|
if (typeof cb === 'function') {
|
||||||
cb(_app)
|
cb(_app)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
// Special JSDOM
|
// Special JSDOM
|
||||||
if (typeof window._onNuxtLoaded === 'function') {
|
if (typeof window.<%= globals.loadedCallback %> === 'function') {
|
||||||
window._onNuxtLoaded(_app)
|
window.<%= globals.loadedCallback %>(_app)
|
||||||
}
|
}
|
||||||
// Add router hooks
|
// Add router hooks
|
||||||
router.afterEach((to, from) => {
|
router.afterEach((to, from) => {
|
||||||
// Wait for fixPrepatch + $data updates
|
// Wait for fixPrepatch + $data updates
|
||||||
Vue.nextTick(() => _app.$nuxt.$emit('routeChanged', to, from))
|
Vue.nextTick(() => _app.<%= globals.nuxt %>.$emit('routeChanged', to, from))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -523,7 +534,7 @@ function getNuxtChildComponents($parent, $components = []) {
|
|||||||
function hotReloadAPI (_app) {
|
function hotReloadAPI (_app) {
|
||||||
if (!module.hot) return
|
if (!module.hot) return
|
||||||
|
|
||||||
let $components = getNuxtChildComponents(_app.$nuxt, [])
|
let $components = getNuxtChildComponents(_app.<%= globals.nuxt %>, [])
|
||||||
|
|
||||||
$components.forEach(addHotReload.bind(_app))
|
$components.forEach(addHotReload.bind(_app))
|
||||||
}
|
}
|
||||||
@ -623,11 +634,11 @@ async function mountApp(__app) {
|
|||||||
|
|
||||||
// Mounts Vue app to DOM element
|
// Mounts Vue app to DOM element
|
||||||
const mount = () => {
|
const mount = () => {
|
||||||
_app.$mount('#__nuxt')
|
_app.$mount('#<%= globals.id %>')
|
||||||
|
|
||||||
// Listen for first Vue update
|
// Listen for first Vue update
|
||||||
Vue.nextTick(() => {
|
Vue.nextTick(() => {
|
||||||
// Call window.onNuxtReady callbacks
|
// Call window.{{globals.readyCallback}} callbacks
|
||||||
nuxtReady(_app)
|
nuxtReady(_app)
|
||||||
<% if (isDev) { %>
|
<% if (isDev) { %>
|
||||||
// Enable hot reloading
|
// Enable hot reloading
|
||||||
|
@ -5,8 +5,8 @@ export default {
|
|||||||
render (h, { parent, data, props }) {
|
render (h, { parent, data, props }) {
|
||||||
data.nuxtChild = true
|
data.nuxtChild = true
|
||||||
const _parent = parent
|
const _parent = parent
|
||||||
const transitions = parent.$nuxt.nuxt.transitions
|
const transitions = parent.<%= globals.nuxt %>.nuxt.transitions
|
||||||
const defaultTransition = parent.$nuxt.nuxt.defaultTransition
|
const defaultTransition = parent.<%= globals.nuxt %>.nuxt.defaultTransition
|
||||||
|
|
||||||
let depth = 0
|
let depth = 0
|
||||||
while (parent) {
|
while (parent) {
|
||||||
@ -33,8 +33,8 @@ export default {
|
|||||||
let beforeEnter = listeners.beforeEnter
|
let beforeEnter = listeners.beforeEnter
|
||||||
listeners.beforeEnter = (el) => {
|
listeners.beforeEnter = (el) => {
|
||||||
// Ensure to trigger scroll event after calling scrollBehavior
|
// Ensure to trigger scroll event after calling scrollBehavior
|
||||||
window.$nuxt.$nextTick(() => {
|
window.<%= globals.nuxt %>.$nextTick(() => {
|
||||||
window.$nuxt.$emit('triggerScroll')
|
window.<%= globals.nuxt %>.$emit('triggerScroll')
|
||||||
})
|
})
|
||||||
if (beforeEnter) return beforeEnter.call(_parent, el)
|
if (beforeEnter) return beforeEnter.call(_parent, el)
|
||||||
}
|
}
|
||||||
|
@ -135,7 +135,7 @@ async function createApp (ssrContext) {
|
|||||||
store[key] = app[key]
|
store[key] = app[key]
|
||||||
<% } %>
|
<% } %>
|
||||||
// Check if plugin not already installed
|
// Check if plugin not already installed
|
||||||
const installKey = '__nuxt_' + key + '_installed__'
|
const installKey = '__<%= globals.pluginPrefix %>_' + key + '_installed__'
|
||||||
if (Vue[installKey]) return
|
if (Vue[installKey]) return
|
||||||
Vue[installKey] = true
|
Vue[installKey] = true
|
||||||
// Call Vue.use() to install the plugin into vm
|
// Call Vue.use() to install the plugin into vm
|
||||||
@ -153,8 +153,8 @@ async function createApp (ssrContext) {
|
|||||||
<% if (store) { %>
|
<% if (store) { %>
|
||||||
if (process.client) {
|
if (process.client) {
|
||||||
// Replace store state before plugins execution
|
// Replace store state before plugins execution
|
||||||
if (window.__NUXT__ && window.__NUXT__.state) {
|
if (window.<%= globals.context %> && window.<%= globals.context %>.state) {
|
||||||
store.replaceState(window.__NUXT__.state)
|
store.replaceState(window.<%= globals.context %>.state)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
<% } %>
|
<% } %>
|
||||||
|
@ -67,7 +67,7 @@ const scrollBehavior = function (to, from, savedPosition) {
|
|||||||
|
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
// wait for the out transition to complete (if necessary)
|
// wait for the out transition to complete (if necessary)
|
||||||
window.$nuxt.$once('triggerScroll', () => {
|
window.<%= globals.nuxt %>.$once('triggerScroll', () => {
|
||||||
// coords will be used if no selector is provided,
|
// coords will be used if no selector is provided,
|
||||||
// or if the selector didn't match any element.
|
// or if the selector didn't match any element.
|
||||||
if (to.hash) {
|
if (to.hash) {
|
||||||
|
@ -46,7 +46,7 @@ export default async (ssrContext) => {
|
|||||||
ssrContext.next = createNext(ssrContext)
|
ssrContext.next = createNext(ssrContext)
|
||||||
// Used for beforeNuxtRender({ Components, nuxtState })
|
// Used for beforeNuxtRender({ Components, nuxtState })
|
||||||
ssrContext.beforeRenderFns = []
|
ssrContext.beforeRenderFns = []
|
||||||
// Nuxt object (window.__NUXT__)
|
// Nuxt object (window{{globals.context}}, defaults to window.__NUXT__)
|
||||||
ssrContext.nuxt = { layout: 'default', data: [], error: null<%= (store ? ', state: null' : '') %>, serverRendered: true }
|
ssrContext.nuxt = { layout: 'default', data: [], error: null<%= (store ? ', state: null' : '') %>, serverRendered: true }
|
||||||
// Create the app definition and the instance (created for each request)
|
// Create the app definition and the instance (created for each request)
|
||||||
const { app, router<%= (store ? ', store' : '') %> } = await createApp(ssrContext)
|
const { app, router<%= (store ? ', store' : '') %> } = await createApp(ssrContext)
|
||||||
@ -125,7 +125,6 @@ export default async (ssrContext) => {
|
|||||||
await _app.loadLayout(layout)
|
await _app.loadLayout(layout)
|
||||||
if (ssrContext.nuxt.error) return renderErrorPage()
|
if (ssrContext.nuxt.error) return renderErrorPage()
|
||||||
layout = _app.setLayout(layout)
|
layout = _app.setLayout(layout)
|
||||||
// ...Set layout to __NUXT__
|
|
||||||
ssrContext.nuxt.layout = _app.layoutName
|
ssrContext.nuxt.layout = _app.layoutName
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -2,12 +2,12 @@ import Vue from 'vue'
|
|||||||
|
|
||||||
const noopData = () => ({})
|
const noopData = () => ({})
|
||||||
|
|
||||||
// window.onNuxtReady(() => console.log('Ready')) hook
|
// window.{{globals.loadedCallback}} hook
|
||||||
// Useful for jsdom testing or plugins (https://github.com/tmpvar/jsdom#dealing-with-asynchronous-script-loading)
|
// Useful for jsdom testing or plugins (https://github.com/tmpvar/jsdom#dealing-with-asynchronous-script-loading)
|
||||||
if (process.client) {
|
if (process.client) {
|
||||||
window._nuxtReadyCbs = []
|
window.<%= globals.readyCallback %>Cbs = []
|
||||||
window.onNuxtReady = (cb) => {
|
window.<%= globals.readyCallback %> = (cb) => {
|
||||||
window._nuxtReadyCbs.push(cb)
|
window.<%= globals.readyCallback %>Cbs.push(cb)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -134,7 +134,6 @@ export async function setContext(app, context) {
|
|||||||
if (!status) {
|
if (!status) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// Used in middleware
|
|
||||||
app.context._redirected = true
|
app.context._redirected = true
|
||||||
// if only 1 or 2 arguments: redirect('/') or redirect('/', { foo: 'bar' })
|
// if only 1 or 2 arguments: redirect('/') or redirect('/', { foo: 'bar' })
|
||||||
let pathType = typeof path
|
let pathType = typeof path
|
||||||
@ -171,8 +170,12 @@ export async function setContext(app, context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (process.server) app.context.beforeNuxtRender = fn => context.beforeRenderFns.push(fn)
|
if (process.server) {
|
||||||
if (process.client) app.context.nuxtState = window.__NUXT__
|
app.context.beforeNuxtRender = fn => context.beforeRenderFns.push(fn)
|
||||||
|
}
|
||||||
|
if (process.client) {
|
||||||
|
app.context.nuxtState = window.<%= globals.context %>
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Dynamic keys
|
// Dynamic keys
|
||||||
app.context.next = context.next
|
app.context.next = context.next
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<style>
|
<style>
|
||||||
body, html, #__nuxt {
|
body, html, #<%= globals.id %> {
|
||||||
background: <%= options.background %>;
|
background: <%= options.background %>;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<style>
|
<style>
|
||||||
body, html, #__nuxt {
|
body, html, #<%= globals.id %> {
|
||||||
background: <%= options.background %>;
|
background: <%= options.background %>;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<style>
|
<style>
|
||||||
body, html, #__nuxt {
|
body, html, #<%= globals.id %> {
|
||||||
background: <%= options.background %>;
|
background: <%= options.background %>;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<style>
|
<style>
|
||||||
body, html, #__nuxt {
|
body, html, #<%= globals.id %> {
|
||||||
background: <%= options.background %>;
|
background: <%= options.background %>;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<style>
|
<style>
|
||||||
body, html, #__nuxt {
|
body, html, #<%= globals.id %> {
|
||||||
background: <%= options.background %>;
|
background: <%= options.background %>;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<style>
|
<style>
|
||||||
body, html, #__nuxt {
|
body, html, #<%= globals.id %> {
|
||||||
background: <%= options.background %>;
|
background: <%= options.background %>;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<style>
|
<style>
|
||||||
body, html, #__nuxt {
|
body, html, #<%= globals.id %> {
|
||||||
background: <%= options.background %>;
|
background: <%= options.background %>;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<style>
|
<style>
|
||||||
body, html, #__nuxt {
|
body, html, #<%= globals.id %> {
|
||||||
background: <%= options.background %>;
|
background: <%= options.background %>;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<style>
|
<style>
|
||||||
body, html, #__nuxt {
|
body, html, #<%= globals.id %> {
|
||||||
background: <%= options.background %>;
|
background: <%= options.background %>;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<style>
|
<style>
|
||||||
body, html, #__nuxt {
|
body, html, #<%= globals.id %> {
|
||||||
background: <%= options.background %>;
|
background: <%= options.background %>;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<style>
|
<style>
|
||||||
body, html, #__nuxt {
|
body, html, #<%= globals.id %> {
|
||||||
background: <%= options.background %>;
|
background: <%= options.background %>;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
@ -16,9 +16,19 @@ import Glob from 'glob'
|
|||||||
import upath from 'upath'
|
import upath from 'upath'
|
||||||
import consola from 'consola'
|
import consola from 'consola'
|
||||||
|
|
||||||
import { r, wp, wChunk, createRoutes, parallel, sequence, relativeTo, waitFor } from '../common/utils'
|
import {
|
||||||
import Options from '../common/options'
|
r,
|
||||||
|
wp,
|
||||||
|
wChunk,
|
||||||
|
createRoutes,
|
||||||
|
parallel,
|
||||||
|
sequence,
|
||||||
|
relativeTo,
|
||||||
|
waitFor,
|
||||||
|
determineGlobals
|
||||||
|
} from '../common/utils'
|
||||||
|
|
||||||
|
import Options from '../common/options'
|
||||||
import PerfLoader from './webpack/utils/perf-loader'
|
import PerfLoader from './webpack/utils/perf-loader'
|
||||||
import ClientWebpackConfig from './webpack/client'
|
import ClientWebpackConfig from './webpack/client'
|
||||||
import ServerWebpackConfig from './webpack/server'
|
import ServerWebpackConfig from './webpack/server'
|
||||||
@ -30,6 +40,7 @@ export default class Builder {
|
|||||||
this.nuxt = nuxt
|
this.nuxt = nuxt
|
||||||
this.isStatic = false // Flag to know if the build is for a generated app
|
this.isStatic = false // Flag to know if the build is for a generated app
|
||||||
this.options = nuxt.options
|
this.options = nuxt.options
|
||||||
|
this.globals = determineGlobals(nuxt.options.globalName, nuxt.options.globals)
|
||||||
|
|
||||||
// Fields that set on build
|
// Fields that set on build
|
||||||
this.compilers = []
|
this.compilers = []
|
||||||
@ -214,6 +225,8 @@ export default class Builder {
|
|||||||
head: this.options.head,
|
head: this.options.head,
|
||||||
middleware: fsExtra.existsSync(path.join(this.options.srcDir, this.options.dir.middleware)),
|
middleware: fsExtra.existsSync(path.join(this.options.srcDir, this.options.dir.middleware)),
|
||||||
store: this.options.store,
|
store: this.options.store,
|
||||||
|
globalName: this.options.globalName,
|
||||||
|
globals: this.globals,
|
||||||
css: this.options.css,
|
css: this.options.css,
|
||||||
plugins: this.plugins,
|
plugins: this.plugins,
|
||||||
appPath: './App.js',
|
appPath: './App.js',
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import path from 'path'
|
import path from 'path'
|
||||||
import fs from 'fs'
|
import fs from 'fs'
|
||||||
|
import _ from 'lodash'
|
||||||
import env from 'std-env'
|
import env from 'std-env'
|
||||||
|
|
||||||
const nuxtDir = fs.existsSync(path.resolve(__dirname, '..', 'package.json'))
|
const nuxtDir = fs.existsSync(path.resolve(__dirname, '..', 'package.json'))
|
||||||
@ -14,6 +15,17 @@ export default {
|
|||||||
// Mode
|
// Mode
|
||||||
mode: 'universal',
|
mode: 'universal',
|
||||||
|
|
||||||
|
// Global name
|
||||||
|
globalName: `nuxt`,
|
||||||
|
globals: {
|
||||||
|
id: globalName => `__${globalName}`,
|
||||||
|
nuxt: globalName => `$${globalName}`,
|
||||||
|
context: globalName => `__${globalName.toUpperCase()}__`,
|
||||||
|
pluginPrefix: globalName => globalName,
|
||||||
|
readyCallback: globalName => `on${_.capitalize(globalName)}Ready`,
|
||||||
|
loadedCallback: globalName => `_on${_.capitalize(globalName)}Loaded`
|
||||||
|
},
|
||||||
|
|
||||||
// Server options
|
// Server options
|
||||||
server: {
|
server: {
|
||||||
https: false,
|
https: false,
|
||||||
|
@ -43,6 +43,10 @@ Options.from = function (_options) {
|
|||||||
options.extensions = [options.extensions]
|
options.extensions = [options.extensions]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
options.globalName = (_.isString(options.globalName) && /^[a-zA-Z]+$/.test(options.globalName))
|
||||||
|
? options.globalName.toLowerCase()
|
||||||
|
: 'nuxt'
|
||||||
|
|
||||||
// Resolve rootDir
|
// Resolve rootDir
|
||||||
options.rootDir = hasValue(options.rootDir) ? path.resolve(options.rootDir) : process.cwd()
|
options.rootDir = hasValue(options.rootDir) ? path.resolve(options.rootDir) : process.cwd()
|
||||||
|
|
||||||
|
@ -349,3 +349,15 @@ export const guardDir = function guardDir(options, key1, key2) {
|
|||||||
throw new Error(errorMessage)
|
throw new Error(errorMessage)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const determineGlobals = function determineGlobals(globalName, globals) {
|
||||||
|
const _globals = {}
|
||||||
|
for (const global in globals) {
|
||||||
|
if (typeof globals[global] === 'function') {
|
||||||
|
_globals[global] = globals[global](globalName)
|
||||||
|
} else {
|
||||||
|
_globals[global] = globals[global]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return _globals
|
||||||
|
}
|
||||||
|
@ -10,7 +10,7 @@ import connect from 'connect'
|
|||||||
import launchMiddleware from 'launch-editor-middleware'
|
import launchMiddleware from 'launch-editor-middleware'
|
||||||
import consola from 'consola'
|
import consola from 'consola'
|
||||||
|
|
||||||
import { isUrl, timeout, waitFor } from '../common/utils'
|
import { isUrl, timeout, waitFor, determineGlobals } from '../common/utils'
|
||||||
import defaults from '../common/nuxt.config'
|
import defaults from '../common/nuxt.config'
|
||||||
|
|
||||||
import MetaRenderer from './meta'
|
import MetaRenderer from './meta'
|
||||||
@ -23,6 +23,7 @@ export default class Renderer {
|
|||||||
constructor(nuxt) {
|
constructor(nuxt) {
|
||||||
this.nuxt = nuxt
|
this.nuxt = nuxt
|
||||||
this.options = nuxt.options
|
this.options = nuxt.options
|
||||||
|
this.globals = determineGlobals(nuxt.options.globalName, nuxt.options.globals)
|
||||||
|
|
||||||
// Will be set by createRenderer
|
// Will be set by createRenderer
|
||||||
this.bundleRenderer = null
|
this.bundleRenderer = null
|
||||||
@ -311,7 +312,7 @@ export default class Renderer {
|
|||||||
getPreloadFiles
|
getPreloadFiles
|
||||||
} = await this.metaRenderer.render(context)
|
} = await this.metaRenderer.render(context)
|
||||||
const APP =
|
const APP =
|
||||||
`<div id="__nuxt">${this.resources.loadingHTML}</div>` + BODY_SCRIPTS
|
`<div id="${this.globals.id}">${this.resources.loadingHTML}</div>` + BODY_SCRIPTS
|
||||||
|
|
||||||
// Detect 404 errors
|
// Detect 404 errors
|
||||||
if (
|
if (
|
||||||
@ -341,7 +342,7 @@ export default class Renderer {
|
|||||||
let APP = await this.bundleRenderer.renderToString(context)
|
let APP = await this.bundleRenderer.renderToString(context)
|
||||||
|
|
||||||
if (!context.nuxt.serverRendered) {
|
if (!context.nuxt.serverRendered) {
|
||||||
APP = '<div id="__nuxt"></div>'
|
APP = `<div id="${this.globals.id}"></div>`
|
||||||
}
|
}
|
||||||
const m = context.meta.inject()
|
const m = context.meta.inject()
|
||||||
let HEAD =
|
let HEAD =
|
||||||
@ -361,7 +362,7 @@ export default class Renderer {
|
|||||||
|
|
||||||
await this.nuxt.callHook('render:routeContext', context.nuxt)
|
await this.nuxt.callHook('render:routeContext', context.nuxt)
|
||||||
|
|
||||||
const serializedSession = `window.__NUXT__=${devalue(context.nuxt)};`
|
const serializedSession = `window.${this.globals.context}=${devalue(context.nuxt)};`
|
||||||
|
|
||||||
const cspScriptSrcHashSet = new Set()
|
const cspScriptSrcHashSet = new Set()
|
||||||
if (this.options.render.csp) {
|
if (this.options.render.csp) {
|
||||||
@ -430,7 +431,7 @@ export default class Renderer {
|
|||||||
const { window } = await jsdom.JSDOM.fromURL(url, options)
|
const { window } = await jsdom.JSDOM.fromURL(url, options)
|
||||||
// If Nuxt could not be loaded (error from the server-side)
|
// If Nuxt could not be loaded (error from the server-side)
|
||||||
const nuxtExists = window.document.body.innerHTML.includes(
|
const nuxtExists = window.document.body.innerHTML.includes(
|
||||||
this.options.render.ssr ? 'window.__NUXT__' : '<div id="__nuxt">'
|
this.options.render.ssr ? `window.${this.globals.context}` : `<div id="${this.globals.id}">`
|
||||||
)
|
)
|
||||||
/* istanbul ignore if */
|
/* istanbul ignore if */
|
||||||
if (!nuxtExists) {
|
if (!nuxtExists) {
|
||||||
@ -439,8 +440,9 @@ export default class Renderer {
|
|||||||
throw error
|
throw error
|
||||||
}
|
}
|
||||||
// Used by nuxt.js to say when the components are loaded and the app ready
|
// Used by nuxt.js to say when the components are loaded and the app ready
|
||||||
|
const onNuxtLoaded = this.globals.loadedCallback
|
||||||
await timeout(new Promise((resolve) => {
|
await timeout(new Promise((resolve) => {
|
||||||
window._onNuxtLoaded = () => resolve(window)
|
window[onNuxtLoaded] = () => resolve(window)
|
||||||
}), 20000, 'Components loading in renderAndGetWindow was not completed in 20s')
|
}), 20000, 'Components loading in renderAndGetWindow was not completed in 20s')
|
||||||
if (options.virtualConsole) {
|
if (options.virtualConsole) {
|
||||||
// after window initialized successfully
|
// after window initialized successfully
|
||||||
|
4
test/fixtures/with-config/nuxt.config.js
vendored
4
test/fixtures/with-config/nuxt.config.js
vendored
@ -91,5 +91,9 @@ export default {
|
|||||||
static: {
|
static: {
|
||||||
maxAge: '1y'
|
maxAge: '1y'
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
globalName: 'noxxt',
|
||||||
|
globals: {
|
||||||
|
id: 'custom-nuxt-id'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,4 +21,20 @@ describe('basic config defaults', () => {
|
|||||||
expect(options.build.vendor).toBeUndefined()
|
expect(options.build.vendor).toBeUndefined()
|
||||||
expect(consola.warn).toHaveBeenCalledWith('vendor has been deprecated due to webpack4 optimization')
|
expect(consola.warn).toHaveBeenCalledWith('vendor has been deprecated due to webpack4 optimization')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('globalName uses nuxt as default if not set', () => {
|
||||||
|
const options = Options.from({})
|
||||||
|
expect(options.globalName).toEqual('nuxt')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('globalName uses nuxt as default if set to something other than only letters', () => {
|
||||||
|
let options = Options.from({ globalName: '12foo4' })
|
||||||
|
expect(options.globalName).toEqual('nuxt')
|
||||||
|
|
||||||
|
options = Options.from({ globalName: 'foo bar' })
|
||||||
|
expect(options.globalName).toEqual('nuxt')
|
||||||
|
|
||||||
|
options = Options.from({ globalName: 'foo?' })
|
||||||
|
expect(options.globalName).toEqual('nuxt')
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
@ -51,11 +51,22 @@ describe('with-config', () => {
|
|||||||
expect(html.includes('::-webkit-input-placeholder')).toBe(true)
|
expect(html.includes('::-webkit-input-placeholder')).toBe(true)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('/test/ (custom globalName)', async () => {
|
||||||
|
const window = await nuxt.renderAndGetWindow(url('/test/'))
|
||||||
|
const html = window.document.body.innerHTML
|
||||||
|
expect(html.includes('id="custom-nuxt-id">')).toBe(true)
|
||||||
|
expect(html.includes('id="__nuxt">')).toBe(false)
|
||||||
|
expect(window.__NOXXT__).toBeDefined()
|
||||||
|
expect(window.__NUXT__).toBeUndefined()
|
||||||
|
expect(window.$noxxt).toBeDefined()
|
||||||
|
expect(window.$nuxt).toBeDefined() // for Vue Dev Tools detection
|
||||||
|
})
|
||||||
|
|
||||||
test('/test/ (router base)', async () => {
|
test('/test/ (router base)', async () => {
|
||||||
const window = await nuxt.renderAndGetWindow(url('/test/'))
|
const window = await nuxt.renderAndGetWindow(url('/test/'))
|
||||||
|
|
||||||
const html = window.document.body.innerHTML
|
const html = window.document.body.innerHTML
|
||||||
expect(window.__NUXT__.layout).toBe('default')
|
expect(window.__NOXXT__.layout).toBe('default')
|
||||||
expect(html.includes('<h1>Default layout</h1>')).toBe(true)
|
expect(html.includes('<h1>Default layout</h1>')).toBe(true)
|
||||||
expect(html.includes('<h1>I have custom configurations</h1>')).toBe(true)
|
expect(html.includes('<h1>I have custom configurations</h1>')).toBe(true)
|
||||||
|
|
||||||
@ -65,7 +76,7 @@ describe('with-config', () => {
|
|||||||
test('/test/about (custom layout)', async () => {
|
test('/test/about (custom layout)', async () => {
|
||||||
const window = await nuxt.renderAndGetWindow(url('/test/about'))
|
const window = await nuxt.renderAndGetWindow(url('/test/about'))
|
||||||
const html = window.document.body.innerHTML
|
const html = window.document.body.innerHTML
|
||||||
expect(window.__NUXT__.layout).toBe('custom')
|
expect(window.__NOXXT__.layout).toBe('custom')
|
||||||
expect(html.includes('<h1>Custom layout</h1>')).toBe(true)
|
expect(html.includes('<h1>Custom layout</h1>')).toBe(true)
|
||||||
expect(html.includes('<h1>About page</h1>')).toBe(true)
|
expect(html.includes('<h1>About page</h1>')).toBe(true)
|
||||||
})
|
})
|
||||||
@ -73,7 +84,7 @@ describe('with-config', () => {
|
|||||||
test('/test/desktop (custom layout in desktop folder)', async () => {
|
test('/test/desktop (custom layout in desktop folder)', async () => {
|
||||||
const window = await nuxt.renderAndGetWindow(url('/test/desktop'))
|
const window = await nuxt.renderAndGetWindow(url('/test/desktop'))
|
||||||
const html = window.document.body.innerHTML
|
const html = window.document.body.innerHTML
|
||||||
expect(window.__NUXT__.layout).toBe('desktop/default')
|
expect(window.__NOXXT__.layout).toBe('desktop/default')
|
||||||
expect(html.includes('<h1>Default desktop layout</h1>')).toBe(true)
|
expect(html.includes('<h1>Default desktop layout</h1>')).toBe(true)
|
||||||
expect(html.includes('<h1>Desktop page</h1>')).toBe(true)
|
expect(html.includes('<h1>Desktop page</h1>')).toBe(true)
|
||||||
})
|
})
|
||||||
@ -81,7 +92,7 @@ describe('with-config', () => {
|
|||||||
test('/test/mobile (custom layout in mobile folder)', async () => {
|
test('/test/mobile (custom layout in mobile folder)', async () => {
|
||||||
const window = await nuxt.renderAndGetWindow(url('/test/mobile'))
|
const window = await nuxt.renderAndGetWindow(url('/test/mobile'))
|
||||||
const html = window.document.body.innerHTML
|
const html = window.document.body.innerHTML
|
||||||
expect(window.__NUXT__.layout).toBe('mobile/default')
|
expect(window.__NOXXT__.layout).toBe('mobile/default')
|
||||||
expect(html.includes('<h1>Default mobile layout</h1>')).toBe(true)
|
expect(html.includes('<h1>Default mobile layout</h1>')).toBe(true)
|
||||||
expect(html.includes('<h1>Mobile page</h1>')).toBe(true)
|
expect(html.includes('<h1>Mobile page</h1>')).toBe(true)
|
||||||
})
|
})
|
||||||
|
@ -19,11 +19,12 @@ export default class Browser {
|
|||||||
await this.browser.close()
|
await this.browser.close()
|
||||||
}
|
}
|
||||||
|
|
||||||
async page(url) {
|
async page(url, globalName = 'nuxt') {
|
||||||
if (!this.browser) throw new Error('Please call start() before page(url)')
|
if (!this.browser) throw new Error('Please call start() before page(url)')
|
||||||
const page = await this.browser.newPage()
|
const page = await this.browser.newPage()
|
||||||
await page.goto(url)
|
await page.goto(url)
|
||||||
await page.waitForFunction('!!window.$nuxt')
|
page.$nuxtGlobalHandle = `window.$${globalName}`
|
||||||
|
await page.waitForFunction(`!!${page.$nuxtGlobalHandle}`)
|
||||||
page.html = () =>
|
page.html = () =>
|
||||||
page.evaluate(() => window.document.documentElement.outerHTML)
|
page.evaluate(() => window.document.documentElement.outerHTML)
|
||||||
page.$text = selector => page.$eval(selector, el => el.textContent)
|
page.$text = selector => page.$eval(selector, el => el.textContent)
|
||||||
@ -37,21 +38,24 @@ export default class Browser {
|
|||||||
(els, attr) => els.map(el => el.getAttribute(attr)),
|
(els, attr) => els.map(el => el.getAttribute(attr)),
|
||||||
attr
|
attr
|
||||||
)
|
)
|
||||||
page.$nuxt = await page.evaluateHandle('window.$nuxt')
|
|
||||||
|
page.$nuxt = await page.evaluateHandle(page.$nuxtGlobalHandle)
|
||||||
|
|
||||||
page.nuxt = {
|
page.nuxt = {
|
||||||
async navigate(path, waitEnd = true) {
|
async navigate(path, waitEnd = true) {
|
||||||
const hook = page.evaluate(() => {
|
const hook = page.evaluate(`
|
||||||
return new Promise(resolve =>
|
new Promise(resolve =>
|
||||||
window.$nuxt.$once('routeChanged', resolve)
|
${page.$nuxtGlobalHandle}.$once('routeChanged', resolve)
|
||||||
).then(() => new Promise(resolve => setTimeout(resolve, 50)))
|
).then(() => new Promise(resolve => setTimeout(resolve, 50)))
|
||||||
})
|
`)
|
||||||
await page.evaluate(
|
await page.evaluate(
|
||||||
($nuxt, path) => $nuxt.$router.push(path),
|
($nuxt, path) => $nuxt.$router.push(path),
|
||||||
page.$nuxt,
|
page.$nuxt,
|
||||||
path
|
path
|
||||||
)
|
)
|
||||||
if (waitEnd) await hook
|
if (waitEnd) {
|
||||||
|
await hook
|
||||||
|
}
|
||||||
return { hook }
|
return { hook }
|
||||||
},
|
},
|
||||||
routeData() {
|
routeData() {
|
||||||
|
Loading…
Reference in New Issue
Block a user