HTML и статические ресурсы

HTML

Стартовый файл

Файл public/index.html — шаблон, который будет обрабатываться html-webpack-plugin. На этапе сборки, ссылки на все ресурсы будут внедряться автоматически. Кроме того, Vue CLI автоматически внедряет подсказки для ресурсов (preload/prefetch), ссылки на манифест/иконки (когда используется PWA-плагин), и ссылки на ресурсы для файлов JavaScript и CSS, созданных во время сборки.

Интерполяции

Поскольку стартовый файл используется в качестве шаблона, можно использовать синтаксис шаблонов lodash для интерполяции значений в нём:

  • <%= VALUE %> для неэкранированной подстановки;
  • <%- VALUE %> для экранированного HTML-кода;
  • <% expression %> для потоков управления JavaScript.

В дополнение к значениям по умолчанию, предоставляемым html-webpack-plugin, все переменные окружения в клиентском коде также доступны напрямую. Например, чтобы использовать значение BASE_URL:

<link rel="icon" href="<%= BASE_URL %>favicon.ico">

См. также:

Preload

<link rel="preload"> — это подсказки для браузера, указывающие на ресурсы, которые необходимо загрузить в первую очередь. Запросы на такие ресурсы будут отправлены ещё на этапе загрузки страницы, до начала её рендеринга.

По умолчанию приложение Vue CLI автоматически генерирует preload-подсказки для всех файлов, которые необходимы при первоначальном рендеринге вашего приложения.

Эти подсказки внедряются @vue/preload-webpack-plugin и могут быть изменены / удалены с помощью chainWebpack через config.plugin('preload').

Prefetch

<link rel="prefetch"> — это подсказки для ресурсов, которые сообщают браузеру предварительно загрузить контент, который пользователь может посетить в ближайшем будущем, пока браузер находится в режиме ожидания после загрузки страницы.

По умолчанию приложение Vue CLI автоматически генерирует prefetch-подсказки для всех JavaScript-файлов, сгенерированных для асинхронных фрагментов (в результате разделения кода с помощью динамических импортов import()).

Эти подсказки внедряются @vue/preload-webpack-plugin и могут быть изменены / удалены с помощью chainWebpack через config.plugin('prefetch').

Примечание для многостраничных конфигураций

При использовании многостраничной конфигурации имя плагина нужно изменить в соответствии со структурой prefetch-{pagename}, например prefetch-app.

Например:

// vue.config.js
module.exports = {
  chainWebpack: config => {
    // удаляем prefetch плагин:
    config.plugins.delete('prefetch')

    // ИЛИ
    // изменяем его настройки:
    config.plugin('prefetch').tap(options => {
      options[0].fileBlacklist = options[0].fileBlacklist || []
      options[0].fileBlacklist.push(/myasyncRoute(.)+?\.js$/)
      return options
    })
  }
}

Когда prefetch плагин отключён, вы можете вручную указывать необходимые фрагменты для prefetch с помощью инлайновых комментариев для webpack:

import(/* webpackPrefetch: true */ './someAsyncComponent.vue')

Webpack добавит prefetch-ссылки когда родительский фрагмент будет загружен.

Совет

Использование prefetch ссылок нагружает канал связи. Если у вас большое приложение с множеством асинхронных фрагментов (chunks) и ваши пользователи в основном используют мобильные устройства (а значит, чувствительны к использованию канала связи), вы можете пожелать отключить использование prefetch ссылок и вручную выбирать фрагменты для prefetch.

Отключение генерации index.html

При использовании Vue CLI с существующим бэкендом, вам может потребоваться отключить генерацию index.html, чтобы сгенерированные ресурсы могли быть использованы с другим документом по умолчанию. Для этого добавьте в файл vue.config.js следующее:

// vue.config.js
module.exports = {
  // отключение хэшей в именах файлов
  filenameHashing: false,
  // удаление плагинов webpack связанных с HTML
  chainWebpack: config => {
    config.plugins.delete('html')
    config.plugins.delete('preload')
    config.plugins.delete('prefetch')
  }
}

Однако, это не рекомендуется потому что:

  • Жёстко заданные имена файлов затрудняют реализацию эффективного управления кэшированием.
  • Жёстко заданные имена файлов плохо работают с разделением кода, что генерирует дополнительные файлы JavaScript с различными именами файлов.
  • Жёстко заданные имена файлов не работают с современным режимом.

