chore: cleanup eslint rules with latest `@nuxt/eslint-config` (#26653)

This commit is contained in:
Anthony Fu 2024-04-05 20:08:32 +02:00 committed by GitHub
parent ee608cea2c
commit f209158352
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
357 changed files with 2713 additions and 2952 deletions

2
.gitignore vendored
View File

@ -73,3 +73,5 @@ Temporary Items
fixtures-temp fixtures-temp
.pnpm-store .pnpm-store
eslint-typegen.d.ts
.eslintcache

View File

@ -1,280 +1,215 @@
// Configs // @ts-check
// import standard from "eslint-config-standard" import { createConfigForNuxt } from '@nuxt/eslint-config/flat'
// import nuxt from '@nuxt/eslint-config' // @ts-expect-error missing types
// Plugins
import path from 'node:path'
import { fileURLToPath } from 'node:url'
import jsdoc from 'eslint-plugin-jsdoc'
import esImport from 'eslint-plugin-import'
import unicorn from 'eslint-plugin-unicorn'
import noOnlyTests from 'eslint-plugin-no-only-tests' import noOnlyTests from 'eslint-plugin-no-only-tests'
import typegen from 'eslint-typegen'
// @ts-expect-error missing types
import perfectionist from 'eslint-plugin-perfectionist'
/** export default createConfigForNuxt({
* eslintrc compatibility features: {
* @see https://eslint.org/docs/latest/use/configure/migration-guide#using-eslintrc-configs-in-flat-config stylistic: {
* @see https://github.com/eslint/eslintrc#usage-esm commaDangle: 'always-multiline',
*/ },
import { FlatCompat } from '@eslint/eslintrc' tooling: true,
import js from '@eslint/js' },
const __filename = fileURLToPath(import.meta.url)
const __dirname = path.dirname(__filename)
const compat = new FlatCompat({
baseDirectory: __dirname,
recommendedConfig: js.configs.recommended
}) })
.prepend(
// TODO: Type definition?
export default [
{ {
// Ignores have to be a separate object to be treated as global ignores
// Don't add other attributes to this object
ignores: [ ignores: [
'**/dist/**', 'packages/schema/schema/**',
'**/.nuxt/**', ],
'**/.nuxt-*/**',
'**/.output/**',
'**/.output-*/**',
'**/public/**',
'**/node_modules/**',
'packages/schema/schema',
// TODO: remove when fully migrated to flat config
'**/*.d.mts'
]
},
// standard,
...compat.extends('eslint-config-standard'),
jsdoc.configs['flat/recommended'],
// nuxt,
...compat.extends('@nuxt/eslint-config'),
esImport.configs.typescript,
{
rules: {
'import/export': 'off'
}
}, },
{ {
files: ['**/*.vue', '**/*.ts', '**/*.mts', '**/*.js', '**/*.cjs', '**/*.mjs'],
languageOptions: { languageOptions: {
globals: { globals: {
$fetch: 'readonly',
NodeJS: 'readonly', NodeJS: 'readonly',
$fetch: 'readonly'
}
}, },
plugins: {
jsdoc,
import: esImport,
unicorn,
'no-only-tests': noOnlyTests
}, },
name: 'local/settings',
settings: {
jsdoc: {
ignoreInternal: true,
tagNamePreference: {
note: 'note',
warning: 'warning',
},
},
},
},
)
.override('nuxt/javascript', {
rules: { rules: {
// Imports should come first 'curly': ['error', 'all'], // Including if blocks with a single statement
'import/first': 'error',
// Other import rules
'import/no-mutable-exports': 'error',
// Allow unresolved imports
'import/no-unresolved': 'off',
// Allow paren-less arrow functions only when there's no braces
'arrow-parens': ['error', 'as-needed', { requireForBlockBody: true }],
// Allow async-await
'generator-star-spacing': 'off',
// Prefer const over let
'prefer-const': ['error', { destructuring: 'any', ignoreReadBeforeAssign: false }],
// No single if in an "else" block
'no-lonely-if': 'error',
// Force curly braces for control flow,
// including if blocks with a single statement
curly: ['error', 'all'],
// No async function without await
'require-await': 'error',
// Force dot notation when possible
'dot-notation': 'error', 'dot-notation': 'error',
'no-var': 'error',
// Force object shorthand where possible
'object-shorthand': 'error',
// No useless destructuring/importing/exporting renames
'no-useless-rename': 'error',
/**********************/
/* Unicorn Rules */
/**********************/
// Pass error message when throwing errors
'unicorn/error-message': 'error',
// Uppercase regex escapes
'unicorn/escape-case': 'error',
// Array.isArray instead of instanceof
'unicorn/no-array-instanceof': 'error',
// Prevent deprecated `new Buffer()`
'unicorn/no-new-buffer': 'error',
// Keep regex literals safe!
'unicorn/no-unsafe-regex': 'off',
// Lowercase number formatting for octal, hex, binary (0x12 instead of 0X12)
'unicorn/number-literal-case': 'error',
// ** instead of Math.pow()
'unicorn/prefer-exponentiation-operator': 'error',
// includes over indexOf when checking for existence
'unicorn/prefer-includes': 'error',
// String methods startsWith/endsWith instead of more complicated stuff
'unicorn/prefer-starts-ends-with': 'error',
// textContent instead of innerText
'unicorn/prefer-text-content': 'error',
// Enforce throwing type error when throwing error while checking typeof
'unicorn/prefer-type-error': 'error',
// Use new when throwing error
'unicorn/throw-new-error': 'error',
'sort-imports': [
'error',
{
ignoreDeclarationSort: true
}
],
'no-only-tests/no-only-tests': 'error',
'unicorn/prefer-node-protocol': 'error',
'no-console': ['warn', { allow: ['warn', 'error', 'debug'] }], 'no-console': ['warn', { allow: ['warn', 'error', 'debug'] }],
'vue/one-component-per-file': 'off', 'no-lonely-if': 'error', // No single if in an "else" block
'vue/require-default-prop': 'off', 'no-useless-rename': 'error',
'object-shorthand': 'error',
'prefer-const': ['error', { destructuring: 'any', ignoreReadBeforeAssign: false }],
'require-await': 'error',
'sort-imports': ['error', { ignoreDeclarationSort: true }],
},
})
// Vue stylistic rules from `@antfu/eslint-config` .override('nuxt/typescript/rules', {
'vue/array-bracket-spacing': ['error', 'never'], rules: {
'vue/arrow-spacing': ['error', { after: true, before: true }], '@typescript-eslint/ban-ts-comment': [
'vue/block-spacing': ['error', 'always'],
'vue/block-tag-newline': [
'error', 'error',
{ {
multiline: 'always', 'ts-expect-error': 'allow-with-description',
singleline: 'always' 'ts-ignore': true,
} },
], ],
'vue/brace-style': ['error', 'stroustrup', { allowSingleLine: true }], '@typescript-eslint/no-dynamic-delete': 'off',
'vue/comma-dangle': ['error', 'always-multiline'], '@typescript-eslint/no-unused-vars': [
'vue/comma-spacing': ['error', { after: true, before: false }],
'vue/comma-style': ['error', 'last'],
'vue/html-comment-content-spacing': [
'error', 'error',
'always',
{ {
exceptions: ['-'] argsIgnorePattern: '^_',
} ignoreRestSiblings: true,
varsIgnorePattern: '^_',
},
], ],
'vue/key-spacing': ['error', { afterColon: true, beforeColon: false }], '@typescript-eslint/triple-slash-reference': 'off',
'vue/keyword-spacing': ['error', { after: true, before: true }], '@typescript-eslint/unified-signatures': 'off',
'vue/object-curly-newline': 'off', ...{
'vue/object-curly-spacing': ['error', 'always'], // TODO: Discuss if we want to enable this
'vue/object-property-newline': [ '@typescript-eslint/ban-types': 'off',
'error', // TODO: Discuss if we want to enable this
{ allowMultiplePropertiesPerLine: true } '@typescript-eslint/no-explicit-any': 'off',
], // TODO: Discuss if we want to enable this
'vue/operator-linebreak': ['error', 'before'], '@typescript-eslint/no-invalid-void-type': 'off',
'vue/padding-line-between-blocks': ['error', 'always'], },
'vue/quote-props': ['error', 'consistent-as-needed'], },
'vue/space-in-parens': ['error', 'never'], })
'vue/template-curly-spacing': 'error',
'jsdoc/require-jsdoc': 'off', .override('nuxt/tooling/unicorn', {
'jsdoc/require-param': 'off', rules: {
'jsdoc/require-returns': 'off', 'unicorn/no-new-array': 'off',
'jsdoc/require-param-type': 'off', 'unicorn/prefer-dom-node-text-content': 'off',
'import/order': [ },
'error', })
.override('nuxt/vue/rules', {
rules: {
},
})
// Stylistic rules
.override('nuxt/stylistic', {
rules: {
'@stylistic/brace-style': ['error', '1tbs', { allowSingleLine: true }],
'@stylistic/indent-binary-ops': 'off',
'@stylistic/max-statements-per-line': 'off',
'@stylistic/operator-linebreak': 'off',
'@stylistic/quote-props': ['error', 'consistent'],
'@stylistic/space-before-function-paren': ['error', 'always'],
},
})
// Append local rules
.append(
{ {
pathGroups: [ files: ['**/*.vue', '**/*.ts', '**/*.mts', '**/*.js', '**/*.cjs', '**/*.mjs'],
{ name: 'local/rules',
pattern: '#vue-router', rules: {
group: 'external'
}
]
}
],
'import/no-restricted-paths': [ 'import/no-restricted-paths': [
'error', 'error',
{ {
zones: [ zones: [
{ {
from: 'packages/nuxt/src/!(core)/**/*', from: 'packages/nuxt/src/!(core)/**/*',
message: 'core should not directly import from modules.',
target: 'packages/nuxt/src/core', target: 'packages/nuxt/src/core',
message: 'core should not directly import from modules.'
}, },
{ {
from: 'packages/nuxt/src/!(app)/**/*', from: 'packages/nuxt/src/!(app)/**/*',
message: 'app should not directly import from modules.',
target: 'packages/nuxt/src/app', target: 'packages/nuxt/src/app',
message: 'app should not directly import from modules.'
}, },
{ {
from: 'packages/nuxt/src/app/**/index.ts', from: 'packages/nuxt/src/app/**/index.ts',
message: 'should not import from barrel/index files',
target: 'packages/nuxt/src', target: 'packages/nuxt/src',
message: 'should not import from barrel/index files'
}, },
{ {
from: 'packages/nitro', from: 'packages/nitro',
message: 'nitro should not directly import other packages.',
target: 'packages/!(nitro)/**/*', target: 'packages/!(nitro)/**/*',
message: 'nitro should not directly import other packages.' },
}
]
}
], ],
'@typescript-eslint/consistent-type-imports': [ },
],
'import/order': [
'error', 'error',
{ {
disallowTypeAnnotations: false pathGroups: [
}
],
'@typescript-eslint/ban-ts-comment': [
'error',
{ {
'ts-expect-error': 'allow-with-description', group: 'external',
'ts-ignore': true pattern: '#vue-router',
} },
], ],
'@typescript-eslint/prefer-ts-expect-error': 'error', },
'@typescript-eslint/no-unused-vars': [
'error',
{
argsIgnorePattern: '^_',
varsIgnorePattern: '^_',
ignoreRestSiblings: true
}
], ],
'jsdoc/check-tag-names': [ 'jsdoc/check-tag-names': [
'error', 'error',
{ {
definedTags: ['__NO_SIDE_EFFECTS__'] definedTags: [
} 'experimental',
] '__NO_SIDE_EFFECTS__',
],
}, },
settings: { ],
jsdoc: {
ignoreInternal: true,
tagNamePreference: {
warning: 'warning',
note: 'note'
}
}
}
}, },
{
files: ['packages/schema/**'],
rules: {
'jsdoc/valid-types': 'off',
'jsdoc/check-tag-names': [
'error',
{
definedTags: ['experimental']
}
]
}
}, },
{ {
files: ['packages/nuxt/src/app/**', 'test/**', '**/runtime/**', '**/*.test.ts'], files: ['packages/nuxt/src/app/**', 'test/**', '**/runtime/**', '**/*.test.ts'],
name: 'local/disables/client-console',
rules: { rules: {
'no-console': 'off' 'no-console': 'off',
} },
}, },
{ {
files: ['test/fixtures/**'], files: ['**/fixtures/**', '**/fixture/**'],
name: 'local/disables/fixtures',
rules: { rules: {
'@typescript-eslint/no-unused-vars': 'off', '@typescript-eslint/no-unused-vars': 'off',
'vue/valid-v-for': 'off' '@typescript-eslint/triple-slash-reference': 'off',
} 'vue/multi-word-component-names': 'off',
} 'vue/valid-v-for': 'off',
] },
},
{
files: ['test/**', '**/*.test.ts'],
name: 'local/disables/tests',
plugins: {
'no-only-tests': noOnlyTests,
},
rules: {
'@typescript-eslint/no-explicit-any': 'off',
'no-console': 'off',
'no-only-tests/no-only-tests': 'error',
},
},
// Sort rule keys in eslint config
{
files: ['**/eslint.config.mjs'],
name: 'local/sort-eslint-config',
plugins: {
perfectionist,
},
rules: {
'perfectionist/sort-objects': 'error',
},
},
)
// Generate type definitions for the eslint config
.onResolved((configs) => {
return typegen(configs)
})

View File

@ -9,8 +9,8 @@ export default defineNuxtConfig({
function () { function () {
addPluginTemplate({ addPluginTemplate({
filename: 'plugins/my-plugin.mjs', filename: 'plugins/my-plugin.mjs',
getContents: () => 'export default defineNuxtPlugin({ name: \'my-plugin\' })' getContents: () => 'export default defineNuxtPlugin({ name: \'my-plugin\' })',
}) })
} },
] ],
}) })

View File

@ -13,8 +13,8 @@
"cleanup": "rimraf 'packages/**/node_modules' 'playground/node_modules' 'node_modules'", "cleanup": "rimraf 'packages/**/node_modules' 'playground/node_modules' 'node_modules'",
"dev": "pnpm play", "dev": "pnpm play",
"dev:prepare": "pnpm --filter './packages/**' prepack --stub", "dev:prepare": "pnpm --filter './packages/**' prepack --stub",
"lint": "eslint .", "lint": "eslint . --cache",
"lint:fix": "eslint . --fix", "lint:fix": "eslint . --cache --fix",
"lint:docs": "markdownlint ./docs && case-police 'docs/**/*.md' *.md", "lint:docs": "markdownlint ./docs && case-police 'docs/**/*.md' *.md",
"lint:docs:fix": "markdownlint ./docs --fix && case-police 'docs/**/*.md' *.md --fix", "lint:docs:fix": "markdownlint ./docs --fix && case-police 'docs/**/*.md' *.md --fix",
"lint:knip": "pnpx knip", "lint:knip": "pnpx knip",
@ -44,13 +44,13 @@
"magic-string": "^0.30.9" "magic-string": "^0.30.9"
}, },
"devDependencies": { "devDependencies": {
"@eslint/eslintrc": "3.0.2",
"@eslint/js": "8.57.0", "@eslint/js": "8.57.0",
"@nuxt/eslint-config": "0.2.0", "@nuxt/eslint-config": "0.3.0",
"@nuxt/kit": "workspace:*", "@nuxt/kit": "workspace:*",
"@nuxt/test-utils": "3.12.0", "@nuxt/test-utils": "3.12.0",
"@nuxt/webpack-builder": "workspace:*", "@nuxt/webpack-builder": "workspace:*",
"@testing-library/vue": "8.0.3", "@testing-library/vue": "8.0.3",
"@types/eslint__js": "^8.42.3",
"@types/fs-extra": "11.0.4", "@types/fs-extra": "11.0.4",
"@types/node": "20.12.4", "@types/node": "20.12.4",
"@types/semver": "7.5.8", "@types/semver": "7.5.8",
@ -61,11 +61,9 @@
"consola": "3.2.3", "consola": "3.2.3",
"devalue": "4.3.2", "devalue": "4.3.2",
"eslint": "8.57.0", "eslint": "8.57.0",
"eslint-config-standard": "17.1.0",
"eslint-plugin-import": "2.29.1",
"eslint-plugin-jsdoc": "48.2.2",
"eslint-plugin-no-only-tests": "3.1.0", "eslint-plugin-no-only-tests": "3.1.0",
"eslint-plugin-unicorn": "52.0.0", "eslint-plugin-perfectionist": "^2.8.0",
"eslint-typegen": "^0.2.0",
"execa": "8.0.1", "execa": "8.0.1",
"fs-extra": "11.2.0", "fs-extra": "11.2.0",
"globby": "14.0.1", "globby": "14.0.1",

View File

@ -3,14 +3,14 @@ import { defineBuildConfig } from 'unbuild'
export default defineBuildConfig({ export default defineBuildConfig({
declaration: true, declaration: true,
entries: [ entries: [
'src/index' 'src/index',
], ],
externals: [ externals: [
'@nuxt/schema', '@nuxt/schema',
'nitropack', 'nitropack',
'webpack', 'webpack',
'vite', 'vite',
'h3' 'h3',
], ],
failOnWarn: false failOnWarn: false,
}) })

View File

@ -42,7 +42,7 @@ export interface ExtendViteConfigOptions extends ExtendConfigOptions {}
*/ */
export function extendWebpackConfig ( export function extendWebpackConfig (
fn: ((config: WebpackConfig) => void), fn: ((config: WebpackConfig) => void),
options: ExtendWebpackConfigOptions = {} options: ExtendWebpackConfigOptions = {},
) { ) {
const nuxt = useNuxt() const nuxt = useNuxt()
@ -74,7 +74,7 @@ export function extendWebpackConfig (
*/ */
export function extendViteConfig ( export function extendViteConfig (
fn: ((config: ViteConfig) => void), fn: ((config: ViteConfig) => void),
options: ExtendViteConfigOptions = {} options: ExtendViteConfigOptions = {},
) { ) {
const nuxt = useNuxt() const nuxt = useNuxt()

View File

@ -18,7 +18,7 @@ export async function checkNuxtCompatibility (constraints: NuxtCompatibility, nu
if (!satisfies(normalizeSemanticVersion(nuxtVersion), constraints.nuxt, { includePrerelease: true })) { if (!satisfies(normalizeSemanticVersion(nuxtVersion), constraints.nuxt, { includePrerelease: true })) {
issues.push({ issues.push({
name: 'nuxt', name: 'nuxt',
message: `Nuxt version \`${constraints.nuxt}\` is required but currently using \`${nuxtVersion}\`` message: `Nuxt version \`${constraints.nuxt}\` is required but currently using \`${nuxtVersion}\``,
}) })
} }
} }
@ -30,12 +30,12 @@ export async function checkNuxtCompatibility (constraints: NuxtCompatibility, nu
if (bridgeRequirement === true && !hasBridge) { if (bridgeRequirement === true && !hasBridge) {
issues.push({ issues.push({
name: 'bridge', name: 'bridge',
message: 'Nuxt bridge is required' message: 'Nuxt bridge is required',
}) })
} else if (bridgeRequirement === false && hasBridge) { } else if (bridgeRequirement === false && hasBridge) {
issues.push({ issues.push({
name: 'bridge', name: 'bridge',
message: 'Nuxt bridge is not supported' message: 'Nuxt bridge is not supported',
}) })
} }
} }

View File

@ -49,7 +49,7 @@ export async function addComponent (opts: AddComponentOptions) {
shortPath: opts.filePath, shortPath: opts.filePath,
priority: 0, priority: 0,
meta: {}, meta: {},
...opts ...opts,
} }
nuxt.hook('components:extend', (components: Component[]) => { nuxt.hook('components:extend', (components: Component[]) => {

View File

@ -5,7 +5,7 @@ describe('resolveGroupSyntax', () => {
it('should resolve single group syntax', () => { it('should resolve single group syntax', () => {
expect(resolveGroupSyntax('**/*.{spec}.{js,ts}')).toStrictEqual([ expect(resolveGroupSyntax('**/*.{spec}.{js,ts}')).toStrictEqual([
'**/*.spec.js', '**/*.spec.js',
'**/*.spec.ts' '**/*.spec.ts',
]) ])
}) })
@ -14,13 +14,13 @@ describe('resolveGroupSyntax', () => {
'**/*.spec.js', '**/*.spec.js',
'**/*.spec.ts', '**/*.spec.ts',
'**/*.test.js', '**/*.test.js',
'**/*.test.ts' '**/*.test.ts',
]) ])
}) })
it('should do nothing with normal globs', () => { it('should do nothing with normal globs', () => {
expect(resolveGroupSyntax('**/*.spec.js')).toStrictEqual([ expect(resolveGroupSyntax('**/*.spec.js')).toStrictEqual([
'**/*.spec.js' '**/*.spec.js',
]) ])
}) })
}) })

View File

@ -30,7 +30,7 @@ export {
requireModule, requireModule,
importModule, importModule,
tryImportModule, tryImportModule,
tryRequireModule tryRequireModule,
} from './internal/cjs' } from './internal/cjs'
export type { ResolveModuleOptions, RequireModuleOptions } from './internal/cjs' export type { ResolveModuleOptions, RequireModuleOptions } from './internal/cjs'
export { tryResolveModule } from './internal/esm' export { tryResolveModule } from './internal/esm'

View File

@ -66,14 +66,14 @@ export function getModulePaths (paths?: string[] | string) {
global.__NUXT_PREPATHS__, global.__NUXT_PREPATHS__,
paths || [], paths || [],
process.cwd(), process.cwd(),
global.__NUXT_PATHS__ global.__NUXT_PATHS__,
).filter(Boolean) as string[] ).filter(Boolean) as string[]
} }
/** @deprecated Do not use CJS utils */ /** @deprecated Do not use CJS utils */
export function resolveModule (id: string, opts: ResolveModuleOptions = {}) { export function resolveModule (id: string, opts: ResolveModuleOptions = {}) {
return normalize(_require.resolve(id, { return normalize(_require.resolve(id, {
paths: getModulePaths(opts.paths) paths: getModulePaths(opts.paths),
})) }))
} }

View File

@ -16,7 +16,7 @@ export function addLayout (this: any, template: NuxtTemplate | string, name?: st
const layout = (nuxt.options as any).layouts[layoutName] const layout = (nuxt.options as any).layouts[layoutName]
if (layout) { if (layout) {
return logger.warn( return logger.warn(
`Not overriding \`${layoutName}\` (provided by \`${layout}\`) with \`${src || filename}\`.` `Not overriding \`${layoutName}\` (provided by \`${layout}\`) with \`${src || filename}\`.`,
) )
} }
(nuxt.options as any).layouts[layoutName] = `./${filename}` (nuxt.options as any).layouts[layoutName] = `./${filename}`
@ -31,12 +31,12 @@ export function addLayout (this: any, template: NuxtTemplate | string, name?: st
if (layoutName in app.layouts) { if (layoutName in app.layouts) {
const relativePath = relative(nuxt.options.srcDir, app.layouts[layoutName].file) const relativePath = relative(nuxt.options.srcDir, app.layouts[layoutName].file)
return logger.warn( return logger.warn(
`Not overriding \`${layoutName}\` (provided by \`~/${relativePath}\`) with \`${src || filename}\`.` `Not overriding \`${layoutName}\` (provided by \`~/${relativePath}\`) with \`${src || filename}\`.`,
) )
} }
app.layouts[layoutName] = { app.layouts[layoutName] = {
file: join('#build', filename), file: join('#build', filename),
name: layoutName name: layoutName,
} }
}) })
} }

View File

@ -17,7 +17,7 @@ export async function loadNuxtConfig (opts: LoadNuxtConfigOptions): Promise<Nuxt
extend: { extendKey: ['theme', 'extends'] }, extend: { extendKey: ['theme', 'extends'] },
dotenv: true, dotenv: true,
globalRc: true, globalRc: true,
...opts ...opts,
}) })
delete (globalThis as any).defineNuxtConfig delete (globalThis as any).defineNuxtConfig
const { configFile, layers = [], cwd } = result const { configFile, layers = [], cwd } = result
@ -45,8 +45,8 @@ export async function loadNuxtConfig (opts: LoadNuxtConfigOptions): Promise<Nuxt
cwd, cwd,
config: { config: {
rootDir: cwd, rootDir: cwd,
srcDir: cwd srcDir: cwd,
} },
}) })
} }

View File

