refactor(kit,nuxt,schema): use consola and improve test dx (#23302)

This commit is contained in:
Pooya Parsa 2023-09-19 23:26:15 +02:00 committed by GitHub
parent a661d58fc2
commit 2bf9028f7e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
60 changed files with 215 additions and 86 deletions

View File

@ -26,7 +26,7 @@
], ],
"no-only-tests/no-only-tests": "error", "no-only-tests/no-only-tests": "error",
"unicorn/prefer-node-protocol": "error", "unicorn/prefer-node-protocol": "error",
"no-console": "off", "no-console": "warn",
"vue/multi-word-component-names": "off", "vue/multi-word-component-names": "off",
"vue/one-component-per-file": "off", "vue/one-component-per-file": "off",
"vue/require-default-prop": "off", "vue/require-default-prop": "off",
@ -120,6 +120,12 @@
} }
] ]
} }
},
{
"files": ["packages/nuxt/src/app/**", "test/**", "**/runtime/**"],
"rules": {
"no-console": "off"
}
} }
], ],
"settings": { "settings": {

View File

@ -2,6 +2,7 @@ import { kebabCase, pascalCase } from 'scule'
import type { Component, ComponentsDir } from '@nuxt/schema' import type { Component, ComponentsDir } from '@nuxt/schema'
import { useNuxt } from './context' import { useNuxt } from './context'
import { assertNuxtCompatibility } from './compatibility' import { assertNuxtCompatibility } from './compatibility'
import { logger } from './logger'
/** /**
* Register a directory to be scanned for components and imported only when used. * Register a directory to be scanned for components and imported only when used.
@ -57,7 +58,7 @@ export async function addComponent (opts: AddComponentOptions) {
// but we warn if they are equal. // but we warn if they are equal.
if (newPriority === existingPriority) { if (newPriority === existingPriority) {
const name = existingComponent.pascalName || existingComponent.kebabName const name = existingComponent.pascalName || existingComponent.kebabName
console.warn(`Overriding ${name} component. You can specify a \`priority\` option when calling \`addComponent\` to avoid this warning.`) logger.warn(`Overriding ${name} component. You can specify a \`priority\` option when calling \`addComponent\` to avoid this warning.`)
} }
Object.assign(existingComponent, component) Object.assign(existingComponent, component)
} else { } else {

View File

@ -4,6 +4,7 @@ import { template as lodashTemplate } from 'lodash-es'
import { genDynamicImport, genImport, genSafeVariableName } from 'knitwork' import { genDynamicImport, genImport, genSafeVariableName } from 'knitwork'
import type { NuxtTemplate } from '@nuxt/schema' import type { NuxtTemplate } from '@nuxt/schema'
import { logger } from '../logger'
/** @deprecated */ /** @deprecated */
// TODO: Remove support for compiling ejs templates in v4 // TODO: Remove support for compiling ejs templates in v4
@ -14,7 +15,7 @@ export async function compileTemplate (template: NuxtTemplate, ctx: any) {
const srcContents = await fsp.readFile(template.src, 'utf-8') const srcContents = await fsp.readFile(template.src, 'utf-8')
return lodashTemplate(srcContents, {})(data) return lodashTemplate(srcContents, {})(data)
} catch (err) { } catch (err) {
console.error('Error compiling template: ', template) logger.error('Error compiling template: ', template)
throw err throw err
} }
} }

View File

