mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-22 05:35:13 +00:00
feat(nuxt): allow configuring spa loading indicator (#21640)
This commit is contained in:
parent
343a46d5f9
commit
c66c82e6a0
@ -67,6 +67,11 @@ export default defineNuxtConfig({
|
||||
})
|
||||
```
|
||||
|
||||
::alert{type=info}
|
||||
If you do use `ssr: false`, you should also place an HTML file in `~/app/spa-loading-template.html` with some HTML you would like to use to render a loading screen that will be rendered until your app is hydrated.
|
||||
:ReadMore{link="/docs/api/configuration/nuxt-config#spaloadingindicator"}
|
||||
::
|
||||
|
||||
## Hybrid Rendering
|
||||
|
||||
Hybrid rendering allows different caching rules per route using **Route Rules** and decides how the server should respond to a new request on a given URL.
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { existsSync, promises as fsp } from 'node:fs'
|
||||
import { existsSync, promises as fsp, readFileSync } from 'node:fs'
|
||||
import { join, relative, resolve } from 'pathe'
|
||||
import { build, copyPublicAssets, createDevServer, createNitro, prepare, prerender, scanHandlers, writeTypes } from 'nitropack'
|
||||
import type { Nitro, NitroConfig } from 'nitropack'
|
||||
@ -10,6 +10,8 @@ import { dynamicEventHandler } from 'h3'
|
||||
import { createHeadCore } from '@unhead/vue'
|
||||
import { renderSSRHead } from '@unhead/ssr'
|
||||
import type { Nuxt } from 'nuxt/schema'
|
||||
// @ts-expect-error TODO: add legacy type support for subpath imports
|
||||
import { template as defaultSpaLoadingTemplate } from '@nuxt/ui-templates/templates/spa-loading-icon.mjs'
|
||||
|
||||
import { distDir } from '../dirs'
|
||||
import { ImportProtectionPlugin } from './plugins/import-protection'
|
||||
@ -29,6 +31,13 @@ export async function initNitro (nuxt: Nuxt & { _nitro?: Nitro }) {
|
||||
? [new RegExp(`node_modules\\/(?!${excludePaths.join('|')})`)]
|
||||
: [/node_modules/]
|
||||
|
||||
const spaLoadingTemplatePath = nuxt.options.spaLoadingTemplate ?? resolve(nuxt.options.srcDir, 'app/spa-loading-template.html')
|
||||
if (spaLoadingTemplatePath !== false && !existsSync(spaLoadingTemplatePath)) {
|
||||
if (nuxt.options.spaLoadingTemplate) {
|
||||
console.warn(`[nuxt] Could not load custom \`spaLoadingTemplate\` path as it does not exist: \`${spaLoadingTemplatePath}\`.`)
|
||||
}
|
||||
}
|
||||
|
||||
const nitroConfig: NitroConfig = defu(_nitroConfig, <NitroConfig>{
|
||||
debug: nuxt.options.debug,
|
||||
rootDir: nuxt.options.rootDir,
|
||||
@ -75,7 +84,15 @@ export async function initNitro (nuxt: Nuxt & { _nitro?: Nitro }) {
|
||||
devHandlers: [],
|
||||
baseURL: nuxt.options.app.baseURL,
|
||||
virtual: {
|
||||
'#internal/nuxt.config.mjs': () => nuxt.vfs['#build/nuxt.config']
|
||||
'#internal/nuxt.config.mjs': () => nuxt.vfs['#build/nuxt.config'],
|
||||
'#spa-template': () => {
|
||||
try {
|
||||
if (spaLoadingTemplatePath) {
|
||||
return `export const template = ${JSON.stringify(readFileSync(spaLoadingTemplatePath, 'utf-8'))}`
|
||||
}
|
||||
} catch {}
|
||||
return `export const template = ${JSON.stringify(defaultSpaLoadingTemplate({}))}`
|
||||
}
|
||||
},
|
||||
routeRules: {
|
||||
'/__nuxt_error': { cache: false }
|
||||
|
@ -112,9 +112,12 @@ const getSSRRenderer = lazyCachedFunction(async () => {
|
||||
const getSPARenderer = lazyCachedFunction(async () => {
|
||||
const manifest = await getClientManifest()
|
||||
|
||||
// @ts-expect-error virtual file
|
||||
const spaTemplate = await import('#spa-template').then(r => r.template).catch(() => '')
|
||||
|
||||
const options = {
|
||||
manifest,
|
||||
renderToString: () => `<${appRootTag} id="${appRootId}"></${appRootTag}>`,
|
||||
renderToString: () => `<${appRootTag} id="${appRootId}">${spaTemplate}</${appRootTag}>`,
|
||||
buildAssetsURL
|
||||
}
|
||||
// Create SPA renderer and cache the result for all requests
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { defineUntypedSchema } from 'untyped'
|
||||
import { defu } from 'defu'
|
||||
import { resolve } from 'pathe'
|
||||
import type { AppHeadMetaObject } from '../types/head'
|
||||
|
||||
export default defineUntypedSchema({
|
||||
@ -177,6 +178,65 @@ export default defineUntypedSchema({
|
||||
rootTag: 'div',
|
||||
},
|
||||
|
||||
/** A path to an HTML file, the contents of which will be inserted into any HTML page
|
||||
* rendered with `ssr: false`.
|
||||
*
|
||||
* By default Nuxt will look in `~/app/spa-loading-template.html` for this file.
|
||||
*
|
||||
* You can set this to `false` to disable any loading indicator.
|
||||
*
|
||||
* 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
|
||||
* ```html
|
||||
* <!-- https://github.com/barelyhuman/snips/blob/dev/pages/css-loader.md -->
|
||||
* <div class="loader"></div>
|
||||
* <style>
|
||||
* .loader {
|
||||
* display: block;
|
||||
* position: fixed;
|
||||
* z-index: 1031;
|
||||
* top: 50%;
|
||||
* left: 50%;
|
||||
* transform: translate(-50%, -50%);
|
||||
* width: 18px;
|
||||
* height: 18px;
|
||||
* box-sizing: border-box;
|
||||
* border: solid 2px transparent;
|
||||
* border-top-color: #000;
|
||||
* border-left-color: #000;
|
||||
* border-bottom-color: #efefef;
|
||||
* border-right-color: #efefef;
|
||||
* border-radius: 50%;
|
||||
* -webkit-animation: loader 400ms linear infinite;
|
||||
* animation: loader 400ms linear infinite;
|
||||
* }
|
||||
*
|
||||
* \@-webkit-keyframes loader {
|
||||
* 0% {
|
||||
* -webkit-transform: rotate(0deg);
|
||||
* }
|
||||
* 100% {
|
||||
* -webkit-transform: rotate(360deg);
|
||||
* }
|
||||
* }
|
||||
* \@keyframes loader {
|
||||
* 0% {
|
||||
* transform: rotate(0deg);
|
||||
* }
|
||||
* 100% {
|
||||
* transform: rotate(360deg);
|
||||
* }
|
||||
* }
|
||||
* </style>
|
||||
* ```
|
||||
*
|
||||
* @type {string | false}
|
||||
*/
|
||||
spaLoadingTemplate: {
|
||||
$resolve: async (val, get) => typeof val === 'string' ? resolve(await get('srcDir'), val) : (val ?? null)
|
||||
},
|
||||
|
||||
/**
|
||||
* An array of nuxt app plugins.
|
||||
*
|
||||
|
@ -5310,6 +5310,17 @@ packages:
|
||||
slash: 3.0.0
|
||||
dev: true
|
||||
|
||||
/globby@13.1.4:
|
||||
resolution: {integrity: sha512-iui/IiiW+QrJ1X1hKH5qwlMQyv34wJAYwH1vrf8b9kBA4sNiif3gKsMHa+BrdnOpEudWjpotfa7LrTzB1ERS/g==}
|
||||
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
|
||||
dependencies:
|
||||
dir-glob: 3.0.1
|
||||
fast-glob: 3.2.12
|
||||
ignore: 5.2.4
|
||||
merge2: 1.4.1
|
||||
slash: 4.0.0
|
||||
dev: true
|
||||
|
||||
/globby@13.2.0:
|
||||
resolution: {integrity: sha512-jWsQfayf13NvqKUIL3Ta+CIqMnvlaIDFveWE/dpOZ9+3AMEJozsxDvKA02zync9UuvOM8rOXzsD5GqKP4OnWPQ==}
|
||||
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
|
||||
@ -6425,7 +6436,7 @@ packages:
|
||||
defu: 6.1.2
|
||||
esbuild: 0.17.19
|
||||
fs-extra: 11.1.1
|
||||
globby: 13.2.0
|
||||
globby: 13.1.4
|
||||
jiti: 1.18.2
|
||||
mlly: 1.3.0
|
||||
mri: 1.2.0
|
||||
@ -8452,7 +8463,7 @@ packages:
|
||||
consola: 3.1.0
|
||||
defu: 6.1.2
|
||||
esbuild: 0.17.19
|
||||
globby: 13.2.0
|
||||
globby: 13.1.4
|
||||
hookable: 5.5.3
|
||||
jiti: 1.18.2
|
||||
magic-string: 0.30.0
|
||||
|
@ -35,7 +35,7 @@ describe.skipIf(process.env.SKIP_BUNDLE_SIZE === 'true' || process.env.ECOSYSTEM
|
||||
|
||||
it('default server bundle size', async () => {
|
||||
stats.server = await analyzeSizes(['**/*.mjs', '!node_modules'], serverDir)
|
||||
expect.soft(roundToKilobytes(stats.server.totalBytes)).toMatchInlineSnapshot('"61.3k"')
|
||||
expect.soft(roundToKilobytes(stats.server.totalBytes)).toMatchInlineSnapshot('"62.1k"')
|
||||
|
||||
const modules = await analyzeSizes('node_modules/**/*', serverDir)
|
||||
expect.soft(roundToKilobytes(modules.totalBytes)).toMatchInlineSnapshot('"2295k"')
|
||||
|
Loading…
Reference in New Issue
Block a user