Как и зачем использовать JSX с Vue.js

Я знаю, что есть, по крайней мере, некоторые поклонники Vue.js, которые ненавидят идею размещения HTML в JavaScript. Файлы .vue, которые помещают JavaScript в <script> теги «там, где он принадлежит», являются наиболее близкими к объединению разметки и кода шаблона. Эта статья также для них. Я постараюсь объяснить, почему их опасения не достигают цели. Затем я объясню, как начать работу с JSX и TypeScript на Vue.js.

Нет, не совсем, это не HTML. Это другой синтаксис для того же вызова h().

Что на самом деле представляет собой JSX

Если вы уже знаете, что такое JSX, не стесняйтесь переходить к следующему разделу, где я расскажу о том, как выполняется настройка.

JSX - это не HTML. Период. Попытка сравнить JSX с HTML похожа на попытку сравнить JavaScript с Java. Они могут выглядеть похожими, но это совершенно разные звери.

Чтобы понять JSX, вам сначала нужно понять функцию рендеринга Vue.js.

Как вы уже знаете, Vue.js может использовать скомпилированные шаблоны или функции рендеринга. Скомпилированные шаблоны легко рассуждать (если вы знаете HTML). Это то, чем они являются: разметка HTML в строковой форме. Они компилируются в JavaScript. Функции рендеринга, как следует из названия, уже содержат код, поэтому компиляции нет (во время выполнения или иначе). Они генерируют виртуальные деревья DOM.

Обычно вы пишете такие функции рендеринга:

@Component
class Foo extends Vue {
  name = "foo";
  public render(h: CreateElement): VNode {
    return h(
      "div", 
      {
        "class": "foo", 
        attribs: {"data-id": "12"}
      }, 
      [this.name]
    );
  }
}

Это преобразуется в <div class="foo" data-id="12">foo</div>. Печатать это не так сложно, но нужно подумать, прежде чем вы поймете, что делает. Я сам смог написать это после 15 минут практики. Я не думаю, что это такой уж плохой способ его написания, но он не похож на HTML, и я понимаю, что кому-то может казаться, что это могло произойти из-за чьих-то посторонних взглядов.

Этот API низкоуровневый. Он предназначен для того, чтобы оставаться под сахарным покровом скомпилированных шаблонов и не использоваться напрямую (по крайней мере, это мое предположение; я не могу представить, зачем кому-то делать этот API для повседневного использования. -дневное использование).

Просто щелкни пальцем. Уродливый код, приведенный выше, превращается примерно в это:

@Component
class Foo extends Vue {
  name = "foo";
  public render(h: CreateElement): VNode {
    return (
      <div class="foo" attribs={{"data-id": "12"}}>
        {this.name}
      </div>
    );
  }
}

Это что-то вроде HTML, правда? Если прищуриться очень сильно. И посмотри в другую сторону. Нет, не совсем, это не HTML. Это другой синтаксис для того же вызова h(). Не больше и не меньше: строго синтаксис. Под капотом вы все еще вызываете функции, и вы должны знать сигнатуру функции, чтобы успешно ее вызвать. Вы не можете, например, сделать что-то вроде <div class="foo" data-id="12">. Это не будет работать.

В качестве примечания: у React гораздо более приятный синтаксис для написания JSX (они его изобрели, так что он фигурирует).

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

Как заставить JSX работать с TypeScript

Теперь, когда мы ясно понимаем, что JSX находится в контексте Vue.js, давайте поговорим о том, как заставить его работать с TypeScript.

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

Шаг 1. Настройте компилятор TypeScript

Файл tsconfig.json должен содержать следующие параметры компилятора:

{
  "compilerOptions": {
    ....
    "jsx": "react",
    "jsxFactory": "h"
  }
}

Параметр jsx включает JSX. Второй вариант, jsxFactory, указывает TypeScript использовать h() вызовы для тегов JSX. По умолчанию это React.createElement(), что, как вы, наверное, догадались, работает только с React.

Шаг 2. Добавьте определения типа JSX

Где-то в вашем проекте вам нужно включить это определение типа:

import Vue, { VNode } from "vue";
declare global {
  namespace JSX {
    interface Element extends VNode {}
    interface ElementClass extends Vue {}
    interface IntrinsicElements {
      [elem: string]: any;
    }
  }
}

Я добавляю это в свой проект: обычно у меня есть файл с именем app.d.ts в корне исходных текстов проекта, и я добавляю туда такую ​​строку:

///<reference path="./types/jsx.d.ts"/>

В качестве альтернативы вы можете добавить typesRoot ключ в свой tsconfig.json и указать в нем каталог, в котором вы будете хранить файл jsx.d.ts:

{
  "compilerOptions": {
    ...
    "typesRoot": ["./node_modules/@types", "./types"]
  }
}

Шаг 3: переименуйте модуль TypeScript в .tsx

Модули, содержащие JSX, должны иметь .tsx расширение. Не спрашивайте почему.

Шаг 4. Прочтите об API

API - это непросто. На самом деле это довольно некрасиво. Но вы должны знать это, чтобы писать на JSX эффективно.

Как сделать это лучше

Это мысль, с которой я сейчас обдумываю. Весь опыт можно было бы значительно улучшить, если бы h() API был немного лучше с самого начала.

Например, если бы он мог разумно различать атрибуты HTML, свойства, привязки, стили и классы, нам бы не пришлось их вкладывать. И так далее. Поскольку h() - это просто функция в локальной области видимости, я полагаю, мы могли бы подойти к ней довольно творчески.

Это просто домашнее задание или любимый проект.

Заключение

Надеюсь, теперь вы хотя бы понимаете, что такое JSX и хотите ли вы его использовать. Если вам понравилась эта идея, я надеюсь, что помог вам понять, как интегрировать ее в TypeScript.

Если вы нашли эту статью полезной, не забудьте порекомендовать ее и поделиться ею.