@ -7,6 +7,7 @@ import { useNuxt } from '../context'
import { requireModule } from '../internal/cjs' import { requireModule } from '../internal/cjs'
import { importModule } from '../internal/esm' import { importModule } from '../internal/esm'
import { resolveAlias, resolvePath } from '../resolve' import { resolveAlias, resolvePath } from '../resolve'
import { logger } from '../logger'
/** Installs a module on a Nuxt instance. */ /** Installs a module on a Nuxt instance. */
export async function installModule (moduleToInstall: string | NuxtModule, inlineOptions?: any, nuxt: Nuxt = useNuxt()) { export async function installModule (moduleToInstall: string | NuxtModule, inlineOptions?: any, nuxt: Nuxt = useNuxt()) {
@ -65,7 +66,7 @@ export async function loadNuxtModuleInstance (nuxtModule: string | NuxtModule, n
// Prefer ESM resolution if possible // Prefer ESM resolution if possible
nuxtModule = await importModule(src, nuxt.options.modulesDir).catch(() => null) ?? requireModule(src, { paths: nuxt.options.modulesDir }) nuxtModule = await importModule(src, nuxt.options.modulesDir).catch(() => null) ?? requireModule(src, { paths: nuxt.options.modulesDir })
} catch (error: unknown) { } catch (error: unknown) {
console.error(`Error while requiring module \`${nuxtModule}\`: ${error}`) logger.error(`Error while requiring module \`${nuxtModule}\`: ${error}`)
throw error throw error
} }
// nuxt-module-builder generates a module.json with metadata including the version // nuxt-module-builder generates a module.json with metadata including the version

View File

@ -3,6 +3,7 @@ import type { NitroRouteConfig } from 'nitropack'
import { defu } from 'defu' import { defu } from 'defu'
import { useNuxt } from './context' import { useNuxt } from './context'
import { isNuxt2 } from './compatibility' import { isNuxt2 } from './compatibility'
import { logger } from './logger'
export function extendPages (cb: NuxtHooks['pages:extend']) { export function extendPages (cb: NuxtHooks['pages:extend']) {
const nuxt = useNuxt() const nuxt = useNuxt()
@ -54,7 +55,7 @@ export function addRouteMiddleware (input: NuxtMiddleware | NuxtMiddleware[], op
if (options.override === true) { if (options.override === true) {
app.middleware[find] = middleware app.middleware[find] = middleware
} else { } else {
console.warn(`'${middleware.name}' middleware already exists at '${app.middleware[find].path}'. You can set \`override: true\` to replace it.`) logger.warn(`'${middleware.name}' middleware already exists at '${app.middleware[find].path}'. You can set \`override: true\` to replace it.`)
} }
} else { } else {
app.middleware.push(middleware) app.middleware.push(middleware)

View File

@ -3,6 +3,7 @@ import type { NuxtPlugin, NuxtPluginTemplate } from '@nuxt/schema'
import { useNuxt } from './context' import { useNuxt } from './context'
import { addTemplate } from './template' import { addTemplate } from './template'
import { resolveAlias } from './resolve' import { resolveAlias } from './resolve'
import { logger } from './logger'
/** /**
* Normalize a nuxt plugin object * Normalize a nuxt plugin object
@ -22,7 +23,7 @@ export function normalizePlugin (plugin: NuxtPlugin | string): NuxtPlugin {
// TODO: only scan top-level files #18418 // TODO: only scan top-level files #18418
const nonTopLevelPlugin = plugin.src.match(/\/plugins\/[^/]+\/index\.[^/]+$/i) const nonTopLevelPlugin = plugin.src.match(/\/plugins\/[^/]+\/index\.[^/]+$/i)
if (nonTopLevelPlugin && nonTopLevelPlugin.length > 0 && !useNuxt().options.plugins.find(i => (typeof i === 'string' ? i : i.src).endsWith(nonTopLevelPlugin[0]))) { if (nonTopLevelPlugin && nonTopLevelPlugin.length > 0 && !useNuxt().options.plugins.find(i => (typeof i === 'string' ? i : i.src).endsWith(nonTopLevelPlugin[0]))) {
console.warn(`[warn] [nuxt] [deprecation] You are using a plugin that is within a subfolder of your plugins directory without adding it to your config explicitly. You can move it to the top-level plugins directory, or include the file '~${nonTopLevelPlugin[0]}' in your plugins config (https://nuxt.com/docs/api/configuration/nuxt-config#plugins-1) to remove this warning.`) logger.warn(`[deprecation] You are using a plugin that is within a subfolder of your plugins directory without adding it to your config explicitly. You can move it to the top-level plugins directory, or include the file '~${nonTopLevelPlugin[0]}' in your plugins config (https://nuxt.com/docs/api/configuration/nuxt-config#plugins-1) to remove this warning.`)
} }
// Normalize full path to plugin // Normalize full path to plugin

View File

@ -5,6 +5,7 @@ import { pascalCase } from 'scule'
import { resolve } from 'pathe' import { resolve } from 'pathe'
import type { Component, ComponentsOptions } from 'nuxt/schema' import type { Component, ComponentsOptions } from 'nuxt/schema'
import { logger } from '@nuxt/kit'
import { distDir } from '../dirs' import { distDir } from '../dirs'
import { isVue } from '../core/utils' import { isVue } from '../core/utils'
@ -54,7 +55,7 @@ export const loaderPlugin = createUnplugin((options: LoaderOptions) => {
imports.add(genImport(serverComponentRuntime, [{ name: 'createServerComponent' }])) imports.add(genImport(serverComponentRuntime, [{ name: 'createServerComponent' }]))
imports.add(`const ${identifier} = createServerComponent(${JSON.stringify(name)})`) imports.add(`const ${identifier} = createServerComponent(${JSON.stringify(name)})`)
if (!options.experimentalComponentIslands) { if (!options.experimentalComponentIslands) {
console.warn(`Standalone server components (\`${name}\`) are not yet supported without enabling \`experimental.componentIslands\`.`) logger.warn(`Standalone server components (\`${name}\`) are not yet supported without enabling \`experimental.componentIslands\`.`)
} }
return identifier return identifier
} }

View File

@ -1,6 +1,6 @@
import { statSync } from 'node:fs' import { statSync } from 'node:fs'
import { normalize, relative, resolve } from 'pathe' import { normalize, relative, resolve } from 'pathe'
import { addPluginTemplate, addTemplate, addVitePlugin, addWebpackPlugin, defineNuxtModule, resolveAlias, updateTemplates } from '@nuxt/kit' import { addPluginTemplate, addTemplate, addVitePlugin, addWebpackPlugin, defineNuxtModule, logger, resolveAlias, updateTemplates } from '@nuxt/kit'
import type { Component, ComponentsDir, ComponentsOptions } from 'nuxt/schema' import type { Component, ComponentsDir, ComponentsOptions } from 'nuxt/schema'
import { distDir } from '../dirs' import { distDir } from '../dirs'
@ -86,7 +86,7 @@ export default defineNuxtModule<ComponentsOptions>({
const present = isDirectory(dirPath) const present = isDirectory(dirPath)
if (!present && !DEFAULT_COMPONENTS_DIRS_RE.test(dirOptions.path)) { if (!present && !DEFAULT_COMPONENTS_DIRS_RE.test(dirOptions.path)) {
console.warn('Components directory not found: `' + dirPath + '`') logger.warn('Components directory not found: `' + dirPath + '`')
} }
return { return {
@ -156,7 +156,7 @@ export default defineNuxtModule<ComponentsOptions>({
const path = resolve(nuxt.options.srcDir, relativePath) const path = resolve(nuxt.options.srcDir, relativePath)
if (componentDirs.some(dir => dir.path === path)) { if (componentDirs.some(dir => dir.path === path)) {
console.info(`Directory \`${relativePath}/\` ${event === 'addDir' ? 'created' : 'removed'}`) logger.info(`Directory \`${relativePath}/\` ${event === 'addDir' ? 'created' : 'removed'}`)
return nuxt.callHook('restart') return nuxt.callHook('restart')
} }
}) })

View File

@ -2,7 +2,7 @@ import { readdir } from 'node:fs/promises'
import { basename, dirname, extname, join, relative } from 'pathe' import { basename, dirname, extname, join, relative } from 'pathe'
import { globby } from 'globby' import { globby } from 'globby'
import { pascalCase, splitByCase } from 'scule' import { pascalCase, splitByCase } from 'scule'
import { isIgnored, useNuxt } from '@nuxt/kit' import { isIgnored, logger, useNuxt } from '@nuxt/kit'
// eslint-disable-next-line vue/prefer-import-from-vue // eslint-disable-next-line vue/prefer-import-from-vue
import { hyphenate } from '@vue/shared' import { hyphenate } from '@vue/shared'
import { withTrailingSlash } from 'ufo' import { withTrailingSlash } from 'ufo'
@ -44,7 +44,7 @@ export async function scanComponents (dirs: ComponentsDir[], srcDir: string): Pr
const nuxt = useNuxt() const nuxt = useNuxt()
const original = relative(nuxt.options.srcDir, dir.path) const original = relative(nuxt.options.srcDir, dir.path)
const corrected = relative(nuxt.options.srcDir, join(dirname(dir.path), caseCorrected)) const corrected = relative(nuxt.options.srcDir, join(dirname(dir.path), caseCorrected))
console.warn(`[nuxt] Components not scanned from \`~/${corrected}\`. Did you mean to name the directory \`~/${original}\` instead?`) logger.warn(`Components not scanned from \`~/${corrected}\`. Did you mean to name the directory \`~/${original}\` instead?`)
continue continue
} }
} }
@ -130,7 +130,7 @@ export async function scanComponents (dirs: ComponentsDir[], srcDir: string): Pr
// Ignore files like `~/components/index.vue` which end up not having a name at all // Ignore files like `~/components/index.vue` which end up not having a name at all
if (!componentName) { if (!componentName) {
console.warn(`[nuxt] Component did not resolve to a file name in \`~/${relative(srcDir, filePath)}\`.`) logger.warn(`Component did not resolve to a file name in \`~/${relative(srcDir, filePath)}\`.`)
continue continue
} }
@ -189,7 +189,7 @@ export function resolveComponentName (fileName: string, prefixParts: string[]) {
} }
function warnAboutDuplicateComponent (componentName: string, filePath: string, duplicatePath: string) { function warnAboutDuplicateComponent (componentName: string, filePath: string, duplicatePath: string) {
console.warn(`[nuxt] 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

@ -1,7 +1,7 @@
import { promises as fsp, mkdirSync, writeFileSync } from 'node:fs' import { promises as fsp, mkdirSync, writeFileSync } from 'node:fs'
import { dirname, join, resolve } from 'pathe' import { dirname, join, resolve } from 'pathe'
import { defu } from 'defu' import { defu } from 'defu'
import { compileTemplate, findPath, normalizePlugin, normalizeTemplate, resolveAlias, resolveFiles, resolvePath, templateUtils, tryResolveModule } from '@nuxt/kit' import { compileTemplate, findPath, logger, normalizePlugin, normalizeTemplate, resolveAlias, resolveFiles, resolvePath, templateUtils, tryResolveModule } from '@nuxt/kit'
import type { Nuxt, NuxtApp, NuxtPlugin, NuxtTemplate, ResolvedNuxtTemplate } from 'nuxt/schema' import type { Nuxt, NuxtApp, NuxtPlugin, NuxtTemplate, ResolvedNuxtTemplate } from 'nuxt/schema'
import * as defaultTemplates from './templates' import * as defaultTemplates from './templates'
@ -43,7 +43,7 @@ export async function generateApp (nuxt: Nuxt, app: NuxtApp, options: { filter?:
const fullPath = template.dst || resolve(nuxt.options.buildDir, template.filename!) const fullPath = template.dst || resolve(nuxt.options.buildDir, template.filename!)
const mark = performance.mark(fullPath) const mark = performance.mark(fullPath)
const contents = await compileTemplate(template, templateContext).catch((e) => { const contents = await compileTemplate(template, templateContext).catch((e) => {
console.error(`[nuxt] Could not compile template \`${template.filename}\`.`) logger.error(`Could not compile template \`${template.filename}\`.`)
throw e throw e
}) })
@ -61,7 +61,7 @@ export async function generateApp (nuxt: Nuxt, app: NuxtApp, options: { filter?:
const setupTime = perf ? Math.round((perf.duration * 100)) / 100 : 0 // TODO: remove when Node 14 reaches EOL const setupTime = perf ? Math.round((perf.duration * 100)) / 100 : 0 // TODO: remove when Node 14 reaches EOL
if (nuxt.options.debug || setupTime > 500) { if (nuxt.options.debug || setupTime > 500) {
console.info(`[nuxt] compiled \`${template.filename}\` in ${setupTime}ms`) logger.info(`Compiled \`${template.filename}\` in ${setupTime}ms`)
} }
if (template.write) { if (template.write) {
@ -191,7 +191,7 @@ export async function annotatePlugins (nuxt: Nuxt, plugins: NuxtPlugin[]) {
...plugin ...plugin
}) })
} catch (e) { } catch (e) {
console.warn(`[nuxt] Could not resolve \`${plugin.src}\`.`) logger.warn(`Could not resolve \`${plugin.src}\`.`)
_plugins.push(plugin) _plugins.push(plugin)
} }
} }

View File

@ -2,7 +2,7 @@ import { pathToFileURL } from 'node:url'
import type { EventType } from '@parcel/watcher' import type { EventType } from '@parcel/watcher'
import type { FSWatcher } from 'chokidar' import type { FSWatcher } from 'chokidar'
import chokidar from 'chokidar' import chokidar from 'chokidar'
import { isIgnored, tryResolveModule, useNuxt } from '@nuxt/kit' import { isIgnored, logger, tryResolveModule, useNuxt } from '@nuxt/kit'
import { interopDefault } from 'mlly' import { interopDefault } from 'mlly'
import { debounce } from 'perfect-debounce' import { debounce } from 'perfect-debounce'
import { normalize, relative, resolve } from 'pathe' import { normalize, relative, resolve } from 'pathe'
@ -93,6 +93,7 @@ function createGranularWatcher () {
const nuxt = useNuxt() const nuxt = useNuxt()
if (nuxt.options.debug) { if (nuxt.options.debug) {
// eslint-disable-next-line no-console
console.time('[nuxt] builder:chokidar:watch') console.time('[nuxt] builder:chokidar:watch')
} }
@ -131,6 +132,7 @@ function createGranularWatcher () {
watcher.on('ready', () => { watcher.on('ready', () => {
pending-- pending--
if (nuxt.options.debug && !pending) { if (nuxt.options.debug && !pending) {
// eslint-disable-next-line no-console
console.timeEnd('[nuxt] builder:chokidar:watch') console.timeEnd('[nuxt] builder:chokidar:watch')
} }
}) })
@ -140,6 +142,7 @@ function createGranularWatcher () {
async function createParcelWatcher () { async function createParcelWatcher () {
const nuxt = useNuxt() const nuxt = useNuxt()
if (nuxt.options.debug) { if (nuxt.options.debug) {
// eslint-disable-next-line no-console
console.time('[nuxt] builder:parcel:watch') console.time('[nuxt] builder:parcel:watch')
} }
const watcherPath = await tryResolveModule('@parcel/watcher', [nuxt.options.rootDir, ...nuxt.options.modulesDir]) const watcherPath = await tryResolveModule('@parcel/watcher', [nuxt.options.rootDir, ...nuxt.options.modulesDir])
@ -162,6 +165,7 @@ async function createParcelWatcher () {
}) })
watcher.then((subscription) => { watcher.then((subscription) => {
if (nuxt.options.debug) { if (nuxt.options.debug) {
// eslint-disable-next-line no-console
console.timeEnd('[nuxt] builder:parcel:watch') console.timeEnd('[nuxt] builder:parcel:watch')
} }
nuxt.hook('close', () => subscription.unsubscribe()) nuxt.hook('close', () => subscription.unsubscribe())
@ -169,7 +173,7 @@ async function createParcelWatcher () {
} }
return true return true
} }
console.warn('[nuxt] falling back to `chokidar-granular` as `@parcel/watcher` cannot be resolved in your project.') logger.warn('Falling back to `chokidar-granular` as `@parcel/watcher` cannot be resolved in your project.')
return false return false
} }

View File

@ -1,4 +1,4 @@
import { findPath } from '@nuxt/kit' import { findPath, logger } from '@nuxt/kit'
import { basename } from 'pathe' import { basename } from 'pathe'
import { generateApp as _generateApp } from './app' import { generateApp as _generateApp } from './app'
@ -18,11 +18,11 @@ export async function checkForExternalConfigurationFiles () {
const foundOneExternalConfig = warningMessages.length === 1 const foundOneExternalConfig = warningMessages.length === 1
if (foundOneExternalConfig) { if (foundOneExternalConfig) {
console.warn(warningMessages[0]) logger.warn(warningMessages[0])
} else { } else {
const warningsAsList = warningMessages.map(message => `- ${message}`).join('\n') const warningsAsList = warningMessages.map(message => `- ${message}`).join('\n')
const warning = `Found multiple external configuration files: \n\n${warningsAsList}` const warning = `Found multiple external configuration files: \n\n${warningsAsList}`
console.warn(warning) logger.warn(warning)
} }
} }

View File

@ -421,7 +421,7 @@ function spaLoadingTemplate (nuxt: Nuxt) {
} }
if (nuxt.options.spaLoadingTemplate) { if (nuxt.options.spaLoadingTemplate) {
console.warn(`[nuxt] Could not load custom \`spaLoadingTemplate\` path as it does not exist: \`${nuxt.options.spaLoadingTemplate}\`.`) logger.warn(`Could not load custom \`spaLoadingTemplate\` path as it does not exist: \`${nuxt.options.spaLoadingTemplate}\`.`)
} }
return '' return ''

View File

@ -389,7 +389,7 @@ async function initNuxt (nuxt: Nuxt) {
// Core Nuxt files: app.vue, error.vue and app.config.ts // Core Nuxt files: app.vue, error.vue and app.config.ts
const isFileChange = ['add', 'unlink'].includes(event) const isFileChange = ['add', 'unlink'].includes(event)
if (isFileChange && RESTART_RE.test(path)) { if (isFileChange && RESTART_RE.test(path)) {
console.info(`\`${path}\` ${event === 'add' ? 'created' : 'removed'}`) logger.info(`\`${path}\` ${event === 'add' ? 'created' : 'removed'}`)
return nuxt.callHook('restart') return nuxt.callHook('restart')
} }
}) })
@ -406,7 +406,7 @@ async function initNuxt (nuxt: Nuxt) {
// Add prerender payload support // Add prerender payload support
const nitro = useNitro() const nitro = useNitro()
if (nitro.options.static && nuxt.options.experimental.payloadExtraction === undefined) { if (nitro.options.static && nuxt.options.experimental.payloadExtraction === undefined) {
console.warn('Using experimental payload extraction for full-static output. You can opt-out by setting `experimental.payloadExtraction` to `false`.') logger.warn('Using experimental payload extraction for full-static output. You can opt-out by setting `experimental.payloadExtraction` to `false`.')
nuxt.options.experimental.payloadExtraction = true nuxt.options.experimental.payloadExtraction = true
} }
nitro.options.replace['process.env.NUXT_PAYLOAD_EXTRACTION'] = String(!!nuxt.options.experimental.payloadExtraction) nitro.options.replace['process.env.NUXT_PAYLOAD_EXTRACTION'] = String(!!nuxt.options.experimental.payloadExtraction)

View File

@ -9,6 +9,7 @@ import type { Nuxt } from '@nuxt/schema'
import { createUnplugin } from 'unplugin' import { createUnplugin } from 'unplugin'
import MagicString from 'magic-string' import MagicString from 'magic-string'
import { normalize } from 'pathe' import { normalize } from 'pathe'
import { logger } from '@nuxt/kit'
// eslint-disable-next-line import/no-restricted-paths // eslint-disable-next-line import/no-restricted-paths
import type { ObjectPlugin, PluginMeta } from '#app' import type { ObjectPlugin, PluginMeta } from '#app'
@ -122,7 +123,7 @@ export const RemovePluginMetadataPlugin = (nuxt: Nuxt) => createUnplugin(() => {
const exports = findExports(code) const exports = findExports(code)
const defaultExport = exports.find(e => e.type === 'default' || e.name === 'default') const defaultExport = exports.find(e => e.type === 'default' || e.name === 'default')
if (!defaultExport) { if (!defaultExport) {
console.error(`[warn] [nuxt] Plugin \`${plugin.src}\` has no default export and will be ignored at build time. Add \`export default defineNuxtPlugin(() => {})\` to your plugin.`) logger.warn(`Plugin \`${plugin.src}\` has no default export and will be ignored at build time. Add \`export default defineNuxtPlugin(() => {})\` to your plugin.`)
s.overwrite(0, code.length, 'export default () => {}') s.overwrite(0, code.length, 'export default () => {}')
return { return {
code: s.toString(), code: s.toString(),
@ -140,7 +141,7 @@ export const RemovePluginMetadataPlugin = (nuxt: Nuxt) => createUnplugin(() => {
enter (_node) { enter (_node) {
if (_node.type === 'ExportDefaultDeclaration' && (_node.declaration.type === 'FunctionDeclaration' || _node.declaration.type === 'ArrowFunctionExpression')) { if (_node.type === 'ExportDefaultDeclaration' && (_node.declaration.type === 'FunctionDeclaration' || _node.declaration.type === 'ArrowFunctionExpression')) {
if ('params' in _node.declaration && _node.declaration.params.length > 1) { if ('params' in _node.declaration && _node.declaration.params.length > 1) {
console.warn(`[warn] [nuxt] Plugin \`${plugin.src}\` is in legacy Nuxt 2 format (context, inject) which is likely to be broken and will be ignored.`) logger.warn(`Plugin \`${plugin.src}\` is in legacy Nuxt 2 format (context, inject) which is likely to be broken and will be ignored.`)
s.overwrite(0, code.length, 'export default () => {}') s.overwrite(0, code.length, 'export default () => {}')
wrapped = true // silence a duplicate error wrapped = true // silence a duplicate error
return return
@ -155,7 +156,7 @@ export const RemovePluginMetadataPlugin = (nuxt: Nuxt) => createUnplugin(() => {
if (node.arguments[0].type !== 'ObjectExpression') { if (node.arguments[0].type !== 'ObjectExpression') {
// TODO: Warn if legacy plugin format is detected // TODO: Warn if legacy plugin format is detected
if ('params' in node.arguments[0] && node.arguments[0].params.length > 1) { if ('params' in node.arguments[0] && node.arguments[0].params.length > 1) {
console.warn(`[warn] [nuxt] Plugin \`${plugin.src}\` is in legacy Nuxt 2 format (context, inject) which is likely to be broken and will be ignored.`) logger.warn(`Plugin \`${plugin.src}\` is in legacy Nuxt 2 format (context, inject) which is likely to be broken and will be ignored.`)
s.overwrite(0, code.length, 'export default () => {}') s.overwrite(0, code.length, 'export default () => {}')
return return
} }
@ -184,12 +185,12 @@ export const RemovePluginMetadataPlugin = (nuxt: Nuxt) => createUnplugin(() => {
} }
}) })
} catch (e) { } catch (e) {
console.error(e) logger.error(e)
return return
} }
if (!wrapped) { if (!wrapped) {
console.warn(`[warn] [nuxt] Plugin \`${plugin.src}\` is not wrapped in \`defineNuxtPlugin\`. It is advised to wrap your plugins as in the future this may enable enhancements.`) logger.warn(`Plugin \`${plugin.src}\` is not wrapped in \`defineNuxtPlugin\`. It is advised to wrap your plugins as in the future this may enable enhancements.`)
} }
if (s.hasChanged()) { if (s.hasChanged()) {

View File

@ -1,7 +1,7 @@
import { parseNodeModulePath, resolvePath } from 'mlly' import { parseNodeModulePath, resolvePath } from 'mlly'
import { isAbsolute, normalize } from 'pathe' import { isAbsolute, normalize } from 'pathe'
import type { Plugin } from 'vite' import type { Plugin } from 'vite'
import { resolveAlias } from '@nuxt/kit' import { logger, resolveAlias } from '@nuxt/kit'
import type { Nuxt } from '@nuxt/schema' import type { Nuxt } from '@nuxt/schema'
import { pkgDir } from '../../dirs' import { pkgDir } from '../../dirs'
@ -23,7 +23,7 @@ export function resolveDeepImportsPlugin (nuxt: Nuxt): Plugin {
// 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(() => {
console.log('[nuxt] Could not resolve id', id, importer) logger.log('Could not resolve id', id, importer)
return null return null
}) })
} }

View File

@ -6,7 +6,7 @@ import chokidar from 'chokidar'
import { interopDefault } from 'mlly' import { interopDefault } from 'mlly'
import { defu } from 'defu' import { defu } from 'defu'
import { debounce } from 'perfect-debounce' import { debounce } from 'perfect-debounce'
import { createResolver, defineNuxtModule, tryResolveModule } from '@nuxt/kit' import { createResolver, defineNuxtModule, logger, tryResolveModule } from '@nuxt/kit'
import { import {
generateTypes, generateTypes,
resolveSchema as resolveUntypedSchema resolveSchema as resolveUntypedSchema
@ -76,7 +76,7 @@ export default defineNuxtModule({
} }
return return
} }
console.warn('[nuxt] falling back to `chokidar-granular` as `@parcel/watcher` cannot be resolved in your project.') logger.warn('Falling back to `chokidar-granular` as `@parcel/watcher` cannot be resolved in your project.')
} }
const filesToWatch = await Promise.all(nuxt.options._layers.map(layer => const filesToWatch = await Promise.all(nuxt.options._layers.map(layer =>
@ -106,8 +106,8 @@ export default defineNuxtModule({
try { try {
loadedConfig = _resolveSchema(filePath) loadedConfig = _resolveSchema(filePath)
} catch (err) { } catch (err) {
console.warn( logger.warn(
'[nuxt-config-schema] Unable to load schema from', 'Unable to load schema from',
filePath, filePath,
err err
) )

View File

@ -1,4 +1,4 @@
import { addTemplate, addVitePlugin, addWebpackPlugin, defineNuxtModule, isIgnored, resolveAlias, tryResolveModule, updateTemplates, useNuxt } from '@nuxt/kit' import { addTemplate, addVitePlugin, addWebpackPlugin, defineNuxtModule, isIgnored, logger, resolveAlias, tryResolveModule, updateTemplates, useNuxt } from '@nuxt/kit'
import { isAbsolute, join, normalize, relative, resolve } from 'pathe' import { isAbsolute, join, normalize, relative, resolve } from 'pathe'
import type { Import, Unimport } from 'unimport' import type { Import, Unimport } from 'unimport'
import { createUnimport, scanDirExports } from 'unimport' import { createUnimport, scanDirExports } from 'unimport'
@ -69,7 +69,7 @@ export default defineNuxtModule<Partial<ImportsOptions>>({
const path = resolve(nuxt.options.srcDir, relativePath) const path = resolve(nuxt.options.srcDir, relativePath)
if (composablesDirs.includes(path)) { if (composablesDirs.includes(path)) {
console.info(`Directory \`${relativePath}/\` ${event === 'addDir' ? 'created' : 'removed'}`) logger.info(`Directory \`${relativePath}/\` ${event === 'addDir' ? 'created' : 'removed'}`)
return nuxt.callHook('restart') return nuxt.callHook('restart')
} }
}) })

View File

@ -1,6 +1,6 @@
import { existsSync, readdirSync } from 'node:fs' import { existsSync, readdirSync } from 'node:fs'
import { mkdir, readFile } from 'node:fs/promises' import { mkdir, readFile } from 'node:fs/promises'
import { addBuildPlugin, addComponent, addPlugin, addTemplate, addVitePlugin, addWebpackPlugin, defineNuxtModule, findPath, updateTemplates } from '@nuxt/kit' import { addBuildPlugin, addComponent, addPlugin, addTemplate, addVitePlugin, addWebpackPlugin, defineNuxtModule, findPath, logger, updateTemplates } from '@nuxt/kit'
import { dirname, join, relative, resolve } from 'pathe' import { dirname, join, relative, resolve } from 'pathe'
import { genImport, genObjectFromRawEntries, genString } from 'knitwork' import { genImport, genObjectFromRawEntries, genString } from 'knitwork'
import { joinURL } from 'ufo' import { joinURL } from 'ufo'
@ -67,7 +67,7 @@ export default defineNuxtModule({
if (restartPaths.some(p => p === path || path.startsWith(p + '/'))) { if (restartPaths.some(p => p === path || path.startsWith(p + '/'))) {
const newSetting = await isPagesEnabled() const newSetting = await isPagesEnabled()
if (nuxt.options.pages !== newSetting) { if (nuxt.options.pages !== newSetting) {
console.info('Pages', newSetting ? 'enabled' : 'disabled') logger.info('Pages', newSetting ? 'enabled' : 'disabled')
return nuxt.callHook('restart') return nuxt.callHook('restart')
} }
} }
@ -275,7 +275,7 @@ export default defineNuxtModule({
if (extractedRule) { if (extractedRule) {
if (!glob) { if (!glob) {
const relativePath = relative(nuxt.options.srcDir, path) const relativePath = relative(nuxt.options.srcDir, path)
console.error(`[nuxt] Could not set inline route rules in \`~/${relativePath}\` as it could not be mapped to a Nitro route.`) logger.error(`Could not set inline route rules in \`~/${relativePath}\` as it could not be mapped to a Nitro route.`)
return return
} }
@ -286,9 +286,9 @@ export default defineNuxtModule({
} catch (e: any) { } catch (e: any) {
if (e.toString().includes('Error parsing route rules')) { if (e.toString().includes('Error parsing route rules')) {
const relativePath = relative(nuxt.options.srcDir, path) const relativePath = relative(nuxt.options.srcDir, path)
console.error(`[nuxt] Error parsing route rules within \`~/${relativePath}\`. They should be JSON-serializable.`) logger.error(`Error parsing route rules within \`~/${relativePath}\`. They should be JSON-serializable.`)
} else { } else {
console.error(e) logger.error(e)
} }
} }
} }

View File

@ -8,6 +8,7 @@ import type { Node } from 'estree-walker'
import { walk } from 'estree-walker' import { walk } from 'estree-walker'
import MagicString from 'magic-string' import MagicString from 'magic-string'
import { isAbsolute } from 'pathe' import { isAbsolute } from 'pathe'
import { logger } from '@nuxt/kit'
export interface PageMetaPluginOptions { export interface PageMetaPluginOptions {
dev?: boolean dev?: boolean
@ -90,7 +91,7 @@ export const PageMetaPlugin = createUnplugin((options: PageMetaPluginOptions) =>
if (!code) { if (!code) {
s.append(CODE_EMPTY + (options.dev ? CODE_HMR : '')) s.append(CODE_EMPTY + (options.dev ? CODE_HMR : ''))
const { pathname } = parseURL(decodeURIComponent(pathToFileURL(id).href)) const { pathname } = parseURL(decodeURIComponent(pathToFileURL(id).href))
console.error(`The file \`${pathname}\` is not a valid page as it has no content.`) logger.error(`The file \`${pathname}\` is not a valid page as it has no content.`)
} else { } else {
s.overwrite(0, code.length, CODE_EMPTY + (options.dev ? CODE_HMR : '')) s.overwrite(0, code.length, CODE_EMPTY + (options.dev ? CODE_HMR : ''))
} }

View File

@ -44,12 +44,13 @@ declare module 'vue-router' {
interface RouteMeta extends UnwrapRef<PageMeta> {} interface RouteMeta extends UnwrapRef<PageMeta> {}
} }
const warnRuntimeUsage = (method: string) => const warnRuntimeUsage = (method: string) => {
console.warn( console.warn(
`${method}() is a compiler-hint helper that is only usable inside ` + `${method}() is a compiler-hint helper that is only usable inside ` +
'the script block of a single file component which is also a page. Its arguments should be ' + 'the script block of a single file component which is also a page. Its arguments should be ' +
'compiled away and passing it at runtime has no effect.' 'compiled away and passing it at runtime has no effect.'
) )
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars // eslint-disable-next-line @typescript-eslint/no-unused-vars
export const definePageMeta = (meta: PageMeta): void => { export const definePageMeta = (meta: PageMeta): void => {

View File

@ -1,7 +1,7 @@
import fs from 'node:fs' import fs from 'node:fs'
import { extname, normalize, relative, resolve } from 'pathe' import { extname, normalize, relative, resolve } from 'pathe'
import { encodePath } from 'ufo' import { encodePath } from 'ufo'
import { resolveFiles, useNuxt } from '@nuxt/kit' import { logger, resolveFiles, useNuxt } from '@nuxt/kit'
import { genArrayFromRaw, genDynamicImport, genImport, genSafeVariableName } from 'knitwork' import { genArrayFromRaw, genDynamicImport, genImport, genSafeVariableName } from 'knitwork'
import escapeRE from 'escape-string-regexp' import escapeRE from 'escape-string-regexp'
import { filename } from 'pathe/utils' import { filename } from 'pathe/utils'
@ -273,7 +273,7 @@ function prepareRoutes (routes: NuxtPage[], parent?: NuxtPage, names = new Set<s
if (names.has(route.name)) { if (names.has(route.name)) {
const existingRoute = findRouteByName(route.name, routes) const existingRoute = findRouteByName(route.name, routes)
const extra = existingRoute?.name ? `is the same as \`${existingRoute.file}\`` : 'is a duplicate' const extra = existingRoute?.name ? `is the same as \`${existingRoute.file}\`` : 'is a duplicate'
console.warn(`[nuxt] Route name generated for \`${route.file}\` ${extra}. You may wish to set a custom name using \`definePageMeta\` within the page file.`) logger.warn(`Route name generated for \`${route.file}\` ${extra}. You may wish to set a custom name using \`definePageMeta\` within the page file.`)
} }
} }

View File

@ -73,7 +73,8 @@ describe('imports:nuxt', () => {
} }
} catch (e) { } catch (e) {
it('should import composables', () => { it('should import composables', () => {
console.log(e) // eslint-disable-next-line no-console
console.error(e)
expect(false).toBe(true) expect(false).toBe(true)
}) })
} }

View File

@ -107,7 +107,10 @@ const { woooooo, What = isThis } = defineAsyncComponent(async () => {
return {} return {}
}) })
console.log(woooooo) if (import.meta.client) {
// eslint-disable-next-line no-console
console.log(woooooo)
}
const { Deep, assignment: { Pattern = ofComponent } } = defineAsyncComponent(async () => { const { Deep, assignment: { Pattern = ofComponent } } = defineAsyncComponent(async () => {
if (import.meta.client) { if (import.meta.client) {
@ -133,7 +136,10 @@ const [Please, { Dont, Doo }, That] = defineAsyncComponent(async () => {
return {} return {}
}) })
console.log(DontRemoveThisSinceItIsUsedInSetup.props) if (import.meta.client) {
// eslint-disable-next-line no-console
console.log(DontRemoveThisSinceItIsUsedInSetup.props)
}
</script> </script>
<style scoped> <style scoped>

View File

@ -52,6 +52,7 @@
}, },
"dependencies": { "dependencies": {
"@nuxt/ui-templates": "^1.3.1", "@nuxt/ui-templates": "^1.3.1",
"consola": "^3.2.3",
"defu": "^6.1.2", "defu": "^6.1.2",
"hookable": "^5.5.3", "hookable": "^5.5.3",
"pathe": "^1.1.1", "pathe": "^1.1.1",

View File

@ -2,6 +2,7 @@ import { defineUntypedSchema } from 'untyped'
import { defu } from 'defu' import { defu } from 'defu'
import { join } from 'pathe' import { join } from 'pathe'
import { isTest } from 'std-env' import { isTest } from 'std-env'
import { consola } from 'consola'
export default defineUntypedSchema({ export default defineUntypedSchema({
/** /**
@ -50,7 +51,7 @@ export default defineUntypedSchema({
logLevel: { logLevel: {
$resolve: (val) => { $resolve: (val) => {
if (val && !['silent', 'info', 'verbose'].includes(val)) { if (val && !['silent', 'info', 'verbose'].includes(val)) {
console.warn(`Invalid \`logLevel\` option: \`${val}\`. Must be one of: \`silent\`, \`info\`, \`verbose\`.`) consola.warn(`Invalid \`logLevel\` option: \`${val}\`. Must be one of: \`silent\`, \`info\`, \`verbose\`.`)
} }
return val ?? (isTest ? 'silent' : 'info') return val ?? (isTest ? 'silent' : 'info')
} }

View File

@ -1,3 +1,4 @@
import { consola } from 'consola'
import { resolve } from 'pathe' import { resolve } from 'pathe'
import { isTest } from 'std-env' import { isTest } from 'std-env'
import { withoutLeadingSlash } from 'ufo' import { withoutLeadingSlash } from 'ufo'
@ -34,7 +35,7 @@ export default defineUntypedSchema({
publicDir: { publicDir: {
$resolve: async (val, get) => { $resolve: async (val, get) => {
if (val) { if (val) {
console.warn('Directly configuring the `vite.publicDir` option is not supported. Instead, set `dir.public`. You can read more in `https://nuxt.com/docs/api/configuration/nuxt-config#public`.') consola.warn('Directly configuring the `vite.publicDir` option is not supported. Instead, set `dir.public`. You can read more in `https://nuxt.com/docs/api/configuration/nuxt-config#public`.')
} }
return val ?? resolve((await get('srcDir')), (await get('dir')).public) return val ?? resolve((await get('srcDir')), (await get('dir')).public)
} }

View File

@ -78,7 +78,7 @@ ${genDynamicImport(path, { wrapper: false })}
// Transform // Transform
const res: SSRTransformResult = await opts.viteServer.transformRequest(id, { ssr: true }).catch((err) => { const res: SSRTransformResult = await opts.viteServer.transformRequest(id, { ssr: true }).catch((err) => {
console.warn(`[SSR] Error transforming ${id}:`, err) logger.warn(`[SSR] Error transforming ${id}:`, err)
// console.error(err) // console.error(err)
}) as SSRTransformResult || { code: '', map: {}, deps: [], dynamicDeps: [] } }) as SSRTransformResult || { code: '', map: {}, deps: [], dynamicDeps: [] }

View File

@ -2,6 +2,7 @@
import { Agent as HTTPSAgent } from 'node:https' import { Agent as HTTPSAgent } from 'node:https'
import { $fetch } from 'ofetch' import { $fetch } from 'ofetch'
// eslint-disable-next-line jsdoc/valid-types
/** @type {import('../vite-node').ViteNodeServerOptions} */ /** @type {import('../vite-node').ViteNodeServerOptions} */
export const viteNodeOptions = JSON.parse(process.env.NUXT_VITE_NODE_OPTIONS || '{}') export const viteNodeOptions = JSON.parse(process.env.NUXT_VITE_NODE_OPTIONS || '{}')

View File

@ -7,6 +7,8 @@ import { consola } from 'consola'
import { viteNodeFetch, viteNodeOptions } from './vite-node-shared.mjs' import { viteNodeFetch, viteNodeOptions } from './vite-node-shared.mjs'
const runner = createRunner() const runner = createRunner()
// eslint-disable-next-line jsdoc/valid-types
/** @type {(ssrContext: import('#app').NuxtSSRContext) => Promise<any>} */ /** @type {(ssrContext: import('#app').NuxtSSRContext) => Promise<any>} */
let render let render
@ -71,7 +73,6 @@ function createRunner () {
/** /**
* @param errorData {any} * @param errorData {any}
* @param id {string} * @param id {string}
* @param importer {string}
*/ */
function formatViteError (errorData, id) { function formatViteError (errorData, id) {
const errorCode = errorData.name || errorData.reasonCode || errorData.code const errorCode = errorData.name || errorData.reasonCode || errorData.code

View File

@ -432,6 +432,9 @@ importers:
'@nuxt/ui-templates': '@nuxt/ui-templates':
specifier: ^1.3.1 specifier: ^1.3.1
version: 1.3.1 version: 1.3.1
consola:
specifier: ^3.2.3
version: 3.2.3
defu: defu:
specifier: ^6.1.2 specifier: ^6.1.2
version: 6.1.2 version: 6.1.2
@ -2520,6 +2523,7 @@ packages:
dependencies: dependencies:
is-glob: 4.0.3 is-glob: 4.0.3
micromatch: 4.0.5 micromatch: 4.0.5
napi-wasm: 1.1.0
bundledDependencies: bundledDependencies:
- napi-wasm - napi-wasm
@ -7910,6 +7914,9 @@ packages:
engines: {node: ^14 || ^16 || >=18} engines: {node: ^14 || ^16 || >=18}
hasBin: true hasBin: true
/napi-wasm@1.1.0:
resolution: {integrity: sha512-lHwIAJbmLSjF9VDRm9GoVOy9AGp3aIvkjv+Kvz9h16QR3uSVYH78PNQUnT2U4X53mhlnV2M7wrhibQ3GHicDmg==}
/natural-compare@1.4.0: /natural-compare@1.4.0:
resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}

View File

@ -1,5 +1,6 @@
import { execSync } from 'node:child_process' import { execSync } from 'node:child_process'
import { inc } from 'semver' import { inc } from 'semver'
import { consola } from 'consola'
import { determineBumpType, loadWorkspace } from './_utils' import { determineBumpType, loadWorkspace } from './_utils'
const nightlyPackages = { const nightlyPackages = {
@ -34,6 +35,6 @@ async function main () {
} }
main().catch((err) => { main().catch((err) => {
console.error(err) consola.error(err)
process.exit(1) process.exit(1)
}) })

View File

@ -1,4 +1,5 @@
import { inc } from 'semver' import { inc } from 'semver'
import { consola } from 'consola'
import { loadWorkspace } from './_utils' import { loadWorkspace } from './_utils'
async function main () { async function main () {
@ -14,6 +15,6 @@ async function main () {
} }
main().catch((err) => { main().catch((err) => {
console.error(err) consola.error(err)
process.exit(1) process.exit(1)
}) })

View File

@ -1,3 +1,4 @@
import { consola } from 'consola'
import { loadWorkspace } from './_utils' import { loadWorkspace } from './_utils'
async function main () { async function main () {
@ -16,6 +17,6 @@ async function main () {
} }
main().catch((err) => { main().catch((err) => {
console.error(err) consola.error(err)
process.exit(1) process.exit(1)
}) })

View File

@ -93,11 +93,13 @@ const crawler = {
}) })
} }
}, },
/* eslint-disable jsdoc/valid-types */
/** /**
* @param {Error | null} error * @param {Error | null} error
* @param {import('ofetch').FetchResponse<any> & { $: import('cheerio').CheerioAPI | null }} res * @param {import('ofetch').FetchResponse<any> & { $: import('cheerio').CheerioAPI | null }} res
* @param {() => void} done * @param {() => void} done
*/ */
/* eslint-enable jsdoc/valid-types */
callback (error, res, done) { callback (error, res, done) {
const $ = res.$ const $ = res.$
const uri = res.url const uri = res.url

View File

@ -2,6 +2,7 @@ import { execSync } from 'node:child_process'
import { $fetch } from 'ofetch' import { $fetch } from 'ofetch'
import { inc } from 'semver' import { inc } from 'semver'
import { generateMarkDown, getCurrentGitBranch, loadChangelogConfig } from 'changelogen' import { generateMarkDown, getCurrentGitBranch, loadChangelogConfig } from 'changelogen'
import { consola } from 'consola'
import { determineBumpType, getLatestCommits, loadWorkspace } from './_utils' import { determineBumpType, getLatestCommits, loadWorkspace } from './_utils'
async function main () { async function main () {
@ -72,6 +73,6 @@ async function main () {
} }
main().catch((err) => { main().catch((err) => {
console.error(err) consola.error(err)
process.exit(1) process.exit(1)
}) })

View File

@ -18,6 +18,7 @@ emit('some-event', '42')
// @ts-expect-error an invalid argument // @ts-expect-error an invalid argument
emit('some-event', 42) emit('some-event', 42)
// @ts-expect-error an unknown event // @ts-expect-error an unknown event
// eslint-disable-next-line vue/require-explicit-emits
emit('unknown-event', 42) emit('unknown-event', 42)
</script> </script>

View File

@ -7,7 +7,9 @@ defineExpose({ exposedFunc })
await new Promise(resolve => setTimeout(resolve, 300)) await new Promise(resolve => setTimeout(resolve, 300))
onMounted(() => { console.log('mounted') }) onMounted(() => {
console.log('mounted')
})
</script> </script>
<template> <template>

View File

@ -8,5 +8,7 @@
<script setup> <script setup>
await Promise.resolve() await Promise.resolve()
console.log('isHydrating: ' + useNuxtApp().isHydrating) if (import.meta.client) {
console.log('isHydrating: ' + useNuxtApp().isHydrating)
}
</script> </script>

View File

@ -7,7 +7,9 @@
<script setup> <script setup>
await Promise.resolve() await Promise.resolve()
console.log('isHydrating: ' + useNuxtApp().isHydrating) if (import.meta.client) {
console.log('isHydrating: ' + useNuxtApp().isHydrating)
}
definePageMeta({ definePageMeta({
layout: 'custom' layout: 'custom'
}) })

View File

@ -6,7 +6,9 @@
<script setup> <script setup>
await Promise.resolve() await Promise.resolve()
console.log('isHydrating: ' + useNuxtApp().isHydrating) if (import.meta.client) {
console.log('isHydrating: ' + useNuxtApp().isHydrating)
}
definePageMeta({ definePageMeta({
layout: 'custom-async' layout: 'custom-async'
}) })

View File

@ -8,7 +8,9 @@
</template> </template>
<script setup> <script setup>
console.log('Running Child Setup') if (import.meta.client) {
console.log('Running Child Setup')
}
const route = useRoute() const route = useRoute()
definePageMeta({ definePageMeta({

View File

@ -8,7 +8,9 @@
</template> </template>
<script setup> <script setup>
console.log('Running Child Setup') if (import.meta.client) {
console.log('Running Child Setup')
}
const route = useRoute() const route = useRoute()
definePageMeta({ definePageMeta({

View File

@ -2,21 +2,27 @@
import { useCustomKeyedComposable } from '~/other-composables-folder/custom-keyed-composable' import { useCustomKeyedComposable } from '~/other-composables-folder/custom-keyed-composable'
const useLocalState = () => useState(() => { const useLocalState = () => useState(() => {
if (import.meta.client) { console.error('running usestate') } if (import.meta.client) {
console.error('running usestate')
}
return { foo: Math.random() } return { foo: Math.random() }
}) })
const useStateTest1 = useLocalState() const useStateTest1 = useLocalState()
const useStateTest2 = useLocalState() const useStateTest2 = useLocalState()
const useLocalAsyncData = () => useAsyncData(() => { const useLocalAsyncData = () => useAsyncData(() => {
if (import.meta.client) { console.error('running asyncdata') } if (import.meta.client) {
console.error('running asyncdata')
}
return Promise.resolve({ foo: Math.random() }) return Promise.resolve({ foo: Math.random() })
}, { transform: data => data.foo }) }, { transform: data => data.foo })
const { data: useAsyncDataTest1 } = await useLocalAsyncData() const { data: useAsyncDataTest1 } = await useLocalAsyncData()
const { data: useAsyncDataTest2 } = await useLocalAsyncData() const { data: useAsyncDataTest2 } = await useLocalAsyncData()
const useLocalLazyAsyncData = () => useLazyAsyncData(() => { const useLocalLazyAsyncData = () => useLazyAsyncData(() => {
if (import.meta.client) { console.error('running asyncdata') } if (import.meta.client) {
console.error('running asyncdata')
}
return Promise.resolve({ foo: Math.random() }) return Promise.resolve({ foo: Math.random() })
}, { transform: data => data.foo }) }, { transform: data => data.foo })
const { data: useLazyAsyncDataTest1 } = await useLocalLazyAsyncData() const { data: useLazyAsyncDataTest1 } = await useLocalLazyAsyncData()
@ -24,7 +30,9 @@ const { data: useLazyAsyncDataTest2 } = await useLocalLazyAsyncData()
const useLocalFetch = () => useFetch('/api/counter', { const useLocalFetch = () => useFetch('/api/counter', {
transform: (data) => { transform: (data) => {
if (import.meta.client) { console.error('running client-side transform') } if (import.meta.client) {
console.error('running client-side transform')
}
return data.count return data.count
} }
}) })

View File

@ -7,7 +7,9 @@ definePageMeta({
alias: ['/setup-should-not-run'], alias: ['/setup-should-not-run'],
middleware: to => to.path === '/navigate-to-error' ? navigateTo('/setup-should-not-run') : undefined middleware: to => to.path === '/navigate-to-error' ? navigateTo('/setup-should-not-run') : undefined
}) })
console.log('running setup') if (import.meta.client) {
console.log('running setup')
}
useNuxtApp().hook('app:rendered', () => { useNuxtApp().hook('app:rendered', () => {
throw new Error('this should not run') throw new Error('this should not run')
}) })

View File

@ -9,7 +9,9 @@ definePageMeta({
return navigateTo({ path: '/' }, { redirectCode: 307 }) return navigateTo({ path: '/' }, { redirectCode: 307 })
} }
}) })
console.log('running setup') if (import.meta.client) {
console.log('running setup')
}
useNuxtApp().hook('app:rendered', () => { useNuxtApp().hook('app:rendered', () => {
throw new Error('this should not run') throw new Error('this should not run')
}) })

View File

@ -18,8 +18,11 @@ const links = [
const route = useRoute() const route = useRoute()
const windowState = computed(() => { const windowState = computed(() => {
console.log(route.fullPath) if (import.meta.client) {
return import.meta.client ? window.history.state.foo : '' console.log(route.fullPath)
return window.history.state.foo
}
return ''
}) })
</script> </script>

View File

@ -1,8 +1,12 @@
<script setup lang="ts"> <script setup lang="ts">
console.log('[async]') if (import.meta.client) {
console.log('[async]')
}
const route = useRoute('suspense-async-parent') const route = useRoute('suspense-async-parent')
await new Promise(resolve => setTimeout(resolve, 100)) await new Promise(resolve => setTimeout(resolve, 100))
console.log('[async] running async data') if (import.meta.client) {
console.log('[async] running async data')
}
</script> </script>
<template> <template>

View File

@ -1,8 +1,12 @@
<script setup lang="ts"> <script setup lang="ts">
console.log('[async] [async]') if (import.meta.client) {
console.log('[async] [async]')
}
const route = useRoute('suspense-async-parent-async-child') const route = useRoute('suspense-async-parent-async-child')
await new Promise(resolve => setTimeout(resolve, 500)) await new Promise(resolve => setTimeout(resolve, 500))
console.log(`[async] [${route.params.parent}] [async] [${route.params.child}] running async data`) if (import.meta.client) {
console.log(`[async] [${route.params.parent}] [async] [${route.params.child}] running async data`)
}
const data = route.params const data = route.params
</script> </script>

View File

@ -1,5 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
process.client && console.log('[async] [sync]') if (import.meta.client) {
console.log('[async] [sync]')
}
const route = useRoute('suspense-async-parent-sync-child') const route = useRoute('suspense-async-parent-sync-child')
</script> </script>

View File

@ -1,5 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
process.client && console.log('[sync]') if (import.meta.client) {
console.log('[sync]')
}
const route = useRoute('suspense-async-parent') const route = useRoute('suspense-async-parent')
</script> </script>

View File

@ -1,8 +1,12 @@
<script setup lang="ts"> <script setup lang="ts">
process.client && console.log('[sync] [async]') if (import.meta.client) {
console.log('[sync] [async]')
}
const route = useRoute('suspense-async-parent-sync-child') const route = useRoute('suspense-async-parent-sync-child')
await new Promise(resolve => setTimeout(resolve, 500)) await new Promise(resolve => setTimeout(resolve, 500))
process.client && console.log(`[sync] [${route.params.parent}] [async] [${route.params.child}] running async data`) if (import.meta.client) {
console.log(`[sync] [${route.params.parent}] [async] [${route.params.child}] running async data`)
}
const data = route.params const data = route.params
</script> </script>

View File

@ -1,5 +1,7 @@
<script setup lang="ts"> <script setup lang="ts">
process.client && console.log('[sync] [sync]') if (import.meta.client) {
console.log('[sync] [sync]')
}
const route = useRoute('suspense-sync-parent-sync-child') const route = useRoute('suspense-sync-parent-sync-child')
</script> </script>

View File

@ -3,7 +3,9 @@ definePageMeta({
layout: 'custom2' layout: 'custom2'
}) })
console.log('Running With Layout2 Page Setup') if (import.meta.client) {
console.log('Running With Layout2 Page Setup')
}
</script> </script>
<template> <template>
<div id="with-layout2"> <div id="with-layout2">

View File

@ -1,3 +1,5 @@
export default defineNuxtPlugin((nuxtApp) => { export default defineNuxtPlugin((nuxtApp) => {
nuxtApp.hook('app:chunkError', () => console.log('caught chunk load error')) nuxtApp.hook('app:chunkError', () => {
console.log('caught chunk load error')
})
}) })

View File

@ -1,6 +1,9 @@
<script setup lang="ts"> <script setup lang="ts">
import { componentNames } from '#components' import { componentNames } from '#components'
console.log(componentNames)
// prevent treeshaking of #components import
defineExpose({ componentNames })
// @ts-expect-error this is not usable outside a pages directory // @ts-expect-error this is not usable outside a pages directory
definePageMeta({ definePageMeta({
// this should be fully tree-shaken out // this should be fully tree-shaken out

27
test/setup-env.ts Normal file
View File

@ -0,0 +1,27 @@
import { consola } from 'consola'
import { vi } from 'vitest'
import { logger } from '../packages/kit'
consola.mockTypes(() => vi.fn())
logger.mockTypes(() => vi.fn())
const _warn = console.warn.bind(console)
const hiddenWarns = [
'[@vue/reactivity-transform]',
'[Vue warn]: Component',
'[Vue router warn]'
]
console.warn = (arg0: any, ...args: any[]) => {
if ((typeof arg0 === 'string') && hiddenWarns.some(w => arg0.includes(w))) {
return
}
_warn(...args)
}
// for (const t of ['uncaughtException', 'unhandledRejection'] as const) {
// process.on(t, (err) => {
// console.error(`[nuxt test suite] [${t}]`, err)
// })
// }

View File

@ -30,7 +30,11 @@ export async function renderPage (path = '/') {
pageErrors.push(err) pageErrors.push(err)
}) })
page.on('request', (req) => { page.on('request', (req) => {
requests.push(req.url().replace(url('/'), '/')) try {
requests.push(req.url().replace(url('/'), '/'))
} catch (err) {
// TODO
}
}) })
if (path) { if (path) {

View File

@ -16,6 +16,7 @@ export default defineConfig({
}, },
test: { test: {
globalSetup: './test/setup.ts', globalSetup: './test/setup.ts',
setupFiles: ['./test/setup-env.ts'],
testTimeout: isWindows ? 60000 : 10000, testTimeout: isWindows ? 60000 : 10000,
// Excluded plugin because it should throw an error when accidentally loaded via Nuxt // Excluded plugin because it should throw an error when accidentally loaded via Nuxt
exclude: [...configDefaults.exclude, '**/test/nuxt/**', '**/test.ts', '**/this-should-not-load.spec.js'], exclude: [...configDefaults.exclude, '**/test/nuxt/**', '**/test.ts', '**/this-should-not-load.spec.js'],