mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-22 05:35:13 +00:00
feat(schema): v4 opt-in with future.compatibilityVersion
(#26925)
This commit is contained in:
parent
ed79a1d4bf
commit
505e706dcb
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
@ -198,6 +198,7 @@ jobs:
|
||||
builder: ["vite", "webpack"]
|
||||
context: ["async", "default"]
|
||||
manifest: ["manifest-on", "manifest-off"]
|
||||
version: ["v4", "v3"]
|
||||
node: [18]
|
||||
exclude:
|
||||
- env: "dev"
|
||||
@ -234,6 +235,7 @@ jobs:
|
||||
TEST_BUILDER: ${{ matrix.builder }}
|
||||
TEST_MANIFEST: ${{ matrix.manifest }}
|
||||
TEST_CONTEXT: ${{ matrix.context }}
|
||||
TEST_V4: ${{ matrix.version == 'v4' }}
|
||||
SKIP_BUNDLE_SIZE: ${{ github.event_name != 'push' || matrix.env == 'dev' || matrix.builder == 'webpack' || matrix.context == 'default' || runner.os == 'Windows' }}
|
||||
|
||||
- uses: codecov/codecov-action@84508663e988701840491b86de86b666e8a86bed # v4.3.0
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { promises as fsp, mkdirSync, writeFileSync } from 'node:fs'
|
||||
import { dirname, join, relative, resolve } from 'pathe'
|
||||
import { defu } from 'defu'
|
||||
import { compileTemplate, findPath, logger, normalizePlugin, normalizeTemplate, resolveAlias, resolveFiles, resolvePath, templateUtils, tryResolveModule } from '@nuxt/kit'
|
||||
import { compileTemplate as _compileTemplate, findPath, logger, normalizePlugin, normalizeTemplate, resolveAlias, resolveFiles, resolvePath, templateUtils, tryResolveModule } from '@nuxt/kit'
|
||||
import type { Nuxt, NuxtApp, NuxtPlugin, NuxtTemplate, ResolvedNuxtTemplate } from 'nuxt/schema'
|
||||
|
||||
import * as defaultTemplates from './templates'
|
||||
@ -39,6 +39,8 @@ export async function generateApp (nuxt: Nuxt, app: NuxtApp, options: { filter?:
|
||||
const filteredTemplates = (app.templates as Array<ResolvedNuxtTemplate<any>>)
|
||||
.filter(template => !options.filter || options.filter(template))
|
||||
|
||||
const compileTemplate = nuxt.options.experimental.compileTemplate ? _compileTemplate : futureCompileTemplate
|
||||
|
||||
const writes: Array<() => void> = []
|
||||
await Promise.allSettled(filteredTemplates
|
||||
.map(async (template) => {
|
||||
@ -91,6 +93,24 @@ export async function generateApp (nuxt: Nuxt, app: NuxtApp, options: { filter?:
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
async function futureCompileTemplate<T> (template: NuxtTemplate<T>, ctx: { nuxt: Nuxt, app: NuxtApp, utils?: unknown }) {
|
||||
delete ctx.utils
|
||||
|
||||
if (template.src) {
|
||||
try {
|
||||
return await fsp.readFile(template.src, 'utf-8')
|
||||
} catch (err) {
|
||||
logger.error(`[nuxt] Error reading template from \`${template.src}\``)
|
||||
throw err
|
||||
}
|
||||
}
|
||||
if (template.getContents) {
|
||||
return template.getContents({ ...ctx, options: template.options! })
|
||||
}
|
||||
|
||||
throw new Error('[nuxt] Invalid template. Templates must have either `src` or `getContents`: ' + JSON.stringify(template))
|
||||
}
|
||||
|
||||
export async function resolveApp (nuxt: Nuxt, app: NuxtApp) {
|
||||
// Resolve main (app.vue)
|
||||
if (!app.mainComponent) {
|
||||
|
@ -85,7 +85,7 @@ function createWatcher () {
|
||||
})
|
||||
|
||||
// TODO: consider moving to emit absolute path in 3.8 or 4.0
|
||||
watcher.on('all', (event, path) => nuxt.callHook('builder:watch', event, normalize(relative(nuxt.options.srcDir, path))))
|
||||
watcher.on('all', (event, path) => nuxt.callHook('builder:watch', event, nuxt.options.experimental.relativeWatchPaths ? normalize(relative(nuxt.options.srcDir, path)) : normalize(path)))
|
||||
nuxt.hook('close', () => watcher?.close())
|
||||
}
|
||||
|
||||
@ -116,7 +116,7 @@ function createGranularWatcher () {
|
||||
path = normalize(path)
|
||||
if (!pending) {
|
||||
// TODO: consider moving to emit absolute path in 3.8 or 4.0
|
||||
nuxt.callHook('builder:watch', event, relative(nuxt.options.srcDir, path))
|
||||
nuxt.callHook('builder:watch', event, nuxt.options.experimental.relativeWatchPaths ? relative(nuxt.options.srcDir, path) : path)
|
||||
}
|
||||
if (event === 'unlinkDir' && path in watchers) {
|
||||
watchers[path]?.close()
|
||||
@ -125,7 +125,7 @@ function createGranularWatcher () {
|
||||
if (event === 'addDir' && path !== dir && !ignoredDirs.has(path) && !pathsToWatch.includes(path) && !(path in watchers) && !isIgnored(path)) {
|
||||
watchers[path] = chokidar.watch(path, { ...nuxt.options.watchers.chokidar, ignored: [isIgnored] })
|
||||
// TODO: consider moving to emit absolute path in 3.8 or 4.0
|
||||
watchers[path].on('all', (event, p) => nuxt.callHook('builder:watch', event, normalize(relative(nuxt.options.srcDir, p))))
|
||||
watchers[path].on('all', (event, p) => nuxt.callHook('builder:watch', event, nuxt.options.experimental.relativeWatchPaths ? normalize(relative(nuxt.options.srcDir, p)) : normalize(p)))
|
||||
nuxt.hook('close', () => watchers[path]?.close())
|
||||
}
|
||||
})
|
||||
@ -159,7 +159,7 @@ async function createParcelWatcher () {
|
||||
for (const event of events) {
|
||||
if (isIgnored(event.path)) { continue }
|
||||
// TODO: consider moving to emit absolute path in 3.8 or 4.0
|
||||
nuxt.callHook('builder:watch', watchEvents[event.type], normalize(relative(nuxt.options.srcDir, event.path)))
|
||||
nuxt.callHook('builder:watch', watchEvents[event.type], nuxt.options.experimental.relativeWatchPaths ? normalize(relative(nuxt.options.srcDir, event.path)) : normalize(event.path))
|
||||
}
|
||||
}, {
|
||||
ignore: [
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { pathToFileURL } from 'node:url'
|
||||
import { existsSync, promises as fsp, readFileSync } from 'node:fs'
|
||||
import { cpus } from 'node:os'
|
||||
import { join, normalize, relative, resolve } from 'pathe'
|
||||
import { join, relative, resolve } from 'pathe'
|
||||
import { createRouter as createRadixRouter, exportMatcher, toRouteMatcher } from 'radix3'
|
||||
import { randomUUID } from 'uncrypto'
|
||||
import { joinURL, withTrailingSlash } from 'ufo'
|
||||
@ -409,8 +409,9 @@ export async function initNitro (nuxt: Nuxt & { _nitro?: Nitro }) {
|
||||
|
||||
// Trigger Nitro reload when SPA loading template changes
|
||||
const spaLoadingTemplateFilePath = await spaLoadingTemplatePath(nuxt)
|
||||
nuxt.hook('builder:watch', async (_event, path) => {
|
||||
if (normalize(path) === spaLoadingTemplateFilePath) {
|
||||
nuxt.hook('builder:watch', async (_event, relativePath) => {
|
||||
const path = resolve(nuxt.options.srcDir, relativePath)
|
||||
if (path === spaLoadingTemplateFilePath) {
|
||||
await nitro.hooks.callHook('rollup:reload')
|
||||
}
|
||||
})
|
||||
|
@ -324,7 +324,7 @@ export default defineNuxtModule({
|
||||
}
|
||||
|
||||
nuxt.hook('builder:watch', async (event, relativePath) => {
|
||||
const path = join(nuxt.options.srcDir, relativePath)
|
||||
const path = resolve(nuxt.options.srcDir, relativePath)
|
||||
if (!(path in pageToGlobMap)) { return }
|
||||
if (event === 'unlink') {
|
||||
delete inlineRules[path]
|
||||
|
@ -6,6 +6,11 @@ export default defineUntypedSchema({
|
||||
* (possibly major) version of the framework.
|
||||
*/
|
||||
future: {
|
||||
/**
|
||||
* Enable early access to Nuxt v4 features or flags.
|
||||
* @type {3 | 4}
|
||||
*/
|
||||
compatibilityVersion: 3,
|
||||
/**
|
||||
* This enables 'Bundler' module resolution mode for TypeScript, which is the recommended setting
|
||||
* for frameworks like Nuxt and Vite.
|
||||
@ -329,7 +334,11 @@ export default defineUntypedSchema({
|
||||
* Options that apply to `useAsyncData` (and also therefore `useFetch`)
|
||||
*/
|
||||
useAsyncData: {
|
||||
deep: true,
|
||||
deep: {
|
||||
async $resolve (val, get) {
|
||||
return val ?? !((await get('future') as Record<string, unknown>).compatibilityVersion === 4)
|
||||
},
|
||||
},
|
||||
},
|
||||
/** @type {Pick<typeof import('ofetch')['FetchOptions'], 'timeout' | 'retry' | 'retryDelay' | 'retryStatusCodes'>} */
|
||||
useFetch: {},
|
||||
@ -349,5 +358,42 @@ export default defineUntypedSchema({
|
||||
* @type {boolean}
|
||||
*/
|
||||
clientNodeCompat: false,
|
||||
|
||||
/**
|
||||
* Whether to use `lodash.template` to compile Nuxt templates.
|
||||
*
|
||||
* This flag will be removed with the release of v4 and exists only for
|
||||
* advance testing within Nuxt v3.12+.
|
||||
*/
|
||||
compileTemplate: {
|
||||
async $resolve (val, get) {
|
||||
return val ?? ((await get('future') as Record<string, unknown>).compatibilityVersion !== 4)
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* Whether to provide a legacy `templateUtils` object (with `serialize`,
|
||||
* `importName` and `importSources`) when compiling Nuxt templates.
|
||||
*
|
||||
* This flag will be removed with the release of v4 and exists only for
|
||||
* advance testing within Nuxt v3.12+.
|
||||
*/
|
||||
templateUtils: {
|
||||
async $resolve (val, get) {
|
||||
return val ?? ((await get('future') as Record<string, unknown>).compatibilityVersion !== 4)
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* Whether to provide relative paths in the `builder:watch` hook.
|
||||
*
|
||||
* This flag will be removed with the release of v4 and exists only for
|
||||
* advance testing within Nuxt v3.12+.
|
||||
*/
|
||||
relativeWatchPaths: {
|
||||
async $resolve (val, get) {
|
||||
return val ?? ((await get('future') as Record<string, unknown>).compatibilityVersion !== 4)
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
1
test/fixtures/basic-types/nuxt.config.ts
vendored
1
test/fixtures/basic-types/nuxt.config.ts
vendored
@ -7,6 +7,7 @@ export default defineNuxtConfig({
|
||||
},
|
||||
future: {
|
||||
typescriptBundlerResolution: process.env.MODULE_RESOLUTION === 'bundler',
|
||||
compatibilityVersion: process.env.TEST_V4 === 'true' ? 4 : 3,
|
||||
},
|
||||
buildDir: process.env.NITRO_BUILD_DIR,
|
||||
builder: process.env.TEST_BUILDER as 'webpack' | 'vite' ?? 'vite',
|
||||
|
1
test/fixtures/basic/nuxt.config.ts
vendored
1
test/fixtures/basic/nuxt.config.ts
vendored
@ -11,6 +11,7 @@ declare module 'nitropack' {
|
||||
}
|
||||
|
||||
export default defineNuxtConfig({
|
||||
future: { compatibilityVersion: process.env.TEST_V4 === 'true' ? 4 : 3 },
|
||||
app: {
|
||||
pageTransition: true,
|
||||
layoutTransition: true,
|
||||
|
1
test/fixtures/minimal-types/nuxt.config.ts
vendored
1
test/fixtures/minimal-types/nuxt.config.ts
vendored
@ -1,3 +1,4 @@
|
||||
export default defineNuxtConfig({
|
||||
future: { compatibilityVersion: process.env.TEST_V4 === 'true' ? 4 : 3 },
|
||||
experimental: { appManifest: true },
|
||||
})
|
||||
|
1
test/fixtures/minimal/nuxt.config.ts
vendored
1
test/fixtures/minimal/nuxt.config.ts
vendored
@ -3,6 +3,7 @@ import { fileURLToPath } from 'node:url'
|
||||
const testWithInlineVue = process.env.EXTERNAL_VUE === 'false'
|
||||
|
||||
export default defineNuxtConfig({
|
||||
future: { compatibilityVersion: process.env.TEST_V4 === 'true' ? 4 : 3 },
|
||||
pages: false,
|
||||
experimental: {
|
||||
externalVue: !testWithInlineVue,
|
||||
|
@ -1,5 +1,6 @@
|
||||
// https://nuxt.com/docs/api/nuxt-config
|
||||
export default defineNuxtConfig({
|
||||
future: { compatibilityVersion: process.env.TEST_V4 === 'true' ? 4 : 3 },
|
||||
experimental: {
|
||||
externalVue: false,
|
||||
},
|
||||
|
1
test/fixtures/suspense/nuxt.config.ts
vendored
1
test/fixtures/suspense/nuxt.config.ts
vendored
@ -3,6 +3,7 @@ import { fileURLToPath } from 'node:url'
|
||||
const testWithInlineVue = process.env.EXTERNAL_VUE === 'false'
|
||||
|
||||
export default defineNuxtConfig({
|
||||
future: { compatibilityVersion: process.env.TEST_V4 === 'true' ? 4 : 3 },
|
||||
experimental: {
|
||||
externalVue: !testWithInlineVue,
|
||||
},
|
||||
|
Loading…
Reference in New Issue
Block a user