@ -33,7 +33,7 @@ export async function loadNuxt (opts: LoadNuxtOptions): Promise<Nuxt> {
throw new Error(`Cannot find any nuxt version from ${opts.cwd}`) throw new Error(`Cannot find any nuxt version from ${opts.cwd}`)
} }
const pkg = await readPackageJSON(nearestNuxtPkg) const pkg = await readPackageJSON(nearestNuxtPkg)
const majorVersion = pkg.version ? parseInt(pkg.version.split('.')[0]) : '' const majorVersion = pkg.version ? Number.parseInt(pkg.version.split('.')[0]) : ''
const rootDir = pathToFileURL(opts.cwd || process.cwd()).href const rootDir = pathToFileURL(opts.cwd || process.cwd()).href
@ -51,7 +51,7 @@ export async function loadNuxt (opts: LoadNuxtOptions): Promise<Nuxt> {
for: opts.dev ? 'dev' : 'build', for: opts.dev ? 'dev' : 'build',
configOverrides: opts.overrides, configOverrides: opts.overrides,
ready: opts.ready, ready: opts.ready,
envConfig: opts.dotenv // TODO: Backward format conversion envConfig: opts.dotenv, // TODO: Backward format conversion
}) })
// Mock new hookable methods // Mock new hookable methods

View File

@ -10,21 +10,21 @@ describe('nuxt module compatibility', () => {
modules: [ modules: [
defineNuxtModule({ defineNuxtModule({
meta: { meta: {
name: 'nuxt-module-foo' name: 'nuxt-module-foo',
} },
}), }),
[ [
defineNuxtModule({ defineNuxtModule({
meta: { meta: {
name: 'module-instance-with-options' name: 'module-instance-with-options',
} },
}), }),
{ {
foo: 'bar' foo: 'bar',
} },
] ],
] ],
} },
}) })
expect(hasNuxtModule('nuxt-module-foo', nuxt)).toStrictEqual(true) expect(hasNuxtModule('nuxt-module-foo', nuxt)).toStrictEqual(true)
expect(hasNuxtModule('module-instance-with-options', nuxt)).toStrictEqual(true) expect(hasNuxtModule('module-instance-with-options', nuxt)).toStrictEqual(true)
@ -35,8 +35,8 @@ describe('nuxt module compatibility', () => {
const module = defineNuxtModule({ const module = defineNuxtModule({
meta: { meta: {
name: 'nuxt-module-foo', name: 'nuxt-module-foo',
version: '1.0.0' version: '1.0.0',
} },
}) })
expect(await getNuxtModuleVersion(module, nuxt)).toEqual('1.0.0') expect(await getNuxtModuleVersion(module, nuxt)).toEqual('1.0.0')
await nuxt.close() await nuxt.close()
@ -46,8 +46,8 @@ describe('nuxt module compatibility', () => {
const module = defineNuxtModule({ const module = defineNuxtModule({
meta: { meta: {
name: 'nuxt-module-foo', name: 'nuxt-module-foo',
version: '1.0.0' version: '1.0.0',
} },
}) })
expect(await hasNuxtModuleCompatibility(module, '^1.0.0', nuxt)).toStrictEqual(true) expect(await hasNuxtModuleCompatibility(module, '^1.0.0', nuxt)).toStrictEqual(true)
expect(await hasNuxtModuleCompatibility(module, '^2.0.0', nuxt)).toStrictEqual(false) expect(await hasNuxtModuleCompatibility(module, '^2.0.0', nuxt)).toStrictEqual(false)

View File

@ -36,7 +36,7 @@ export async function hasNuxtModuleCompatibility (module: string | NuxtModule, s
return false return false
} }
return satisfies(normalizeSemanticVersion(version), semverVersion, { return satisfies(normalizeSemanticVersion(version), semverVersion, {
includePrerelease: true includePrerelease: true,
}) })
} }

View File

@ -89,8 +89,8 @@ export function defineNuxtModule<OptionsT extends ModuleOptions> (definition: Mo
// Return module install result // Return module install result
return defu(res, <ModuleSetupReturn> { return defu(res, <ModuleSetupReturn> {
timings: { timings: {
setup: setupTime setup: setupTime,
} },
}) })
} }
@ -138,10 +138,10 @@ function nuxt2Shims (nuxt: Nuxt) {
plugins: nuxt.options.plugins, plugins: nuxt.options.plugins,
templates: [ templates: [
...templates.templatesFiles, ...templates.templatesFiles,
...virtualTemplates ...virtualTemplates,
], ],
templateVars: templates.templateVars templateVars: templates.templateVars,
} },
} }
for await (const template of virtualTemplates) { for await (const template of virtualTemplates) {
const contents = await compileTemplate({ ...template, src: '' }, context) const contents = await compileTemplate({ ...template, src: '' }, context)

View File

@ -46,7 +46,7 @@ export async function installModule (moduleToInstall: string | NuxtModule, inlin
nuxt.options._installedModules.push({ nuxt.options._installedModules.push({
meta: defu(await nuxtModule.getMeta?.(), buildTimeModuleMeta), meta: defu(await nuxtModule.getMeta?.(), buildTimeModuleMeta),
timings: res.timings, timings: res.timings,
entryPath: typeof moduleToInstall === 'string' ? resolveAlias(moduleToInstall) : undefined entryPath: typeof moduleToInstall === 'string' ? resolveAlias(moduleToInstall) : undefined,
}) })
} }

View File

@ -14,7 +14,7 @@ function normalizeHandlerMethod (handler: NitroEventHandler) {
return { return {
method, method,
...handler, ...handler,
handler: normalize(handler.handler) handler: normalize(handler.handler),
} }
} }

View File

@ -127,7 +127,7 @@ export function createResolver (base: string | URL): Resolver {
return { return {
resolve: (...path) => resolve(base as string, ...path), resolve: (...path) => resolve(base as string, ...path),
resolvePath: (path, opts) => resolvePath(path, { cwd: base as string, ...opts }) resolvePath: (path, opts) => resolvePath(path, { cwd: base as string, ...opts }),
} }
} }

View File

@ -119,7 +119,7 @@ export async function _generateTypes (nuxt: Nuxt) {
const modulePaths = await resolveNuxtModule(rootDirWithSlash, const modulePaths = await resolveNuxtModule(rootDirWithSlash,
nuxt.options._installedModules nuxt.options._installedModules
.filter(m => m.entryPath) .filter(m => m.entryPath)
.map(m => getDirectory(m.entryPath)) .map(m => getDirectory(m.entryPath)),
) )
const tsConfig: TSConfig = defu(nuxt.options.typescript?.tsConfig, { const tsConfig: TSConfig = defu(nuxt.options.typescript?.tsConfig, {
@ -142,7 +142,7 @@ export async function _generateTypes (nuxt: Nuxt) {
noEmit: true, noEmit: true,
resolveJsonModule: true, resolveJsonModule: true,
allowSyntheticDefaultImports: true, allowSyntheticDefaultImports: true,
paths: {} paths: {},
}, },
include: [ include: [
'./nuxt.d.ts', './nuxt.d.ts',
@ -153,19 +153,19 @@ export async function _generateTypes (nuxt: Nuxt) {
.filter(srcOrCwd => !srcOrCwd.startsWith(rootDirWithSlash) || srcOrCwd.includes('node_modules')) .filter(srcOrCwd => !srcOrCwd.startsWith(rootDirWithSlash) || srcOrCwd.includes('node_modules'))
.map(srcOrCwd => join(relative(nuxt.options.buildDir, srcOrCwd), '**/*')), .map(srcOrCwd => join(relative(nuxt.options.buildDir, srcOrCwd), '**/*')),
...nuxt.options.typescript.includeWorkspace && nuxt.options.workspaceDir !== nuxt.options.rootDir ? [join(relative(nuxt.options.buildDir, nuxt.options.workspaceDir), '**/*')] : [], ...nuxt.options.typescript.includeWorkspace && nuxt.options.workspaceDir !== nuxt.options.rootDir ? [join(relative(nuxt.options.buildDir, nuxt.options.workspaceDir), '**/*')] : [],
...modulePaths.map(m => join(relativeWithDot(nuxt.options.buildDir, m), 'runtime')) ...modulePaths.map(m => join(relativeWithDot(nuxt.options.buildDir, m), 'runtime')),
], ],
exclude: [ exclude: [
...nuxt.options.modulesDir.map(m => relativeWithDot(nuxt.options.buildDir, m)), ...nuxt.options.modulesDir.map(m => relativeWithDot(nuxt.options.buildDir, m)),
...modulePaths.map(m => join(relativeWithDot(nuxt.options.buildDir, m), 'runtime/server')), ...modulePaths.map(m => join(relativeWithDot(nuxt.options.buildDir, m), 'runtime/server')),
// nitro generate output: https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/core/nitro.ts#L186 // nitro generate output: https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/core/nitro.ts#L186
relativeWithDot(nuxt.options.buildDir, resolve(nuxt.options.rootDir, 'dist')) relativeWithDot(nuxt.options.buildDir, resolve(nuxt.options.rootDir, 'dist')),
] ],
} satisfies TSConfig) } satisfies TSConfig)
const aliases: Record<string, string> = { const aliases: Record<string, string> = {
...nuxt.options.alias, ...nuxt.options.alias,
'#build': nuxt.options.buildDir '#build': nuxt.options.buildDir,
} }
// Exclude bridge alias types to support Volar // Exclude bridge alias types to support Volar
@ -215,7 +215,7 @@ export async function _generateTypes (nuxt: Nuxt) {
const references: TSReference[] = await Promise.all([ const references: TSReference[] = await Promise.all([
...nuxt.options.modules, ...nuxt.options.modules,
...nuxt.options._modules ...nuxt.options._modules,
] ]
.filter(f => typeof f === 'string') .filter(f => typeof f === 'string')
.map(async id => ({ types: (await readPackageJSON(id, { url: nodeModulePaths }).catch(() => null))?.name || id }))) .map(async id => ({ types: (await readPackageJSON(id, { url: nodeModulePaths }).catch(() => null))?.name || id })))
@ -246,12 +246,12 @@ export async function _generateTypes (nuxt: Nuxt) {
...declarations, ...declarations,
'', '',
'export {}', 'export {}',
'' '',
].join('\n') ].join('\n')
return { return {
declaration, declaration,
tsConfig tsConfig,
} }
} }

View File

@ -14,7 +14,7 @@ const mockNuxt = {
srcDir: '/my-app', srcDir: '/my-app',
alias: { alias: {
'~': '/my-app', '~': '/my-app',
'some-custom-alias': '/my-app/some-alias' 'some-custom-alias': '/my-app/some-alias',
}, },
typescript: { includeWorkspace: false }, typescript: { includeWorkspace: false },
buildDir: '/my-app/.nuxt', buildDir: '/my-app/.nuxt',
@ -22,9 +22,9 @@ const mockNuxt = {
modules: [], modules: [],
_layers: [{ config: { srcDir: '/my-app' } }], _layers: [{ config: { srcDir: '/my-app' } }],
_installedModules: [], _installedModules: [],
_modules: [] _modules: [],
}, },
callHook: () => {} callHook: () => {},
} satisfies DeepPartial<Nuxt> as unknown as Nuxt } satisfies DeepPartial<Nuxt> as unknown as Nuxt
const mockNuxtWithOptions = (options: NuxtConfig) => defu({ options }, mockNuxt) as Nuxt const mockNuxtWithOptions = (options: NuxtConfig) => defu({ options }, mockNuxt) as Nuxt
@ -49,7 +49,7 @@ describe('tsConfig generation', () => {
it('should add exclude for module paths', async () => { it('should add exclude for module paths', async () => {
const { tsConfig } = await _generateTypes(mockNuxtWithOptions({ const { tsConfig } = await _generateTypes(mockNuxtWithOptions({
modulesDir: ['/my-app/modules/test/node_modules', '/my-app/modules/node_modules', '/my-app/node_modules/@some/module/node_modules'] modulesDir: ['/my-app/modules/test/node_modules', '/my-app/modules/node_modules', '/my-app/node_modules/@some/module/node_modules'],
})) }))
expect(tsConfig.exclude).toMatchInlineSnapshot(` expect(tsConfig.exclude).toMatchInlineSnapshot(`
[ [

View File

@ -9,7 +9,7 @@ const fixtures = {
'basic test fixture': 'test/fixtures/basic', 'basic test fixture': 'test/fixtures/basic',
'basic test fixture (types)': 'test/fixtures/basic-types', 'basic test fixture (types)': 'test/fixtures/basic-types',
'minimal test fixture': 'test/fixtures/minimal', 'minimal test fixture': 'test/fixtures/minimal',
'minimal test fixture (types)': 'test/fixtures/minimal-types' 'minimal test fixture (types)': 'test/fixtures/minimal-types',
} }
describe('loadNuxtConfig', () => { describe('loadNuxtConfig', () => {

View File

@ -13,23 +13,23 @@ export default defineBuildConfig({
'core', 'core',
'head', 'head',
'components', 'components',
'pages' 'pages',
].map(name => ({ input: `src/${name}/runtime/`, outDir: `dist/${name}/runtime`, format: 'esm', ext: 'js' } as BuildEntry)) ].map(name => ({ input: `src/${name}/runtime/`, outDir: `dist/${name}/runtime`, format: 'esm', ext: 'js' } as BuildEntry)),
], ],
hooks: { hooks: {
'mkdist:entry:options' (_ctx, _entry, mkdistOptions) { 'mkdist:entry:options' (_ctx, _entry, mkdistOptions) {
mkdistOptions.addRelativeDeclarationExtensions = true mkdistOptions.addRelativeDeclarationExtensions = true
} },
}, },
dependencies: [ dependencies: [
'nuxi', 'nuxi',
'vue-router', 'vue-router',
'ofetch' 'ofetch',
], ],
externals: [ externals: [
'nuxt', 'nuxt',
'nuxt/schema', 'nuxt/schema',
'@vue/shared', '@vue/shared',
'@unhead/vue' '@unhead/vue',
] ],
}) })

View File

@ -1,8 +1,7 @@
/* eslint-disable jsdoc/require-jsdoc */
function defineNuxtConfig (config) { function defineNuxtConfig (config) {
return config return config
} }
module.exports = { module.exports = {
defineNuxtConfig defineNuxtConfig,
} }

View File

@ -1,5 +1,6 @@
import type { NuxtConfig } from 'nuxt/schema' import type { NuxtConfig } from 'nuxt/schema'
import type { ConfigLayerMeta, DefineConfig } from 'c12' import type { ConfigLayerMeta, DefineConfig } from 'c12'
export { NuxtConfig } from 'nuxt/schema' export { NuxtConfig } from 'nuxt/schema'
export interface DefineNuxtConfig extends DefineConfig<NuxtConfig, ConfigLayerMeta> {} export interface DefineNuxtConfig extends DefineConfig<NuxtConfig, ConfigLayerMeta> {}

View File

@ -1,4 +1,3 @@
// eslint-disable-next-line import/export
export * from 'vue' export * from 'vue'
export const install = () => {} export const install = () => {}

View File

@ -6,7 +6,7 @@ export const requestIdleCallback: Window['requestIdleCallback'] = import.meta.se
const start = Date.now() const start = Date.now()
const idleDeadline = { const idleDeadline = {
didTimeout: false, didTimeout: false,
timeRemaining: () => Math.max(0, 50 - (Date.now() - start)) timeRemaining: () => Math.max(0, 50 - (Date.now() - start)),
} }
return setTimeout(() => { cb(idleDeadline) }, 1) return setTimeout(() => { cb(idleDeadline) }, 1)
})) }))

View File

@ -8,7 +8,7 @@ export const setInterval = import.meta.client
if (import.meta.dev) { if (import.meta.dev) {
throw createError({ throw createError({
statusCode: 500, statusCode: 500,
message: intervalError message: intervalError,
}) })
} }

View File

@ -6,26 +6,26 @@ export default defineComponent({
inheritAttrs: false, inheritAttrs: false,
props: { props: {
uid: { uid: {
type: String type: String,
}, },
fallbackTag: { fallbackTag: {
type: String, type: String,
default: () => 'div' default: () => 'div',
}, },
fallback: { fallback: {
type: String, type: String,
default: () => '' default: () => '',
}, },
placeholder: { placeholder: {
type: String type: String,
}, },
placeholderTag: { placeholderTag: {
type: String type: String,
}, },
keepFallback: { keepFallback: {
type: Boolean, type: Boolean,
default: () => false default: () => false,
} },
}, },
emits: ['ssr-error'], emits: ['ssr-error'],
setup (props, ctx) { setup (props, ctx) {
@ -49,5 +49,5 @@ export default defineComponent({
} }
return ctx.slots.default?.() return ctx.slots.default?.()
} }
} },
}) })

View File

@ -1,6 +1,6 @@
import { defineComponent, getCurrentInstance, onErrorCaptured, ref } from 'vue' import { defineComponent, getCurrentInstance, onErrorCaptured, ref } from 'vue'
import { ssrRenderAttrs, ssrRenderSlot, ssrRenderVNode } from 'vue/server-renderer' import { ssrRenderAttrs, ssrRenderSlot, ssrRenderVNode } from 'vue/server-renderer'
// eslint-disable-next-line
import { isPromise } from '@vue/shared' import { isPromise } from '@vue/shared'
import { useState } from '../composables/state' import { useState } from '../composables/state'
import { useNuxtApp } from '../nuxt' import { useNuxtApp } from '../nuxt'
@ -11,31 +11,31 @@ const NuxtClientFallbackServer = defineComponent({
inheritAttrs: false, inheritAttrs: false,
props: { props: {
uid: { uid: {
type: String type: String,
}, },
fallbackTag: { fallbackTag: {
type: String, type: String,
default: () => 'div' default: () => 'div',
}, },
fallback: { fallback: {
type: String, type: String,
default: () => '' default: () => '',
}, },
placeholder: { placeholder: {
type: String type: String,
}, },
placeholderTag: { placeholderTag: {
type: String type: String,
}, },
keepFallback: { keepFallback: {
type: Boolean, type: Boolean,
default: () => false default: () => false,
} },
}, },
emits: { emits: {
'ssr-error' (_error: unknown) { 'ssr-error' (_error: unknown) {
return true return true
} },
}, },
async setup (props, ctx) { async setup (props, ctx) {
const vm = getCurrentInstance() const vm = getCurrentInstance()
@ -86,7 +86,7 @@ const NuxtClientFallbackServer = defineComponent({
push(ctx.ssrVNodes.getBuffer()) push(ctx.ssrVNodes.getBuffer())
push('<!--]-->') push('<!--]-->')
} }
} },
}) })
export default NuxtClientFallbackServer export default NuxtClientFallbackServer

View File

@ -8,7 +8,7 @@ export const clientOnlySymbol: InjectionKey<boolean> = Symbol.for('nuxt:client-o
export default defineComponent({ export default defineComponent({
name: 'ClientOnly', name: 'ClientOnly',
inheritAttrs: false, inheritAttrs: false,
// eslint-disable-next-line vue/require-prop-types
props: ['fallback', 'placeholder', 'placeholderTag', 'fallbackTag'], props: ['fallback', 'placeholder', 'placeholderTag', 'fallbackTag'],
setup (_, { slots, attrs }) { setup (_, { slots, attrs }) {
const mounted = ref(false) const mounted = ref(false)
@ -28,7 +28,7 @@ export default defineComponent({
const fallbackTag = props.fallbackTag || props.placeholderTag || 'span' const fallbackTag = props.fallbackTag || props.placeholderTag || 'span'
return createElementBlock(fallbackTag, attrs, fallbackStr) return createElementBlock(fallbackTag, attrs, fallbackStr)
} }
} },
}) })
const cache = new WeakMap() const cache = new WeakMap()

View File

@ -7,5 +7,5 @@ export default defineComponent({
return () => props.slots.default?.() return () => props.slots.default?.()
} }
return () => props.slots.fallback?.() return () => props.slots.fallback?.()
} },
}) })

View File

@ -10,8 +10,8 @@ export default defineComponent({
props: { props: {
context: { context: {
type: Object as () => { name: string, props?: Record<string, any> }, type: Object as () => { name: string, props?: Record<string, any> },
required: true required: true,
} },
}, },
setup (props) { setup (props) {
const component = islandComponents[props.context.name] as ReturnType<typeof defineAsyncComponent> const component = islandComponents[props.context.name] as ReturnType<typeof defineAsyncComponent>
@ -19,7 +19,7 @@ export default defineComponent({
if (!component) { if (!component) {
throw createError({ throw createError({
statusCode: 404, statusCode: 404,
statusMessage: `Island component not found: ${props.context.name}` statusMessage: `Island component not found: ${props.context.name}`,
}) })
} }
@ -28,5 +28,5 @@ export default defineComponent({
}) })
return () => createVNode(component || 'span', { ...props.context.props, 'data-island-uid': '' }) return () => createVNode(component || 'span', { ...props.context.props, 'data-island-uid': '' })
} },
}) })

View File

@ -5,7 +5,7 @@ export default defineComponent({
emits: { emits: {
error (_error: unknown) { error (_error: unknown) {
return true return true
} },
}, },
setup (_props, { slots, emit }) { setup (_props, { slots, emit }) {
const error = ref<Error | null>(null) const error = ref<Error | null>(null)
@ -25,5 +25,5 @@ export default defineComponent({
} }
return () => error.value ? slots.error?.({ error, clearError }) : slots.default?.() return () => error.value ? slots.error?.({ error, clearError }) : slots.default?.()
} },
}) })

View File

@ -6,7 +6,7 @@
import { defineAsyncComponent } from 'vue' import { defineAsyncComponent } from 'vue'
const props = defineProps({ const props = defineProps({
error: Object error: Object,
}) })
// Deliberately prevent reactive update when error is cleared // Deliberately prevent reactive update when error is cleared
@ -26,7 +26,7 @@ const stacktrace = _error.stack
text, text,
internal: (line.includes('node_modules') && !line.includes('.cache')) || internal: (line.includes('node_modules') && !line.includes('.cache')) ||
line.includes('internal') || line.includes('internal') ||
line.includes('new Promise') line.includes('new Promise'),
} }
}).map(i => `<span class="stack${i.internal ? ' internal' : ''}">${i.text}</span>`).join('\n') }).map(i => `<span class="stack${i.internal ? ' internal' : ''}">${i.text}</span>`).join('\n')
: '' : ''

View File

@ -48,25 +48,25 @@ export default defineComponent({
props: { props: {
name: { name: {
type: String, type: String,
required: true required: true,
}, },
lazy: Boolean, lazy: Boolean,
props: { props: {
type: Object, type: Object,
default: () => undefined default: () => undefined,
}, },
context: { context: {
type: Object, type: Object,
default: () => ({}) default: () => ({}),
}, },
source: { source: {
type: String, type: String,
default: () => undefined default: () => undefined,
}, },
dangerouslyLoadClientComponents: { dangerouslyLoadClientComponents: {
type: Boolean, type: Boolean,
default: false default: false,
} },
}, },
emits: ['error'], emits: ['error'],
async setup (props, { slots, expose, emit }) { async setup (props, { slots, expose, emit }) {
@ -99,9 +99,9 @@ export default defineComponent({
...(import.meta.server && import.meta.prerender) ...(import.meta.server && import.meta.prerender)
? {} ? {}
: { params: { ...props.context, props: props.props ? JSON.stringify(props.props) : undefined } }, : { params: { ...props.context, props: props.props ? JSON.stringify(props.props) : undefined } },
result: toRevive result: toRevive,
}, },
...result ...result,
} }
} }
@ -168,7 +168,7 @@ export default defineComponent({
// $fetch handles the app.baseURL in dev // $fetch handles the app.baseURL in dev
const r = await eventFetch(withQuery(((import.meta.dev && import.meta.client) || props.source) ? url : joinURL(config.app.baseURL ?? '', url), { const r = await eventFetch(withQuery(((import.meta.dev && import.meta.client) || props.source) ? url : joinURL(config.app.baseURL ?? '', url), {
...props.context, ...props.context,
props: props.props ? JSON.stringify(props.props) : undefined props: props.props ? JSON.stringify(props.props) : undefined,
})) }))
const result = import.meta.server || !import.meta.dev ? await r.json() : (r as FetchResponse<NuxtIslandResponse>)._data const result = import.meta.server || !import.meta.dev ? await r.json() : (r as FetchResponse<NuxtIslandResponse>)._data
// TODO: support passing on more headers // TODO: support passing on more headers
@ -219,7 +219,7 @@ export default defineComponent({
} }
expose({ expose({
refresh: () => fetchComponent(true) refresh: () => fetchComponent(true),
}) })
if (import.meta.hot) { if (import.meta.hot) {
@ -261,7 +261,7 @@ export default defineComponent({
teleports.push(createVNode(Teleport, teleports.push(createVNode(Teleport,
// use different selectors for even and odd teleportKey to force trigger the teleport // use different selectors for even and odd teleportKey to force trigger the teleport
{ to: import.meta.client ? `${isKeyOdd ? 'div' : ''}[data-island-uid="${uid.value}"][data-island-slot="${slot}"]` : `uid=${uid.value};slot=${slot}` }, { to: import.meta.client ? `${isKeyOdd ? 'div' : ''}[data-island-uid="${uid.value}"][data-island-slot="${slot}"]` : `uid=${uid.value};slot=${slot}` },
{ default: () => (payloads.slots?.[slot].props?.length ? payloads.slots[slot].props : [{}]).map((data: any) => slots[slot]?.(data)) }) { default: () => (payloads.slots?.[slot].props?.length ? payloads.slots[slot].props : [{}]).map((data: any) => slots[slot]?.(data)) }),
) )
} }
} }
@ -275,7 +275,7 @@ export default defineComponent({
replaced = replaced.replaceAll(`data-island-slot="${slot}">`, full => full + slots[slot]) replaced = replaced.replaceAll(`data-island-slot="${slot}">`, full => full + slots[slot])
} }
teleports.push(createVNode(Teleport, { to: `uid=${uid.value};client=${id}` }, { teleports.push(createVNode(Teleport, { to: `uid=${uid.value};client=${id}` }, {
default: () => [createStaticVNode(replaced, 1)] default: () => [createStaticVNode(replaced, 1)],
})) }))
} }
} }
@ -286,9 +286,9 @@ export default defineComponent({
// use different selectors for even and odd teleportKey to force trigger the teleport // use different selectors for even and odd teleportKey to force trigger the teleport
const vnode = createVNode(Teleport, { to: `${isKeyOdd ? 'div' : ''}[data-island-uid='${uid.value}'][data-island-component="${id}"]` }, { const vnode = createVNode(Teleport, { to: `${isKeyOdd ? 'div' : ''}[data-island-uid='${uid.value}'][data-island-component="${id}"]` }, {
default: () => { default: () => {
return [h(component, props, Object.fromEntries(Object.entries(slots || {}).map(([k, v]) => ([k, () => createStaticVNode(`<div style="display: contents" data-island-uid data-island-slot="${k}">${v}</div>`, 1) return [h(component, props, Object.fromEntries(Object.entries(slots || {}).map(([k, v]) => ([k, () => createStaticVNode(`<div style="display: contents" data-island-uid data-island-slot="${k}">${v}</div>`, 1),
]))))] ]))))]
} },
}) })
teleports.push(vnode) teleports.push(vnode)
} }
@ -297,8 +297,8 @@ export default defineComponent({
} }
return h(Fragment, teleports) return h(Fragment, teleports)
}, _cache, 1) }, _cache, 1),
] ]
} }
} },
}) })

