Vue CLI: меняем индекс-файл при сборке
Те, кто уже работал с Vue.js при помощи Vue CLI, знают, что эта надстройка над вебпаком берёт очень многие вещи на себя, упрощая процесс сборки проекта и развития его экосистемы.
Можно, к примеру, добавить плагин для PWA и без лишних телодвижений превратить своё приложение в PWA. Также Vue CLI контролирует сборку приложения, создавая файловую структуру и заполняя файл index.html
Поворотный момент
Буквально неделю назад передо мной встала задача в результате сборки проекта при помощи Vue CLI получать не html-файл, а php, в котором реализуется некая серверная логика.
Поверхностное гугление показало, что можно использовать webpack-php-loader для сборки проекта. Однако это не решало мою проблему: насколько я понял, этот лоадер запускает php на машине, на которой происходит сборка, рендерит его и на выходе всё равно выдаёт html. Мне это не подходило, так как в php я работал с юзерагентом, передаваемым конкретным пользователем.
Решение - vue.config.js
В итоге мне удалось найти инструкцию, как указать файл, который при сборке будет считаться за “шаблон”, а также как переименовать выходной файл после сборки проекта. Делается это в файле vue.config.js.
Давайте определим себе задачу: закрыть доступ пользователям Internet Explorer 9.
Вкратце, этот файл позволяет (очень сложным путём, по-моему мнению) переопределить некоторые настройки вебпака для сборки проекта. Именно здесь мы и будем работать.
Если у вас ещё нет этого файла, создайте его в корне вашего проекта (на одном уровне с package.json) и поместите туда экспортный объект в синтаксисе Node.js:
// ./vue.config.js
module.exports = {
}Далее, в папке src вашего проекта, создайте файл-шаблон, который будет использоваться при сборке. ВАЖНО: не удаляйте оригинальный файл index.html из папки public! Он нужен нам, чтобы работать в development-режиме и сохранить всякие прелести вроде хот-релоад.
Допустим, он называется index_template.php Скопируйте в него содержимое файла ./public/index.html, добавив где нужно логику на php.
// ./src/index_template.php
<?php
$isIE9 = strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE 9.') !== false;
if ($isIE9) {
die('Браузер не поддердживается!');
}
?>
<!DOCTYPE html>
<html lang="ru">
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon.png">
<title>Site title</title>
</head>
<body>
<noscript>
<strong>We're sorry but website doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript>
<div id="app"></div>
<!-- built files will be auto injected -->
</body>
</html>
Здесь мы просто для примера определяем, точно ли IE9 перед нами, и если да, прекращаем выполнение скрипта.
Осталось прописать настройки в vue.config.js
Первым делом сообщим, что после наполнения файла содержимым сохранять его нужно не как index.html, а как index.php:
// ./vue.config.js
module.exports = {
indexPath: 'index.php'
}Эта настройка создаст в папке dist файл с нужным расширением.
Далее напишем настройку для изменения файла-шаблона. Делается это, на первый вгляд, весьма нетривиально, но сейчас я не хотел бы углубляться в устройство конфиг-файла Vue. Так что рассмотрим лишь те моменты, которые важны для темы публикации.
// ./vue.config.js
module.exports ={
indexPath: 'index.php',
// Добавляем это:
chainWebpack: config => {
if (process.env.NODE_ENV === 'production') {
config
.plugin('html')
.tap(args => {
args[0].template = './src/index_template.php'
args[0].minify.removeAttributeQuotes = false
return args
})
}
}
}Здесь мы обращаемся к html-загрузчику вебпака, и сообщаем, что при сборке в production шаблон теперь находится по адресу ./src/index_template.php. Также мы говорим, что при минификации кода не нужно удалять кавычки атрибутов, так как иногда это может нарушить работу php-скрипта.
На этом всё! Попробуйте запустить npm run build и вы увидите в папке dist файл index.php, полностью готовый к работе на продакшн-сервере!
Таким образом вы можете перенаправить вывод сборки в любой другой файл: TWIG, EJS и так далее.
Если у вас есть другое решение этого вопроса - я буду только рад с ним ознакомиться.