- PVSM.RU - https://www.pvsm.ru -

Новый механизм JSX трансформации в React 17 Release Candidate

В React 17 Release Candidate появляется новый способ трансформации JSX. С ним, в бандле, не понадобится сам Реакт, хотя для использования хуков он всё ещё нужен. Это и есть основной бенефит нового механизма. Под катом краткий перевод статьи в блоге ReactJS [1].

Что такое JSX Трансформация

Так как браузеры не понимают JSX “из коробки”, разработчики полагаются на компиляторы типа Babel или Typescript что бы трансформировать JSX в обычный JS. В React 17 Release Candidate [2] появился новый, опциональный механизм трасформации JSX в JS.
Вот его преимущества:

  • Использование JSX без импорта Реакт
  • В зависимости от настроек бандл может слегка уменьшиться
  • В будущем будут доступны фичи для упрощения работы с реактом

(Возможно я не совсем точно перевёл — вот оригинал: It will enable future improvements that reduce the number of concepts you need to learn React)

Апгрейд никак не меняет сам JSX и все компиляторы как работали так и будут работать. Нет никаких планов по отказу от них. Планируется поддержка нового механизма JSX Transform для старых версий Реакт: 16.х, 15.х, 14.х, вот здесь [3] инструкции для апгрейда.

Что изменилось

Старая JSX трасформация работала следующим образом:
Код

import React from 'react';

function App() {
  return <h1>Hello World</h1>;
}

Трасформировался в

import React from 'react';

function App() {
  return React.createElement('h1', null, 'Hello world');
}

Но это не супер и вот почему:

Что бы это решить в React 17 появляются две новые точки входа предназначенные для использования другими инструментами такими как Babel и Typescript и теперь вместо трансформации в React.createElement импортируются и вызываются новые функции из пакета React.

Предположим ваш код выглядел вот так:

function App() {
  return <h1>Hello World</h1>;
}

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

// Inserted by a compiler (don't import it yourself!)
import {jsx as _jsx} from 'react/jsx-runtime';

function App() {
  return _jsx('h1', { children: 'Hello world' });
}

Новый механизм не импортирует React, хотя он всё ещё нужен для работы хуков.

Новая трансформация полностью совместима со всем существующим JSX кодом, ничего менять не придётся. Вот здесь [5] технические подробности работы новой трансформации JSX.

Как апгрейдить

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

Для апгрейда нужны две вещи:

  • Версия Реакт с поддержкой новой трансформации. Пока что это только 17, но в будущем 16.х, 15.х и 14.х
  • Совместимый компилятор (см. ниже)

Create React App
Create React App поддержка будет в релизе v4.0 [6] сейчас он в бета тестировании (на 22.09.20)

Next.js
Next.js v9.5.3 [7]+ уже использует новую Реакт трансформацию для совместимых версий.

Gatsby
Gatsby v2.24.5 [8]+ уже использует новую Реакт трансформацию для совместимых версий.

примечание

Если у вас в Gatsby вот такая ошибка [9] после апгрейда на 17.0.0-rc.2, запустите npm update

Ручная настройка Babel
Поддержка с версии v7.9.0 [10] и выше

Если вы используете babel [11]/plugin-transform-react-jsx:

# npm
npm update @babel/core @babel/plugin-transform-react-jsx
# yarn
yarn upgrade @babel/core @babel/plugin-transform-react-jsx

Если вы используете babel [11]/preset-react:

# npm
npm update @babel/core @babel/preset-react
# yarn
yarn upgrade @babel/core @babel/preset-react

Сейчас для трансформации JSX, в babel [11]/plugin-transform-react-jsx и в babel [11]/preset-react, по умолчанию включена опция {«runtime»: «classic»} это старая версия трансформации. Для включения новой трансформации нужна опция {«runtime»: «automatic»}

Если вы используете babel [11]/preset-react

{
  "presets": [
    ["@babel/preset-react", {
      "runtime": "automatic"
    }]
  ]
}

Если вы используете babel [11]/plugin-transform-react-jsx

{
  "plugins": [
    ["@babel/plugin-transform-react-jsx", {
      "runtime": "automatic"
    }]
  ]
}

Начиная с версии Babel 8, «automatic» будет значением по умолчанию для обоих плагинов. Вот здесь более подробная документация @babel/plugin-transform-react-jsx [12] and @babel/preset-react [13].

Примечание