View File

@ -2,7 +2,6 @@ import type { DefineComponent, MaybeRef, VNode } from 'vue'
import { Suspense, Transition, computed, defineComponent, h, inject, mergeProps, nextTick, onMounted, provide, ref, unref } from 'vue' import { Suspense, Transition, computed, defineComponent, h, inject, mergeProps, nextTick, onMounted, provide, ref, unref } from 'vue'
import type { RouteLocationNormalizedLoaded } from 'vue-router' import type { RouteLocationNormalizedLoaded } from 'vue-router'
// eslint-disable-next-line import/no-restricted-paths
import type { PageMeta } from '../../pages/runtime/composables' import type { PageMeta } from '../../pages/runtime/composables'
import { useRoute, useRouter } from '../composables/router' import { useRoute, useRouter } from '../composables/router'
@ -23,7 +22,7 @@ const LayoutLoader = defineComponent({
inheritAttrs: false, inheritAttrs: false,
props: { props: {
name: String, name: String,
layoutProps: Object layoutProps: Object,
}, },
async setup (props, context) { async setup (props, context) {
// This is a deliberate hack - this component must always be called with an explicit key to ensure // This is a deliberate hack - this component must always be called with an explicit key to ensure
@ -32,7 +31,7 @@ const LayoutLoader = defineComponent({
const LayoutComponent = await layouts[props.name]().then((r: any) => r.default || r) const LayoutComponent = await layouts[props.name]().then((r: any) => r.default || r)
return () => h(LayoutComponent, props.layoutProps, context.slots) return () => h(LayoutComponent, props.layoutProps, context.slots)
} },
}) })
export default defineComponent({ export default defineComponent({
@ -41,12 +40,12 @@ export default defineComponent({
props: { props: {
name: { name: {
type: [String, Boolean, Object] as unknown as () => unknown extends PageMeta['layout'] ? MaybeRef<string | false> : PageMeta['layout'], type: [String, Boolean, Object] as unknown as () => unknown extends PageMeta['layout'] ? MaybeRef<string | false> : PageMeta['layout'],
default: null default: null,
}, },
fallback: { fallback: {
type: [String, Object] as unknown as () => unknown extends PageMeta['layout'] ? MaybeRef<string> : PageMeta['layout'], type: [String, Object] as unknown as () => unknown extends PageMeta['layout'] ? MaybeRef<string> : PageMeta['layout'],
default: null default: null,
} },
}, },
setup (props, context) { setup (props, context) {
const nuxtApp = useNuxtApp() const nuxtApp = useNuxtApp()
@ -94,12 +93,12 @@ export default defineComponent({
key: layout.value || undefined, key: layout.value || undefined,
name: layout.value, name: layout.value,
shouldProvide: !props.name, shouldProvide: !props.name,
hasTransition: !!transitionProps hasTransition: !!transitionProps,
}, context.slots) }, context.slots),
}) }),
}).default() }).default()
} }
} },
}) as unknown as DefineComponent<{ }) as unknown as DefineComponent<{
name?: (unknown extends PageMeta['layout'] ? MaybeRef<string | false> : PageMeta['layout']) | undefined name?: (unknown extends PageMeta['layout'] ? MaybeRef<string | false> : PageMeta['layout']) | undefined
}> }>
@ -109,17 +108,17 @@ const LayoutProvider = defineComponent({
inheritAttrs: false, inheritAttrs: false,
props: { props: {
name: { name: {
type: [String, Boolean] as unknown as () => string | false type: [String, Boolean] as unknown as () => string | false,
}, },
layoutProps: { layoutProps: {
type: Object type: Object,
}, },
hasTransition: { hasTransition: {
type: Boolean type: Boolean,
}, },
shouldProvide: { shouldProvide: {
type: Boolean type: Boolean,
} },
}, },
setup (props, context) { setup (props, context) {
// Prevent reactivity when the page will be rerendered in a different suspense fork // Prevent reactivity when the page will be rerendered in a different suspense fork
@ -127,7 +126,7 @@ const LayoutProvider = defineComponent({
const name = props.name const name = props.name
if (props.shouldProvide) { if (props.shouldProvide) {
provide(LayoutMetaSymbol, { provide(LayoutMetaSymbol, {
isCurrent: (route: RouteLocationNormalizedLoaded) => name === (route.meta.layout ?? 'default') isCurrent: (route: RouteLocationNormalizedLoaded) => name === (route.meta.layout ?? 'default'),
}) })
} }
@ -159,7 +158,7 @@ const LayoutProvider = defineComponent({
vnode = h( vnode = h(
LayoutLoader, LayoutLoader,
{ key: name, layoutProps: props.layoutProps, name }, { key: name, layoutProps: props.layoutProps, name },
context.slots context.slots,
) )
return vnode return vnode
@ -168,8 +167,8 @@ const LayoutProvider = defineComponent({
return h( return h(
LayoutLoader, LayoutLoader,
{ key: name, layoutProps: props.layoutProps, name }, { key: name, layoutProps: props.layoutProps, name },
context.slots context.slots,
) )
} }
} },
}) })

View File

@ -4,7 +4,7 @@ import type {
ComputedRef, ComputedRef,
DefineComponent, DefineComponent,
InjectionKey, PropType, InjectionKey, PropType,
VNodeProps VNodeProps,
} from 'vue' } from 'vue'
import { computed, defineComponent, h, inject, onBeforeUnmount, onMounted, provide, ref, resolveComponent } from 'vue' import { computed, defineComponent, h, inject, onBeforeUnmount, onMounted, provide, ref, resolveComponent } from 'vue'
import type { RouteLocation, RouteLocationRaw, Router, RouterLinkProps } from '#vue-router' import type { RouteLocation, RouteLocationRaw, Router, RouterLinkProps } from '#vue-router'
@ -114,7 +114,7 @@ export function defineNuxtLink (options: NuxtLinkOptions) {
const resolvedPath = { const resolvedPath = {
...to, ...to,
name: undefined, // named routes would otherwise always override trailing slash behavior name: undefined, // named routes would otherwise always override trailing slash behavior
path: applyTrailingSlashBehavior(path, options.trailingSlash) path: applyTrailingSlashBehavior(path, options.trailingSlash),
} }
return resolvedPath return resolvedPath
@ -127,85 +127,85 @@ export function defineNuxtLink (options: NuxtLinkOptions) {
to: { to: {
type: [String, Object] as PropType<RouteLocationRaw>, type: [String, Object] as PropType<RouteLocationRaw>,
default: undefined, default: undefined,
required: false required: false,
}, },
href: { href: {
type: [String, Object] as PropType<RouteLocationRaw>, type: [String, Object] as PropType<RouteLocationRaw>,
default: undefined, default: undefined,
required: false required: false,
}, },
// Attributes // Attributes
target: { target: {
type: String as PropType<NuxtLinkProps['target']>, type: String as PropType<NuxtLinkProps['target']>,
default: undefined, default: undefined,
required: false required: false,
}, },
rel: { rel: {
type: String as PropType<NuxtLinkProps['rel']>, type: String as PropType<NuxtLinkProps['rel']>,
default: undefined, default: undefined,
required: false required: false,
}, },
noRel: { noRel: {
type: Boolean as PropType<NuxtLinkProps['noRel']>, type: Boolean as PropType<NuxtLinkProps['noRel']>,
default: undefined, default: undefined,
required: false required: false,
}, },
// Prefetching // Prefetching
prefetch: { prefetch: {
type: Boolean as PropType<NuxtLinkProps['prefetch']>, type: Boolean as PropType<NuxtLinkProps['prefetch']>,
default: undefined, default: undefined,
required: false required: false,
}, },
noPrefetch: { noPrefetch: {
type: Boolean as PropType<NuxtLinkProps['noPrefetch']>, type: Boolean as PropType<NuxtLinkProps['noPrefetch']>,
default: undefined, default: undefined,
required: false required: false,
}, },
// Styling // Styling
activeClass: { activeClass: {
type: String as PropType<NuxtLinkProps['activeClass']>, type: String as PropType<NuxtLinkProps['activeClass']>,
default: undefined, default: undefined,
required: false required: false,
}, },
exactActiveClass: { exactActiveClass: {
type: String as PropType<NuxtLinkProps['exactActiveClass']>, type: String as PropType<NuxtLinkProps['exactActiveClass']>,
default: undefined, default: undefined,
required: false required: false,
}, },
prefetchedClass: { prefetchedClass: {
type: String as PropType<NuxtLinkProps['prefetchedClass']>, type: String as PropType<NuxtLinkProps['prefetchedClass']>,
default: undefined, default: undefined,
required: false required: false,
}, },
// Vue Router's `<RouterLink>` additional props // Vue Router's `<RouterLink>` additional props
replace: { replace: {
type: Boolean as PropType<NuxtLinkProps['replace']>, type: Boolean as PropType<NuxtLinkProps['replace']>,
default: undefined, default: undefined,
required: false required: false,
}, },
ariaCurrentValue: { ariaCurrentValue: {
type: String as PropType<NuxtLinkProps['ariaCurrentValue']>, type: String as PropType<NuxtLinkProps['ariaCurrentValue']>,
default: undefined, default: undefined,
required: false required: false,
}, },
// Edge cases handling // Edge cases handling
external: { external: {
type: Boolean as PropType<NuxtLinkProps['external']>, type: Boolean as PropType<NuxtLinkProps['external']>,
default: undefined, default: undefined,
required: false required: false,
}, },
// Slot API // Slot API
custom: { custom: {
type: Boolean as PropType<NuxtLinkProps['custom']>, type: Boolean as PropType<NuxtLinkProps['custom']>,
default: undefined, default: undefined,
required: false required: false,
} },
}, },
setup (props, { slots }) { setup (props, { slots }) {
const router = useRouter() const router = useRouter()
@ -269,7 +269,7 @@ export function defineNuxtLink (options: NuxtLinkOptions) {
const path = typeof to.value === 'string' ? to.value : router.resolve(to.value).fullPath const path = typeof to.value === 'string' ? to.value : router.resolve(to.value).fullPath
await Promise.all([ await Promise.all([
nuxtApp.hooks.callHook('link:prefetch', path).catch(() => {}), nuxtApp.hooks.callHook('link:prefetch', path).catch(() => {}),
!isExternal.value && preloadRouteComponents(to.value as string, router).catch(() => {}) !isExternal.value && preloadRouteComponents(to.value as string, router).catch(() => {}),
]) ])
prefetched.value = true prefetched.value = true
}) })
@ -303,7 +303,7 @@ export function defineNuxtLink (options: NuxtLinkOptions) {
exactActiveClass: props.exactActiveClass || options.exactActiveClass, exactActiveClass: props.exactActiveClass || options.exactActiveClass,
replace: props.replace, replace: props.replace,
ariaCurrentValue: props.ariaCurrentValue, ariaCurrentValue: props.ariaCurrentValue,
custom: props.custom custom: props.custom,
} }
// `custom` API cannot support fallthrough attributes as the slot // `custom` API cannot support fallthrough attributes as the slot
@ -319,7 +319,7 @@ export function defineNuxtLink (options: NuxtLinkOptions) {
return h( return h(
resolveComponent('RouterLink'), resolveComponent('RouterLink'),
routerLinkProps, routerLinkProps,
slots.default slots.default,
) )
} }
@ -344,7 +344,7 @@ export function defineNuxtLink (options: NuxtLinkOptions) {
* A fallback rel of `noopener noreferrer` is applied for external links or links that open in a new tab. * A fallback rel of `noopener noreferrer` is applied for external links or links that open in a new tab.
* This solves a reverse tabnapping security flaw in browsers pre-2021 as well as improving privacy. * This solves a reverse tabnapping security flaw in browsers pre-2021 as well as improving privacy.
*/ */
(isAbsoluteUrl.value || hasTarget.value) ? 'noopener noreferrer' : '' (isAbsoluteUrl.value || hasTarget.value) ? 'noopener noreferrer' : '',
) || null ) || null
// https://router.vuejs.org/api/#custom // https://router.vuejs.org/api/#custom
@ -372,20 +372,20 @@ export function defineNuxtLink (options: NuxtLinkOptions) {
matched: [], matched: [],
redirectedFrom: undefined, redirectedFrom: undefined,
meta: {}, meta: {},
href href,
} satisfies RouteLocation & { href: string } } satisfies RouteLocation & { href: string }
}, },
rel, rel,
target, target,
isExternal: isExternal.value, isExternal: isExternal.value,
isActive: false, isActive: false,
isExactActive: false isExactActive: false,
}) })
} }
return h('a', { ref: el, href, rel, target }, slots.default?.()) return h('a', { ref: el, href, rel, target }, slots.default?.())
} }
} },
}) as unknown as DefineComponent<NuxtLinkProps> }) as unknown as DefineComponent<NuxtLinkProps>
} }
@ -441,7 +441,7 @@ function useObserver (): { observe: ObserveFn } | undefined {
} }
const _observer = nuxtApp._observer = { const _observer = nuxtApp._observer = {
observe observe,
} }
return _observer return _observer

View File

@ -6,34 +6,34 @@ export default defineComponent({
props: { props: {
throttle: { throttle: {
type: Number, type: Number,
default: 200 default: 200,
}, },
duration: { duration: {
type: Number, type: Number,
default: 2000 default: 2000,
}, },
height: { height: {
type: Number, type: Number,
default: 3 default: 3,
}, },
color: { color: {
type: [String, Boolean], type: [String, Boolean],
default: 'repeating-linear-gradient(to right,#00dc82 0%,#34cdfe 50%,#0047e1 100%)' default: 'repeating-linear-gradient(to right,#00dc82 0%,#34cdfe 50%,#0047e1 100%)',
}, },
estimatedProgress: { estimatedProgress: {
type: Function as unknown as () => (duration: number, elapsed: number) => number, type: Function as unknown as () => (duration: number, elapsed: number) => number,
required: false required: false,
} },
}, },
setup (props, { slots, expose }) { setup (props, { slots, expose }) {
const { progress, isLoading, start, finish, clear } = useLoadingIndicator({ const { progress, isLoading, start, finish, clear } = useLoadingIndicator({
duration: props.duration, duration: props.duration,
throttle: props.throttle, throttle: props.throttle,
estimatedProgress: props.estimatedProgress estimatedProgress: props.estimatedProgress,
}) })
expose({ expose({
progress, isLoading, start, finish, clear progress, isLoading, start, finish, clear,
}) })
return () => h('div', { return () => h('div', {
@ -52,8 +52,8 @@ export default defineComponent({
transform: `scaleX(${progress.value}%)`, transform: `scaleX(${progress.value}%)`,
transformOrigin: 'left', transformOrigin: 'left',
transition: 'transform 0.1s, height 0.4s, opacity 0.4s', transition: 'transform 0.1s, height 0.4s, opacity 0.4s',
zIndex: 999999 zIndex: 999999,
} },
}, slots) }, slots)
} },
}) })

View File

@ -4,14 +4,14 @@ function renderStubMessage (name: string) {
throw createError({ throw createError({
fatal: true, fatal: true,
statusCode: 500, statusCode: 500,
statusMessage: `${name} is provided by @nuxt/image. Check your console to install it or run 'npx nuxi@latest module add @nuxt/image'` statusMessage: `${name} is provided by @nuxt/image. Check your console to install it or run 'npx nuxi@latest module add @nuxt/image'`,
}) })
} }
export const NuxtImg = { export const NuxtImg = {
setup: () => renderStubMessage('<NuxtImg>') setup: () => renderStubMessage('<NuxtImg>'),
} }
export const NuxtPicture = { export const NuxtPicture = {
setup: () => renderStubMessage('<NuxtPicture>') setup: () => renderStubMessage('<NuxtPicture>'),
} }

View File

@ -5,7 +5,7 @@ import { useNuxtApp } from '../nuxt'
import { paths } from '#build/components-chunk' import { paths } from '#build/components-chunk'
type ExtendedComponent = Component & { type ExtendedComponent = Component & {
__file: string, __file: string
__name: string __name: string
} }
@ -21,11 +21,11 @@ export default defineComponent({
props: { props: {
to: { to: {
type: String, type: String,
required: true required: true,
}, },
nuxtClient: { nuxtClient: {
type: Boolean, type: Boolean,
default: false default: false,
}, },
/** /**
* ONLY used in dev mode since we use build:manifest result in production * ONLY used in dev mode since we use build:manifest result in production
@ -33,8 +33,8 @@ export default defineComponent({
*/ */
rootDir: { rootDir: {
type: String, type: String,
default: null default: null,
} },
}, },
setup (props, { slots }) { setup (props, { slots }) {
const nuxtApp = useNuxtApp() const nuxtApp = useNuxtApp()
@ -47,19 +47,19 @@ export default defineComponent({
return () => { return () => {
const slot = slots.default!()[0] const slot = slots.default!()[0]
const slotType = (slot.type as ExtendedComponent) const slotType = slot.type as ExtendedComponent
const name = (slotType.__name || slotType.name) as string const name = (slotType.__name || slotType.name) as string
islandContext.components[props.to] = { islandContext.components[props.to] = {
chunk: import.meta.dev ? '_nuxt/' + paths[name] : paths[name], chunk: import.meta.dev ? '_nuxt/' + paths[name] : paths[name],
props: slot.props || {} props: slot.props || {},
} }
return [h('div', { return [h('div', {
style: 'display: contents;', 'style': 'display: contents;',
'data-island-uid': '', 'data-island-uid': '',
'data-island-component': props.to 'data-island-component': props.to,
}, []), h(Teleport, { to: props.to }, slot)] }, []), h(Teleport, { to: props.to }, slot)]
} }
} },
}) })

View File

@ -12,14 +12,14 @@ export default defineComponent({
props: { props: {
name: { name: {
type: String, type: String,
required: true required: true,
}, },
/** /**
* must be an array to handle v-for * must be an array to handle v-for
*/ */
props: { props: {
type: Object as () => Array<any> type: Object as () => Array<any>,
} },
}, },
setup (props, { slots }) { setup (props, { slots }) {
const nuxtApp = useNuxtApp() const nuxtApp = useNuxtApp()
@ -30,7 +30,7 @@ export default defineComponent({
const componentName = inject(NuxtTeleportIslandSymbol, false) const componentName = inject(NuxtTeleportIslandSymbol, false)
islandContext.slots[props.name] = { islandContext.slots[props.name] = {
props: (props.props || []) as unknown[] props: (props.props || []) as unknown[],
} }
return () => { return () => {
@ -38,18 +38,18 @@ export default defineComponent({
if (nuxtApp.ssrContext?.islandContext && slots.default) { if (nuxtApp.ssrContext?.islandContext && slots.default) {
vnodes.push(h('div', { vnodes.push(h('div', {
style: 'display: contents;', 'style': 'display: contents;',
'data-island-uid': '', 'data-island-uid': '',
'data-island-slot': props.name 'data-island-slot': props.name,
}, { }, {
// Teleport in slot to not be hydrated client-side with the staticVNode // Teleport in slot to not be hydrated client-side with the staticVNode
default: () => [createVNode(Teleport, { to: `island-slot=${componentName};${props.name}` }, slots.default?.())] default: () => [createVNode(Teleport, { to: `island-slot=${componentName};${props.name}` }, slots.default?.())],
})) }))
} else { } else {
vnodes.push(h('div', { vnodes.push(h('div', {
style: 'display: contents;', 'style': 'display: contents;',
'data-island-uid': '', 'data-island-uid': '',
'data-island-slot': props.name 'data-island-slot': props.name,
})) }))
} }
@ -59,5 +59,5 @@ export default defineComponent({
return vnodes return vnodes
} }
} },
}) })

View File

@ -7,15 +7,15 @@ export const RouteProvider = defineComponent({
props: { props: {
vnode: { vnode: {
type: Object as () => VNode, type: Object as () => VNode,
required: true required: true,
}, },
route: { route: {
type: Object as () => RouteLocationNormalizedLoaded, type: Object as () => RouteLocationNormalizedLoaded,
required: true required: true,
}, },
vnodeRef: Object as () => Ref<any>, vnodeRef: Object as () => Ref<any>,
renderKey: String, renderKey: String,
trackRootNodes: Boolean trackRootNodes: Boolean,
}, },
setup (props) { setup (props) {
// Prevent reactivity when the page will be rerendered in a different suspense fork // Prevent reactivity when the page will be rerendered in a different suspense fork
@ -26,7 +26,7 @@ export const RouteProvider = defineComponent({
const route = {} as RouteLocation const route = {} as RouteLocation
for (const key in props.route) { for (const key in props.route) {
Object.defineProperty(route, key, { Object.defineProperty(route, key, {
get: () => previousKey === props.renderKey ? props.route[key as keyof RouteLocationNormalizedLoaded] : previousRoute[key as keyof RouteLocationNormalizedLoaded] get: () => previousKey === props.renderKey ? props.route[key as keyof RouteLocationNormalizedLoaded] : previousRoute[key as keyof RouteLocationNormalizedLoaded],
}) })
} }
@ -52,5 +52,5 @@ export const RouteProvider = defineComponent({
return h(props.vnode, { ref: props.vnodeRef }) return h(props.vnode, { ref: props.vnodeRef })
} }
} },
}) })

View File

@ -4,5 +4,5 @@ export default defineComponent({
name: 'ServerPlaceholder', name: 'ServerPlaceholder',
render () { render () {
return createElementBlock('div') return createElementBlock('div')
} },
}) })

View File

@ -20,8 +20,8 @@ export default (url: string) => defineComponent({
return () => [ return () => [
h('div', 'Component Test Wrapper for ' + query.path), h('div', 'Component Test Wrapper for ' + query.path),
h('div', { id: 'nuxt-component-root' }, [ h('div', { id: 'nuxt-component-root' }, [
h(comp, { ...attrs, ...props, ...urlProps }) h(comp, { ...attrs, ...props, ...urlProps }),
]) ]),
] ]
} },
}) })

View File

