Как и зачем настраивать сборку, позволяющую писать компоненты .vue на TypeScript.

Хорошо, может быть, и не целый день, но настройка инструментов для нового проекта все равно занимает слишком много времени. И некоторые вещи на мой вкус все еще слишком сложны. Не хорошее "сложное", как в сложном. Скорее утомительно. Да, я говорю о webpack, TypeScript и .vue файлах. Здесь я хочу показать, что я сделал, и почему я все же решил это сделать.

Если вы просто ищете быстрое исправление TypeScript, это относительно просто. Берите webpack-блоки и настраивайте менее чем за 5 минут. То, что я пытался сделать, было немного более экзотическим, если хотите. Я хотел использовать Vue и, в частности, .vue файлы с TypeScript. Информация разбросана по всей сети, поэтому я подумал, что неплохо было бы собрать ее здесь в качестве краткого справочника.

ОБНОВЛЕНИЕ от 8 мая 2017 г. С тех пор, как я написал эту статью, почти выпущена версия webpack-blocks 1.0.0. Он уже доступен в NPM, поэтому я нашел время, чтобы выпустить некоторый код, обсуждаемый в этой статье. Я опубликую отдельный пост, в котором будут описаны изменения по сравнению с исходной статьей.

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

Почему файлы .vue?

Прежде всего, позвольте мне объяснить, почему я хотел начать с .vue файлов (если вы не знаете, что это такое, посмотрите здесь). Эти однофайловые многоязычные пакеты - это не просто средства для группировки того, что в противном случае было бы набором разрозненных файлов. Нет, у них есть свои навороты, которые выходят за рамки простого объединения кода.

Например, шаблоны HTML закодированы в HTML, поэтому вы получаете подсветку синтаксиса, автозаполнение с учетом контекста и / или поддержку emmet. Великих разработчиков JavaScript мало, поэтому кодирование простого HTML (в отличие от JSX и, что еще хуже, гиперкрипта) может иметь большое значение. Да, я знаю, что есть истории о дизайнерах и новичках, которые берут в руки гиперкрипт и тому подобное, и им действительно нравится, но тогда вы должны помнить, что даже опытные разработчики JavaScript иногда не сдаются без боя.

Во-вторых, CSS с областью видимости. Если вы все еще думаете, что БЭМ имеет место в правильно настроенной интерфейсной структуре, тогда хорошо, вы понимаете важность и проблемы хорошо организованного CSS. Вы можете получить удовольствие от ограниченного CSS. Я не собираюсь продавать вам CSS с ограниченной областью видимости. Это как наркотики: они продаются сами по себе. Просто попробуйте. Попробуй.

Все это, а также тот факт, что я имею дело с одним файлом, а не с тремя или четырьмя, являются достаточными аргументами, чтобы потратить дополнительное время на то, чтобы .vue файлы работали с TypeScript.

Почему именно TypeScript?

Это то, к чему вы должны прийти самостоятельно, если вообще когда-либо. Раньше люди использовали нетипизированный JavaScript, и он действительно работает. Фактически, я пытался выбрать между TypeScript и LiveScript, который представляет собой нетипизированную функционально приправленную версию CoffeeScript с кратким и несколько странным синтаксисом.

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

Если вам нужно наглядно показать, каково использовать TypeScript в производстве, есть отличная статья от команды Slack.

Хватит говорить, давайте код… а может, и нет

Прежде чем мы сможем кодировать, нам нужно настроить инструменты.

Сначала подберем webpack-блоки. Это самый простой способ настроить webpack, о котором я знаю. Что ж, проще всего после простого копирования и вставки существующей конфигурации, но вы меня поняли.

Теперь сразу же webpack-block не поддерживает .vue файлы. Есть два сторонних пакета, которые позволяют использовать .vue файлы.

Встроенная конфигурация TypeScript в блоках webpack использует awesome-typescript-loader. Это хороший загрузчик, но он не хорошо работает с .vue файлами. (У него тоже странное имя, но это моя проблема.) В дополнение к пакету для настройки vue-loader нам также нужен пакет, который будет настраивать ts-loader, который имеет некоторые положения для работы с форматами контейнеров, такими как .vue.

npm i -D webpack-blocks-vue webpack-blocks-ts

В итоге вы получаете что-то вроде этого webpack.config.js файла. Важные моменты, на которые следует обратить внимание:

  • Мы передаем параметр { appendTsSuffixTo: [/\.vue$/] } в ts-loader, потому что в противном случае компилятор TypeScript не хочет сотрудничать. Это приводит к тому, что .vue файлы обрабатываются как .vue.ts, именно так, как они нравятся компилятору TypeScript.
  • Мы не используем Babel. Если вы хотите использовать JSX, возможно, вы захотите его использовать, но я этого не сделаю.
  • Мы передаем { esModule: true } в vue-loader. Эта опция указывает загрузчику испускать модули ES2015 вместо модулей CommonJS. Судя по всему, TypeScript не любит модули CommonJS.

Вам также необходимо сообщить TypeScript, что такое .vue файлы и как с ними работать. Для этого добавляем в дерево исходных текстов vue.d.ts файл. Это определение сообщает TypeScript, каким будет тип экспорта по умолчанию из файла .vue.

Можем ли мы сейчас кодировать?

Да мы можем. Как я уже упоминал во введении, нельзя просто писать код, как раньше, и ожидать, что все заработает. Кодирование .vue файлов для TypeScript требует другого подхода. Но не бойтесь. Альтернативный синтаксис имеет большой смысл и, на мой взгляд, делает код более читаемым (не говоря уже о хороших качествах проверки типов).

Сначала вам нужно добавить дополнительную зависимость: vue-property-decorator.

Тогда ваш компонент будет выглядеть примерно так:

<template>
  <div class="hello">Hello, {{ name }}</div>
</template>
<script lang="ts">
import Vue from 'vue'
import { Component, Prop } from 'vue-property-decorator'
@Component
export default class Hello extends Vue {
  @Prop
  name: string
}
</script>
<style scoped>
.hello {
  font-size: 200px;
  font-family: sans-serif;
}
</style>

Я не буду вдаваться в подробности здесь, потому что и vue-property-decorator, и vue-class-component, на котором он основан, довольно хорошо документированы и просты в использовании.

Главное, на что следует обратить внимание, это то, что этот стиль удаляет большую часть магии / шаблона (или, по крайней мере, скрывает его). Вместо того, чтобы определять наблюдателей и методы во вложенных объектах, а затем использовать this для обозначения внешнего объекта (который по праву запускает проверку типов TypeScript), все методы определены для объекта, с которым привязан this. Это делает все немного проще для понимания и следования, делает вещи немного ближе к тому, как обычно работает JavaScript.

Вы найдете полный пример в моем репозитории vue-ts-sandbox.

В качестве примечания: даже если вас не волнует TypeScript, вы можете использовать эти декораторы с Babel.

Стоит ли оно того?

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

Как я уже сказал в разделе Почему именно TypeScript, вы должны достичь этого самостоятельно.

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

Прямо сейчас для этого требуются дополнительные усилия, но подумайте об этом: модульное тестирование требует немного дополнительных усилий (гораздо больше, чем это!), И никто не будет спорить, что модульное тестирование того не стоит. В том же духе это просто еще один уровень, который способствует качеству кода. Во всяком случае, я так на это смотрю.