Забравете за AMD завинаги, вече няма основателна причина да използвате AMD

Модулите на AMD бяха много популярни. Много уеб приложения и уеб сайтове са разработени с помощта на AMD модули. Но напоследък модулите ES явно надминаха наследените модули на AMD.

По това време най-привлекателната характеристика на модулите на AMD беше, че те, за разлика от модулите CommonJS, можеха да работят в браузър без допълнителна предварителна обработка. Стъпките на изграждане по време на разработката отнемат време и усложняват отстраняването на грешки. Модулите ES също не е необходимо да бъдат трансформирани и групирани, за да бъдат изпълнени в браузър. В сравнение с AMD, ES модулите имат допълнителни полезни функции. Редът на зареждане е ясно дефиниран и съобщенията за грешки по време на зареждане са по-информативни. „Кръговите зависимости са любимата ми функция. Цикличните зависимости позволяват бързи корекции и преработване на кода, като същевременно поддържат приложението функционално». Динамичните импортирания, базирани на обещание, позволяват зареждане на код само когато е необходимо. „Модулите за предварително зареждане и кеширане правят групирането незаменимо, поне в корпоративните приложения.“ Групирането с Rollup е по-лесно от групирането на AMD модули с Webpack.

Единственото относително ограничение на ES модулите е, че те все още не поддържат импортиране на HTML шаблони. Така че засега текстовите файлове могат да се зареждат с най-високо ниво await.

Как да мигрирам от AMD към ES модули

Доскоро поддържах няколко приложения с предни части, съставени от няколкостотин AMD модула. За да опростя тяхното разработване, наскоро преобразувах приложенията в ES модули. С изключение на редки модули със сложни условни динамични импорти, преобразуването е лесно — define() аргумента се преобразуват в import изрази и return във функциите се заменят с export default. Всъщност основната причина за съществуването на export default в ES модулите е да се даде възможност за лесна миграция от AMD.

За да автоматизирам до голяма степен трансформацията, разработих прост инструмент, базиран на Nodejs. Приложението зависи от библиотека за анализатор на JavaScript acorn (Ако никога не сте използвали анализатори на JavaScript, може да ви е интересно да видите за всеки случай какво правят https://astexplorer.net/).

Не планирам повече да използвам моя инструмент, защото нямам повече приложения за мигриране. Но може би моят инструмент или части от него могат да бъдат полезни за някой друг.

За да илюстрирам възможностите на инструмента, по-долу показвам цветни снимки с входа и очаквания изход, който се използва в изчерпателните тестови случаи на инструмента.

Много начини за дефиниране на модул

AMD модул е ​​дефиниран във функцията define(). Обикновено define() получава масив с модулни пътища и функция, която получава изброените модули и връща модул.

define() с масив от зависимости и функция

Всеки път на зависимост заедно със съответния параметър на дефиниционната функция се превръща в израз import. return на функцията става export default. define() се премахва.

define() зарежда HTML шаблон

RequireJS позволява зареждане на текстови зависимости с помощта на плъгина text.js. ES модулите поддържат импортиране на JSON, но все още не поддържат импортиране на HTML. HTML шаблон може да бъде зареден в ES модул с най-високо ниво await. „Описах този подход в по-ранна публикация.“

define() с масив от зависимости и функция без оператор за връщане

Полученият ES модул няма експорти:

define() с функция без параметри

Тъй като изходният AMD модул няма зависимости, получените ES модули нямат imports.

define() с функция без израз за връщане

define() с обект

Обработка на requirejs()

За разлика от define(), requirejs() не създава модул, той обикновено се използва в main.js за зареждане на дефинираните модули и стартиране на приложението.

requirejs() с масив и функция на зависимост

Третира се като define() с функция без оператор return.

Вложени requirejs()

Докато define() не може да бъде вложено, requirejs() може да бъде вътре в requirejs() или define(). Вложено requirejs() се използва в условия за условно импортиране. Но динамичното импортиране с requirejs() е сравнително рядко и може да бъде сложно, така че е по-лесно да се обработят точно ръчно, отколкото да се състави надежден код за преобразуване в динамично импортиране. Моят инструмент замества само вложените requirejs() с функционално еквивалентни import().

Същият резултат, ако requirejs() е вложен в define().

Бърза миграция

Процедурата е бърза. Включва няколко бързи стъпки:

  • Преди миграцията, ангажирайте всички необвързани промени в локалното хранилище на git. С git можете да оцените всички промени, въведени от инструмента.
  • Отворете командния ред, отидете в папката, съдържаща инструмента, и инсталирайте зависимостите: npm install
  • Стартирайте инструмента, като изпълните команда, указваща папката, съдържаща AMD модули. Инструментът преобразува *.js файловете във всички подпапки на родителската папка: node main.js path/to/folder/with/js-files
  • Сега обектът paths на обекта, предаден на requirejs.config(), трябва да бъде преобразуван в карта за импортиране в HTML файла, обикновено index.html, зареждайки JavaScript кода. Изброените в paths URL адреси на папките и модулите трябва да бъдат коригирани, например с префикс js/, тъй като в картите за импортиране URL адресите са относителни към файла, съдържащ картата за импортиране. Ако никога не сте използвали карти за импортиране, прочетете пост към точката.
  • Опитайте да стартирате преобразуваното приложение. Ако не успее, можете да видите причината в конзолата. Първоначално приложението може да се провали поради неправилно дефинираните спецификатори на модула в картата за импортиране. Но след няколко корекции в картата за импортиране, приложението ще започне да работи. Освен форматиране, повечето от преобразуваните модули не се нуждаят от допълнителна ръчна последваща обработка.
  • Ако приложението източник е имало requirejs() базирани импортирания, проверете ги и коригирайте автоматично трансформирания код.

Вдлъбнатина

Конвертираният код не е форматиран. Може да се форматира чрез стартиране на допълнителна библиотека, но лично аз предпочетох да виждам ясно кои файлове не са редактирани от мен след конвертирането. Когато променям код, винаги го форматирам.

Инструментът за мигриране на базиран на AMD JavaScript код в ES модули може да бъде изтеглен от https://github.com/marianc000/amdToEsm