@ -36,7 +36,7 @@ export function isChangingPage (to: RouteLocationNormalized, from: RouteLocation
if (generateRouteKey(to) !== generateRouteKey(from)) { return true } if (generateRouteKey(to) !== generateRouteKey(from)) { return true }
const areComponentsSame = to.matched.every((comp, index) => const areComponentsSame = to.matched.every((comp, index) =>
comp.components && comp.components.default === from.matched[index]?.components?.default comp.components && comp.components.default === from.matched[index]?.components?.default,
) )
if (areComponentsSame) { if (areComponentsSame) {
return false return false
@ -44,7 +44,6 @@ export function isChangingPage (to: RouteLocationNormalized, from: RouteLocation
return true return true
} }
// eslint-disable-next-line no-use-before-define
export type SSRBuffer = SSRBufferItem[] & { hasAsync?: boolean } export type SSRBuffer = SSRBufferItem[] & { hasAsync?: boolean }
export type SSRBufferItem = string | SSRBuffer | Promise<SSRBuffer> export type SSRBufferItem = string | SSRBuffer | Promise<SSRBuffer>
@ -71,7 +70,7 @@ export function createBuffer () {
if (isPromise(item) || (isArray(item) && item.hasAsync)) { if (isPromise(item) || (isArray(item) && item.hasAsync)) {
buffer.hasAsync = true buffer.hasAsync = true
} }
} },
} }
} }
@ -95,7 +94,7 @@ export function vforToArray (source: any): any[] {
} else if (isObject(source)) { } else if (isObject(source)) {
if (source[Symbol.iterator as any]) { if (source[Symbol.iterator as any]) {
return Array.from(source as Iterable<any>, item => return Array.from(source as Iterable<any>, item =>
item item,
) )
} else { } else {
const keys = Object.keys(source) const keys = Object.keys(source)

View File

@ -257,7 +257,7 @@ export function useAsyncData<
data: _ref(options.getCachedData!(key, nuxtApp) ?? options.default!()), data: _ref(options.getCachedData!(key, nuxtApp) ?? options.default!()),
pending: ref(!hasCachedData()), pending: ref(!hasCachedData()),
error: toRef(nuxtApp.payload._errors, key), error: toRef(nuxtApp.payload._errors, key),
status: ref('idle') status: ref('idle'),
} }
} }
@ -477,8 +477,8 @@ export function useNuxtData<DataT = any> (key: string): { data: Ref<DataT | null
} else { } else {
nuxtApp.payload.data[key] = value nuxtApp.payload.data[key] = value
} }
} },
}) }),
} }
} }

View File

@ -38,7 +38,7 @@ export const defineNuxtComponent: typeof defineComponent =
if (!setup && !options.asyncData && !options.head) { if (!setup && !options.asyncData && !options.head) {
return { return {
[NuxtComponentIndicator]: true, [NuxtComponentIndicator]: true,
...options ...options,
} }
} }
@ -66,6 +66,6 @@ export const defineNuxtComponent: typeof defineComponent =
.finally(() => { .finally(() => {
promises.length = 0 promises.length = 0
}) })
} },
} as DefineComponent } as DefineComponent
} }

View File

@ -29,7 +29,7 @@ const CookieDefaults = {
path: '/', path: '/',
watch: true, watch: true,
decode: val => destr(decodeURIComponent(val)), decode: val => destr(decodeURIComponent(val)),
encode: val => encodeURIComponent(typeof val === 'string' ? val : JSON.stringify(val)) encode: val => encodeURIComponent(typeof val === 'string' ? val : JSON.stringify(val)),
} satisfies CookieOptions<any> } satisfies CookieOptions<any>
const store = import.meta.client && cookieStore ? window.cookieStore : undefined const store = import.meta.client && cookieStore ? window.cookieStore : undefined
@ -220,7 +220,7 @@ function cookieRef<T> (value: T | undefined, delay: number, shouldWatch: boolean
internalRef.value = newValue internalRef.value = newValue
trigger() trigger()
} },
} }
}) })
} }

View File

@ -14,9 +14,9 @@ export interface NuxtError<DataT = unknown> extends H3Error<DataT> {}
/** @since 3.0.0 */ /** @since 3.0.0 */
export const showError = <DataT = unknown>( export const showError = <DataT = unknown>(
error: string | Error | (Partial<NuxtError<DataT>> & { error: string | Error | (Partial<NuxtError<DataT>> & {
status?: number; status?: number
statusText?: string; statusText?: string
}) }),
) => { ) => {
const nuxtError = createError<DataT>(error) const nuxtError = createError<DataT>(error)
@ -52,22 +52,22 @@ export const clearError = async (options: { redirect?: string } = {}) => {
/** @since 3.0.0 */ /** @since 3.0.0 */
export const isNuxtError = <DataT = unknown>( export const isNuxtError = <DataT = unknown>(
error?: string | object error?: string | object,
): error is NuxtError<DataT> => !!error && typeof error === 'object' && NUXT_ERROR_SIGNATURE in error ): error is NuxtError<DataT> => !!error && typeof error === 'object' && NUXT_ERROR_SIGNATURE in error
/** @since 3.0.0 */ /** @since 3.0.0 */
export const createError = <DataT = unknown>( export const createError = <DataT = unknown>(
error: string | Error | (Partial<NuxtError<DataT>> & { error: string | Error | (Partial<NuxtError<DataT>> & {
status?: number; status?: number
statusText?: string; statusText?: string
}) }),
) => { ) => {
const nuxtError: NuxtError<DataT> = createH3Error<DataT>(error) const nuxtError: NuxtError<DataT> = createH3Error<DataT>(error)
Object.defineProperty(nuxtError, NUXT_ERROR_SIGNATURE, { Object.defineProperty(nuxtError, NUXT_ERROR_SIGNATURE, {
value: true, value: true,
configurable: false, configurable: false,
writable: false writable: false,
}) })
return nuxtError return nuxtError

View File

@ -21,7 +21,7 @@ type ComputedOptions<T extends Record<string, any>> = {
} }
interface NitroFetchOptions<R extends NitroFetchRequest, M extends AvailableRouterMethod<R> = AvailableRouterMethod<R>> extends FetchOptions { interface NitroFetchOptions<R extends NitroFetchRequest, M extends AvailableRouterMethod<R> = AvailableRouterMethod<R>> extends FetchOptions {
method?: M; method?: M
} }
type ComputedFetchOptions<R extends NitroFetchRequest, M extends AvailableRouterMethod<R>> = ComputedOptions<NitroFetchOptions<R, M>> type ComputedFetchOptions<R extends NitroFetchRequest, M extends AvailableRouterMethod<R>> = ComputedOptions<NitroFetchOptions<R, M>>
@ -32,7 +32,7 @@ export interface UseFetchOptions<
PickKeys extends KeysOf<DataT> = KeysOf<DataT>, PickKeys extends KeysOf<DataT> = KeysOf<DataT>,
DefaultT = null, DefaultT = null,
R extends NitroFetchRequest = string & {}, R extends NitroFetchRequest = string & {},
M extends AvailableRouterMethod<R> = AvailableRouterMethod<R> M extends AvailableRouterMethod<R> = AvailableRouterMethod<R>,
> extends Omit<AsyncDataOptions<ResT, DataT, PickKeys, DefaultT>, 'watch'>, ComputedFetchOptions<R, M> { > extends Omit<AsyncDataOptions<ResT, DataT, PickKeys, DefaultT>, 'watch'>, ComputedFetchOptions<R, M> {
key?: string key?: string
$fetch?: typeof globalThis.$fetch $fetch?: typeof globalThis.$fetch
@ -90,7 +90,7 @@ export function useFetch<
> ( > (
request: Ref<ReqT> | ReqT | (() => ReqT), request: Ref<ReqT> | ReqT | (() => ReqT),
arg1?: string | UseFetchOptions<_ResT, DataT, PickKeys, DefaultT, ReqT, Method>, arg1?: string | UseFetchOptions<_ResT, DataT, PickKeys, DefaultT, ReqT, Method>,
arg2?: string arg2?: string,
) { ) {
const [opts = {}, autoKey] = typeof arg1 === 'string' ? [{}, arg1] : [arg1, arg2] const [opts = {}, autoKey] = typeof arg1 === 'string' ? [{}, arg1] : [arg1, arg2]
@ -127,7 +127,7 @@ export function useFetch<
const _fetchOptions = reactive({ const _fetchOptions = reactive({
...fetchDefaults, ...fetchDefaults,
...fetchOptions, ...fetchOptions,
cache: typeof opts.cache === 'boolean' ? undefined : opts.cache cache: typeof opts.cache === 'boolean' ? undefined : opts.cache,
}) })
const _asyncDataOptions: AsyncDataOptions<_ResT, DataT, PickKeys, DefaultT> = { const _asyncDataOptions: AsyncDataOptions<_ResT, DataT, PickKeys, DefaultT> = {
@ -140,7 +140,7 @@ export function useFetch<
getCachedData, getCachedData,
deep, deep,
dedupe, dedupe,
watch: watch === false ? [] : [_fetchOptions, _request, ...(watch || [])] watch: watch === false ? [] : [_fetchOptions, _request, ...(watch || [])],
} }
if (import.meta.dev && import.meta.client) { if (import.meta.dev && import.meta.client) {
@ -220,7 +220,7 @@ export function useLazyFetch<
> ( > (
request: Ref<ReqT> | ReqT | (() => ReqT), request: Ref<ReqT> | ReqT | (() => ReqT),
arg1?: string | Omit<UseFetchOptions<_ResT, DataT, PickKeys, DefaultT, ReqT, Method>, 'lazy'>, arg1?: string | Omit<UseFetchOptions<_ResT, DataT, PickKeys, DefaultT, ReqT, Method>, 'lazy'>,
arg2?: string arg2?: string,
) { ) {
const [opts = {}, autoKey] = typeof arg1 === 'string' ? [{}, arg1] : [arg1, arg2] const [opts = {}, autoKey] = typeof arg1 === 'string' ? [{}, arg1] : [arg1, arg2]
@ -231,7 +231,7 @@ export function useLazyFetch<
return useFetch<ResT, ErrorT, ReqT, Method, _ResT, DataT, PickKeys, DefaultT>(request, { return useFetch<ResT, ErrorT, ReqT, Method, _ResT, DataT, PickKeys, DefaultT>(request, {
...opts, ...opts,
lazy: true lazy: true,
}, },
// @ts-expect-error we pass an extra argument with the resolved auto-key to prevent another from being injected // @ts-expect-error we pass an extra argument with the resolved auto-key to prevent another from being injected
autoKey) autoKey)
@ -240,7 +240,7 @@ export function useLazyFetch<
function generateOptionSegments<_ResT, DataT, DefaultT> (opts: UseFetchOptions<_ResT, DataT, any, DefaultT, any, any>) { function generateOptionSegments<_ResT, DataT, DefaultT> (opts: UseFetchOptions<_ResT, DataT, any, DefaultT, any, any>) {
const segments: Array<string | undefined | Record<string, string>> = [ const segments: Array<string | undefined | Record<string, string>> = [
toValue(opts.method as MaybeRef<string | undefined> | undefined)?.toUpperCase() || 'GET', toValue(opts.method as MaybeRef<string | undefined> | undefined)?.toUpperCase() || 'GET',
toValue(opts.baseURL) toValue(opts.baseURL),
] ]
for (const _obj of [opts.params || opts.query]) { for (const _obj of [opts.params || opts.query]) {
const obj = toValue(_obj) const obj = toValue(_obj)

View File

@ -9,7 +9,7 @@ export {
/** @deprecated Import `useSeoMeta` from `#imports` instead. This may be removed in a future minor version. */ /** @deprecated Import `useSeoMeta` from `#imports` instead. This may be removed in a future minor version. */
useSeoMeta, useSeoMeta,
/** @deprecated Import `useServerSeoMeta` from `#imports` instead. This may be removed in a future minor version. */ /** @deprecated Import `useServerSeoMeta` from `#imports` instead. This may be removed in a future minor version. */
useServerSeoMeta useServerSeoMeta,
} from '@unhead/vue' } from '@unhead/vue'
export { defineNuxtComponent } from './component' export { defineNuxtComponent } from './component'

View File

@ -148,7 +148,7 @@ function createLoadingIndicator (opts: Partial<LoadingIndicatorOpts> = {}) {
start, start,
set, set,
finish, finish,
clear clear,
} }
} }

View File

@ -46,7 +46,7 @@ export function getAppManifest (): Promise<NuxtAppManifest> {
export async function getRouteRules (url: string) { export async function getRouteRules (url: string) {
if (import.meta.server) { if (import.meta.server) {
const _routeRulesMatcher = toRouteMatcher( const _routeRulesMatcher = toRouteMatcher(
createRadixRouter({ routes: useRuntimeConfig().nitro!.routeRules }) createRadixRouter({ routes: useRuntimeConfig().nitro!.routeRules }),
) )
return defu({} as Record<string, any>, ..._routeRulesMatcher.matchAll(url).reverse()) return defu({} as Record<string, any>, ..._routeRulesMatcher.matchAll(url).reverse())
} }

View File

@ -44,8 +44,8 @@ export function preloadPayload (url: string, opts: LoadPayloadOptions = {}) {
const payloadURL = _getPayloadURL(url, opts) const payloadURL = _getPayloadURL(url, opts)
useHead({ useHead({
link: [ link: [
{ rel: 'modulepreload', href: payloadURL } { rel: 'modulepreload', href: payloadURL },
] ],
}) })
} }
@ -109,7 +109,7 @@ export async function getNuxtClientPayload () {
payloadCache = { payloadCache = {
...inlineData, ...inlineData,
...externalData, ...externalData,
...window.__NUXT__ ...window.__NUXT__,
} }
return payloadCache return payloadCache
@ -125,7 +125,7 @@ export async function parsePayload (payload: string) {
*/ */
export function definePayloadReducer ( export function definePayloadReducer (
name: string, name: string,
reduce: (data: any) => any reduce: (data: any) => any,
) { ) {
if (import.meta.server) { if (import.meta.server) {
useNuxtApp().ssrContext!._payloadReducers[name] = reduce useNuxtApp().ssrContext!._payloadReducers[name] = reduce
@ -140,7 +140,7 @@ export function definePayloadReducer (
*/ */
export function definePayloadReviver ( export function definePayloadReviver (
name: string, name: string,
revive: (data: any) => any | undefined revive: (data: any) => any | undefined,
) { ) {
if (import.meta.dev && getCurrentInstance()) { if (import.meta.dev && getCurrentInstance()) {
console.warn('[nuxt] [definePayloadReviver] This function must be called in a Nuxt plugin that is `unshift`ed to the beginning of the Nuxt plugins array.') console.warn('[nuxt] [definePayloadReviver] This function must be called in a Nuxt plugin that is `unshift`ed to the beginning of the Nuxt plugins array.')

View File

@ -36,7 +36,7 @@ function _loadAsyncComponent (component: Component) {
} }
/** @since 3.0.0 */ /** @since 3.0.0 */
export async function preloadRouteComponents (to: RouteLocationRaw, router: Router & { _routePreloaded?: Set<string>; _preloadPromises?: Array<Promise<any>> } = useRouter()): Promise<void> { export async function preloadRouteComponents (to: RouteLocationRaw, router: Router & { _routePreloaded?: Set<string>, _preloadPromises?: Array<Promise<any>> } = useRouter()): Promise<void> {
if (import.meta.server) { return } if (import.meta.server) { return }
const { path, matched } = router.resolve(to) const { path, matched } = router.resolve(to)

View File

@ -11,8 +11,8 @@ interface Preview {
} }
interface PreviewModeOptions<S> { interface PreviewModeOptions<S> {
shouldEnable?: (state: Preview['state']) => boolean, shouldEnable?: (state: Preview['state']) => boolean
getState?: (state: Preview['state']) => S, getState?: (state: Preview['state']) => S
} }
type EnteredState = Record<any, unknown> | null | undefined | void type EnteredState = Record<any, unknown> | null | undefined | void
@ -23,13 +23,13 @@ let unregisterRefreshHook: (() => any) | undefined
export function usePreviewMode<S extends EnteredState> (options: PreviewModeOptions<S> = {}) { export function usePreviewMode<S extends EnteredState> (options: PreviewModeOptions<S> = {}) {
const preview = useState<Preview>('_preview-state', () => ({ const preview = useState<Preview>('_preview-state', () => ({
enabled: false, enabled: false,
state: {} state: {},
})) }))
if (preview.value._initialized) { if (preview.value._initialized) {
return { return {
enabled: toRef(preview.value, 'enabled'), enabled: toRef(preview.value, 'enabled'),
state: preview.value.state as S extends void ? Preview['state'] : (NonNullable<S> & Preview['state']) state: preview.value.state as S extends void ? Preview['state'] : (NonNullable<S> & Preview['state']),
} }
} }
@ -67,7 +67,7 @@ export function usePreviewMode<S extends EnteredState> (options: PreviewModeOpti
return { return {
enabled: toRef(preview.value, 'enabled'), enabled: toRef(preview.value, 'enabled'),
state: preview.value.state as S extends void ? Preview['state'] : (NonNullable<S> & Preview['state']) state: preview.value.state as S extends void ? Preview['state'] : (NonNullable<S> & Preview['state']),
} }
} }

View File

@ -4,7 +4,6 @@ import type { NavigationFailure, NavigationGuard, RouteLocationNormalized, Route
import { sanitizeStatusCode } from 'h3' import { sanitizeStatusCode } from 'h3'
import { hasProtocol, isScriptProtocol, joinURL, parseURL, withQuery } from 'ufo' import { hasProtocol, isScriptProtocol, joinURL, parseURL, withQuery } from 'ufo'
// eslint-disable-next-line import/no-restricted-paths
import type { PageMeta } from '../../pages/runtime/composables' import type { PageMeta } from '../../pages/runtime/composables'
import { useNuxtApp, useRuntimeConfig } from '../nuxt' import { useNuxtApp, useRuntimeConfig } from '../nuxt'
@ -170,7 +169,7 @@ export const navigateTo = (to: RouteLocationRaw | undefined | null, options?: Na
nuxtApp.ssrContext!._renderResponse = { nuxtApp.ssrContext!._renderResponse = {
statusCode: sanitizeStatusCode(options?.redirectCode || 302, 302), statusCode: sanitizeStatusCode(options?.redirectCode || 302, 302),
body: `<!DOCTYPE html><html><head><meta http-equiv="refresh" content="0; url=${encodedLoc}"></head></html>`, body: `<!DOCTYPE html><html><head><meta http-equiv="refresh" content="0; url=${encodedLoc}"></head></html>`,
headers: { location } headers: { location },
} }
return response return response
} }

View File

@ -40,7 +40,7 @@ export function useState <T> (...args: any): Ref<T> {
/** @since 3.6.0 */ /** @since 3.6.0 */
export function clearNuxtState ( export function clearNuxtState (
keys?: string | string[] | ((key: string) => boolean) keys?: string | string[] | ((key: string) => boolean),
): void { ): void {
const nuxtApp = useNuxtApp() const nuxtApp = useNuxtApp()
const _allKeys = Object.keys(nuxtApp.payload.state) const _allKeys = Object.keys(nuxtApp.payload.state)

View File

@ -52,7 +52,7 @@ if (import.meta.client) {
if (vueAppPromise) { return vueAppPromise } if (vueAppPromise) { return vueAppPromise }
const isSSR = Boolean( const isSSR = Boolean(
window.__NUXT__?.serverRendered || window.__NUXT__?.serverRendered ||
document.getElementById('__NUXT_DATA__')?.dataset.ssr === 'true' document.getElementById('__NUXT_DATA__')?.dataset.ssr === 'true',
) )
const vueApp = isSSR ? createSSRApp(RootComponent) : createApp(RootComponent) const vueApp = isSSR ? createSSRApp(RootComponent) : createApp(RootComponent)

View File

@ -1,9 +1,9 @@
/// <reference path="types/augments.d.ts" /> /// <reference path="types/augments.d.ts" />
export * from './nuxt' export * from './nuxt'
// eslint-disable-next-line import/no-restricted-paths
export * from './composables/index' export * from './composables/index'
// eslint-disable-next-line import/no-restricted-paths
export * from './components/index' export * from './components/index'
export * from './config' export * from './config'
export * from './compat/idle-callback' export * from './compat/idle-callback'

View File

@ -1,4 +1,3 @@
/* eslint-disable no-use-before-define */
import { effectScope, getCurrentInstance, hasInjectionContext, reactive } from 'vue' import { effectScope, getCurrentInstance, hasInjectionContext, reactive } from 'vue'
import type { App, EffectScope, Ref, VNode, onErrorCaptured } from 'vue' import type { App, EffectScope, Ref, VNode, onErrorCaptured } from 'vue'
import type { RouteLocationNormalizedLoaded } from '#vue-router' import type { RouteLocationNormalizedLoaded } from '#vue-router'
@ -23,7 +22,7 @@ import type { ViewTransition } from './plugins/view-transitions.client'
import type { NuxtAppLiterals } from '#app' import type { NuxtAppLiterals } from '#app'
const nuxtAppCtx = /* @__PURE__ */ getContext<NuxtApp>('nuxt-app', { const nuxtAppCtx = /* @__PURE__ */ getContext<NuxtApp>('nuxt-app', {
asyncContext: !!__NUXT_ASYNC_CONTEXT__ && import.meta.server asyncContext: !!__NUXT_ASYNC_CONTEXT__ && import.meta.server,
}) })
type HookResult = Promise<void> | void type HookResult = Promise<void> | void
@ -236,17 +235,17 @@ export function createNuxtApp (options: CreateOptions) {
globalName: 'nuxt', globalName: 'nuxt',
versions: { versions: {
get nuxt () { return __NUXT_VERSION__ }, get nuxt () { return __NUXT_VERSION__ },
get vue () { return nuxtApp.vueApp.version } get vue () { return nuxtApp.vueApp.version },
}, },
payload: reactive({ payload: reactive({
data: {}, data: {},
state: {}, state: {},
once: new Set<string>(), once: new Set<string>(),
_errors: {}, _errors: {},
...(import.meta.client ? window.__NUXT__ ?? {} : { serverRendered: true }) ...(import.meta.client ? window.__NUXT__ ?? {} : { serverRendered: true }),
}), }),
static: { static: {
data: {} data: {},
}, },
runWithContext: (fn: any) => nuxtApp._scope.run(() => callWithNuxt(nuxtApp, fn)), runWithContext: (fn: any) => nuxtApp._scope.run(() => callWithNuxt(nuxtApp, fn)),
isHydrating: import.meta.client, isHydrating: import.meta.client,
@ -271,7 +270,7 @@ export function createNuxtApp (options: CreateOptions) {
_asyncDataPromises: {}, _asyncDataPromises: {},
_asyncData: {}, _asyncData: {},
_payloadRevivers: {}, _payloadRevivers: {},
...options ...options,
} as any as NuxtApp } as any as NuxtApp
nuxtApp.hooks = createHooks<RuntimeNuxtHooks>() nuxtApp.hooks = createHooks<RuntimeNuxtHooks>()
@ -319,7 +318,7 @@ export function createNuxtApp (options: CreateOptions) {
// Expose client runtime-config to the payload // Expose client runtime-config to the payload
nuxtApp.ssrContext!.config = { nuxtApp.ssrContext!.config = {
public: options.ssrContext!.runtimeConfig.public, public: options.ssrContext!.runtimeConfig.public,
app: options.ssrContext!.runtimeConfig.app app: options.ssrContext!.runtimeConfig.app,
} }
} }

View File

@ -23,6 +23,6 @@ export default defineNuxtPlugin({
} }
}, },
env: { env: {
islands: false islands: false,
} },
}) })

View File

@ -30,5 +30,5 @@ export default defineNuxtPlugin({
reloadAppAtPath(to) reloadAppAtPath(to)
} }
}) })
} },
}) })

View File

@ -16,23 +16,23 @@ export default defineNuxtPlugin({
{ {
source: 'list', source: 'list',
urls: [...externalURLs.value], urls: [...externalURLs.value],
requires: ['anonymous-client-ip-when-cross-origin'] requires: ['anonymous-client-ip-when-cross-origin'],
} },
] ],
}) }),
} }
} }
const head = useHead({ const head = useHead({
script: [generateRules()] script: [generateRules()],
}) })
nuxtApp.hook('link:prefetch', (url) => { nuxtApp.hook('link:prefetch', (url) => {
const { protocol } = parseURL(url) const { protocol } = parseURL(url)
if (protocol && ['http:', 'https:'].includes(protocol)) { if (protocol && ['http:', 'https:'].includes(protocol)) {
externalURLs.value.add(url) externalURLs.value.add(url)
head?.patch({ head?.patch({
script: [generateRules()] script: [generateRules()],
}) })
} }
}) })
} },
}) })

View File

@ -6,5 +6,5 @@ export default defineNuxtPlugin({
enforce: 'pre', enforce: 'pre',
setup (nuxtApp) { setup (nuxtApp) {
createDebugger(nuxtApp.hooks, { tag: 'nuxt-app' }) createDebugger(nuxtApp.hooks, { tag: 'nuxt-app' })
} },
}) })

View File