Вместо этого вы должны использовать опцию indexPath, чтобы указать сгенерированный HTML в качестве шаблона вашего фреймворка на стороне сервера.

Создание многостраничного приложения

Не каждое приложение должно быть одностраничным (SPA). Vue CLI поддерживает создание многостраничных приложений с помощью опции pages в vue.config.js. Код приложения будет эффективно переиспользоваться между его частями для оптимизации скорости загрузки.

Обработка статических ресурсов

Статические ресурсы могут обрабатываться двумя различными способами:

  • Импорт в JavaScript или указание ссылки на них в шаблоне/CSS с использованием относительных путей. Такие ресурсы будут обрабатываться webpack.

  • Расположение в каталоге public и добавление ссылки на них с использованием абсолютных путей. Такие ресурсы просто копируются и не обрабатываются webpack.

Импорты относительных путей

Если вы ссылаетесь на статический ресурс, используя относительный путь (должен начинаться с .) внутри JavaScript, CSS или *.vue файлов, то он будет добавлен в дерево зависимостей webpack. В процессе компиляции все URL ресурсов, такие как <img src="...">, background: url(...) и CSS @import будут обрабатываться как зависимости модуля.

Например, url(./image.png) будет преобразован в require('./image.png'), а тег шаблона

<img src="./image.png">

будет скомпилирован в:

h('img', { attrs: { src: require('./image.png') }})

Внутри используется file-loader для определения конечного расположения файла с хэшем версии и правильный путь относительно корня, а также url-loader для инлайн-встраивания ресурсов, чей размер меньше 8 КБайт, чтобы уменьшить количество HTTP-запросов к серверу.

Изменить размер можно через chainWebpack. Например, чтобы установить лимит в 4 КБайт:

// vue.config.js
module.exports = {
  chainWebpack: config => {
    config.module
      .rule('images')
        .set('parser', {
          dataUrlCondition: {
            maxSize: 4 * 1024 // 4KiB
          }
        })
  }
}

Правила преобразования URL

  • Если в URL абсолютный путь (например, /images/foo.png), он будет оставлен как есть.

  • Если URL начинается с ., он будет интерпретироваться как запрос модуля относительно текущего каталога и разрешаться на основе структуры каталогов вашей файловой системы.

  • Если URL начинается с ~, то всё что после него будет интерпретироваться как запрос модуля. Это означает, что вы можете ссылаться на ресурсы даже внутри node_modules:

    <img src="~some-npm-package/foo.png">
    
  • Если URL начинается с @, то он также будет интерпретироваться как запрос модуля. Это удобно, потому что Vue CLI по умолчанию добавляет псевдоним @ для <projectRoot>/src. (только в шаблонах)

Каталог public

Любые статические ресурсы в каталоге public просто копируются в каталог итоговой сборки и не будут обрабатываться webpack. Вы должны ссылаться на них, используя абсолютные пути.

Обратите внимание, что мы рекомендуем импортировать ресурсы как часть дерева зависимостей модуля, чтобы они обрабатывались webpack со следующими преимуществами:

  • Скрипты и стили минифицируются и объединяются, уменьшая количество сетевых запросов.
  • Недостающие файлы вызывают ошибку сборки вместо ошибок 404 для пользователей.
  • Имена файлов в результате будут с хэшем, поэтому не нужно беспокоиться о том, что браузеры используют старые версии из кэша.

Каталог public предоставляется для крайних случаев, поэтому, когда вы ссылаетесь на него по абсолютному пути, необходимо учитывать, где будет опубликовано ваше приложение. Если публикуется не в корне домена, нужно указать префикс для URL-адресов в publicPath:

  • В public/index.html или других HTML-файлах, используемых html-webpack-plugin в качестве шаблонов, необходимо добавлять префикс в ссылки с помощью <%= BASE_URL %>:

    <link rel="icon" href="<%= BASE_URL %>favicon.ico">
    
  • В шаблонах потребуется сначала передать BASE_URL в компонент:

    data () {
      return {
        publicPath: process.env.BASE_URL
      }
    }
    

    А затем использовать в шаблоне:

    <img :src="`${publicPath}my-image.png`">
    

Когда использовать каталог public

  • Вам требуется файл с определённым именем в каталоге сборки.
  • У вас тысячи изображений и необходимо динамически ссылаться на их пути.
  • Какая-нибудь библиотека несовместима с Webpack и у вас нет другого варианта, кроме как подключения её через тег <script>.