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

View File

@ -2,6 +2,7 @@ import { kebabCase, pascalCase } from 'scule'
import type { Component, ComponentsDir } from '@nuxt/schema'
import { useNuxt } from './context'
import { assertNuxtCompatibility } from './compatibility'
import { logger } from './logger'
/**
* 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.
if (newPriority === existingPriority) {
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)
} else {

View File

@ -4,6 +4,7 @@ import { template as lodashTemplate } from 'lodash-es'
import { genDynamicImport, genImport, genSafeVariableName } from 'knitwork'
import type { NuxtTemplate } from '@nuxt/schema'
import { logger } from '../logger'
/** @deprecated */
// 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')
return lodashTemplate(srcContents, {})(data)
} catch (err) {
console.error('Error compiling template: ', template)
logger.error('Error compiling template: ', template)
throw err
}
}

View File

@ -7,6 +7,7 @@ import { useNuxt } from '../context'
import { requireModule } from '../internal/cjs'
import { importModule } from '../internal/esm'
import { resolveAlias, resolvePath } from '../resolve'
import { logger } from '../logger'
/** Installs a module on a Nuxt instance. */
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
nuxtModule = await importModule(src, nuxt.options.modulesDir).catch(() => null) ?? requireModule(src, { paths: nuxt.options.modulesDir })
} catch (error: unknown) {
console.error(`Error while requiring module \`${nuxtModule}\`: ${error}`)
logger.error(`Error while requiring module \`${nuxtModule}\`: ${error}`)
throw error
}
// 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 { useNuxt } from './context'
import { isNuxt2 } from './compatibility'
import { logger } from './logger'
export function extendPages (cb: NuxtHooks['pages:extend']) {
const nuxt = useNuxt()
@ -54,7 +55,7 @@ export function addRouteMiddleware (input: NuxtMiddleware | NuxtMiddleware[], op
if (options.override === true) {
app.middleware[find] = middleware
} 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 {
app.middleware.push(middleware)

View File

@ -3,6 +3,7 @@ import type { NuxtPlugin, NuxtPluginTemplate } from '@nuxt/schema'
import { useNuxt } from './context'
import { addTemplate } from './template'
import { resolveAlias } from './resolve'
import { logger } from './logger'
/**
* Normalize a nuxt plugin object
@ -22,7 +23,7 @@ export function normalizePlugin (plugin: NuxtPlugin | string): NuxtPlugin {
// TODO: only scan top-level files #18418
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]))) {
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

View File

@ -5,6 +5,7 @@ import { pascalCase } from 'scule'
import { resolve } from 'pathe'
import type { Component, ComponentsOptions } from 'nuxt/schema'
import { logger } from '@nuxt/kit'
import { distDir } from '../dirs'
import { isVue } from '../core/utils'
@ -54,7 +55,7 @@ export const loaderPlugin = createUnplugin((options: LoaderOptions) => {
imports.add(genImport(serverComponentRuntime, [{ name: 'createServerComponent' }]))
imports.add(`const ${identifier} = createServerComponent(${JSON.stringify(name)})`)
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
}

View File

@ -1,6 +1,6 @@
import { statSync } from 'node:fs'
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 { distDir } from '../dirs'
@ -86,7 +86,7 @@ export default defineNuxtModule<ComponentsOptions>({
const present = isDirectory(dirPath)
if (!present && !DEFAULT_COMPONENTS_DIRS_RE.test(dirOptions.path)) {
console.warn('Components directory not found: `' + dirPath + '`')
logger.warn('Components directory not found: `' + dirPath + '`')
}
return {
@ -156,7 +156,7 @@ export default defineNuxtModule<ComponentsOptions>({
const path = resolve(nuxt.options.srcDir, relativePath)
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')
}
})

View File

@ -2,7 +2,7 @@ import { readdir } from 'node:fs/promises'
import { basename, dirname, extname, join, relative } from 'pathe'
import { globby } from 'globby'
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
import { hyphenate } from '@vue/shared'
import { withTrailingSlash } from 'ufo'
@ -44,7 +44,7 @@ export async function scanComponents (dirs: ComponentsDir[], srcDir: string): Pr
const nuxt = useNuxt()
const original = relative(nuxt.options.srcDir, dir.path)
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
}
}
@ -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
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
}
@ -189,7 +189,7 @@ export function resolveComponentName (fileName: string, prefixParts: 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 - ${duplicatePath}`
)

View File

@ -1,7 +1,7 @@
import { promises as fsp, mkdirSync, writeFileSync } from 'node:fs'
import { dirname, join, resolve } from 'pathe'
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 * 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 mark = performance.mark(fullPath)
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
})
@ -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
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) {
@ -191,7 +191,7 @@ export async function annotatePlugins (nuxt: Nuxt, plugins: NuxtPlugin[]) {
...plugin
})
} catch (e) {
console.warn(`[nuxt] Could not resolve \`${plugin.src}\`.`)
logger.warn(`Could not resolve \`${plugin.src}\`.`)
_plugins.push(plugin)
}
}

View File

@ -2,7 +2,7 @@ import { pathToFileURL } from 'node:url'
import type { EventType } from '@parcel/watcher'
import type { FSWatcher } 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 { debounce } from 'perfect-debounce'
import { normalize, relative, resolve } from 'pathe'
@ -93,6 +93,7 @@ function createGranularWatcher () {
const nuxt = useNuxt()
if (nuxt.options.debug) {
// eslint-disable-next-line no-console
console.time('[nuxt] builder:chokidar:watch')
}
@ -131,6 +132,7 @@ function createGranularWatcher () {
watcher.on('ready', () => {
pending--
if (nuxt.options.debug && !pending) {
// eslint-disable-next-line no-console
console.timeEnd('[nuxt] builder:chokidar:watch')
}
})
@ -140,6 +142,7 @@ function createGranularWatcher () {
async function createParcelWatcher () {
const nuxt = useNuxt()
if (nuxt.options.debug) {
// eslint-disable-next-line no-console
console.time('[nuxt] builder:parcel:watch')
}
const watcherPath = await tryResolveModule('@parcel/watcher', [nuxt.options.rootDir, ...nuxt.options.modulesDir])
@ -162,6 +165,7 @@ async function createParcelWatcher () {
})
watcher.then((subscription) => {
if (nuxt.options.debug) {
// eslint-disable-next-line no-console
console.timeEnd('[nuxt] builder:parcel:watch')
}
nuxt.hook('close', () => subscription.unsubscribe())
@ -169,7 +173,7 @@ async function createParcelWatcher () {
}
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
}

View File

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

View File

@ -389,7 +389,7 @@ async function initNuxt (nuxt: Nuxt) {
// Core Nuxt files: app.vue, error.vue and app.config.ts
const isFileChange = ['add', 'unlink'].includes(event)
if (isFileChange && RESTART_RE.test(path)) {
console.info(`\`${path}\` ${event === 'add' ? 'created' : 'removed'}`)
logger.info(`\`${path}\` ${event === 'add' ? 'created' : 'removed'}`)
return nuxt.callHook('restart')
}
})
@ -406,7 +406,7 @@ async function initNuxt (nuxt: Nuxt) {
// Add prerender payload support
const nitro = useNitro()
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
}
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 MagicString from 'magic-string'
import { normalize } from 'pathe'
import { logger } from '@nuxt/kit'
// eslint-disable-next-line import/no-restricted-paths
import type { ObjectPlugin, PluginMeta } from '#app'
@ -122,7 +123,7 @@ export const RemovePluginMetadataPlugin = (nuxt: Nuxt) => createUnplugin(() => {
const exports = findExports(code)
const defaultExport = exports.find(e => e.type === 'default' || e.name === 'default')
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 () => {}')
return {
code: s.toString(),
@ -140,7 +141,7 @@ export const RemovePluginMetadataPlugin = (nuxt: Nuxt) => createUnplugin(() => {
enter (_node) {
if (_node.type === 'ExportDefaultDeclaration' && (_node.declaration.type === 'FunctionDeclaration' || _node.declaration.type === 'ArrowFunctionExpression')) {
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 () => {}')
wrapped = true // silence a duplicate error
return
@ -155,7 +156,7 @@ export const RemovePluginMetadataPlugin = (nuxt: Nuxt) => createUnplugin(() => {
if (node.arguments[0].type !== 'ObjectExpression') {
// TODO: Warn if legacy plugin format is detected
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 () => {}')
return
}
@ -184,12 +185,12 @@ export const RemovePluginMetadataPlugin = (nuxt: Nuxt) => createUnplugin(() => {
}
})
} catch (e) {
console.error(e)
logger.error(e)
return
}
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()) {

View File

@ -1,7 +1,7 @@
import { parseNodeModulePath, resolvePath } from 'mlly'
import { isAbsolute, normalize } from 'pathe'
import type { Plugin } from 'vite'
import { resolveAlias } from '@nuxt/kit'
import { logger, resolveAlias } from '@nuxt/kit'
import type { Nuxt } from '@nuxt/schema'
import { pkgDir } from '../../dirs'
@ -23,7 +23,7 @@ export function resolveDeepImportsPlugin (nuxt: Nuxt): Plugin {
// TODO: respect nitro runtime conditions
conditions: options.ssr ? ['node', 'import', 'require'] : ['import', 'require']
}).catch(() => {
console.log('[nuxt] Could not resolve id', id, importer)
logger.log('Could not resolve id', id, importer)
return null
})
}

View File

@ -6,7 +6,7 @@ import chokidar from 'chokidar'
import { interopDefault } from 'mlly'
import { defu } from 'defu'
import { debounce } from 'perfect-debounce'
import { createResolver, defineNuxtModule, tryResolveModule } from '@nuxt/kit'
import { createResolver, defineNuxtModule, logger, tryResolveModule } from '@nuxt/kit'
import {
generateTypes,
resolveSchema as resolveUntypedSchema
@ -76,7 +76,7 @@ export default defineNuxtModule({
}
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 =>
@ -106,8 +106,8 @@ export default defineNuxtModule({
try {
loadedConfig = _resolveSchema(filePath)
} catch (err) {
console.warn(
'[nuxt-config-schema] Unable to load schema from',
logger.warn(
'Unable to load schema from',
filePath,
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 type { Import, Unimport } from 'unimport'
import { createUnimport, scanDirExports } from 'unimport'
@ -69,7 +69,7 @@ export default defineNuxtModule<Partial<ImportsOptions>>({
const path = resolve(nuxt.options.srcDir, relativePath)
if (composablesDirs.includes(path)) {
console.info(`Directory \`${relativePath}/\` ${event === 'addDir' ? 'created' : 'removed'}`)
logger.info(`Directory \`${relativePath}/\` ${event === 'addDir' ? 'created' : 'removed'}`)
return nuxt.callHook('restart')
}
})

View File

@ -1,6 +1,6 @@
import { existsSync, readdirSync } from 'node:fs'
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 { genImport, genObjectFromRawEntries, genString } from 'knitwork'
import { joinURL } from 'ufo'
@ -67,7 +67,7 @@ export default defineNuxtModule({
if (restartPaths.some(p => p === path || path.startsWith(p + '/'))) {
const newSetting = await isPagesEnabled()
if (nuxt.options.pages !== newSetting) {
console.info('Pages', newSetting ? 'enabled' : 'disabled')
logger.info('Pages', newSetting ? 'enabled' : 'disabled')
return nuxt.callHook('restart')
}
}
@ -275,7 +275,7 @@ export default defineNuxtModule({
if (extractedRule) {
if (!glob) {
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
}
@ -286,9 +286,9 @@ export default defineNuxtModule({
} catch (e: any) {
if (e.toString().includes('Error parsing route rules')) {
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 {
console.error(e)
logger.error(e)
}
}
}

View File

@ -8,6 +8,7 @@ import type { Node } from 'estree-walker'
import { walk } from 'estree-walker'
import MagicString from 'magic-string'
import { isAbsolute } from 'pathe'
import { logger } from '@nuxt/kit'
export interface PageMetaPluginOptions {
dev?: boolean
@ -90,7 +91,7 @@ export const PageMetaPlugin = createUnplugin((options: PageMetaPluginOptions) =>
if (!code) {
s.append(CODE_EMPTY + (options.dev ? CODE_HMR : ''))
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 {
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> {}
}
const warnRuntimeUsage = (method: string) =>
const warnRuntimeUsage = (method: string) => {
console.warn(
`${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 ' +
'compiled away and passing it at runtime has no effect.'
)
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
export const definePageMeta = (meta: PageMeta): void => {

View File

@ -1,7 +1,7 @@
import fs from 'node:fs'
import { extname, normalize, relative, resolve } from 'pathe'
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 escapeRE from 'escape-string-regexp'
import { filename } from 'pathe/utils'
@ -273,7 +273,7 @@ function prepareRoutes (routes: NuxtPage[], parent?: NuxtPage, names = new Set<s
if (names.has(route.name)) {
const existingRoute = findRouteByName(route.name, routes)
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) {
it('should import composables', () => {
console.log(e)
// eslint-disable-next-line no-console
console.error(e)
expect(false).toBe(true)
})
}

View File

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

View File

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

View File

@ -2,6 +2,7 @@ import { defineUntypedSchema } from 'untyped'
import { defu } from 'defu'
import { join } from 'pathe'
import { isTest } from 'std-env'
import { consola } from 'consola'
export default defineUntypedSchema({
/**
@ -50,7 +51,7 @@ export default defineUntypedSchema({
logLevel: {
$resolve: (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')
}

View File

@ -1,3 +1,4 @@
import { consola } from 'consola'
import { resolve } from 'pathe'
import { isTest } from 'std-env'
import { withoutLeadingSlash } from 'ufo'
@ -34,7 +35,7 @@ export default defineUntypedSchema({
publicDir: {
$resolve: async (val, get) => {
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)
}

View File

@ -78,7 +78,7 @@ ${genDynamicImport(path, { wrapper: false })}
// Transform
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)
}) as SSRTransformResult || { code: '', map: {}, deps: [], dynamicDeps: [] }

View File

@ -2,6 +2,7 @@
import { Agent as HTTPSAgent } from 'node:https'
import { $fetch } from 'ofetch'
// eslint-disable-next-line jsdoc/valid-types
/** @type {import('../vite-node').ViteNodeServerOptions} */
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'
const runner = createRunner()
// eslint-disable-next-line jsdoc/valid-types
/** @type {(ssrContext: import('#app').NuxtSSRContext) => Promise<any>} */
let render
@ -71,7 +73,6 @@ function createRunner () {
/**
* @param errorData {any}
* @param id {string}
* @param importer {string}
*/
function formatViteError (errorData, id) {
const errorCode = errorData.name || errorData.reasonCode || errorData.code

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -7,7 +7,9 @@ definePageMeta({
alias: ['/setup-should-not-run'],
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', () => {
throw new Error('this should not run')
})

View File

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

View File

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

View File

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

View File

@ -1,8 +1,12 @@
<script setup lang="ts">
console.log('[async] [async]')
if (import.meta.client) {
console.log('[async] [async]')
}
const route = useRoute('suspense-async-parent-async-child')
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
</script>

View File

@ -1,5 +1,7 @@
<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')
</script>

View File

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

View File

@ -1,8 +1,12 @@
<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')
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
</script>

View File

@ -1,5 +1,7 @@
<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')
</script>

View File

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

View File

@ -1,3 +1,5 @@
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">
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
definePageMeta({
// 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)
})
page.on('request', (req) => {
try {
requests.push(req.url().replace(url('/'), '/'))
} catch (err) {
// TODO
}
})
if (path) {

View File

@ -16,6 +16,7 @@ export default defineConfig({
},
test: {
globalSetup: './test/setup.ts',
setupFiles: ['./test/setup-env.ts'],
testTimeout: isWindows ? 60000 : 10000,
// 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'],