# Однофайловые компоненты

# Введение

Во многих проектах, глобальные компоненты объявляются с помощью app.component и затем app.mount('#app') для указания элемента-контейнера в теле каждой страницы.

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

  • Глобальное определение заставляет указывать уникальное имя каждому компоненту.
  • В строковых шаблонах не хватает подсветки синтаксиса. Кроме того, для многострочного HTML приходится использовать уродливые конструкции со слэшами для переноса строк.
  • Нет модульной поддержки CSS — в то время как HTML и JavaScript разбиваются на модули-компоненты, CSS оказывается за бортом.
  • Отсутствие шага сборки ограничивает использованием HTML и ES5 JavaScript и не позволяет использовать препроцессоры, например Pug (бывший Jade) и Babel.

Эти проблемы решаются с помощью однофайловых компонентов, файлов с расширением .vue. Их можно использовать с инструментами сборки, такими как Webpack и Browserify.

Вот пример такого файла, который называется Hello.vue:

Пример однофайлового компонента (кликните для просмотра кода)

С однофайловыми компонентами получили:

Как говорилось ранее, можно также использовать препроцессоры, такие как Pug, Babel (с модулями ES2015) и Stylus для создания более понятных и функциональных компонентов.

Пример однофайлового компонента с использованием пре-процессоров (кликните для просмотра кода)

Перечисленные варианты даны лишь для примера. С тем же успехом можно использовать TypeScript, SCSS, PostCSS, или любые другие пре- или постпроцессоры. При использовании Webpack вместе с vue-loader также получаете и прекрасную поддержку CSS-модулей.

# Что насчёт разделения ответственности?

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

Если идея однофайловых компонентов не по душе — можно вынести в отдельные файлы JavaScript и CSS и пользоваться возможностями горячей замены модулей и прекомпиляции:

<!-- my-component.vue -->
<template>
  <div>Это будет предварительно скомпилировано</div>
</template>
<script src="./my-component.js"></script>
<style src="./my-component.css"></style>
1
2
3
4
5
6

# Начало работы

# Песочница с примером

Начать изучение однофайловых компонентов можно с этого простого todo приложения (opens new window) на CodeSandbox.

# Для новичков в модульных системах сборки JavaScript

С использования .vue-компонентов начинается мир продвинутых JavaScript-приложений. А это значит, что нужно будет освоить некоторые дополнительные инструменты, если ещё этого не сделали:

После того как уделили время этим ресурсам, советуем разобраться с Vue CLI (opens new window). Следуйте инструкциям, чтобы создать рабочий проект с .vue-компонентами, ES2015, webpack и горячей перезагрузкой модулей.

# Для продвинутых пользователей

О большинстве настроек конфигурации сборки позаботится CLI, но при необходимости всё можно настроить детальнее через соответствующие опции конфигурации (opens new window).

Если предпочитаете с нуля создавать конфигурацию сборки, то потребуется вручную настроить webpack для работы с vue-loader (opens new window). Подробнее о webpack можно узнать в его официальной документации (opens new window) и на сайте webpack learning academy (opens new window).

# Сборка с Rollup

Большая часть времени разработки сторонней библиотеки уходит на то, чтобы позволить пользователям библиотеки использовать преимущества tree shaking (opens new window). Для поддержки tree-shaking требуется сборка в виде esm модуля. Поскольку webpack и, соответственно, vue-cli не поддерживают сборку esm модулей, потребуется использовать Rollup (opens new window).

# Установка Rollup

Сначала необходимо установить Rollup и несколько зависимостей для него:

npm install --save-dev rollup @rollup/plugin-commonjs rollup-plugin-vue
1

Это минимальный набор плагинов rollup, необходимых для компиляции esm модулей. Можно также добавить rollup-plugin-babel (opens new window) для транспиляции кода и node-resolve (opens new window), если используются зависимости, которые должны поставляться в итоговой сборке библиотеки.

# Конфигурация Rollup

Для конфигурации сборки с Rollup нужно создать файл rollup.config.js в корне проекта:

touch rollup.config.js
1

После создания файла нужно открыть его в любом редакторе и добавить следующий код:

// импорт используемых плагинов
import commonjs from 'rollup-plugin-commonjs'
import VuePlugin from 'rollup-plugin-vue'
import pkg from './package.json' // импорт package.json для переиспользования имени

export default {
  // файл, который будет содержать все экспортируемые компоненты/функции
  input: 'src/index.js',
  // массив выходных форматов
  output: [
    {
      file: pkg.module, // название создаваемой esm библиотеки
      format: 'esm', // выбранный формат
      sourcemap: true, // флаг rollup для генерации sourcemaps
    }
  ],
  // массив плагинов, которые используем
  plugins: [
    commonjs(),
    VuePlugin()
  ],
  // указываем rollup не добавлять Vue в сборку библиотеки
  external: ['vue']
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

# Конфигурирование package.json

Чтобы воспользоваться только что созданным esm модулем необходимо добавить в файл package.json несколько полей:

 "scripts": {
   ...
   "build": "rollup -c rollup.config.js",
   ...
 },
 "module": "dist/my-library-name.esm.js",
 "files": [
   "dist/",
 ],
1
2
3
4
5
6
7
8
9

Таким образом уточняем следующее:

  • каким образом собирать пакет
  • какие файлы хотим упаковать в пакет
  • какой файл будет esm модулем

# Сборка umd и cjs модулей

Можно одновременно собирать и umd и cjs модули, достаточно добавить несколько строк конфигурации в rollup.config.js и package.json

# rollup.config.js
output: [
  ...
   {
      file: pkg.main,
      format: 'cjs',
      sourcemap: true,
    },
    {
      file: pkg.unpkg,
      format: 'umd',
      name: 'MyLibraryName',
      sourcemap: true,
      globals: {
        vue: 'Vue',
      },
    },
]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# package.json
"module": "dist/my-library-name.esm.js",
"main": "dist/my-library-name.cjs.js",
"unpkg": "dist/my-library-name.global.js",
1
2
3