@ -20,8 +20,8 @@ export default defineNuxtPlugin((nuxtApp) => {
const logger = createConsola({ const logger = createConsola({
formatOptions: { formatOptions: {
colors: true, colors: true,
date: true date: true,
} },
}) })
const hydrationLogs = new Set<string>() const hydrationLogs = new Set<string>()
consola.wrapConsole() consola.wrapConsole()
@ -32,7 +32,7 @@ export default defineNuxtPlugin((nuxtApp) => {
} catch { } catch {
// silently ignore - the worst case is a user gets log twice // silently ignore - the worst case is a user gets log twice
} }
} },
}) })
nuxtApp.hook('dev:ssr-logs', (logs) => { nuxtApp.hook('dev:ssr-logs', (logs) => {
for (const log of logs) { for (const log of logs) {

View File

@ -32,5 +32,5 @@ export default defineNuxtPlugin({
setTimeout(getAppManifest, 1000) setTimeout(getAppManifest, 1000)
} }
}) })
} },
}) })

View File

@ -8,7 +8,7 @@ export default defineNuxtPlugin({
const { _registeredComponents } = this.$nuxt.ssrContext const { _registeredComponents } = this.$nuxt.ssrContext
const { __moduleIdentifier } = this.$options const { __moduleIdentifier } = this.$options
_registeredComponents.add(__moduleIdentifier) _registeredComponents.add(__moduleIdentifier)
} },
}) })
} },
}) })

View File

@ -15,6 +15,6 @@ export default defineNuxtPlugin({
} catch { } catch {
// don't throw an error if we have issues reading sessionStorage // don't throw an error if we have issues reading sessionStorage
} }
} },
} },
}) })

View File

@ -14,7 +14,7 @@ const revivers: Record<string, (data: any) => any> = {
ShallowRef: data => shallowRef(data), ShallowRef: data => shallowRef(data),
ShallowReactive: data => shallowReactive(data), ShallowReactive: data => shallowReactive(data),
Ref: data => ref(data), Ref: data => ref(data),
Reactive: data => reactive(data) Reactive: data => reactive(data),
} }
if (componentIslands) { if (componentIslands) {
@ -23,7 +23,7 @@ if (componentIslands) {
if (!nuxtApp.isHydrating) { if (!nuxtApp.isHydrating) {
nuxtApp.payload.data[key] = nuxtApp.payload.data[key] || $fetch(`/__nuxt_island/${key}.json`, { nuxtApp.payload.data[key] = nuxtApp.payload.data[key] || $fetch(`/__nuxt_island/${key}.json`, {
responseType: 'json', responseType: 'json',
...params ? { params } : {} ...params ? { params } : {},
}).then((r) => { }).then((r) => {
nuxtApp.payload.data[key] = r nuxtApp.payload.data[key] = r
return r return r
@ -34,9 +34,9 @@ if (componentIslands) {
state: {}, state: {},
head: { head: {
link: [], link: [],
style: [] style: [],
}, },
...result ...result,
} }
} }
} }
@ -51,5 +51,5 @@ export default defineNuxtPlugin({
Object.assign(nuxtApp.payload, await nuxtApp.runWithContext(getNuxtClientPayload)) Object.assign(nuxtApp.payload, await nuxtApp.runWithContext(getNuxtClientPayload))
// For backwards compatibility - TODO: remove later // For backwards compatibility - TODO: remove later
window.__NUXT__ = nuxtApp.payload window.__NUXT__ = nuxtApp.payload
} },
}) })

View File

@ -13,7 +13,7 @@ const reducers: Record<string, (data: any) => any> = {
ShallowRef: data => isRef(data) && isShallow(data) && data.value, ShallowRef: data => isRef(data) && isShallow(data) && data.value,
ShallowReactive: data => isReactive(data) && isShallow(data) && toRaw(data), ShallowReactive: data => isReactive(data) && isShallow(data) && toRaw(data),
Ref: data => isRef(data) && data.value, Ref: data => isRef(data) && data.value,
Reactive: data => isReactive(data) && toRaw(data) Reactive: data => isReactive(data) && toRaw(data),
} }
if (componentIslands) { if (componentIslands) {
@ -26,5 +26,5 @@ export default defineNuxtPlugin({
for (const reducer in reducers) { for (const reducer in reducers) {
definePayloadReducer(reducer, reducers[reducer as keyof typeof reducers]) definePayloadReducer(reducer, reducers[reducer as keyof typeof reducers])
} }
} },
}) })

View File

@ -41,7 +41,7 @@ function getRouteFromPath (fullPath: string | Partial<Route>) {
fullPath = stringifyParsedURL({ fullPath = stringifyParsedURL({
pathname: fullPath.path || '', pathname: fullPath.path || '',
search: stringifyQuery(fullPath.query || {}), search: stringifyQuery(fullPath.query || {}),
hash: fullPath.hash || '' hash: fullPath.hash || '',
}) })
} }
@ -57,7 +57,7 @@ function getRouteFromPath (fullPath: string | Partial<Route>) {
matched: [], matched: [],
redirectedFrom: undefined, redirectedFrom: undefined,
meta: {}, meta: {},
href: fullPath href: fullPath,
} }
} }
@ -112,7 +112,7 @@ export default defineNuxtPlugin<{ route: Route, router: Router }>({
'navigate:before': [], 'navigate:before': [],
'resolve:before': [], 'resolve:before': [],
'navigate:after': [], 'navigate:after': [],
error: [] 'error': [],
} }
const registerHook = <T extends keyof RouterHooks> (hook: T, guard: RouterHooks[T]) => { const registerHook = <T extends keyof RouterHooks> (hook: T, guard: RouterHooks[T]) => {
@ -191,7 +191,7 @@ export default defineNuxtPlugin<{ route: Route, router: Router }>({
if (index !== -1) { if (index !== -1) {
routes.splice(index, 1) routes.splice(index, 1)
} }
} },
} }
nuxtApp.vueApp.component('RouterLink', defineComponent({ nuxtApp.vueApp.component('RouterLink', defineComponent({
@ -199,14 +199,14 @@ export default defineNuxtPlugin<{ route: Route, router: Router }>({
props: { props: {
to: { to: {
type: String, type: String,
required: true required: true,
}, },
custom: Boolean, custom: Boolean,
replace: Boolean, replace: Boolean,
// Not implemented // Not implemented
activeClass: String, activeClass: String,
exactActiveClass: String, exactActiveClass: String,
ariaCurrentValue: String ariaCurrentValue: String,
}, },
setup: (props, { slots }) => { setup: (props, { slots }) => {
const navigate = () => handleNavigation(props.to!, props.replace) const navigate = () => handleNavigation(props.to!, props.replace)
@ -216,7 +216,7 @@ export default defineNuxtPlugin<{ route: Route, router: Router }>({
? slots.default?.({ href: props.to, navigate, route }) ? slots.default?.({ href: props.to, navigate, route })
: h('a', { href: props.to, onClick: (e: MouseEvent) => { e.preventDefault(); return navigate() } }, slots) : h('a', { href: props.to, onClick: (e: MouseEvent) => { e.preventDefault(); return navigate() } }, slots)
} }
} },
})) }))
if (import.meta.client) { if (import.meta.client) {
@ -231,7 +231,7 @@ export default defineNuxtPlugin<{ route: Route, router: Router }>({
// Handle middleware // Handle middleware
nuxtApp._middleware = nuxtApp._middleware || { nuxtApp._middleware = nuxtApp._middleware || {
global: [], global: [],
named: {} named: {},
} }
const initialLayout = nuxtApp.payload.state._layout const initialLayout = nuxtApp.payload.state._layout
@ -271,8 +271,8 @@ export default defineNuxtPlugin<{ route: Route, router: Router }>({
statusCode: 404, statusCode: 404,
statusMessage: `Page Not Found: ${initialURL}`, statusMessage: `Page Not Found: ${initialURL}`,
data: { data: {
path: initialURL path: initialURL,
} },
}) })
delete nuxtApp._processingMiddleware delete nuxtApp._processingMiddleware
return nuxtApp.runWithContext(() => showError(error)) return nuxtApp.runWithContext(() => showError(error))
@ -295,8 +295,8 @@ export default defineNuxtPlugin<{ route: Route, router: Router }>({
return { return {
provide: { provide: {
route, route,
router router,
} },
}
} }
},
}) })

View File

@ -1,9 +1,7 @@
// eslint-disable-next-line import/no-restricted-paths
export type { PageMeta } from '../pages/runtime/index' export type { PageMeta } from '../pages/runtime/index'
export interface NuxtAppLiterals { export interface NuxtAppLiterals {
[key: string]: string [key: string]: string
} }
// eslint-disable-next-line import/no-restricted-paths
export type { NuxtIslandContext, NuxtIslandResponse, NuxtRenderHTMLContext } from '../core/runtime/nitro/renderer' export type { NuxtIslandContext, NuxtIslandResponse, NuxtRenderHTMLContext } from '../core/runtime/nitro/renderer'

View File

@ -4,9 +4,10 @@ import MagicString from 'magic-string'
import { isAbsolute, relative } from 'pathe' import { isAbsolute, relative } from 'pathe'
import { hash } from 'ohash' import { hash } from 'ohash'
import { isVue } from '../core/utils' import { isVue } from '../core/utils'
interface LoaderOptions { interface LoaderOptions {
sourcemap?: boolean sourcemap?: boolean
transform?: ComponentsOptions['transform'], transform?: ComponentsOptions['transform']
rootDir: string rootDir: string
} }
const CLIENT_FALLBACK_RE = /<(NuxtClientFallback|nuxt-client-fallback)( [^>]*)?>/ const CLIENT_FALLBACK_RE = /<(NuxtClientFallback|nuxt-client-fallback)( [^>]*)?>/
@ -45,9 +46,9 @@ export const clientFallbackAutoIdPlugin = createUnplugin((options: LoaderOptions
code: s.toString(), code: s.toString(),
map: options.sourcemap map: options.sourcemap
? s.generateMap({ hires: true }) ? s.generateMap({ hires: true })
: undefined : undefined,
}
} }
} }
},
} }
}) })

View File

@ -53,7 +53,7 @@ export const islandsTransform = createUnplugin((options: ServerOnlyComponentTran
const components = options.getComponents() const components = options.getComponents()
const islands = components.filter(component => const islands = components.filter(component =>
component.island || (component.mode === 'server' && !components.some(c => c.pascalName === component.pascalName && c.mode === 'client')) component.island || (component.mode === 'server' && !components.some(c => c.pascalName === component.pascalName && c.mode === 'client')),
) )
const { pathname } = parseURL(decodeURIComponent(pathToFileURL(id).href)) const { pathname } = parseURL(decodeURIComponent(pathToFileURL(id).href))
return islands.some(c => c.filePath === pathname) return islands.some(c => c.filePath === pathname)
@ -129,17 +129,16 @@ export const islandsTransform = createUnplugin((options: ServerOnlyComponentTran
}) })
if (!isVite && hasNuxtClient) { if (!isVite && hasNuxtClient) {
// eslint-disable-next-line no-console
console.warn(`nuxt-client attribute and client components within islands is only supported with Vite. file: ${id}`) console.warn(`nuxt-client attribute and client components within islands is only supported with Vite. file: ${id}`)
} }
if (s.hasChanged()) { if (s.hasChanged()) {
return { return {
code: s.toString(), code: s.toString(),
map: s.generateMap({ source: id, includeContent: true }) map: s.generateMap({ source: id, includeContent: true }),
}
} }
} }
},
} }
}) })
@ -187,8 +186,8 @@ export const componentsChunkPlugin = createUnplugin((options: ComponentChunkOpti
config.build = defu(config.build, { config.build = defu(config.build, {
rollupOptions: { rollupOptions: {
input: {}, input: {},
output: {} output: {},
} },
}) })
const rollupOptions = config.build.rollupOptions! const rollupOptions = config.build.rollupOptions!
@ -228,7 +227,7 @@ export const componentsChunkPlugin = createUnplugin((options: ComponentChunkOpti
} }
fs.writeFileSync(join(buildDir, 'components-chunk.mjs'), `export const paths = ${JSON.stringify(pathAssociation, null, 2)}`) fs.writeFileSync(join(buildDir, 'components-chunk.mjs'), `export const paths = ${JSON.stringify(pathAssociation, null, 2)}`)
} },
} },
} }
}) })

View File

@ -99,10 +99,10 @@ export const loaderPlugin = createUnplugin((options: LoaderOptions) => {
code: s.toString(), code: s.toString(),
map: options.sourcemap map: options.sourcemap
? s.generateMap({ hires: true }) ? s.generateMap({ hires: true })
: undefined : undefined,
}
} }
} }
},
} }
}) })

View File

@ -25,15 +25,15 @@ export type getComponentsT = (mode?: 'client' | 'server' | 'all') => Component[]
export default defineNuxtModule<ComponentsOptions>({ export default defineNuxtModule<ComponentsOptions>({
meta: { meta: {
name: 'components', name: 'components',
configKey: 'components' configKey: 'components',
}, },
defaults: { defaults: {
dirs: [] dirs: [],
}, },
setup (componentOptions, nuxt) { setup (componentOptions, nuxt) {
let componentDirs: ComponentsDir[] = [] let componentDirs: ComponentsDir[] = []
const context = { const context = {
components: [] as Component[] components: [] as Component[],
} }
const getComponents: getComponentsT = (mode) => { const getComponents: getComponentsT = (mode) => {
@ -50,12 +50,12 @@ export default defineNuxtModule<ComponentsOptions>({
return [ return [
{ priority: options?.priority || 0, path: resolve(cwd, 'components/islands'), island: true }, { priority: options?.priority || 0, path: resolve(cwd, 'components/islands'), island: true },
{ priority: options?.priority || 0, path: resolve(cwd, 'components/global'), global: true }, { priority: options?.priority || 0, path: resolve(cwd, 'components/global'), global: true },
{ priority: options?.priority || 0, path: resolve(cwd, 'components') } { priority: options?.priority || 0, path: resolve(cwd, 'components') },
] ]
} }
if (typeof dir === 'string') { if (typeof dir === 'string') {
return [ return [
{ priority: options?.priority || 0, path: resolve(cwd, resolveAlias(dir)) } { priority: options?.priority || 0, path: resolve(cwd, resolveAlias(dir)) },
] ]
} }
if (!dir) { if (!dir) {
@ -65,7 +65,7 @@ export default defineNuxtModule<ComponentsOptions>({
return dirs.map(_dir => ({ return dirs.map(_dir => ({
priority: options?.priority || 0, priority: options?.priority || 0,
..._dir, ..._dir,
path: resolve(cwd, resolveAlias(_dir.path)) path: resolve(cwd, resolveAlias(_dir.path)),
})) }))
} }
@ -100,15 +100,15 @@ export default defineNuxtModule<ComponentsOptions>({
ignore: [ ignore: [
'**/*{M,.m,-m}ixin.{js,ts,jsx,tsx}', // ignore mixins '**/*{M,.m,-m}ixin.{js,ts,jsx,tsx}', // ignore mixins
'**/*.d.{cts,mts,ts}', // .d.ts files '**/*.d.{cts,mts,ts}', // .d.ts files
...(dirOptions.ignore || []) ...(dirOptions.ignore || []),
], ],
transpile: (transpile === 'auto' ? dirPath.includes('node_modules') : transpile) transpile: (transpile === 'auto' ? dirPath.includes('node_modules') : transpile),
} }
}).filter(d => d.enabled) }).filter(d => d.enabled)
componentDirs = [ componentDirs = [
...componentDirs.filter(dir => !dir.path.includes('node_modules')), ...componentDirs.filter(dir => !dir.path.includes('node_modules')),
...componentDirs.filter(dir => dir.path.includes('node_modules')) ...componentDirs.filter(dir => dir.path.includes('node_modules')),
] ]
nuxt.options.build!.transpile!.push(...componentDirs.filter(dir => dir.transpile).map(dir => dir.path)) nuxt.options.build!.transpile!.push(...componentDirs.filter(dir => dir.transpile).map(dir => dir.path))
@ -179,7 +179,7 @@ export default defineNuxtModule<ComponentsOptions>({
_raw: true, _raw: true,
mode: 'server', mode: 'server',
filePath: serverPlaceholderPath, filePath: serverPlaceholderPath,
chunkName: 'components/' + component.kebabName chunkName: 'components/' + component.kebabName,
}) })
} }
if (component.mode === 'server' && !nuxt.options.ssr && !newComponents.some(other => other.pascalName === component.pascalName && other.mode === 'client')) { if (component.mode === 'server' && !nuxt.options.ssr && !newComponents.some(other => other.pascalName === component.pascalName && other.mode === 'client')) {
@ -206,8 +206,8 @@ export default defineNuxtModule<ComponentsOptions>({
'components.plugin.mjs', 'components.plugin.mjs',
'components.d.ts', 'components.d.ts',
'components.server.mjs', 'components.server.mjs',
'components.client.mjs' 'components.client.mjs',
].includes(template.filename) ].includes(template.filename),
}) })
} }
}) })
@ -219,19 +219,19 @@ export default defineNuxtModule<ComponentsOptions>({
if (nuxt.options.experimental.treeshakeClientOnly && isServer) { if (nuxt.options.experimental.treeshakeClientOnly && isServer) {
config.plugins.push(TreeShakeTemplatePlugin.vite({ config.plugins.push(TreeShakeTemplatePlugin.vite({
sourcemap: !!nuxt.options.sourcemap[mode], sourcemap: !!nuxt.options.sourcemap[mode],
getComponents getComponents,
})) }))
} }
config.plugins.push(clientFallbackAutoIdPlugin.vite({ config.plugins.push(clientFallbackAutoIdPlugin.vite({
sourcemap: !!nuxt.options.sourcemap[mode], sourcemap: !!nuxt.options.sourcemap[mode],
rootDir: nuxt.options.rootDir rootDir: nuxt.options.rootDir,
})) }))
config.plugins.push(loaderPlugin.vite({ config.plugins.push(loaderPlugin.vite({
sourcemap: !!nuxt.options.sourcemap[mode], sourcemap: !!nuxt.options.sourcemap[mode],
getComponents, getComponents,
mode, mode,
transform: typeof nuxt.options.components === 'object' && !Array.isArray(nuxt.options.components) ? nuxt.options.components.transform : undefined, transform: typeof nuxt.options.components === 'object' && !Array.isArray(nuxt.options.components) ? nuxt.options.components.transform : undefined,
experimentalComponentIslands: !!nuxt.options.experimental.componentIslands experimentalComponentIslands: !!nuxt.options.experimental.componentIslands,
})) }))
if (nuxt.options.experimental.componentIslands) { if (nuxt.options.experimental.componentIslands) {
@ -242,7 +242,7 @@ export default defineNuxtModule<ComponentsOptions>({
if (!nuxt.options.dev) { if (!nuxt.options.dev) {
config.plugins.push(componentsChunkPlugin.vite({ config.plugins.push(componentsChunkPlugin.vite({
getComponents, getComponents,
buildDir: nuxt.options.buildDir buildDir: nuxt.options.buildDir,
})) }))
} else { } else {
fs.writeFileSync(join(nuxt.options.buildDir, 'components-chunk.mjs'), `export const paths = ${JSON.stringify( fs.writeFileSync(join(nuxt.options.buildDir, 'components-chunk.mjs'), `export const paths = ${JSON.stringify(
@ -250,7 +250,7 @@ export default defineNuxtModule<ComponentsOptions>({
if (c.filePath.endsWith('.vue') || c.filePath.endsWith('.js') || c.filePath.endsWith('.ts')) { return Object.assign(acc, { [c.pascalName]: `/@fs/${c.filePath}` }) } if (c.filePath.endsWith('.vue') || c.filePath.endsWith('.js') || c.filePath.endsWith('.ts')) { return Object.assign(acc, { [c.pascalName]: `/@fs/${c.filePath}` }) }
const filePath = fs.existsSync(`${c.filePath}.vue`) ? `${c.filePath}.vue` : fs.existsSync(`${c.filePath}.js`) ? `${c.filePath}.js` : `${c.filePath}.ts` const filePath = fs.existsSync(`${c.filePath}.vue`) ? `${c.filePath}.vue` : fs.existsSync(`${c.filePath}.js`) ? `${c.filePath}.js` : `${c.filePath}.ts`
return Object.assign(acc, { [c.pascalName]: `/@fs/${filePath}` }) return Object.assign(acc, { [c.pascalName]: `/@fs/${filePath}` })
}, {} as Record<string, string>) }, {} as Record<string, string>),
)}`) )}`)
} }
} }
@ -260,7 +260,7 @@ export default defineNuxtModule<ComponentsOptions>({
getComponents, getComponents,
rootDir: nuxt.options.rootDir, rootDir: nuxt.options.rootDir,
isDev: nuxt.options.dev, isDev: nuxt.options.dev,
selectiveClient selectiveClient,
})) }))
} }
} }
@ -274,10 +274,10 @@ export default defineNuxtModule<ComponentsOptions>({
if (comp?.mode === 'server') { if (comp?.mode === 'server') {
ctx.server.ws.send({ ctx.server.ws.send({
event: `nuxt-server-component:${comp.pascalName}`, event: `nuxt-server-component:${comp.pascalName}`,
type: 'custom' type: 'custom',
}) })
} }
} },
}) })
} }
}) })
@ -288,25 +288,25 @@ export default defineNuxtModule<ComponentsOptions>({
if (nuxt.options.experimental.treeshakeClientOnly && mode === 'server') { if (nuxt.options.experimental.treeshakeClientOnly && mode === 'server') {
config.plugins.push(TreeShakeTemplatePlugin.webpack({ config.plugins.push(TreeShakeTemplatePlugin.webpack({
sourcemap: !!nuxt.options.sourcemap[mode], sourcemap: !!nuxt.options.sourcemap[mode],
getComponents getComponents,
})) }))
} }
config.plugins.push(clientFallbackAutoIdPlugin.webpack({ config.plugins.push(clientFallbackAutoIdPlugin.webpack({
sourcemap: !!nuxt.options.sourcemap[mode], sourcemap: !!nuxt.options.sourcemap[mode],
rootDir: nuxt.options.rootDir rootDir: nuxt.options.rootDir,
})) }))
config.plugins.push(loaderPlugin.webpack({ config.plugins.push(loaderPlugin.webpack({
sourcemap: !!nuxt.options.sourcemap[mode], sourcemap: !!nuxt.options.sourcemap[mode],
getComponents, getComponents,
mode, mode,
transform: typeof nuxt.options.components === 'object' && !Array.isArray(nuxt.options.components) ? nuxt.options.components.transform : undefined, transform: typeof nuxt.options.components === 'object' && !Array.isArray(nuxt.options.components) ? nuxt.options.components.transform : undefined,
experimentalComponentIslands: !!nuxt.options.experimental.componentIslands experimentalComponentIslands: !!nuxt.options.experimental.componentIslands,
})) }))
if (nuxt.options.experimental.componentIslands) { if (nuxt.options.experimental.componentIslands) {
if (mode === 'server') { if (mode === 'server') {
config.plugins.push(islandsTransform.webpack({ config.plugins.push(islandsTransform.webpack({
getComponents getComponents,
})) }))
} else { } else {
fs.writeFileSync(join(nuxt.options.buildDir, 'components-chunk.mjs'), 'export const paths = {}') fs.writeFileSync(join(nuxt.options.buildDir, 'components-chunk.mjs'), 'export const paths = {}')
@ -314,5 +314,5 @@ export default defineNuxtModule<ComponentsOptions>({
} }
}) })
}) })
} },
}) })

View File

@ -11,9 +11,9 @@ export const createClientPage = (loader: AsyncComponentLoader) => {
setup (_, { attrs }) { setup (_, { attrs }) {
return () => h('div', [ return () => h('div', [
h(ClientOnly, undefined, { h(ClientOnly, undefined, {
default: () => h(page, attrs) default: () => h(page, attrs),
}) }),
]) ])
} },
}) })
} }

View File

@ -14,7 +14,7 @@ export const createServerComponent = (name: string) => {
const islandRef = ref<null | typeof NuxtIsland>(null) const islandRef = ref<null | typeof NuxtIsland>(null)
expose({ expose({
refresh: () => islandRef.value?.refresh() refresh: () => islandRef.value?.refresh(),
}) })
return () => { return () => {
@ -25,10 +25,10 @@ export const createServerComponent = (name: string) => {
ref: islandRef, ref: islandRef,
onError: (err) => { onError: (err) => {
emit('error', err) emit('error', err)
} },
}, slots) }, slots)
} }
} },
}) })
} }
@ -42,7 +42,7 @@ export const createIslandPage = (name: string) => {
const islandRef = ref<null | typeof NuxtIsland>(null) const islandRef = ref<null | typeof NuxtIsland>(null)
expose({ expose({
refresh: () => islandRef.value?.refresh() refresh: () => islandRef.value?.refresh(),
}) })
const route = useRoute() const route = useRoute()
@ -54,10 +54,10 @@ export const createIslandPage = (name: string) => {
name: `page:${name}`, name: `page:${name}`,
lazy: props.lazy, lazy: props.lazy,
ref: islandRef, ref: islandRef,
context: { url: path } context: { url: path },
}, slots) }, slots),
]) ])
} }
} },
}) })
} }

