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

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

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


    Так как браузеры не понимают JSX “из коробки”, разработчики полагаются на компиляторы типа Babel или Typescript, чтобы трансформировать JSX в обычный JS. В React 17 Release Candidate появился новый, опциональный механизм трасформации 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.х, вот здесь инструкции для апгрейда.

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


    Старая 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 кодом, ничего менять не придётся. Вот здесь технические подробности работы новой трансформации JSX.

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


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

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

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

    Create React App

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

    Next.js

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

    Gatsby

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

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

    Ручная настройка Babel

    Поддержка с версии v7.9.0 и выше.

    Если вы используете babel/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/preset-react:

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

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

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

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

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

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

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

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

    ESLint

    Если у вас плагин eslint-plugin-react, то правила 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.

    Flow

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

    Как убрать неиспользуемые импорты 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.

    Похожие публикации

    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама

    Комментарии 5

      +6

      В начале статьи я подумал, что наконец-то React.createElement будет вызываться во время транспиляции, а не в рантайме (результат вызова этой функции — простой объект). А оказалось, что просто поменяли название импортируемого пакета.

      0
      Кстати из за того, что реакт (бабель) конвертировал jsx теги в React.createElement, мне удавалось уменьшить размер бандла до 20%, хотя цель библиотеки была совсем другая, но получил такой интересный сайд эффект.
        0
        удалось уменьшить вот с этой новой трансформацией в 17 версии?

        Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

        Самое читаемое