Краткое изложение практики миграции vue-cli на vit2

Vue.js Vite
Краткое изложение практики миграции vue-cli на vit2

Две недели назад (202.02.17),выпущен vit2.0vite 2.0, как интерфейсный инструмент следующего поколения, использующий собственный ESM браузера, является более зрелым, чем 1.0. До этого я началОбратите внимание на такого рода «новые» интерфейсные инструменты.. На этот раз, воспользовавшись выпуском vite 2.0, существующий проект на основе vue-cli(-service) + vue2 был успешно перенесен.

Миграция прошла гладко и заняла менее половины дня. Тем не менее, в течение всего процесса миграции также возникали небольшие проблемы, которые кратко изложены здесь, чтобы облегчить общение и рекомендации для друзей, столкнувшихся с похожими проблемами.

Предыстория проекта

Прежде чем представить конкретную работу по миграции, сначала кратко расскажите о ситуации с проектом. В настоящее время проект запущен менее чем за год, и долгов по наследству, связанных со строительством, не так уж и много. Проект содержит 1897 файлов модулей (включая модули в node_modules), использует стек технологий vue2 + vuex + typescript, а инструмент сборки использует vue-cli (webpack). Это относительно стандартный стек технологий vue. Поскольку это внутренняя система, у проекта более низкие требования к совместимости, и пользователи в основном используют более новый браузер Chrome (некоторые используют Safari).

Миграционная работа

Ниже приводится подробное описание того, какая обработка была выполнена при миграции.

1. Файл конфигурации

Сначала вам нужно установить vite и создать файл конфигурации vite.

npm i -D vite

Используется в сервисе vue-clivue.config.jsВ качестве файла конфигурации; по умолчанию vite необходимо создатьvite.config.tsкак файл конфигурации. Базовый файл конфигурации прост:

import { defineConfig } from 'vite';

export default defineConfig({
  plugins: [
    // ...
  ],
})

Создайте этот файл конфигурации, и предыдущий файл vue.config.js больше не будет использоваться.

2. Запись и файл HTML

Файл записи также необходимо указать в vite. Но в отличие от webpack, в vite вместо указания js/ts в качестве точки входа в качестве точки входа указывается фактический HTML-файл.

В веб-пакете пользователи делают это, устанавливая запись в запись js (например,src/app.js), чтобы указать файл ввода для упаковки js, дополненный HtmlWebpackPlugin для внедрения сгенерированного пути к файлу js в HTML. И vite использует файл HTML напрямую, он будет анализировать тег скрипта в HTML, чтобы найти файл записи js.

Поэтому мы включаем ссылку тега скрипта на файл js/ts в запись HTML:

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width,initial-scale=1.0">
  <title><%= htmlWebpackPlugin.options.title %></title>
</head>

<body>
  <noscript>
    We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled.
  </noscript>
  <div id="app"></div>
+ <script type="module" src="/src/main.ts"></script>
</body>

</html>

Обратите внимание на приведенное выше<script type="module" src="/src/main.ts"></script>Эта строка, которая использует собственный ESM браузера для загрузки скрипта,/src/main.tsЭто исходное местоположение записи js. Когда запускается режим vite dev, он фактически запускает сервер, аналогичный статическому серверу, и обслуживает каталог исходного кода, поэтому нет необходимости в сложном процессе упаковки модулей, таком как веб-пакет. Загрузка зависимостей модуля будет полностью зависеть от браузера.importОбработка синтаксиса, поэтому вы можете увидеть длинный список каскадов загрузки скриптов:

Обратите внимание и здесьКорневые настройки проекта. По умолчанию этоprocess.cwd(), а index.html также ищется в корне проекта. Для удобства буду./public/index.htmlпереехал в./index.html.

3. Используйте плагин vue

vite 2.0 обеспечивает хорошую поддержку проектов vue, но не сильно связан с vue, поэтому поддерживает создание проектов стека технологий vue в виде подключаемых модулей. Подключаемый модуль vue, рекомендуемый в настоящее время на официальном веб-сайте vite 2.0 (2021.2.28), будетSFC для vue3Лучше использовать вместе. Поэтому здесь используется плагин, предназначенный для поддержки vue2.vite-plugin-vue2, поддерживает JSX, а последняя версия такжеподдержка vit2.

Он также очень прост в использовании:

import { defineConfig } from 'vite';
+ import { createVuePlugin } from 'vite-plugin-vue2';

export default defineConfig({
  plugins: [
+   createVuePlugin(),
  ],
});

4. Отображение путей машинописного текста

При создании проекта ts с помощью vite, если вы используетесопоставление путей машинописного текстафункция, требуется специальная обработка, иначе будет ошибка, что модуль не может быть разрешен (не может быть найден):

Здесь нужно использоватьvite-tsconfig-pathsЭтот плагин выполняет синтаксический анализ и замену сопоставлений путей. Принцип относительно прост, примерно плагин viteловушка идентификатора разрешенияэтап, используяtsconfig-pathsЭта библиотека для преобразования сопоставлений путей в фактические возвращенные сопоставления. Если вам интересно, вы можете посмотреть на реализацию этого плагина, которая относительно краткая.