View File

@ -69,7 +69,7 @@ export async function scanComponents (dirs: ComponentsDir[], srcDir: string): Pr
*/ */
const prefixParts = ([] as string[]).concat( const prefixParts = ([] as string[]).concat(
dir.prefix ? splitByCase(dir.prefix) : [], dir.prefix ? splitByCase(dir.prefix) : [],
(dir.pathPrefix !== false) ? splitByCase(relative(dir.path, dirname(filePath))) : [] (dir.pathPrefix !== false) ? splitByCase(relative(dir.path, dirname(filePath))) : [],
) )
/** /**
@ -118,7 +118,7 @@ export async function scanComponents (dirs: ComponentsDir[], srcDir: string): Pr
shortPath, shortPath,
export: 'default', export: 'default',
// by default, give priority to scanned components // by default, give priority to scanned components
priority: dir.priority ?? 1 priority: dir.priority ?? 1,
} }
if (typeof dir.extendComponent === 'function') { if (typeof dir.extendComponent === 'function') {
@ -160,6 +160,6 @@ export async function scanComponents (dirs: ComponentsDir[], srcDir: string): Pr
function warnAboutDuplicateComponent (componentName: string, filePath: string, duplicatePath: string) { function warnAboutDuplicateComponent (componentName: string, filePath: string, duplicatePath: string) {
logger.warn(`Two component files resolving to the same name \`${componentName}\`:\n` + logger.warn(`Two component files resolving to the same name \`${componentName}\`:\n` +
`\n - ${filePath}` + `\n - ${filePath}` +
`\n - ${duplicatePath}` `\n - ${duplicatePath}`,
) )
} }

View File

@ -13,7 +13,7 @@ const createImportMagicComments = (options: ImportMagicCommentsOptions) => {
return [ return [
`webpackChunkName: "${chunkName}"`, `webpackChunkName: "${chunkName}"`,
prefetch === true || typeof prefetch === 'number' ? `webpackPrefetch: ${prefetch}` : false, prefetch === true || typeof prefetch === 'number' ? `webpackPrefetch: ${prefetch}` : false,
preload === true || typeof preload === 'number' ? `webpackPreload: ${preload}` : false preload === true || typeof preload === 'number' ? `webpackPreload: ${preload}` : false,
].filter(Boolean).join(', ') ].filter(Boolean).join(', ')
} }
@ -58,14 +58,14 @@ export default defineNuxtPlugin({
} }
}) })
` `
} },
} }
export const componentNamesTemplate: NuxtTemplate = { export const componentNamesTemplate: NuxtTemplate = {
filename: 'component-names.mjs', filename: 'component-names.mjs',
getContents ({ app }) { getContents ({ app }) {
return `export const componentNames = ${JSON.stringify(app.components.filter(c => !c.island).map(c => c.pascalName))}` return `export const componentNames = ${JSON.stringify(app.components.filter(c => !c.island).map(c => c.pascalName))}`
} },
} }
export const componentsIslandsTemplate: NuxtTemplate = { export const componentsIslandsTemplate: NuxtTemplate = {
@ -76,7 +76,7 @@ export const componentsIslandsTemplate: NuxtTemplate = {
const islands = components.filter(component => const islands = components.filter(component =>
component.island || component.island ||
// .server components without a corresponding .client component will need to be rendered as an island // .server components without a corresponding .client component will need to be rendered as an island
(component.mode === 'server' && !components.some(c => c.pascalName === component.pascalName && c.mode === 'client')) (component.mode === 'server' && !components.some(c => c.pascalName === component.pascalName && c.mode === 'client')),
) )
const pageExports = pages?.filter(p => (p.mode === 'server' && p.file && p.name)).map((p) => { const pageExports = pages?.filter(p => (p.mode === 'server' && p.file && p.name)).map((p) => {
@ -91,11 +91,11 @@ export const componentsIslandsTemplate: NuxtTemplate = {
const exp = c.export === 'default' ? 'c.default || c' : `c['${c.export}']` const exp = c.export === 'default' ? 'c.default || c' : `c['${c.export}']`
const comment = createImportMagicComments(c) const comment = createImportMagicComments(c)
return ` "${c.pascalName}": defineAsyncComponent(${genDynamicImport(c.filePath, { comment })}.then(c => ${exp}))` return ` "${c.pascalName}": defineAsyncComponent(${genDynamicImport(c.filePath, { comment })}.then(c => ${exp}))`
} },
).concat(pageExports).join(',\n'), ).concat(pageExports).join(',\n'),
'}' '}',
].join('\n') ].join('\n')
} },
} }
export const componentsTypeTemplate = { export const componentsTypeTemplate = {
@ -106,7 +106,7 @@ export const componentsTypeTemplate = {
c.pascalName, c.pascalName,
`typeof ${genDynamicImport(isAbsolute(c.filePath) `typeof ${genDynamicImport(isAbsolute(c.filePath)
? relative(buildDir, c.filePath).replace(/(?<=\w)\.(?!vue)\w+$/g, '') ? relative(buildDir, c.filePath).replace(/(?<=\w)\.(?!vue)\w+$/g, '')
: c.filePath.replace(/(?<=\w)\.(?!vue)\w+$/g, ''), { wrapper: false })}['${c.export}']` : c.filePath.replace(/(?<=\w)\.(?!vue)\w+$/g, ''), { wrapper: false })}['${c.export}']`,
]) ])
return ` return `
@ -132,11 +132,11 @@ ${componentTypes.map(([pascalName, type]) => `export const Lazy${pascalName}: ${
export const componentNames: string[] export const componentNames: string[]
` `
} },
} satisfies NuxtTemplate } satisfies NuxtTemplate
export const componentsMetadataTemplate: NuxtTemplate = { export const componentsMetadataTemplate: NuxtTemplate = {
filename: 'components.json', filename: 'components.json',
write: true, write: true,
getContents: ({ app }) => JSON.stringify(app.components, null, 2) getContents: ({ app }) => JSON.stringify(app.components, null, 2),
} }

View File

@ -18,10 +18,10 @@ export function createTransformPlugin (nuxt: Nuxt, getComponents: getComponentsT
imports: [ imports: [
{ {
name: 'componentNames', name: 'componentNames',
from: '#build/component-names' from: '#build/component-names',
} },
], ],
virtualImports: ['#components'] virtualImports: ['#components'],
}) })
function getComponentsImports (): Import[] { function getComponentsImports (): Import[] {
@ -37,13 +37,13 @@ export function createTransformPlugin (nuxt: Nuxt, getComponents: getComponentsT
{ {
as: c.pascalName, as: c.pascalName,
from: withMode(mode), from: withMode(mode),
name: c.export || 'default' name: c.export || 'default',
}, },
{ {
as: 'Lazy' + c.pascalName, as: 'Lazy' + c.pascalName,
from: withMode([mode, 'async'].filter(Boolean).join(',')), from: withMode([mode, 'async'].filter(Boolean).join(',')),
name: c.export || 'default' name: c.export || 'default',
} },
] ]
}) })
} }
@ -67,36 +67,36 @@ export function createTransformPlugin (nuxt: Nuxt, getComponents: getComponentsT
return { return {
code: [ code: [
'import { defineAsyncComponent } from "vue"', 'import { defineAsyncComponent } from "vue"',
`${exportWording} defineAsyncComponent(() => import(${JSON.stringify(bare)}).then(r => r[${JSON.stringify(componentExport)}] || r.default || r))` `${exportWording} defineAsyncComponent(() => import(${JSON.stringify(bare)}).then(r => r[${JSON.stringify(componentExport)}] || r.default || r))`,
].join('\n'), ].join('\n'),
map: null map: null,
} }
} else if (mode === 'client') { } else if (mode === 'client') {
return { return {
code: [ code: [
genImport(bare, [{ name: componentExport, as: '__component' }]), genImport(bare, [{ name: componentExport, as: '__component' }]),
'import { createClientOnly } from "#app/components/client-only"', 'import { createClientOnly } from "#app/components/client-only"',
`${exportWording} createClientOnly(__component)` `${exportWording} createClientOnly(__component)`,
].join('\n'), ].join('\n'),
map: null map: null,
} }
} else if (mode === 'client,async') { } else if (mode === 'client,async') {
return { return {
code: [ code: [
'import { defineAsyncComponent } from "vue"', 'import { defineAsyncComponent } from "vue"',
'import { createClientOnly } from "#app/components/client-only"', 'import { createClientOnly } from "#app/components/client-only"',
`${exportWording} defineAsyncComponent(() => import(${JSON.stringify(bare)}).then(r => createClientOnly(r[${JSON.stringify(componentExport)}] || r.default || r)))` `${exportWording} defineAsyncComponent(() => import(${JSON.stringify(bare)}).then(r => createClientOnly(r[${JSON.stringify(componentExport)}] || r.default || r)))`,
].join('\n'), ].join('\n'),
map: null map: null,
} }
} else if (mode === 'server' || mode === 'server,async') { } else if (mode === 'server' || mode === 'server,async') {
const name = query.nuxt_component_name const name = query.nuxt_component_name
return { return {
code: [ code: [
`import { createServerComponent } from ${JSON.stringify(serverComponentRuntime)}`, `import { createServerComponent } from ${JSON.stringify(serverComponentRuntime)}`,
`${exportWording} createServerComponent(${JSON.stringify(name)})` `${exportWording} createServerComponent(${JSON.stringify(name)})`,
].join('\n'), ].join('\n'),
map: null map: null,
} }
} else { } else {
throw new Error(`Unknown component mode: ${mode}, this might be an internal bug of Nuxt.`) throw new Error(`Unknown component mode: ${mode}, this might be an internal bug of Nuxt.`)
@ -118,8 +118,8 @@ export function createTransformPlugin (nuxt: Nuxt, getComponents: getComponentsT
code: result.code, code: result.code,
map: nuxt.options.sourcemap.server || nuxt.options.sourcemap.client map: nuxt.options.sourcemap.server || nuxt.options.sourcemap.client
? result.s.generateMap({ hires: true }) ? result.s.generateMap({ hires: true })
: undefined : undefined,
}
} }
},
})) }))
} }

View File

@ -81,13 +81,13 @@ export const TreeShakeTemplatePlugin = createUnplugin((options: TreeShakeTemplat
componentsToRemoveSet.add(nameToRemove) componentsToRemoveSet.add(nameToRemove)
} }
} }
} },
}) })
} }
} }
} }
} }
} },
}) })
const componentsToRemove = [...componentsToRemoveSet] const componentsToRemove = [...componentsToRemoveSet]
@ -107,10 +107,10 @@ export const TreeShakeTemplatePlugin = createUnplugin((options: TreeShakeTemplat
code: s.toString(), code: s.toString(),
map: options.sourcemap map: options.sourcemap
? s.generateMap({ hires: true }) ? s.generateMap({ hires: true })
: undefined : undefined,
}
} }
} }
},
} }
}) })
@ -142,7 +142,7 @@ function removeFromSetupReturn (codeAst: Program, name: string, magicString: Mag
} }
} }
} }
} },
}) })
} }
@ -209,10 +209,10 @@ function isComponentNotCalledInSetup (codeAst: Node, name: string): string | voi
// dev only with $setup or _ctx // dev only with $setup or _ctx
found = (node.property.type === 'Literal' && node.property.value === name) || (node.property.type === 'Identifier' && node.property.name === name) found = (node.property.type === 'Literal' && node.property.value === name) || (node.property.type === 'Identifier' && node.property.name === name)
} }
} },
}) })
} }
} },
}) })
if (!found) { return name } if (!found) { return name }
} }
@ -250,7 +250,7 @@ function removeVariableDeclarator (codeAst: Node, name: string, magicString: Mag
} }
} }
} }
} },
}) })
} }

View File

@ -16,7 +16,7 @@ export function createApp (nuxt: Nuxt, options: Partial<NuxtApp> = {}): NuxtApp
extensions: nuxt.options.extensions, extensions: nuxt.options.extensions,
plugins: [], plugins: [],
components: [], components: [],
templates: [] templates: [],
} as unknown as NuxtApp) as NuxtApp } as unknown as NuxtApp) as NuxtApp
} }
@ -97,8 +97,8 @@ export async function resolveApp (nuxt: Nuxt, app: NuxtApp) {
app.mainComponent = await findPath( app.mainComponent = await findPath(
nuxt.options._layers.flatMap(layer => [ nuxt.options._layers.flatMap(layer => [
join(layer.config.srcDir, 'App'), join(layer.config.srcDir, 'App'),
join(layer.config.srcDir, 'app') join(layer.config.srcDir, 'app'),
]) ]),
) )
} }
if (!app.mainComponent) { if (!app.mainComponent) {
@ -113,7 +113,7 @@ export async function resolveApp (nuxt: Nuxt, app: NuxtApp) {
// Resolve error component // Resolve error component
if (!app.errorComponent) { if (!app.errorComponent) {
app.errorComponent = (await findPath( app.errorComponent = (await findPath(
nuxt.options._layers.map(layer => join(layer.config.srcDir, 'error')) nuxt.options._layers.map(layer => join(layer.config.srcDir, 'error')),
)) ?? resolve(nuxt.options.appDir, 'components/nuxt-error-page.vue') )) ?? resolve(nuxt.options.appDir, 'components/nuxt-error-page.vue')
} }
@ -160,9 +160,9 @@ export async function resolveApp (nuxt: Nuxt, app: NuxtApp) {
...config.srcDir ...config.srcDir
? await resolveFiles(config.srcDir, [ ? await resolveFiles(config.srcDir, [
`${pluginDir}/*{${nuxt.options.extensions.join(',')}}`, `${pluginDir}/*{${nuxt.options.extensions.join(',')}}`,
`${pluginDir}/*/index{${nuxt.options.extensions.join(',')}}` // TODO: remove, only scan top-level plugins #18418 `${pluginDir}/*/index{${nuxt.options.extensions.join(',')}}`, // TODO: remove, only scan top-level plugins #18418
]) ])
: [] : [],
].map(plugin => normalizePlugin(plugin as NuxtPlugin))) ].map(plugin => normalizePlugin(plugin as NuxtPlugin)))
} }
@ -200,7 +200,7 @@ function resolvePaths<Item extends Record<string, any>> (items: Item[], key: { [
if (!item[key]) { return item } if (!item[key]) { return item }
return { return {
...item, ...item,
[key]: await resolvePath(resolveAlias(item[key])) [key]: await resolvePath(resolveAlias(item[key])),
} }
})) }))
} }
@ -214,7 +214,7 @@ export async function annotatePlugins (nuxt: Nuxt, plugins: NuxtPlugin[]) {
const code = plugin.src in nuxt.vfs ? nuxt.vfs[plugin.src] : await fsp.readFile(plugin.src!, 'utf-8') const code = plugin.src in nuxt.vfs ? nuxt.vfs[plugin.src] : await fsp.readFile(plugin.src!, 'utf-8')
_plugins.push({ _plugins.push({
...await extractMetadata(code, IS_TSX.test(plugin.src) ? 'tsx' : 'ts'), ...await extractMetadata(code, IS_TSX.test(plugin.src) ? 'tsx' : 'ts'),
...plugin ...plugin,
}) })
} catch (e) { } catch (e) {
const relativePluginSrc = relative(nuxt.options.rootDir, plugin.src) const relativePluginSrc = relative(nuxt.options.rootDir, plugin.src)

View File

@ -56,7 +56,7 @@ export async function build (nuxt: Nuxt) {
const watchEvents: Record<EventType, 'add' | 'addDir' | 'change' | 'unlink' | 'unlinkDir'> = { const watchEvents: Record<EventType, 'add' | 'addDir' | 'change' | 'unlink' | 'unlinkDir'> = {
create: 'add', create: 'add',
delete: 'unlink', delete: 'unlink',
update: 'change' update: 'change',
} }
async function watch (nuxt: Nuxt) { async function watch (nuxt: Nuxt) {
@ -80,8 +80,8 @@ function createWatcher () {
ignoreInitial: true, ignoreInitial: true,
ignored: [ ignored: [
isIgnored, isIgnored,
'node_modules' 'node_modules',
] ],
}) })
// TODO: consider moving to emit absolute path in 3.8 or 4.0 // TODO: consider moving to emit absolute path in 3.8 or 4.0
@ -164,8 +164,8 @@ async function createParcelWatcher () {
}, { }, {
ignore: [ ignore: [
...nuxt.options.ignore, ...nuxt.options.ignore,
'node_modules' 'node_modules',
] ],
}) })
watcher.then((subscription) => { watcher.then((subscription) => {
if (nuxt.options.debug) { if (nuxt.options.debug) {

View File

@ -30,7 +30,7 @@ async function checkViteConfig () {
return await checkAndWarnAboutConfigFileExistence({ return await checkAndWarnAboutConfigFileExistence({
fileName: 'vite.config', fileName: 'vite.config',
extensions: ['.js', '.mjs', '.ts', '.cjs', '.mts', '.cts'], extensions: ['.js', '.mjs', '.ts', '.cjs', '.mts', '.cts'],
createWarningMessage: foundFile => `Using \`${foundFile}\` is not supported together with Nuxt. Use \`options.vite\` instead. You can read more in \`https://nuxt.com/docs/api/nuxt-config#vite\`.` createWarningMessage: foundFile => `Using \`${foundFile}\` is not supported together with Nuxt. Use \`options.vite\` instead. You can read more in \`https://nuxt.com/docs/api/nuxt-config#vite\`.`,
}) })
} }
@ -39,7 +39,7 @@ async function checkWebpackConfig () {
return await checkAndWarnAboutConfigFileExistence({ return await checkAndWarnAboutConfigFileExistence({
fileName: 'webpack.config', fileName: 'webpack.config',
extensions: ['.js', '.mjs', '.ts', '.cjs', '.mts', '.cts', 'coffee'], extensions: ['.js', '.mjs', '.ts', '.cjs', '.mts', '.cts', 'coffee'],
createWarningMessage: foundFile => `Using \`${foundFile}\` is not supported together with Nuxt. Use \`options.webpack\` instead. You can read more in \`https://nuxt.com/docs/api/nuxt-config#webpack-1\`.` createWarningMessage: foundFile => `Using \`${foundFile}\` is not supported together with Nuxt. Use \`options.webpack\` instead. You can read more in \`https://nuxt.com/docs/api/nuxt-config#webpack-1\`.`,
}) })
} }
@ -48,7 +48,7 @@ async function checkNitroConfig () {
return await checkAndWarnAboutConfigFileExistence({ return await checkAndWarnAboutConfigFileExistence({
fileName: 'nitro.config', fileName: 'nitro.config',
extensions: ['.ts', '.mts'], extensions: ['.ts', '.mts'],
createWarningMessage: foundFile => `Using \`${foundFile}\` is not supported together with Nuxt. Use \`options.nitro\` instead. You can read more in \`https://nuxt.com/docs/api/nuxt-config#nitro\`.` createWarningMessage: foundFile => `Using \`${foundFile}\` is not supported together with Nuxt. Use \`options.nitro\` instead. You can read more in \`https://nuxt.com/docs/api/nuxt-config#nitro\`.`,
}) })
} }
@ -56,13 +56,13 @@ async function checkPostCSSConfig () {
return await checkAndWarnAboutConfigFileExistence({ return await checkAndWarnAboutConfigFileExistence({
fileName: 'postcss.config', fileName: 'postcss.config',
extensions: ['.js', '.cjs'], extensions: ['.js', '.cjs'],
createWarningMessage: foundFile => `Using \`${foundFile}\` is not supported together with Nuxt. Use \`options.postcss\` instead. You can read more in \`https://nuxt.com/docs/api/nuxt-config#postcss\`.` createWarningMessage: foundFile => `Using \`${foundFile}\` is not supported together with Nuxt. Use \`options.postcss\` instead. You can read more in \`https://nuxt.com/docs/api/nuxt-config#postcss\`.`,
}) })
} }
interface CheckAndWarnAboutConfigFileExistenceOptions { interface CheckAndWarnAboutConfigFileExistenceOptions {
fileName: string, fileName: string
extensions: string[], extensions: string[]
createWarningMessage: (foundFile: string) => string createWarningMessage: (foundFile: string) => string
} }

View File

@ -26,7 +26,7 @@ async function promptToInstall (name: string, installCommand: () => Promise<void
const confirm = await logger.prompt(`Do you want to install ${name} package?`, { const confirm = await logger.prompt(`Do you want to install ${name} package?`, {
type: 'confirm', type: 'confirm',
name: 'confirm', name: 'confirm',
initial: true initial: true,
}) })
if (!confirm) { if (!confirm) {
@ -60,6 +60,6 @@ export function installNuxtModule (name: string, options?: EnsurePackageInstalle
export function ensurePackageInstalled (name: string, options: EnsurePackageInstalledOptions) { export function ensurePackageInstalled (name: string, options: EnsurePackageInstalledOptions) {
return promptToInstall(name, () => addDependency(name, { return promptToInstall(name, () => addDependency(name, {
cwd: options.rootDir, cwd: options.rootDir,
dev: true dev: true,
}), options) }), options)
} }

View File

@ -10,7 +10,7 @@ export const addModuleTranspiles = (opts: AddModuleTranspilesOptions = {}) => {
const modules = [ const modules = [
...opts.additionalModules || [], ...opts.additionalModules || [],
...nuxt.options.modules, ...nuxt.options.modules,
...nuxt.options._modules ...nuxt.options._modules,
] ]
.map(m => typeof m === 'string' ? m : Array.isArray(m) ? m[0] : m.src) .map(m => typeof m === 'string' ? m : Array.isArray(m) ? m[0] : m.src)
.filter(m => typeof m === 'string') .filter(m => typeof m === 'string')

View File

@ -23,7 +23,7 @@ import { ImportProtectionPlugin, nuxtImportProtections } from './plugins/import-
const logLevelMapReverse = { const logLevelMapReverse = {
silent: 0, silent: 0,
info: 3, info: 3,
verbose: 3 verbose: 3,
} satisfies Record<NuxtOptions['logLevel'], NitroConfig['logLevel']> } satisfies Record<NuxtOptions['logLevel'], NitroConfig['logLevel']>
export async function initNitro (nuxt: Nuxt & { _nitro?: Nitro }) { export async function initNitro (nuxt: Nuxt & { _nitro?: Nitro }) {
@ -33,7 +33,7 @@ export async function initNitro (nuxt: Nuxt & { _nitro?: Nitro }) {
const excludePaths = nuxt.options._layers const excludePaths = nuxt.options._layers
.flatMap(l => [ .flatMap(l => [
l.cwd.match(/(?<=\/)node_modules\/(.+)$/)?.[1], l.cwd.match(/(?<=\/)node_modules\/(.+)$/)?.[1],
l.cwd.match(/\.pnpm\/.+\/node_modules\/(.+)$/)?.[1] l.cwd.match(/\.pnpm\/.+\/node_modules\/(.+)$/)?.[1],
]) ])
.filter((dir): dir is string => Boolean(dir)) .filter((dir): dir is string => Boolean(dir))
.map(dir => escapeRE(dir)) .map(dir => escapeRE(dir))
@ -46,7 +46,7 @@ export async function initNitro (nuxt: Nuxt & { _nitro?: Nitro }) {
const modules = await resolveNuxtModule(rootDirWithSlash, const modules = await resolveNuxtModule(rootDirWithSlash,
nuxt.options._installedModules nuxt.options._installedModules
.filter(m => m.entryPath) .filter(m => m.entryPath)
.map(m => m.entryPath) .map(m => m.entryPath),
) )
const nitroConfig: NitroConfig = defu(_nitroConfig, { const nitroConfig: NitroConfig = defu(_nitroConfig, {
@ -58,11 +58,11 @@ export async function initNitro (nuxt: Nuxt & { _nitro?: Nitro }) {
buildDir: nuxt.options.buildDir, buildDir: nuxt.options.buildDir,
experimental: { experimental: {
asyncContext: nuxt.options.experimental.asyncContext, asyncContext: nuxt.options.experimental.asyncContext,
typescriptBundlerResolution: nuxt.options.future.typescriptBundlerResolution || nuxt.options.typescript?.tsConfig?.compilerOptions?.moduleResolution?.toLowerCase() === 'bundler' || _nitroConfig.typescript?.tsConfig?.compilerOptions?.moduleResolution?.toLowerCase() === 'bundler' typescriptBundlerResolution: nuxt.options.future.typescriptBundlerResolution || nuxt.options.typescript?.tsConfig?.compilerOptions?.moduleResolution?.toLowerCase() === 'bundler' || _nitroConfig.typescript?.tsConfig?.compilerOptions?.moduleResolution?.toLowerCase() === 'bundler',
}, },
framework: { framework: {
name: 'nuxt', name: 'nuxt',
version: nuxtVersion version: nuxtVersion,
}, },
imports: { imports: {
autoImport: nuxt.options.imports.autoImport as boolean, autoImport: nuxt.options.imports.autoImport as boolean,
@ -70,31 +70,31 @@ export async function initNitro (nuxt: Nuxt & { _nitro?: Nitro }) {
{ {
as: '__buildAssetsURL', as: '__buildAssetsURL',
name: 'buildAssetsURL', name: 'buildAssetsURL',
from: resolve(distDir, 'core/runtime/nitro/paths') from: resolve(distDir, 'core/runtime/nitro/paths'),
}, },
{ {
as: '__publicAssetsURL', as: '__publicAssetsURL',
name: 'publicAssetsURL', name: 'publicAssetsURL',
from: resolve(distDir, 'core/runtime/nitro/paths') from: resolve(distDir, 'core/runtime/nitro/paths'),
}, },
{ {
// TODO: Remove after https://github.com/unjs/nitro/issues/1049 // TODO: Remove after https://github.com/unjs/nitro/issues/1049
as: 'defineAppConfig', as: 'defineAppConfig',
name: 'defineAppConfig', name: 'defineAppConfig',
from: resolve(distDir, 'core/runtime/nitro/config'), from: resolve(distDir, 'core/runtime/nitro/config'),
priority: -1 priority: -1,
} },
], ],
exclude: [...excludePattern, /[\\/]\.git[\\/]/] exclude: [...excludePattern, /[\\/]\.git[\\/]/],
}, },
esbuild: { esbuild: {
options: { exclude: excludePattern } options: { exclude: excludePattern },
}, },
analyze: !nuxt.options.test && nuxt.options.build.analyze && (nuxt.options.build.analyze === true || nuxt.options.build.analyze.enabled) analyze: !nuxt.options.test && nuxt.options.build.analyze && (nuxt.options.build.analyze === true || nuxt.options.build.analyze.enabled)
? { ? {
template: 'treemap', template: 'treemap',
projectRoot: nuxt.options.rootDir, projectRoot: nuxt.options.rootDir,
filename: join(nuxt.options.analyzeDir, '{name}.html') filename: join(nuxt.options.analyzeDir, '{name}.html'),
} }
: false, : false,
scanDirs: nuxt.options._layers.map(layer => (layer.config.serverDir || layer.config.srcDir) && resolve(layer.cwd, layer.config.serverDir || resolve(layer.config.srcDir, 'server'))).filter(Boolean), scanDirs: nuxt.options._layers.map(layer => (layer.config.serverDir || layer.config.srcDir) && resolve(layer.cwd, layer.config.serverDir || resolve(layer.config.srcDir, 'server'))).filter(Boolean),
@ -106,10 +106,10 @@ export async function initNitro (nuxt: Nuxt & { _nitro?: Nitro }) {
baseURL: nuxt.options.app.baseURL, baseURL: nuxt.options.app.baseURL,
virtual: { virtual: {
'#internal/nuxt.config.mjs': () => nuxt.vfs['#build/nuxt.config'], '#internal/nuxt.config.mjs': () => nuxt.vfs['#build/nuxt.config'],
'#spa-template': async () => `export const template = ${JSON.stringify(await spaLoadingTemplate(nuxt))}` '#spa-template': async () => `export const template = ${JSON.stringify(await spaLoadingTemplate(nuxt))}`,
}, },
routeRules: { routeRules: {
'/__nuxt_error': { cache: false } '/__nuxt_error': { cache: false },
}, },
runtimeConfig: { runtimeConfig: {
...nuxt.options.runtimeConfig, ...nuxt.options.runtimeConfig,
@ -117,17 +117,17 @@ export async function initNitro (nuxt: Nuxt & { _nitro?: Nitro }) {
...nuxt.options.runtimeConfig.app, ...nuxt.options.runtimeConfig.app,
baseURL: nuxt.options.runtimeConfig.app.baseURL.startsWith('./') baseURL: nuxt.options.runtimeConfig.app.baseURL.startsWith('./')
? nuxt.options.runtimeConfig.app.baseURL.slice(1) ? nuxt.options.runtimeConfig.app.baseURL.slice(1)
: nuxt.options.runtimeConfig.app.baseURL : nuxt.options.runtimeConfig.app.baseURL,
}, },
nitro: { nitro: {
envPrefix: 'NUXT_', envPrefix: 'NUXT_',
// TODO: address upstream issue with defu types...? // TODO: address upstream issue with defu types...?
...nuxt.options.runtimeConfig.nitro satisfies RuntimeConfig['nitro'] as any ...nuxt.options.runtimeConfig.nitro satisfies RuntimeConfig['nitro'] as any,
} },
}, },
appConfig: nuxt.options.appConfig, appConfig: nuxt.options.appConfig,
appConfigFiles: nuxt.options._layers.map( appConfigFiles: nuxt.options._layers.map(
layer => resolve(layer.config.srcDir, 'app.config') layer => resolve(layer.config.srcDir, 'app.config'),
), ),
typescript: { typescript: {
strict: true, strict: true,
@ -136,14 +136,14 @@ export async function initNitro (nuxt: Nuxt & { _nitro?: Nitro }) {
tsConfig: { tsConfig: {
include: [ include: [
join(nuxt.options.buildDir, 'types/nitro-nuxt.d.ts'), join(nuxt.options.buildDir, 'types/nitro-nuxt.d.ts'),
...modules.map(m => join(relativeWithDot(nuxt.options.buildDir, m), 'runtime/server')) ...modules.map(m => join(relativeWithDot(nuxt.options.buildDir, m), 'runtime/server')),
], ],
exclude: [ exclude: [
...nuxt.options.modulesDir.map(m => relativeWithDot(nuxt.options.buildDir, m)), ...nuxt.options.modulesDir.map(m => relativeWithDot(nuxt.options.buildDir, m)),
// nitro generate output: https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/core/nitro.ts#L186 // nitro generate output: https://github.com/nuxt/nuxt/blob/main/packages/nuxt/src/core/nitro.ts#L186
relativeWithDot(nuxt.options.buildDir, resolve(nuxt.options.rootDir, 'dist')) relativeWithDot(nuxt.options.buildDir, resolve(nuxt.options.rootDir, 'dist')),
] ],
} },
}, },
publicAssets: [ publicAssets: [
nuxt.options.dev nuxt.options.dev
@ -151,17 +151,17 @@ export async function initNitro (nuxt: Nuxt & { _nitro?: Nitro }) {
: { : {
dir: join(nuxt.options.buildDir, 'dist/client', nuxt.options.app.buildAssetsDir), dir: join(nuxt.options.buildDir, 'dist/client', nuxt.options.app.buildAssetsDir),
maxAge: 31536000 /* 1 year */, maxAge: 31536000 /* 1 year */,
baseURL: nuxt.options.app.buildAssetsDir baseURL: nuxt.options.app.buildAssetsDir,
}, },
...nuxt.options._layers ...nuxt.options._layers
.map(layer => join(layer.config.srcDir, (layer.config.rootDir === nuxt.options.rootDir ? nuxt.options : layer.config).dir?.public || 'public')) .map(layer => join(layer.config.srcDir, (layer.config.rootDir === nuxt.options.rootDir ? nuxt.options : layer.config).dir?.public || 'public'))
.filter(dir => existsSync(dir)) .filter(dir => existsSync(dir))
.map(dir => ({ dir })) .map(dir => ({ dir })),
], ],
prerender: { prerender: {
failOnError: true, failOnError: true,
concurrency: cpus().length * 4 || 4, concurrency: cpus().length * 4 || 4,
routes: ([] as string[]).concat(nuxt.options.generate.routes) routes: ([] as string[]).concat(nuxt.options.generate.routes),
}, },
sourceMap: nuxt.options.sourcemap.server, sourceMap: nuxt.options.sourcemap.server,
externals: { externals: {
@ -171,13 +171,13 @@ export async function initNitro (nuxt: Nuxt & { _nitro?: Nitro }) {
: [ : [
...nuxt.options.experimental.externalVue ? [] : ['vue', '@vue/'], ...nuxt.options.experimental.externalVue ? [] : ['vue', '@vue/'],
'@nuxt/', '@nuxt/',
nuxt.options.buildDir nuxt.options.buildDir,
]), ]),
...nuxt.options.build.transpile.filter((i): i is string => typeof i === 'string'), ...nuxt.options.build.transpile.filter((i): i is string => typeof i === 'string'),
'nuxt/dist', 'nuxt/dist',
'nuxt3/dist', 'nuxt3/dist',
'nuxt-nightly/dist', 'nuxt-nightly/dist',
distDir distDir,
], ],
traceInclude: [ traceInclude: [
// force include files used in generated code from the runtime-compiler // force include files used in generated code from the runtime-compiler
@ -187,10 +187,10 @@ export async function initNitro (nuxt: Nuxt & { _nitro?: Nitro }) {
const serverRendererPath = resolve(path, 'vue/server-renderer/index.js') const serverRendererPath = resolve(path, 'vue/server-renderer/index.js')
if (existsSync(serverRendererPath)) { targets.push(serverRendererPath) } if (existsSync(serverRendererPath)) { targets.push(serverRendererPath) }
return targets return targets
}, []) }, []),
]
: []
] ]
: [],
],
}, },
alias: { alias: {
// Vue 3 mocks // Vue 3 mocks
@ -201,7 +201,7 @@ export async function initNitro (nuxt: Nuxt & { _nitro?: Nitro }) {
'@babel/parser': 'unenv/runtime/mock/proxy', '@babel/parser': 'unenv/runtime/mock/proxy',
'@vue/compiler-core': 'unenv/runtime/mock/proxy', '@vue/compiler-core': 'unenv/runtime/mock/proxy',
'@vue/compiler-dom': 'unenv/runtime/mock/proxy', '@vue/compiler-dom': 'unenv/runtime/mock/proxy',
'@vue/compiler-ssr': 'unenv/runtime/mock/proxy' '@vue/compiler-ssr': 'unenv/runtime/mock/proxy',
}, },
'@vue/devtools-api': 'vue-devtools-stub', '@vue/devtools-api': 'vue-devtools-stub',
@ -209,7 +209,7 @@ export async function initNitro (nuxt: Nuxt & { _nitro?: Nitro }) {
'#internal/nuxt/paths': resolve(distDir, 'core/runtime/nitro/paths'), '#internal/nuxt/paths': resolve(distDir, 'core/runtime/nitro/paths'),
// Nuxt aliases // Nuxt aliases
...nuxt.options.alias ...nuxt.options.alias,
}, },
replace: { replace: {
'process.env.NUXT_NO_SSR': nuxt.options.ssr === false, 'process.env.NUXT_NO_SSR': nuxt.options.ssr === false,
@ -220,13 +220,13 @@ export async function initNitro (nuxt: Nuxt & { _nitro?: Nitro }) {
'process.env.NUXT_ASYNC_CONTEXT': !!nuxt.options.experimental.asyncContext, 'process.env.NUXT_ASYNC_CONTEXT': !!nuxt.options.experimental.asyncContext,
'process.env.NUXT_SHARED_DATA': !!nuxt.options.experimental.sharedPrerenderData, 'process.env.NUXT_SHARED_DATA': !!nuxt.options.experimental.sharedPrerenderData,
'process.dev': nuxt.options.dev, 'process.dev': nuxt.options.dev,
__VUE_PROD_DEVTOOLS__: false '__VUE_PROD_DEVTOOLS__': false,
}, },
rollupConfig: { rollupConfig: {
output: {}, output: {},
plugins: [] plugins: [],
}, },
logLevel: logLevelMapReverse[nuxt.options.logLevel] logLevel: logLevelMapReverse[nuxt.options.logLevel],
} satisfies NitroConfig) } satisfies NitroConfig)
// Resolve user-provided paths // Resolve user-provided paths
@ -252,14 +252,14 @@ export async function initNitro (nuxt: Nuxt & { _nitro?: Nitro }) {
{ {
dir: join(tempDir, 'meta'), dir: join(tempDir, 'meta'),
maxAge: 31536000 /* 1 year */, maxAge: 31536000 /* 1 year */,
baseURL: joinURL(manifestPrefix, 'meta') baseURL: joinURL(manifestPrefix, 'meta'),
}, },
// latest build // latest build
{ {
dir: tempDir, dir: tempDir,
maxAge: 1, maxAge: 1,
baseURL: manifestPrefix baseURL: manifestPrefix,
} },
) )
nuxt.options.alias['#app-manifest'] = join(tempDir, `meta/${buildId}.json`) nuxt.options.alias['#app-manifest'] = join(tempDir, `meta/${buildId}.json`)
@ -308,7 +308,7 @@ export async function initNitro (nuxt: Nuxt & { _nitro?: Nitro }) {
// Add pages prerendered but not covered by route rules // Add pages prerendered but not covered by route rules
const prerenderedRoutes = new Set<string>() const prerenderedRoutes = new Set<string>()
const routeRulesMatcher = toRouteMatcher( const routeRulesMatcher = toRouteMatcher(
createRadixRouter({ routes: routeRules }) createRadixRouter({ routes: routeRules }),
) )
if (nitro._prerenderedRoutes?.length) { if (nitro._prerenderedRoutes?.length) {
const payloadSuffix = nuxt.options.experimental.renderJsonPayloads ? '/_payload.json' : '/_payload.js' const payloadSuffix = nuxt.options.experimental.renderJsonPayloads ? '/_payload.json' : '/_payload.js'
@ -327,13 +327,13 @@ export async function initNitro (nuxt: Nuxt & { _nitro?: Nitro }) {
id: buildId, id: buildId,
timestamp: buildTimestamp, timestamp: buildTimestamp,
matcher: exportMatcher(routeRulesMatcher), matcher: exportMatcher(routeRulesMatcher),
prerendered: nuxt.options.dev ? [] : [...prerenderedRoutes] prerendered: nuxt.options.dev ? [] : [...prerenderedRoutes],
} }
await fsp.mkdir(join(tempDir, 'meta'), { recursive: true }) await fsp.mkdir(join(tempDir, 'meta'), { recursive: true })
await fsp.writeFile(join(tempDir, 'latest.json'), JSON.stringify({ await fsp.writeFile(join(tempDir, 'latest.json'), JSON.stringify({
id: buildId, id: buildId,
timestamp: buildTimestamp timestamp: buildTimestamp,
})) }))
await fsp.writeFile(join(tempDir, `meta/${buildId}.json`), JSON.stringify(manifest)) await fsp.writeFile(join(tempDir, `meta/${buildId}.json`), JSON.stringify(manifest))
}) })
@ -362,7 +362,7 @@ export async function initNitro (nuxt: Nuxt & { _nitro?: Nitro }) {
nitroConfig.handlers = nitroConfig.handlers || [] nitroConfig.handlers = nitroConfig.handlers || []
nitroConfig.handlers.push({ nitroConfig.handlers.push({
handler: resolve(distDir, 'core/runtime/nitro/no-ssr'), handler: resolve(distDir, 'core/runtime/nitro/no-ssr'),
middleware: true middleware: true,
}) })
} }
@ -373,8 +373,8 @@ export async function initNitro (nuxt: Nuxt & { _nitro?: Nitro }) {
ImportProtectionPlugin.rollup({ ImportProtectionPlugin.rollup({
rootDir: nuxt.options.rootDir, rootDir: nuxt.options.rootDir,
patterns: nuxtImportProtections(nuxt, { isNitro: true }), patterns: nuxtImportProtections(nuxt, { isNitro: true }),
exclude: [/core[\\/]runtime[\\/]nitro[\\/]renderer/] exclude: [/core[\\/]runtime[\\/]nitro[\\/]renderer/],
}) }),
) )
// Extend nitro config with hook // Extend nitro config with hook
@ -422,8 +422,8 @@ export async function initNitro (nuxt: Nuxt & { _nitro?: Nitro }) {
'internal:nuxt:prerender': { 'internal:nuxt:prerender': {
// TODO: resolve upstream where file URLs are not being resolved/inlined correctly // TODO: resolve upstream where file URLs are not being resolved/inlined correctly
driver: isWindows ? pathToFileURL(cacheDriverPath).href : cacheDriverPath, driver: isWindows ? pathToFileURL(cacheDriverPath).href : cacheDriverPath,
base: cacheDir base: cacheDir,
} },
}) })
// Expose nitro to modules and kit // Expose nitro to modules and kit
@ -446,12 +446,12 @@ export async function initNitro (nuxt: Nuxt & { _nitro?: Nitro }) {
if (Array.isArray(config.resolve!.alias)) { if (Array.isArray(config.resolve!.alias)) {
config.resolve!.alias.push({ config.resolve!.alias.push({
find: 'vue', find: 'vue',
replacement: 'vue/dist/vue.esm-bundler' replacement: 'vue/dist/vue.esm-bundler',
}) })
} else { } else {
config.resolve!.alias = { config.resolve!.alias = {
...config.resolve!.alias, ...config.resolve!.alias,
vue: 'vue/dist/vue.esm-bundler' vue: 'vue/dist/vue.esm-bundler',
} }
} }
} }
@ -462,7 +462,7 @@ export async function initNitro (nuxt: Nuxt & { _nitro?: Nitro }) {
if (Array.isArray(clientConfig!.resolve!.alias)) { if (Array.isArray(clientConfig!.resolve!.alias)) {
clientConfig!.resolve!.alias.push({ clientConfig!.resolve!.alias.push({
name: 'vue', name: 'vue',
alias: 'vue/dist/vue.esm-bundler' alias: 'vue/dist/vue.esm-bundler',
}) })
} else { } else {
clientConfig!.resolve!.alias!.vue = 'vue/dist/vue.esm-bundler' clientConfig!.resolve!.alias!.vue = 'vue/dist/vue.esm-bundler'
@ -477,7 +477,7 @@ export async function initNitro (nuxt: Nuxt & { _nitro?: Nitro }) {
nitro.options.handlers.unshift({ nitro.options.handlers.unshift({
route: '/__nuxt_error', route: '/__nuxt_error',
lazy: true, lazy: true,
handler: resolve(distDir, 'core/runtime/nitro/renderer') handler: resolve(distDir, 'core/runtime/nitro/renderer'),
}) })
if (!nuxt.options.dev && nuxt.options.experimental.noVueServer) { if (!nuxt.options.dev && nuxt.options.experimental.noVueServer) {

View File

@ -10,13 +10,13 @@ import { readPackageJSON, resolvePackageJSON } from 'pkg-types'
import escapeRE from 'escape-string-regexp' import escapeRE from 'escape-string-regexp'
import fse from 'fs-extra' import fse from 'fs-extra'
import { withoutLeadingSlash } from 'ufo' import { withoutLeadingSlash } from 'ufo'
/* eslint-disable import/no-restricted-paths */
import defu from 'defu' import defu from 'defu'
import pagesModule from '../pages/module' import pagesModule from '../pages/module'
import metaModule from '../head/module' import metaModule from '../head/module'
import componentsModule from '../components/module' import componentsModule from '../components/module'
import importsModule from '../imports/module' import importsModule from '../imports/module'
/* eslint-enable */
import { distDir, pkgDir } from '../dirs' import { distDir, pkgDir } from '../dirs'
import { version } from '../../package.json' import { version } from '../../package.json'
import { ImportProtectionPlugin, nuxtImportProtections } from './plugins/import-protection' import { ImportProtectionPlugin, nuxtImportProtections } from './plugins/import-protection'
@ -46,18 +46,18 @@ export function createNuxt (options: NuxtOptions): Nuxt {
ready: () => initNuxt(nuxt), ready: () => initNuxt(nuxt),
close: () => Promise.resolve(hooks.callHook('close', nuxt)), close: () => Promise.resolve(hooks.callHook('close', nuxt)),
vfs: {}, vfs: {},
apps: {} apps: {},
} }
return nuxt return nuxt
} }
const nightlies = { const nightlies = {
nitropack: 'nitropack-nightly', 'nitropack': 'nitropack-nightly',
h3: 'h3-nightly', 'h3': 'h3-nightly',
nuxt: 'nuxt-nightly', 'nuxt': 'nuxt-nightly',
'@nuxt/schema': '@nuxt/schema-nightly', '@nuxt/schema': '@nuxt/schema-nightly',
'@nuxt/kit': '@nuxt/kit-nightly' '@nuxt/kit': '@nuxt/kit-nightly',
} }
async function initNuxt (nuxt: Nuxt) { async function initNuxt (nuxt: Nuxt) {
@ -98,7 +98,7 @@ async function initNuxt (nuxt: Nuxt) {
// Set nitro resolutions for types that might be obscured with shamefully-hoist=false // Set nitro resolutions for types that might be obscured with shamefully-hoist=false
nuxt.options.nitro.typescript = defu(nuxt.options.nitro.typescript, { nuxt.options.nitro.typescript = defu(nuxt.options.nitro.typescript, {
tsConfig: { compilerOptions: { paths: { ...paths } } } tsConfig: { compilerOptions: { paths: { ...paths } } },
}) })
// Add nuxt types // Add nuxt types
@ -132,7 +132,7 @@ async function initNuxt (nuxt: Nuxt) {
rootDir: nuxt.options.rootDir, rootDir: nuxt.options.rootDir,
// Exclude top-level resolutions by plugins // Exclude top-level resolutions by plugins
exclude: [join(nuxt.options.srcDir, 'index.html')], exclude: [join(nuxt.options.srcDir, 'index.html')],
patterns: nuxtImportProtections(nuxt) patterns: nuxtImportProtections(nuxt),
} }
addVitePlugin(() => ImportProtectionPlugin.vite(config)) addVitePlugin(() => ImportProtectionPlugin.vite(config))
addWebpackPlugin(() => ImportProtectionPlugin.webpack(config)) addWebpackPlugin(() => ImportProtectionPlugin.webpack(config))
@ -147,7 +147,7 @@ async function initNuxt (nuxt: Nuxt) {
dev: nuxt.options.dev, dev: nuxt.options.dev,
root: nuxt.options.srcDir, root: nuxt.options.srcDir,
// skip top-level layer (user's project) as the aliases will already be correctly resolved // skip top-level layer (user's project) as the aliases will already be correctly resolved
layers: nuxt.options._layers.slice(1) layers: nuxt.options._layers.slice(1),
})) }))
addWebpackPlugin(() => LayerAliasingPlugin.webpack({ addWebpackPlugin(() => LayerAliasingPlugin.webpack({
sourcemap: !!nuxt.options.sourcemap.server || !!nuxt.options.sourcemap.client, sourcemap: !!nuxt.options.sourcemap.server || !!nuxt.options.sourcemap.client,
@ -155,7 +155,7 @@ async function initNuxt (nuxt: Nuxt) {
root: nuxt.options.srcDir, root: nuxt.options.srcDir,
// skip top-level layer (user's project) as the aliases will already be correctly resolved // skip top-level layer (user's project) as the aliases will already be correctly resolved
layers: nuxt.options._layers.slice(1), layers: nuxt.options._layers.slice(1),
transform: true transform: true,
})) }))
} }
@ -165,8 +165,8 @@ async function initNuxt (nuxt: Nuxt) {
sourcemap: !!nuxt.options.sourcemap.server || !!nuxt.options.sourcemap.client, sourcemap: !!nuxt.options.sourcemap.server || !!nuxt.options.sourcemap.client,
transformerOptions: { transformerOptions: {
...nuxt.options.optimization.asyncTransforms, ...nuxt.options.optimization.asyncTransforms,
helperModule: await tryResolveModule('unctx', nuxt.options.modulesDir) ?? 'unctx' helperModule: await tryResolveModule('unctx', nuxt.options.modulesDir) ?? 'unctx',
} },
} satisfies UnctxTransformPluginOptions } satisfies UnctxTransformPluginOptions
addVitePlugin(() => UnctxTransformPlugin.vite(options)) addVitePlugin(() => UnctxTransformPlugin.vite(options))
addWebpackPlugin(() => UnctxTransformPlugin.webpack(options)) addWebpackPlugin(() => UnctxTransformPlugin.webpack(options))
@ -174,7 +174,7 @@ async function initNuxt (nuxt: Nuxt) {
// Add composable tree-shaking optimisations // Add composable tree-shaking optimisations
const serverTreeShakeOptions: TreeShakeComposablesPluginOptions = { const serverTreeShakeOptions: TreeShakeComposablesPluginOptions = {
sourcemap: !!nuxt.options.sourcemap.server, sourcemap: !!nuxt.options.sourcemap.server,
composables: nuxt.options.optimization.treeShake.composables.server composables: nuxt.options.optimization.treeShake.composables.server,
} }
if (Object.keys(serverTreeShakeOptions.composables).length) { if (Object.keys(serverTreeShakeOptions.composables).length) {
addVitePlugin(() => TreeShakeComposablesPlugin.vite(serverTreeShakeOptions), { client: false }) addVitePlugin(() => TreeShakeComposablesPlugin.vite(serverTreeShakeOptions), { client: false })
@ -182,7 +182,7 @@ async function initNuxt (nuxt: Nuxt) {
} }
const clientTreeShakeOptions: TreeShakeComposablesPluginOptions = { const clientTreeShakeOptions: TreeShakeComposablesPluginOptions = {
sourcemap: !!nuxt.options.sourcemap.client, sourcemap: !!nuxt.options.sourcemap.client,
composables: nuxt.options.optimization.treeShake.composables.client composables: nuxt.options.optimization.treeShake.composables.client,
} }
if (Object.keys(clientTreeShakeOptions.composables).length) { if (Object.keys(clientTreeShakeOptions.composables).length) {
addVitePlugin(() => TreeShakeComposablesPlugin.vite(clientTreeShakeOptions), { server: false }) addVitePlugin(() => TreeShakeComposablesPlugin.vite(clientTreeShakeOptions), { server: false })
@ -206,11 +206,11 @@ async function initNuxt (nuxt: Nuxt) {
addServerPlugin(resolve(distDir, 'core/runtime/nitro/dev-server-logs')) addServerPlugin(resolve(distDir, 'core/runtime/nitro/dev-server-logs'))
nuxt.options.nitro = defu(nuxt.options.nitro, { nuxt.options.nitro = defu(nuxt.options.nitro, {
externals: { externals: {
inline: [/#internal\/dev-server-logs-options/] inline: [/#internal\/dev-server-logs-options/],
}, },
virtual: { virtual: {
'#internal/dev-server-logs-options': () => `export const rootDir = ${JSON.stringify(nuxt.options.rootDir)};` '#internal/dev-server-logs-options': () => `export const rootDir = ${JSON.stringify(nuxt.options.rootDir)};`,
} },
}) })
} }
@ -236,7 +236,7 @@ async function initNuxt (nuxt: Nuxt) {
// Transpile layers within node_modules // Transpile layers within node_modules
nuxt.options.build.transpile.push( nuxt.options.build.transpile.push(
...nuxt.options._layers.filter(i => i.cwd.includes('node_modules')).map(i => i.cwd as string) ...nuxt.options._layers.filter(i => i.cwd.includes('node_modules')).map(i => i.cwd as string),
) )
// Init user modules // Init user modules
@ -258,7 +258,7 @@ async function initNuxt (nuxt: Nuxt) {
const modulesDir = (config.rootDir === nuxt.options.rootDir ? nuxt.options : config).dir?.modules || 'modules' const modulesDir = (config.rootDir === nuxt.options.rootDir ? nuxt.options : config).dir?.modules || 'modules'
const layerModules = await resolveFiles(config.srcDir, [ const layerModules = await resolveFiles(config.srcDir, [
`${modulesDir}/*{${nuxt.options.extensions.join(',')}}`, `${modulesDir}/*{${nuxt.options.extensions.join(',')}}`,
`${modulesDir}/*/index{${nuxt.options.extensions.join(',')}}` `${modulesDir}/*/index{${nuxt.options.extensions.join(',')}}`,
]) ])
for (const mod of layerModules) { for (const mod of layerModules) {
watchedPaths.add(mod) watchedPaths.add(mod)
@ -275,55 +275,55 @@ async function initNuxt (nuxt: Nuxt) {
addComponent({ addComponent({
name: 'NuxtWelcome', name: 'NuxtWelcome',
priority: 10, // built-in that we do not expect the user to override priority: 10, // built-in that we do not expect the user to override
filePath: (await tryResolveModule('@nuxt/ui-templates/templates/welcome.vue', nuxt.options.modulesDir))! filePath: (await tryResolveModule('@nuxt/ui-templates/templates/welcome.vue', nuxt.options.modulesDir))!,
}) })
addComponent({ addComponent({
name: 'NuxtLayout', name: 'NuxtLayout',
priority: 10, // built-in that we do not expect the user to override priority: 10, // built-in that we do not expect the user to override
filePath: resolve(nuxt.options.appDir, 'components/nuxt-layout') filePath: resolve(nuxt.options.appDir, 'components/nuxt-layout'),
}) })
// Add <NuxtErrorBoundary> // Add <NuxtErrorBoundary>
addComponent({ addComponent({
name: 'NuxtErrorBoundary', name: 'NuxtErrorBoundary',
priority: 10, // built-in that we do not expect the user to override priority: 10, // built-in that we do not expect the user to override
filePath: resolve(nuxt.options.appDir, 'components/nuxt-error-boundary') filePath: resolve(nuxt.options.appDir, 'components/nuxt-error-boundary'),
}) })
// Add <ClientOnly> // Add <ClientOnly>
addComponent({ addComponent({
name: 'ClientOnly', name: 'ClientOnly',
priority: 10, // built-in that we do not expect the user to override priority: 10, // built-in that we do not expect the user to override
filePath: resolve(nuxt.options.appDir, 'components/client-only') filePath: resolve(nuxt.options.appDir, 'components/client-only'),
}) })
// Add <DevOnly> // Add <DevOnly>
addComponent({ addComponent({
name: 'DevOnly', name: 'DevOnly',
priority: 10, // built-in that we do not expect the user to override priority: 10, // built-in that we do not expect the user to override
filePath: resolve(nuxt.options.appDir, 'components/dev-only') filePath: resolve(nuxt.options.appDir, 'components/dev-only'),
}) })
// Add <ServerPlaceholder> // Add <ServerPlaceholder>
addComponent({ addComponent({
name: 'ServerPlaceholder', name: 'ServerPlaceholder',
priority: 10, // built-in that we do not expect the user to override priority: 10, // built-in that we do not expect the user to override
filePath: resolve(nuxt.options.appDir, 'components/server-placeholder') filePath: resolve(nuxt.options.appDir, 'components/server-placeholder'),
}) })
// Add <NuxtLink> // Add <NuxtLink>
addComponent({ addComponent({
name: 'NuxtLink', name: 'NuxtLink',
priority: 10, // built-in that we do not expect the user to override priority: 10, // built-in that we do not expect the user to override
filePath: resolve(nuxt.options.appDir, 'components/nuxt-link') filePath: resolve(nuxt.options.appDir, 'components/nuxt-link'),
}) })
// Add <NuxtLoadingIndicator> // Add <NuxtLoadingIndicator>
addComponent({ addComponent({
name: 'NuxtLoadingIndicator', name: 'NuxtLoadingIndicator',
priority: 10, // built-in that we do not expect the user to override priority: 10, // built-in that we do not expect the user to override
filePath: resolve(nuxt.options.appDir, 'components/nuxt-loading-indicator') filePath: resolve(nuxt.options.appDir, 'components/nuxt-loading-indicator'),
}) })
// Add <NuxtClientFallback> // Add <NuxtClientFallback>
@ -333,7 +333,7 @@ async function initNuxt (nuxt: Nuxt) {
_raw: true, _raw: true,
priority: 10, // built-in that we do not expect the user to override priority: 10, // built-in that we do not expect the user to override
filePath: resolve(nuxt.options.appDir, 'components/client-fallback.client'), filePath: resolve(nuxt.options.appDir, 'components/client-fallback.client'),
mode: 'client' mode: 'client',
}) })
addComponent({ addComponent({
@ -341,7 +341,7 @@ async function initNuxt (nuxt: Nuxt) {
_raw: true, _raw: true,
priority: 10, // built-in that we do not expect the user to override priority: 10, // built-in that we do not expect the user to override
filePath: resolve(nuxt.options.appDir, 'components/client-fallback.server'), filePath: resolve(nuxt.options.appDir, 'components/client-fallback.server'),
mode: 'server' mode: 'server',
}) })
} }
@ -350,7 +350,7 @@ async function initNuxt (nuxt: Nuxt) {
addComponent({ addComponent({
name: 'NuxtIsland', name: 'NuxtIsland',
priority: 10, // built-in that we do not expect the user to override priority: 10, // built-in that we do not expect the user to override
filePath: resolve(nuxt.options.appDir, 'components/nuxt-island') filePath: resolve(nuxt.options.appDir, 'components/nuxt-island'),
}) })
if (!nuxt.options.ssr && nuxt.options.experimental.componentIslands !== 'auto') { if (!nuxt.options.ssr && nuxt.options.experimental.componentIslands !== 'auto') {
@ -368,7 +368,7 @@ async function initNuxt (nuxt: Nuxt) {
priority: -1, priority: -1,
filePath: resolve(nuxt.options.appDir, 'components/nuxt-stubs'), filePath: resolve(nuxt.options.appDir, 'components/nuxt-stubs'),
// @ts-expect-error TODO: refactor to nuxi // @ts-expect-error TODO: refactor to nuxi
_internal_install: '@nuxt/image' _internal_install: '@nuxt/image',
}) })
} }
@ -414,10 +414,10 @@ async function initNuxt (nuxt: Nuxt) {
'@nuxt/vite-builder': 'vite/client', '@nuxt/vite-builder': 'vite/client',
'@nuxt/webpack-builder': 'webpack/module', '@nuxt/webpack-builder': 'webpack/module',
// simpler overrides from `typescript.builder` for better DX // simpler overrides from `typescript.builder` for better DX
vite: 'vite/client', 'vite': 'vite/client',
webpack: 'webpack/module', 'webpack': 'webpack/module',
// default 'merged' builder environment for module authors // default 'merged' builder environment for module authors
shared: '@nuxt/schema/builder-env' 'shared': '@nuxt/schema/builder-env',
} }
nuxt.hook('prepare:types', ({ references }) => { nuxt.hook('prepare:types', ({ references }) => {
@ -451,7 +451,7 @@ async function initNuxt (nuxt: Nuxt) {
addRouteMiddleware({ addRouteMiddleware({
name: 'manifest-route-rule', name: 'manifest-route-rule',
path: resolve(nuxt.options.appDir, 'middleware/manifest-route-rule'), path: resolve(nuxt.options.appDir, 'middleware/manifest-route-rule'),
global: true global: true,
}) })
addPlugin(resolve(nuxt.options.appDir, 'plugins/check-outdated-build.client')) addPlugin(resolve(nuxt.options.appDir, 'plugins/check-outdated-build.client'))
@ -535,7 +535,7 @@ export async function loadNuxt (opts: LoadNuxtOptions): Promise<Nuxt> {
if (options.builder === '@nuxt/webpack-builder') { if (options.builder === '@nuxt/webpack-builder') {
if (!await import('./features').then(r => r.ensurePackageInstalled('@nuxt/webpack-builder', { if (!await import('./features').then(r => r.ensurePackageInstalled('@nuxt/webpack-builder', {
rootDir: options.rootDir, rootDir: options.rootDir,
searchPaths: options.modulesDir searchPaths: options.modulesDir,
}))) { }))) {
logger.warn('Failed to install `@nuxt/webpack-builder`, please install it manually, or change the `builder` option to vite in `nuxt.config`') logger.warn('Failed to install `@nuxt/webpack-builder`, please install it manually, or change the `builder` option to vite in `nuxt.config`')
} }
@ -547,15 +547,15 @@ export async function loadNuxt (opts: LoadNuxtOptions): Promise<Nuxt> {
transform: { transform: {
include: options._layers include: options._layers
.filter(i => i.cwd && i.cwd.includes('node_modules')) .filter(i => i.cwd && i.cwd.includes('node_modules'))
.map(i => new RegExp(`(^|\\/)${escapeRE(i.cwd!.split('node_modules/').pop()!)}(\\/|$)(?!node_modules\\/)`)) .map(i => new RegExp(`(^|\\/)${escapeRE(i.cwd!.split('node_modules/').pop()!)}(\\/|$)(?!node_modules\\/)`)),
} },
}]) }])
options._modules.push(schemaModule) options._modules.push(schemaModule)
options.modulesDir.push(resolve(options.workspaceDir, 'node_modules')) options.modulesDir.push(resolve(options.workspaceDir, 'node_modules'))
options.modulesDir.push(resolve(pkgDir, 'node_modules')) options.modulesDir.push(resolve(pkgDir, 'node_modules'))
options.build.transpile.push( options.build.transpile.push(
'@nuxt/ui-templates', // this exposes vue SFCs '@nuxt/ui-templates', // this exposes vue SFCs
'std-env' // we need to statically replace process.env when used in runtime code 'std-env', // we need to statically replace process.env when used in runtime code
) )
options.alias['vue-demi'] = resolve(options.appDir, 'compat/vue-demi') options.alias['vue-demi'] = resolve(options.appDir, 'compat/vue-demi')
options.alias['@vue/composition-api'] = resolve(options.appDir, 'compat/capi') options.alias['@vue/composition-api'] = resolve(options.appDir, 'compat/capi')

View File

@ -21,9 +21,9 @@ export const AsyncContextInjectionPlugin = (nuxt: Nuxt) => createUnplugin(() =>
code: s.toString(), code: s.toString(),
map: nuxt.options.sourcemap.client || nuxt.options.sourcemap.server map: nuxt.options.sourcemap.client || nuxt.options.sourcemap.server
? s.generateMap({ hires: true }) ? s.generateMap({ hires: true })
: undefined : undefined,
}
} }
} }
},
} }
}) })

