feat(nuxt): layers support for spa loading template (#24709)

This commit is contained in:
Alper Doğan 2023-12-13 14:54:56 +03:00 committed by GitHub
parent 1de44a5a5c
commit 3cc333690b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 22 additions and 11 deletions

View File

@ -6,7 +6,7 @@ import { randomUUID } from 'uncrypto'
import { joinURL, withTrailingSlash } from 'ufo'
import { build, copyPublicAssets, createDevServer, createNitro, prepare, prerender, scanHandlers, writeTypes } from 'nitropack'
import type { Nitro, NitroConfig } from 'nitropack'
import { logger, resolveIgnorePatterns, resolveNuxtModule } from '@nuxt/kit'
import { findPath, logger, resolveIgnorePatterns, resolveNuxtModule } from '@nuxt/kit'
import escapeRE from 'escape-string-regexp'
import { defu } from 'defu'
import fsExtra from 'fs-extra'
@ -98,7 +98,7 @@ export async function initNitro (nuxt: Nuxt & { _nitro?: Nitro }) {
baseURL: nuxt.options.app.baseURL,
virtual: {
'#internal/nuxt.config.mjs': () => nuxt.vfs['#build/nuxt.config'],
'#spa-template': () => `export const template = ${JSON.stringify(spaLoadingTemplate(nuxt))}`
'#spa-template': async () => `export const template = ${JSON.stringify(await spaLoadingTemplate(nuxt))}`
},
routeRules: {
'/__nuxt_error': { cache: false }
@ -377,8 +377,9 @@ export async function initNitro (nuxt: Nuxt & { _nitro?: Nitro }) {
const nitro = await createNitro(nitroConfig)
// Trigger Nitro reload when SPA loading template changes
const spaLoadingTemplateFilePath = await spaLoadingTemplatePath(nuxt)
nuxt.hook('builder:watch', async (_event, path) => {
if (normalize(path) === spaLoadingTemplatePath(nuxt)) {
if (normalize(path) === spaLoadingTemplateFilePath) {
await nitro.hooks.callHook('rollup:reload')
}
})
@ -524,16 +525,20 @@ function relativeWithDot (from: string, to: string) {
return relative(from, to).replace(/^([^.])/, './$1') || '.'
}
function spaLoadingTemplatePath (nuxt: Nuxt) {
return typeof nuxt.options.spaLoadingTemplate === 'string'
? resolve(nuxt.options.srcDir, nuxt.options.spaLoadingTemplate)
: resolve(nuxt.options.srcDir, 'app/spa-loading-template.html')
async function spaLoadingTemplatePath (nuxt: Nuxt) {
if (typeof nuxt.options.spaLoadingTemplate === 'string') {
return resolve(nuxt.options.srcDir, nuxt.options.spaLoadingTemplate)
}
function spaLoadingTemplate (nuxt: Nuxt) {
const possiblePaths = nuxt.options._layers.map(layer => join(layer.config.srcDir, 'app/spa-loading-template.html'))
return await findPath(possiblePaths) ?? resolve(nuxt.options.srcDir, 'app/spa-loading-template.html')
}
async function spaLoadingTemplate (nuxt: Nuxt) {
if (nuxt.options.spaLoadingTemplate === false) { return '' }
const spaLoadingTemplate = spaLoadingTemplatePath(nuxt)
const spaLoadingTemplate = await spaLoadingTemplatePath(nuxt)
try {
if (existsSync(spaLoadingTemplate)) {

View File

@ -181,9 +181,10 @@ export default defineUntypedSchema({
/**
* Boolean or a path to an HTML file with the contents of which will be inserted into any HTML page
* rendered with `ssr: false`.
* - If it is unset, it will use `~/app/spa-loading-template.html` if it exists.
* - If it is unset, it will use `~/app/spa-loading-template.html` file in one of your layers, if it exists.
* - If it is false, no SPA loading indicator will be loaded.
* - If true, Nuxt will look for `~/app/spa-loading-template.html` file or a default Nuxt image will be used.
* - If true, Nuxt will look for `~/app/spa-loading-template.html` file in one of your layers, or a
* default Nuxt image will be used.
*
* Some good sources for spinners are [SpinKit](https://github.com/tobiasahlin/SpinKit) or [SVG Spinners](https://icones.js.org/collection/svg-spinners).
* @example ~/app/spa-loading-template.html

View File

@ -64,6 +64,11 @@ describe('route rules', () => {
await expectNoClientErrors('/route-rules/spa')
})
it('should not render loading template in spa mode if it is not enabled', async () => {
const html = await $fetch('/route-rules/spa')
expect(html).toContain('<div id="__nuxt"></div>')
})
it('should allow defining route rules inline', async () => {
const res = await fetch('/route-rules/inline')
expect(res.status).toEqual(200)