# Совместимость с браузерами

## browserslist

Вы заметите поле `browserslist` в файле `package.json` (или файл `.browserslistrc`), где определяется диапазон браузеров под которые разрабатывается проект. Эти значения будут использоваться в [@babel/preset-env][babel-preset-env] и [autoprefixer][autoprefixer] для автоматического определения возможностей JavaScript, которые требуется транспилировать, а также необходимые префиксные правила CSS.

Как указывается диапазон браузеров, можно узнать [здесь][browserslist].

## Полифилы

По умолчанию проект Vue CLI использует [@vue/babel-preset-app][babel-preset-app], в котором используется `@babel/preset-env` и конфигурация `browserslist` для определения необходимых полифилов.

### useBuiltIns: 'usage'

По умолчанию в `@babel/preset-env` будет передаваться [`useBuiltIns: 'usage'`](https://new.babeljs.io/docs/en/next/babel-preset-env.html#usebuiltins-usage) для автоматического определения необходимых полифилов, основываясь на том, какие возможности языка были использованы в исходном коде проекта. Это гарантирует, что в финальную сборку попадёт только минимально необходимое количество полифилов. Однако это также означает, что **если одна из ваших зависимостей имеет специфичные требования к полифилам, то по умолчанию Babel не сможет это определить.**

Если одной из ваших зависимостей требуются полифилы, у вас есть несколько вариантов:

1. **Если зависимость написана в версии ES, которую не поддерживают целевые окружения:** Добавьте эту зависимость в опцию [`transpileDependencies`](../config/#transpiledependencies) в файле `vue.config.js`. Это позволит использовать как синтаксические преобразования, так и определение полифилов для используемых возможностей для этой зависимости.

2. **Если зависимость предоставляет ES5 код и явно перечисляет необходимые полифилы:** вы можете предварительно включить необходимые полифилы с помощью опции [polyfills](https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/babel-preset-app#polyfills) для `@vue/babel-preset-app`. **Обратите внимание, что `es.promise` добавлен по умолчанию, так как он  часто необходим для библиотек, основанных на Promise.**

    ```js
    // babel.config.js
    module.exports = {
      presets: [
        ['@vue/app', {
          polyfills: [
            'es.promise',
            'es.symbol'
          ]
        }]
      ]
    }
    ```

    ::: tip Совет
    Рекомендуется добавлять полифилы таким образом, а не напрямую импортировать их в коде, потому что полифилы перечисленные здесь, могут быть автоматически исключены, если целевым браузерам, указанным в `browserslist`, они не нужны.
    :::

3. **Если зависимость предоставляет ES5 код, но использует возможности ES6+ без явного перечисления необходимых полифилов (например, Vuetify):** Используйте `useBuiltIns: 'entry'` и затем добавьте `import 'core-js/stable'; import 'regenerator-runtime/runtime';` в файл точки входа. Это будет импортировать **ВСЕ** полифилы на основе целей, перечисленных в `browserslist`, так что вам больше не нужно будет беспокоиться о полифилах для зависимостей, но это скорее всего увеличит размер финальной сборки некоторыми неиспользуемыми полифилами.

Подробнее можно изучить в [документации @babel/preset-env](https://new.babeljs.io/docs/en/next/babel-preset-env.html#usebuiltins-usage).

### Полифилы при сборке библиотеки или веб-компонентов

При использовании Vue CLI для [сборки библиотеки или веб-компонентов](./build-targets.md) рекомендуется указывать `useBuiltIns: false` для `@vue/babel-preset-app`, чтобы отключить автоматическое добавление полифилов. Это гарантирует, что вы не добавляете ненужные полифилы в свой код, потому что полифилами должно будет заниматься приложение, где они будут использоваться.

## Современный режим

Благодаря Babel мы можем использовать все новейшие возможности языка ES2015+, но это также означает, что нам необходимо предоставлять транспилированную сборку с полифилами для поддержки старых браузеров. Эти транспилированные сборки зачастую больше в размере, чем оригинальный исходный код в ES2015+, а их парсинг и выполнение происходит медленнее. Учитывая, что сегодня у большинства современных браузеров есть прекрасная поддержка ES2015, становится пустой тратой необходимость предоставлять более тяжёлый и менее эффективный код для них лишь потому, что мы должны поддерживать старые версии браузеров.

Vue CLI предоставляет «Современный режим», чтобы помочь в решении этой проблемы. При сборке для production с помощью следующей команды:

```bash
vue-cli-service build --modern
```

Vue CLI будет собирать **две версии** вашего приложения: первая сборка для современных браузеров, которые поддерживают [ES-модули](https://jakearchibald.com/2017/es-modules-in-browsers/), а вторая сборка для старых браузеров, которые не имеют такой поддержки.

Приятная часть заключается в том, что ничего специально делать при публикации не требуется. Сгенерированный HTML-файл автоматически использует технику, описанную в классном [посте Филлипа Уолтона](https://philipwalton.com/articles/deploying-es2015-code-in-production-today/):

- Современная сборка загружается с помощью `<script type="module">` в браузерах, которые поддерживают модули; они также предзагружаются через `<link rel="modulepreload">`.

- Сборка для старых браузеров загружается с помощью тега `<script nomodule>`, который игнорируется браузерами, поддерживающими ES-модули.

- Исправление ошибки для `<script nomodule>` в Safari 10 также внедряется автоматически.

Для приложения Hello World современная сборка на 16% меньше. В production использование современной сборки приводит к значительному ускорению парсинга и исполнения кода, что повышает производительность загрузки приложения.

::: tip Совет
`<script type="module">` загружаются [всегда с помощью CORS](https://jakearchibald.com/2017/es-modules-in-browsers/#always-cors). Это значит, что ваш сервер должен возвращать корректные заголовки CORS, такие как `Access-Control-Allow-Origin: *`. Если вы хотите загружать скрипты с помощью credentials, установите опцию [crossorigin](../config/#crossorigin) в значение `use-credentials`.

Кроме того, современный режим использует инлайновый скрипт для избежания загрузки обеих сборок в Safari 10, поэтому, если вы используете строгие политики CSP, необходимо явно разрешить инлайновый скрипт с помощью:

```
Content-Security-Policy: script-src 'self' 'sha256-4RS22DYeB7U14dra4KcQYxmwt5HkOInieXK1NUMBmQI='
```
:::

::: tip Определение текущего режима в конфигурации
Иногда может потребоваться изменить конфигурацию webpack только сборки для старых браузеров или только сборки для современных браузеров.

Vue CLI использует две переменных окружения для определения этого:

* `VUE_CLI_MODERN_MODE`: флаг, что сборка была запущена с флагом `--modern`
* `VUE_CLI_MODERN_BUILD`: значение true будет, если текущая конфигурация для современной сборки. В противном случае это сборка для старых браузеров.

**Важно:** Переменные доступны только при вызове/после вызова функций `chainWebpack()` и `configureWebpack()`, (т.е. не напрямую в области видимости модуля `vue.config.js`). Это также означает, что они доступны в файле конфигурации postcss.
:::

::: warning Предостережение: Настройка плагинов webpack
Некоторые плагины, такие как `html-webpack-plugin`, `preload-plugin` и т.п., добавляются только в конфигурации для современного режима. Попытка использовать их опции в конфигурации для старых браузеров может привести к ошибке, так как этих плагинов не будет существовать.

Используйте совет выше об *Определении текущего режима в конфигурации* для управления плагинами только в соответствующем режиме, и/или проверяйте наличие плагина в конфигурации текущего режима, прежде чем использовать их опции.
:::

[autoprefixer]: https://github.com/postcss/autoprefixer
[babel-preset-env]: https://new.babeljs.io/docs/en/next/babel-preset-env.html
[babel-preset-app]: https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/babel-preset-app
[browserslist]: https://github.com/ai/browserslist