Конкретное использование заключается в следующем:

import { defineConfig } from 'vite';
import { createVuePlugin } from 'vite-plugin-vue2';
+ import tsconfigPaths from 'vite-tsconfig-paths';

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    createVuePlugin(),
+   tsconfigPaths(),
  ],
});

5. Замените CommonJS

vite использует ESM как модульное решение, поэтому его использование не поддерживается.requireспособ импорта модулей. В противном случае он сообщит во время выполненияUncaught ReferenceError: require is not definedошибка (браузер не поддерживает CJS, естественно инъекция метода не требуется).

Кроме того, могут возникнуть проблемы совместимости с ESM и CJS. Конечно, это не проблема со сборкой vite, но об этом нужно знать. Проще говоря, в ESM есть понятие по умолчанию, а в CJS — нет. Любая экспортируемая переменная рассматривается CJS как свойство объекта module.exports, а экспорт ESM по умолчанию — это просто свойство module.exports.default объекта cjs. Например, в typescript мы будем использовать конфигурацию esModuleInterop, чтобы позволить tsc добавить некоторый совместимый код, помогающий разрешать импортированные модули, и аналогичные операции есть в webpack.

Например, предыдущий код:

module.exports = {
    SSO_LOGIN_URL: 'https://xxx.yyy.com',
    SSO_LOGOUT_URL: 'https://xxx.yyy.com/cas/logout',
}
const config = require('./config');

И экспорт, и импорт необходимо изменить на ESM, например:

export default {
    SSO_LOGIN_URL: 'https://xxx.yyy.com',
    SSO_LOGOUT_URL: 'https://xxx.yyy.com/cas/logout',
}
import config from './config';

6. Как использовать переменные окружения

При использовании vue-cli (webpack) мы часто используем переменные среды для оценки кода во время выполнения, например:

const REPORTER_HOST = process.env.REPORTER_TYPE === 'mock'
  ? 'http://mock-report.xxx.com'
  : 'http://report.xxx.com';

vite по-прежнему поддерживает переменные средыиспользуется, но больше не доступенprocess.envтакой доступ. но нужно пройтиimport.meta.envдля доступа к переменным среды:

-const REPORTER_HOST = process.env.REPORTER_TYPE === 'mock'
+const REPORTER_HOST = import.meta.env.REPORTER_TYPE === 'mock'
  ? 'http://mock-report.xxx.com'
  : 'http://report.xxx.com';

Подобно веб-пакету, vite такжеНекоторые переменные окружения встроены, можно использовать напрямую.

7.import.meta.env types

Дополнение: vite предоставляет необходимые ему определения типов, которые можно применять напрямуюvite/clientЧтобы представить, вы можете добавить его самостоятельно без следующих методов.

Если вы передаете машинописный текстimport.meta.envДля доступа к переменным среды может появиться сообщение об ошибке ts:类型“ImportMeta”上不存在属性“env”.

Это связано с тем, что в текущей версии (v4.2.2)import.metaОпределение по-прежнемупустой интерфейс:

interface ImportMeta {
}

Но мы можем дополнительно определить тип ImportMeta в проекте с помощью возможности слияния интерфейса, чтобы расширитьimport.meta.envподдержка типа. Например, проект ts, ранее сгенерированный vue-cli, будет сгенерирован в каталоге src.vue-shims.d.tsфайл, вы можете расширить поддержку типа env здесь:

declare global {
  interface ImportMeta {
    env: Record<string, unknown>;
  }
}

Таким образом, вы не получите ошибку.

8. веб-пакет требует контекста

В вебпаке мы можем передатьrequire.contextМетод разрешает модуль «динамически». Обычной практикой является указание каталога и загрузка некоторых модулей через обычное сопоставление, чтобы после добавления новых модулей можно было добиться эффекта «динамического автоматического импорта».

Например, в проекте мы динамически сопоставляем файл route.ts в папке modules и задаем конфигурацию роутера в глобальном vue-router:

const routes = require.context('./modules', true, /([\w\d-]+)\/routes\.ts/)
    .keys()
    .map(id => context(id))
    .map(mod => mod.__esModule ? mod.default : mod)
    .reduce((pre, list) => [...pre, ...list], []);

export default new VueRouter({ routes });

Структура файла следующая:

src/modules
├── admin
│   ├── pages
│   └── routes.ts
├── alert
│   ├── components
│   ├── pages
│   ├── routes.ts
│   ├── store.ts
│   └── utils
├── environment
│   ├── store
│   ├── types
│   └── utils
└── service
    ├── assets
    ├── pages
    ├── routes.ts
    ├── store
    └── types

require context — это уникальный модульный метод, предоставляемый webpack, а не языковой стандарт, поэтому require context больше нельзя использовать в vite. Однако если его полностью изменить на ручной импорт модулей разработчиками, то, во-первых, изменения в существующем коде легко приведут к пропускам импорта модулей, во-вторых, от этого «гибкого» механизма придется отказаться, а последующие режимы разработки также будут изменены на некоторые степень. К счастью, vite2.0 предоставляетИмпорт модулей для шаблонов глобусов. Эта функция может достичь вышеуказанных целей. Конечно, потребуются некоторые изменения кода:

const routesModules = import.meta.globEager<{default: unknown[]}>('./modules/**/routes.ts');
const routes = Object
  .keys(routesModules)
  .reduce<any[]>((pre, k) => [...pre, ...routesMod[k].default], []);

export default new VueRouter({ routes });

в основном дляrequire.contextизменить наimport.meta.globEager, адаптируя тип возвращаемого значения. Конечно, для поддержки типов можно добавить некоторые типы в интерфейс ImportMeta:

declare global {
  interface ImportMeta {
    env: Record<string, unknown>;
+   globEager<T = unknown>(globPath: string): Record<string, T>;
  }
}

Кроме того, упомяните это снова,import.meta.globEagerВыполнит статический анализ во время сборки, чтобы заменить код статическими операторами импорта. Если вы хотите поддерживать динамический импорт, используйтеimport.meta.globметод.

9. API-прокси

vite2.0 по-прежнему предоставляет HTTP-сервер во время локальной разработки (режим DEV), а также поддерживаетУстановить прокси через пункт прокси. Он также используется за тем же, что и webpackhttp-proxy, поэтому настройки прокси для vue-cli можно перенести на vite:

import { defineConfig } from 'vite';
import tsconfigPaths from 'vite-tsconfig-paths';
import { createVuePlugin } from 'vite-plugin-vue2';
+ import proxy from './src/tangram/proxy-table';

export default defineConfig({
  plugins: [
    tsconfigPaths(),
    createVuePlugin(),
  ],
+ server: {
+   proxy,
+ }
});

10. Вставка HTML-контента

На основе vue-cli мы можем использовать HtmlWebpackPlugin веб-пакета для замены значений в HTML, например<%= htmlWebpackPlugin.options.title %>Эта форма заменяет переменную шаблона во время компиляции фактическим значением заголовка. Также очень просто реализовать такую ​​функцию, напримерvite-plugin-html. Этот плагин реализует внедрение переменных шаблона на основе ejs черезtransformIndexHtmlХук, который получает необработанную строку HTML, затем отображает введенные переменные через ejs и возвращает.

Ниже приведен метод настройки с использованием vite-plugin-html после миграции:

import { defineConfig } from 'vite';
import tsconfigPaths from 'vite-tsconfig-paths';
import { createVuePlugin } from 'vite-plugin-vue2';
+ import { injectHtml } from 'vite-plugin-html';

export default defineConfig({
  plugins: [
    tsconfigPaths(),
    createVuePlugin(),
+   injectHtml({
+     injectData: {
+       title: '用户管理系统',
+     },
    }),
  ],
  server: {
    proxy,
  },
});

Измените запись переменной шаблона HTML в соответствии с соответствующими требованиями:

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width,initial-scale=1.0">
- <title><%= htmlWebpackPlugin.options.title %></title>
+ <title><%= title %></title>
</head>

<body>
  <noscript>
-   We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled.
+   We're sorry but <%= title %> doesn't work properly without JavaScript enabled.
  </noscript>
  <div id="app"></div>
  <script type="module" src="/src/main.ts"></script>
</body>

</html>

11. Обработка совместимости

В вводной информации о проекте упоминается, что у проекта очень низкие требования к совместимости, поэтому эта часть фактически не участвует в миграции.

Конечно, если есть проекты, требующие совместимости, можно использовать@vitejs/plugin-legacyплагин. Плагин упаковывает два набора кода, один для современных браузеров и один для старых браузеров с различными полифиллами и совместимостью синтаксиса. Также используйте в HTMLмодульная/номодульная технологияреализовать "условную загрузку" в новых/старых браузерах.

Суммировать

В проекте содержится 1897 файлов модулей (включая модули в node_modules), а время сборки до и после миграции (без кеша) следующее:

vue-cli vite 2
режим разработки ~8s ~400ms
рабочий режим ~42s ~36s

Можно видеть, что эффективность конструкции vite2 значительно повышается в режиме DEV. Это также связано с тем, что в режиме DEV выполняется только небольшая обработка файла модуля и не выполняется тяжелая работа по упаковке. используйте esbuild и rollup для сборки, поэтому повышение эффективности в этом проекте не очевидно.


Выше перечислены некоторые проблемы, с которыми столкнулся автор при переносе vite 2.0 с vue-cli. Все они являются относительно небольшими точками, и в целом миграция не встретила особых препятствий, и мигрировала менее чем за полдня. Конечно, это также зависит от работы по стандартизации JavaScript и HTML в последние годы, так что основной код, который мы пишем, также может иметь определенное единообразие. Это также одно из больших преимуществ, которые эти интерфейсные инструменты приносят нам в программирование, ориентированное на будущее. Я надеюсь, что эта статья может дать ссылку друзьям, которые собираются попытаться перейти на vite 2.0.