Если вы используете не Реакт, вы можете использовать опцию importSource для импорта, если конечно ваша библиотека предоставляет точки входа. Вы так же можете продолжать использовать классическую трансформацию, которая будет поддерживаться и дальше.

ESLint
Если у вас плагин eslint-plugin-react [14], то правила react/jsx-uses-react и react/react-in-jsx-scope больше не нужны и их можно удалить.

{
  // ...
  "rules": {
    // ...
    "react/jsx-uses-react": "off",
    "react/react-in-jsx-scope": "off"
  }
}

TypeScript
Поддержка JSX трансформации с версии 4.1 beta [15].

Flow
Поддержка JSX трансформации с версии 0.126.0 [16] и выше

Как убрать неиспользуемые импорты React

Поскольку новая JSX трансформация автоматически импортирует react/jsx-runtime, React больше не нужен в области видимости для использования JSX. Неиспользуемые импорты это не критично, но если хотите удалить, рекомендуется использовать скрипт codemod.

cd your_project
npx react-codemod update-react-imports

В результате:

  • Удалятся все неиспользуемые импорты React
  • Изменятся все импорты типа import React from «react» на именованные import { useState } from «react». Это предпочтительный способ импорта. Codemod не затронет импорты типа import * as React from «react», это тоже валидный импорт и в 17 версии он будет работать, но в дальнейшем мы будем просить избавляться от него

Код

import React from 'react';

function App() {
  return <h1>Hello World</h1>;
}

Будет заменён на

function App() {
  return <h1>Hello World</h1>;
}

Если вы используете что то другое в реакте (например хук), то в коде появится именованный импорт:
Код

import React from 'react';

function App() {
  const [text, setText] = React.useState('Hello World');
  return <h1>{text}</h1>;
}

Заменится на код

import { useState } from 'react';

function App() {
  const [text, setText] = useState('Hello World');
  return <h1>{text}</h1>;
}

Удаление неиспользуемого импорта поможет подготовиться к следующим версиям Реакта (не 17) в которых будет поддержка ES модулей и не будет дефолтного экспорта.

Благодарности

Мы благодарим команды Babel, TypeScript, Create React App, Next.js, Gatsby, ESLint, и Flow за их помощь в интеграции нового механизма JSX трансформации. Мы также благодарим сообщество Реакт за их отзывы и обсуждения RFC [17]

Автор: Артём Рева

Источник [18]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/javascript/357547

Ссылки в тексте:

[1] статьи в блоге ReactJS: https://reactjs.org/blog/2020/09/22/introducing-the-new-jsx-transform.html

[2] В React 17 Release Candidate: https://reactjs.org/blog/2020/08/10/react-v17-rc.html

[3] здесь: https://reactjs.org/blog/2020/09/22/introducing-the-new-jsx-transform.html#how-to-upgrade-to-the-new-jsx-transform

[4] несколько вариантов улучшить скорость и упростить: https://github.com/reactjs/rfcs/blob/createlement-rfc/text/0000-create-element-changes.md#motivation

[5] здесь: https://github.com/reactjs/rfcs/blob/createlement-rfc/text/0000-create-element-changes.md#detailed-design

[6] релизе v4.0: https://gist.github.com/iansu/4fab7a9bfa5fa6ebc87a908c62f5340b

[7] v9.5.3: https://github.com/vercel/next.js/releases/tag/v9.5.3

[8] v2.24.5: https://github.com/gatsbyjs/gatsby/blob/master/packages/gatsby/CHANGELOG.md#22452-2020-08-28

[9] вот такая ошибка: https://github.com/gatsbyjs/gatsby/issues/26979

[10] v7.9.0: https://babeljs.io/blog/2020/03/16/7.9.0

[11] babel: https://habr.com/ru/users/babel/

[12] @babel/plugin-transform-react-jsx: https://babeljs.io/docs/en/babel-plugin-transform-react-jsx

[13] @babel/preset-react: https://babeljs.io/docs/en/babel-preset-react

[14] eslint-plugin-react: https://github.com/yannickcr/eslint-plugin-react

[15] 4.1 beta: https://devblogs.microsoft.com/typescript/announcing-typescript-4-1-beta/#jsx-factories

[16] 0.126.0: https://github.com/facebook/flow/releases/tag/v0.126.0

[17] RFC: https://github.com/reactjs/rfcs/pull/107

[18] Источник: https://habr.com/ru/post/521930/?utm_source=habrahabr&utm_medium=rss&utm_campaign=521930