← Курс/app.config: глобальные настройки Vue#216 из 257+20 XP

app.config: глобальные настройки Vue

Что такое app.config

При создании Vue-приложения через createApp() возвращается экземпляр приложения с объектом config. Через него настраиваются **глобальные параметры** приложения — до вызова mount().

import { createApp } from 'vue'
import App from './App.vue'

const app = createApp(App)

// Все настройки — до mount()
app.config.errorHandler = ...
app.config.globalProperties.$myUtil = ...

app.mount('#app')

app.config.globalProperties

Добавляет свойства, доступные во **всех компонентах** через this (Options API) или через специальный inject (Composition API):

// main.js
app.config.globalProperties.$formatDate = (date) => {
  return new Intl.DateTimeFormat('ru-RU').format(date)
}

app.config.globalProperties.$http = axios
<!-- В любом компоненте (Options API) -->
<template>
  <p>{{ $formatDate(user.createdAt) }}</p>
</template>

В Composition API доступ через getCurrentInstance():

import { getCurrentInstance } from 'vue'

const { proxy } = getCurrentInstance()
proxy.$formatDate(date)

Лучше использовать app.provide для Composition API (см. ниже).

app.config.errorHandler

Глобальный обработчик **необработанных ошибок** из компонентов. Получает три аргумента: ошибку, экземпляр компонента и строку с описанием источника:

app.config.errorHandler = (error, instance, info) => {
  // error — объект ошибки
  // instance — компонент где произошла ошибка
  // info — строка типа 'v-on handler' / 'lifecycle hook'

  console.error('[Глобальная ошибка]', error)
  console.error('Компонент:', instance?.$options.name)
  console.error('Источник:', info)

  // Отправить в сервис мониторинга (Sentry, Datadog и т.д.)
  errorTracker.capture(error, { component: instance, info })
}

app.config.warnHandler

Перехватывает предупреждения Vue в режиме разработки:

app.config.warnHandler = (msg, instance, trace) => {
  // Игнорируем конкретное предупреждение
  if (msg.includes('missing prop')) return

  console.warn('[Vue Warning]', msg)
  console.warn('Трассировка:', trace)
}

app.provide: глобальные inject-зависимости

app.provide(key, value) позволяет делать значения доступными для **всех компонентов** через inject(). Это предпочтительный способ для Composition API:

// main.js
import { createApp } from 'vue'

const app = createApp(App)

app.provide('apiUrl', 'https://api.example.com')
app.provide('$config', {
  version: '1.0.0',
  env: import.meta.env.MODE
})
<!-- В любом компоненте -->
<script setup>
import { inject } from 'vue'

const apiUrl = inject('apiUrl')
const config = inject('$config')
</script>

app.config.performance

Включает трассировку производительности в DevTools:

app.config.performance = true  // только в dev режиме

app.config.compilerOptions

Настройка шаблонного компилятора (только при runtime compilation):

app.config.compilerOptions.isCustomElement = (tag) => {
  // Сообщаем Vue, что web-components с 'ion-' — не компоненты Vue
  return tag.startsWith('ion-')
}

Примеры

Эмуляция системы app.config: глобальные свойства, обработчик ошибок и provide/inject

// Эмулируем систему конфигурации Vue-приложения

class VueApp {
  constructor(rootComponent) {
    this.rootComponent = rootComponent
    this._mounted = false
    this._provides = {}

    // Аналог app.config
    this.config = {
      globalProperties: {},
      errorHandler: null,
      warnHandler: null,
    }
  }

  // Аналог app.provide
  provide(key, value) {
    this._provides[key] = value
    console.log(`  [provide] Зарегистрирован ключ "${key}"`)
    return this
  }

  // Аналог app.component (упрощённо)
  component(name, definition) {
    console.log(`  [component] Зарегистрирован компонент "${name}"`)
    return this
  }

  // Монтирование
  mount(selector) {
    console.log(`\n  [mount] Приложение смонтировано на "${selector}"`)
    this._mounted = true
    return this
  }

  // Создаём контекст компонента (как при создании экземпляра в Vue)
  createComponentContext(name) {
    const app = this
    return {
      name,
      // inject: ищет значение в provide-хранилище
      inject(key, defaultValue) {
        if (key in app._provides) {
          const value = app._provides[key]
          console.log(`  [inject] "${name}" получил "${key}": ${JSON.stringify(value)}`)
          return value
        }
        console.log(`  [inject] "${name}" не нашёл "${key}", используем default: ${JSON.stringify(defaultValue)}`)
        return defaultValue
      },
      // Доступ к globalProperties
      get globals() {
        return app.config.globalProperties
      },
      // Симуляция выброса ошибки
      throwError(error, info) {
        console.log(`  [error] В компоненте "${name}": ${error.message} (source: ${info})`)
        if (app.config.errorHandler) {
          app.config.errorHandler(error, this, info)
        } else {
          throw error
        }
      }
    }
  }
}

// === Настройка приложения ===
console.log('=== Настройка Vue-приложения ===')

const app = new VueApp({ name: 'App' })

// globalProperties — доступны везде
app.config.globalProperties.$formatDate = (date) =>
  new Intl.DateTimeFormat('ru-RU').format(new Date(date))

app.config.globalProperties.$currency = (n) =>
  new Intl.NumberFormat('ru-RU', { style: 'currency', currency: 'RUB' }).format(n)

// provide — глобальный inject
app.provide('apiUrl', 'https://api.example.com/v2')
app.provide('appConfig', { version: '2.1.0', env: 'development' })

// errorHandler — глобальный обработчик ошибок
app.config.errorHandler = (error, instance, info) => {
  console.log(`  [errorHandler] Поймана ошибка в "${instance.name}": ${error.message}`)
  console.log(`  [errorHandler] Источник: ${info}`)
  // В реальном приложении: Sentry.captureException(error)
}

app.mount('#app')

// === Использование в "компонентах" ===
console.log('\n=== Использование в компонентах ===')

// Компонент UserProfile
const userProfileCtx = app.createComponentContext('UserProfile')
const apiUrl = userProfileCtx.inject('apiUrl')
const appConfig = userProfileCtx.inject('appConfig')
const timeout = userProfileCtx.inject('requestTimeout', 5000)  // с дефолтом

console.log('  apiUrl:', apiUrl)
console.log('  appConfig:', appConfig)
console.log('  timeout (default):', timeout)

// Доступ к globalProperties
console.log('\n  Глобальные утилиты:')
const formatted = userProfileCtx.globals.$formatDate('2024-01-15')
console.log('  $formatDate:', formatted)
const price = userProfileCtx.globals.$currency(1999)
console.log('  $currency:', price)

// Обработка ошибки
console.log('\n=== Глобальный обработчик ошибок ===')
const badComponentCtx = app.createComponentContext('PaymentForm')
badComponentCtx.throwError(new Error('Недостаточно средств'), 'v-on handler')