View File

@ -33,9 +33,9 @@ export const DevOnlyPlugin = createUnplugin((options: DevOnlyPluginOptions) => {
code: s.toString(), code: s.toString(),
map: options.sourcemap map: options.sourcemap
? s.generateMap({ hires: true }) ? s.generateMap({ hires: true })
: undefined : undefined,
}
} }
} }
},
} }
}) })

View File

@ -18,12 +18,12 @@ export const nuxtImportProtections = (nuxt: { options: NuxtOptions }, options: {
patterns.push([ patterns.push([
/^(nuxt|nuxt3|nuxt-nightly)$/, /^(nuxt|nuxt3|nuxt-nightly)$/,
'`nuxt`, `nuxt3` or `nuxt-nightly` cannot be imported directly.' + (options.isNitro ? '' : ' Instead, import runtime Nuxt composables from `#app` or `#imports`.') '`nuxt`, `nuxt3` or `nuxt-nightly` cannot be imported directly.' + (options.isNitro ? '' : ' Instead, import runtime Nuxt composables from `#app` or `#imports`.'),
]) ])
patterns.push([ patterns.push([
/^((|~|~~|@|@@)\/)?nuxt\.config(\.|$)/, /^((|~|~~|@|@@)\/)?nuxt\.config(\.|$)/,
'Importing directly from a `nuxt.config` file is not allowed. Instead, use runtime config or a module.' 'Importing directly from a `nuxt.config` file is not allowed. Instead, use runtime config or a module.',
]) ])
patterns.push([/(^|node_modules\/)@vue\/composition-api/]) patterns.push([/(^|node_modules\/)@vue\/composition-api/])
@ -31,7 +31,7 @@ export const nuxtImportProtections = (nuxt: { options: NuxtOptions }, options: {
for (const mod of nuxt.options.modules.filter(m => typeof m === 'string')) { for (const mod of nuxt.options.modules.filter(m => typeof m === 'string')) {
patterns.push([ patterns.push([
new RegExp(`^${escapeRE(mod as string)}$`), new RegExp(`^${escapeRE(mod as string)}$`),
'Importing directly from module entry-points is not allowed.' 'Importing directly from module entry-points is not allowed.',
]) ])
} }
@ -48,7 +48,7 @@ export const nuxtImportProtections = (nuxt: { options: NuxtOptions }, options: {
if (!options.isNitro) { if (!options.isNitro) {
patterns.push([ patterns.push([
new RegExp(escapeRE(relative(nuxt.options.srcDir, resolve(nuxt.options.srcDir, nuxt.options.serverDir || 'server'))) + '\\/(api|routes|middleware|plugins)\\/'), new RegExp(escapeRE(relative(nuxt.options.srcDir, resolve(nuxt.options.srcDir, nuxt.options.serverDir || 'server'))) + '\\/(api|routes|middleware|plugins)\\/'),
'Importing from server is not allowed in the Vue part of your app.' 'Importing from server is not allowed in the Vue part of your app.',
]) ])
} }
@ -88,6 +88,6 @@ export const ImportProtectionPlugin = createUnplugin(function (options: ImportPr
return _require.resolve('unenv/runtime/mock/proxy') return _require.resolve('unenv/runtime/mock/proxy')
} }
return null return null
} },
} }
}) })

