Sencha Ext JS: за пределами ES5

Использование современного синтаксиса ECMAScript с проектами Sencha Ext JS

Sencha Ext JS поставляется с инструментом сборки с закрытым исходным кодом, в который входит Closure Compiler; в некоторых случаях это не позволяет разработчикам использовать современный синтаксис ECMAScript. В этой статье представлен @coon-js/delorean, инструмент, который решает эту проблему с помощью дополнительного слоя транспиляции.

Одной из причин разочарования при работе с Ext JS является тот факт, что современный синтаксис JavaScript нельзя использовать с этой инфраструктурой: как только Sencha CMD создает пакет или приложение, код, который известно, что он работает в разработке, или тесты не компилируются для производства, или, что еще хуже, он полностью ломается во время производства.

Вот несколько примеров, которые, как известно, ломают сборку с Sencha CMD:

Оператор нулевого объединения:

const foo = null ?? ‘default string’;

Синтаксис деструктурирования присваивания с аргументами функции:

const fn = ([x, y, z]) => ({x, y, z});

Необязательный оператор цепочки:

const adventurer = {
  name: 'Alice',
  cat: {
    name: 'Dinah'
  }
};

const dogName = adventurer.dog?.name;

Причина этого в том, что Sencha CMD — это проприетарный инструмент, который поставляется со встроенным компилятором закрытия; то, как он интегрирован, не позволяет разработчикам точно настраивать процессы сборки. Очевидно, что компилятор Closure требует обновлений для работы с текущими стандартами ECMAScript. Есть несколько параметров конфигурации для пакетов, которые обеспечивают более щадящий (читай: совместимый) синтаксический анализ и транспилирование исходного кода. Однако есть код, который, как известно, дает сбой во время компиляции, даже если код синтаксически правильный.

(Обратитесь к этому списку, чтобы получить представление о том, что работает с Closure Compiler.)

Также обратите внимание, что последняя доступная версия Closure Compiler не обязательно поставляется с последней доступной версией Sencha CMD: v7.6.0.87 Sencha CMD поставляется с v20220301.

@sencha\cmd> dir /s/b | findstr .*closure.*$

@sencha\cmd\dist\lib\closure-compiler-externs-v20220301.jar
@sencha\cmd\dist\lib\closure-compiler-v20220301.jar

К сожалению, Sencha не предоставляет официального руководства по независимому обновлению компилятора Closure.

Когда дела идут в самоволку

Вот пример, который показывает, как производственный код проекта Ext JS ломается при использовании современного ECMAScript. Рассмотрим следующие строки как часть исходного кода разработки:

const fn = ([a, b, c]) => ({a, b, c});

Эта стрелочная функция

  1. использует синтаксис деструктурирующего присваивания для распаковки первых трех записей аргумента массива
  2. создает объект из записей, используя обозначение сокращенных имен свойств
  3. возвращает этот объект

Пусть код будет частью пакета Sencha Ext JS, который можно собрать с помощью команды:

npx @sencha/cmd package build

Версия, используемая с Sencha CMD:

npx @sencha/cmd which

  Sencha Cmd v7.6.0.87

И конфигурация из раздела sencha package.json:

"output": {
    "base": "${package.dir}/build"
},

"compressor": {
    "type": "closure",
    "polyfills": "none"
},

Компиляция не удалась, так как уровень вывода по умолчанию установлен на ES5; это старая спецификация ES, но совместимая с широким спектром браузеров:

Конфигурацию можно настроить таким образом, чтобы можно было указать версию ES, используемую в проекте: Зная, что NEXT — это уровень для последних поддерживаемых функций, конфигурация изменяется на:

"output": {
      "base": "${package.dir}/build",
      "js": {
          "version": "NEXT"
      }
  },
  "language": {
      "js": {
          "input": "NEXT",
          "output": "NEXT"
      }
  },
  "compressor": {
      "type": "closure",
      "polyfills": "none"
  },

Вывод на консоли показывает, что команда NEXT понята, но при компиляции все еще происходит сбой: файлы сборки остаются пустыми.

Видимо, где-то что-то сломалось.

Кажется, что language.js.input вызывает проблемы. Согласно официальной документации Sencha, инструмент поддерживает следующие языковые уровни:

ES3  : ECMAScript 3 language level
ES5  : ECMAScript 5 language level
ES6  : ECMAScript 6 language level (2015)
ES7  : ECMAScript 7 language level (2016)
ES8  : ECMAScript 8 language level (2017)
NEXT : ECMAScript Next (or ES.Next) language level

тогда как Closure Compiler поддерживает следующие спецификации с language_in:

ECMASCRIPT3
ECMASCRIPT5
ECMASCRIPT5_STRICT
ECMASCRIPT_2015
ECMASCRIPT_2016
ECMASCRIPT_2017
ECMASCRIPT_2018
ECMASCRIPT_2019
ECMASCRIPT_2020
ECMASCRIPT_2021 
STABLE
ECMASCRIPT_NEXT (latest features supported) (default: STABLE)

К сожалению, попытка установить язык на любое из значений, поддерживаемых непосредственно компилятором Closure (или его вариациями, такими как ECMASCRIPT_2021, ES10…), приводит к следующему: сообщение об ошибке:

ES8 кажется самым большим общим знаменателем для Sencha CMD и компилятора Closure. Работает следующая конфигурация — процесс сборки не прерывается на полпути, и транспилированный JavaScript оказывается в исходных файлах:

"output": {
    "base": "${package.dir}/build",
    "js": {
        "version": "ES8"
    }
},
"language": {
    "js": {
        "input": "ES8",
        "output": "ES8"
    }
},
"compressor": {
    "type": "closure",
    "polyfills": "none"
}

Однако загрузка сборки в рабочей среде завершается сбоем.

Вот исходный код JavaScript для справки:

const fn = ([a, b, c]) => ({a, b, c});

… и исходный код JavaScript, который заканчивается кодом отладки (например, build/project-debug.js):

const fn = [a,b,c] => ({
    a,
    b,
    c
});

… и это код, созданный для сжатого JavaScript (например, build/project.js):

const c=()=>({a,b,c});

Не нужно много времени, чтобы понять, почему код дает сбой: он синтаксически неверен в отладочной сборке и функционально неверен в сжатой сборке.

Представляем @coon-js/delorean

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

@coon-js/delorean — это инструмент npm, который обеспечивает дополнительный уровень транспиляции поверх Sencha CMD с помощью Babel.

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

Конфигурация delorean по умолчанию гарантирует, что Babel создаст код ES5:

delorean почти не влияет на фактический процесс сборки: он только обновляет существующие сопоставления в файле конфигурации, требуемом Sencha CMD; обычно они представляют собой каталоги, содержащие исходные файлы, относящиеся к проекту. Помимо очевидных каркасов перенесенного проекта, инфраструктура проекта остается нетронутой, что делает возможной почти бесшовную интеграцию в процесс разработки и существующие конвейеры сборки.

Изменения, внесенные в конфигурацию проекта, легко отследить:

         "classpath": [
-            "${package.dir}/src",
-            "${package.dir}/${toolkit.name}/src"
+            "${package.dir}/.deloreanbuild/src",
+            "${package.dir}/.deloreanbuild/${toolkit.name}/src"
         ],
         "overrides": [
-            "${package.dir}/overrides",
-            "${package.dir}/${toolkit.name}/overrides"
+            "${package.dir}/.deloreanbuild/overrides",
+            "${package.dir}/.deloreanbuild/${toolkit.name}/overrides"
         ],

Во время разработки изменения, внесенные delorean, должны быть отменены, чтобы перезагрузка в реальном времени с sencha app watch соответствующим webpack (являющимся частью проектов Ext JS, используемых с npm) по-прежнему работала — и конечно, чтобы браузер использовал исходники из файлов, редактируемых в данный момент разработчиком. (В противном случае среда разработки будет полагаться на транспилированные файлы, созданные ранее delorean.)

Отменить изменения довольно легко, так как простой вызов

npx delorean -r

удаляет любую ссылку на папку .deloreanbuild из файла конфигурации проекта:

Интеграция CI/CD

npx delorean -p и npx delorean -r легко интегрируются с конвейерами CI/CD, обычно используемыми в проектах Sencha Ext JS.
Вы можете автоматизировать транспиляцию, настроив либо build.xml пакета или приложения, либо добавив дополнительные scripts в package.json .

стратегия build.xml

Этот xml-файл обычно доступен с любым пакетом или приложением Ext JS и предоставляет место для добавления параметров и хуков для инструмента Ant, используемого с Sencha CMD. Он позволяет настроить -before-build /-after-build целей (подробнее об этом можно прочитать здесь).

Вы можете использовать delorean, настроив цели с помощью:

<target name="-before-build">
    <exec executable="cmd">
        <arg line="/c npx delorean -p"/>
    </exec>
</target>

<target name="-after-build">
    <exec executable="cmd">
        <arg line="/c npx delorean -r"/>
    </exec>
</target>

Это запустит npx delorean -p до того, как Sencha CMD создаст проект (отсюда -before-build), и отменит все изменения, относящиеся к проекту, после завершения сборки, вызвав npx delorean -r (отсюда -after-build).

Стратегия package.json

Если у вас уже есть скрипт сборки в package.json, который вызывает Sencha CMD, оберните команду build дополнительными вызовами delorean. Вот пример:

{
  "scripts": [
    "build": "npx delorean -p && npm run senchabuild && npx delorean -r",
    "senchabuild": "npm run clean && cross-env webpack --env.profile=desktop --env.environment=production --env.treeshake=yes --env.cmdopts=--uses" 
  ]
}

Дополнительные ресурсы

Репозиторий проекта можно найти по адресу https://github.com/coon-js/delorean. Будем очень признательны за отзывы о конфигурациях, интеграции CI/CD и отчеты о проблемах.

Официальная документация для delorean доступна по адресу https://www.conjoon.org/docs/api/misc/@coon-js/delorean, который также является домом для его проекта, поскольку он возник как часть экосистемы conjoon.

Ранее я писал о выпуске conjoon 1.0.



Соединять

Торстен Зуков-Хомберг| Гитхаб| Твиттер| Ютуб| Инстаграм

Заметки сообщества

В Sencha Discord Server пользователи отреагировали на эту статью и отметили, что было бы также здорово полностью пропустить Sencha CMD и использовать такие инструменты, как webpack или rollup. исключительно для строительных проектов. Я полностью согласен и думаю, что предоставление решения для объединения активов и источников с помощью этих инструментов может быть выполнено с управляемыми усилиями.

Значительные изменения

  • 02 декабря 2022 г.: Небольшие исправления при подготовке к немецкому переводу.
  • 30 ноября 2022 г.: обновлен рис. 2 с конфигурацией externals.
  • 23 ноября 2022 г.: обновлена ​​формулировка, добавлены примечания сообщества.
  • 21 ноября 2022 г .: опубликована первая часть.