View File

@ -25,7 +25,7 @@ export const LayerAliasingPlugin = createUnplugin((options: LayerAliasingOptions
'~': layer.config?.alias?.['~'] || srcDir, '~': layer.config?.alias?.['~'] || srcDir,
'@': layer.config?.alias?.['@'] || srcDir, '@': layer.config?.alias?.['@'] || srcDir,
'~~': layer.config?.alias?.['~~'] || rootDir, '~~': layer.config?.alias?.['~~'] || rootDir,
'@@': layer.config?.alias?.['@@'] || rootDir '@@': layer.config?.alias?.['@@'] || rootDir,
} }
} }
const layers = Object.keys(aliases).sort((a, b) => b.length - a.length) const layers = Object.keys(aliases).sort((a, b) => b.length - a.length)
@ -46,8 +46,8 @@ export const LayerAliasingPlugin = createUnplugin((options: LayerAliasingOptions
if (resolvedId !== id) { if (resolvedId !== id) {
return await this.resolve(resolvedId, importer, { skipSelf: true }) return await this.resolve(resolvedId, importer, { skipSelf: true })
} }
} },
} },
}, },
// webpack-only transform // webpack-only transform
@ -69,9 +69,9 @@ export const LayerAliasingPlugin = createUnplugin((options: LayerAliasingOptions
if (s.hasChanged()) { if (s.hasChanged()) {
return { return {
code: s.toString(), code: s.toString(),
map: options.sourcemap ? s.generateMap({ hires: true }) : undefined map: options.sourcemap ? s.generateMap({ hires: true }) : undefined,
}
} }
} }
},
} }
}) })

View File

@ -11,7 +11,6 @@ import MagicString from 'magic-string'
import { normalize } from 'pathe' import { normalize } from 'pathe'
import { logger } from '@nuxt/kit' import { logger } from '@nuxt/kit'
// eslint-disable-next-line import/no-restricted-paths
import type { ObjectPlugin, PluginMeta } from '#app' import type { ObjectPlugin, PluginMeta } from '#app'
const internalOrderMap = { const internalOrderMap = {
@ -32,13 +31,13 @@ const internalOrderMap = {
// +20: post (user) <-- post mapped to this // +20: post (user) <-- post mapped to this
'user-post': 20, 'user-post': 20,
// +30: post-all (nuxt) // +30: post-all (nuxt)
'nuxt-post-all': 30 'nuxt-post-all': 30,
} }
export const orderMap: Record<NonNullable<ObjectPlugin['enforce']>, number> = { export const orderMap: Record<NonNullable<ObjectPlugin['enforce']>, number> = {
pre: internalOrderMap['user-pre'], pre: internalOrderMap['user-pre'],
default: internalOrderMap['user-default'], default: internalOrderMap['user-default'],
post: internalOrderMap['user-post'] post: internalOrderMap['user-post'],
} }
const metaCache: Record<string, Omit<PluginMeta, 'enforce'>> = {} const metaCache: Record<string, Omit<PluginMeta, 'enforce'>> = {}
@ -50,7 +49,7 @@ export async function extractMetadata (code: string, loader = 'ts' as 'ts' | 'ts
const js = await transform(code, { loader }) const js = await transform(code, { loader })
walk(parse(js.code, { walk(parse(js.code, {
sourceType: 'module', sourceType: 'module',
ecmaVersion: 'latest' ecmaVersion: 'latest',
}) as Node, { }) as Node, {
enter (_node) { enter (_node) {
if (_node.type !== 'CallExpression' || (_node as CallExpression).callee.type !== 'Identifier') { return } if (_node.type !== 'CallExpression' || (_node as CallExpression).callee.type !== 'Identifier') { return }
@ -77,7 +76,7 @@ export async function extractMetadata (code: string, loader = 'ts' as 'ts' | 'ts
meta.order = meta.order || orderMap[meta.enforce || 'default'] || orderMap.default meta.order = meta.order || orderMap[meta.enforce || 'default'] || orderMap.default
delete meta.enforce delete meta.enforce
} },
}) })
metaCache[code] = meta metaCache[code] = meta
return meta as Omit<PluginMeta, 'enforce'> return meta as Omit<PluginMeta, 'enforce'>
@ -88,7 +87,7 @@ const keys: Record<PluginMetaKey, string> = {
name: 'name', name: 'name',
order: 'order', order: 'order',
enforce: 'enforce', enforce: 'enforce',
dependsOn: 'dependsOn' dependsOn: 'dependsOn',
} }
function isMetadataKey (key: string): key is PluginMetaKey { function isMetadataKey (key: string): key is PluginMetaKey {
return key in keys return key in keys
@ -134,7 +133,7 @@ export const RemovePluginMetadataPlugin = (nuxt: Nuxt) => createUnplugin(() => {
s.overwrite(0, code.length, 'export default () => {}') s.overwrite(0, code.length, 'export default () => {}')
return { return {
code: s.toString(), code: s.toString(),
map: nuxt.options.sourcemap.client || nuxt.options.sourcemap.server ? s.generateMap({ hires: true }) : null map: nuxt.options.sourcemap.client || nuxt.options.sourcemap.server ? s.generateMap({ hires: true }) : null,
} }
} }
@ -144,7 +143,7 @@ export const RemovePluginMetadataPlugin = (nuxt: Nuxt) => createUnplugin(() => {
try { try {
walk(this.parse(code, { walk(this.parse(code, {
sourceType: 'module', sourceType: 'module',
ecmaVersion: 'latest' ecmaVersion: 'latest',
}) as Node, { }) as Node, {
enter (_node) { enter (_node) {
if (_node.type === 'ImportSpecifier' && (_node.imported.name === 'defineNuxtPlugin' || _node.imported.name === 'definePayloadPlugin')) { if (_node.type === 'ImportSpecifier' && (_node.imported.name === 'defineNuxtPlugin' || _node.imported.name === 'definePayloadPlugin')) {
@ -193,7 +192,7 @@ export const RemovePluginMetadataPlugin = (nuxt: Nuxt) => createUnplugin(() => {
} }
} }
} }
} },
}) })
} catch (e) { } catch (e) {
logger.error(e) logger.error(e)
@ -207,9 +206,9 @@ export const RemovePluginMetadataPlugin = (nuxt: Nuxt) => createUnplugin(() => {
if (s.hasChanged()) { if (s.hasChanged()) {
return { return {
code: s.toString(), code: s.toString(),
map: nuxt.options.sourcemap.client || nuxt.options.sourcemap.server ? s.generateMap({ hires: true }) : null map: nuxt.options.sourcemap.client || nuxt.options.sourcemap.server ? s.generateMap({ hires: true }) : null,
}
} }
} }
},
} }
}) })

View File

@ -21,11 +21,11 @@ export function resolveDeepImportsPlugin (nuxt: Nuxt): Plugin {
return await this.resolve?.(id, dir || pkgDir, { skipSelf: true }) ?? await resolvePath(id, { return await this.resolve?.(id, dir || pkgDir, { skipSelf: true }) ?? await resolvePath(id, {
url: [dir || pkgDir, ...nuxt.options.modulesDir], url: [dir || pkgDir, ...nuxt.options.modulesDir],
// TODO: respect nitro runtime conditions // TODO: respect nitro runtime conditions
conditions: options.ssr ? ['node', 'import', 'require'] : ['import', 'require'] conditions: options.ssr ? ['node', 'import', 'require'] : ['import', 'require'],
}).catch(() => { }).catch(() => {
logger.debug('Could not resolve id', id, importer) logger.debug('Could not resolve id', id, importer)
return null return null
}) })
} },
} }
} }

View File

@ -40,9 +40,9 @@ export const TreeShakeComposablesPlugin = createUnplugin((options: TreeShakeComp
code: s.toString(), code: s.toString(),
map: options.sourcemap map: options.sourcemap
? s.generateMap({ hires: true }) ? s.generateMap({ hires: true })
: undefined : undefined,
}
} }
} }
},
} }
}) })

View File

@ -28,9 +28,9 @@ export const UnctxTransformPlugin = createUnplugin((options: UnctxTransformPlugi
code: TRANSFORM_MARKER + result.code, code: TRANSFORM_MARKER + result.code,
map: options.sourcemap map: options.sourcemap
? result.magicString.generateMap({ hires: true }) ? result.magicString.generateMap({ hires: true })
: undefined : undefined,
}
} }
} }
},
} }
}) })

Some files were not shown because too many files have changed in this diff Show More