Как постепенно да преминете към уебпакет

Това е втората поредица от две части за това защо и как сменихме нашата система за пакетиране от JavaScript от ad hoc система на Grunt задачи и PHP, към декларативна конфигурация на уебпакет. Щракнете тук, за да отидете на Защо преминахме към уебпакет, за да разберете защо сме преминали към уебпакет.

Тази статия е за вас, ако системата за изграждане на JavaScript на вашата кодова база има проблеми, подобни на нашите в „Защо преминахме към уебпакет“ и искате да мигрирате към уебпакет постепенно, като го разделяте на по-малки стъпки. Някои части на тази статия са специфични за AngularJS 1.x, но останалите могат да бъдат приложени към всяка рамка.

За да направите миграцията възможно най-безболезнена, разделете я на следните стъпки:

  1. Въведете уебпакет заедно с вашата съществуваща система за изграждане, без да променяте кода на приложението си.
  2. Използвайте уебпакет по време на разработка за определен период от време и разрешавайте проблеми, когато възникнат. Пренебрегвайте използването на старата система за изграждане, но продължете да я използвате в производството.
  3. Премахнете остарелата система за изграждане, оставяйки само уебпакет.
  4. Актуализирайте кодовата база с подобрения, които вече са възможни с webpack.

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

По време на разработката веднага се възползвате от определени функции на уебпакетите, като например бързи времена за възстановяване и отстраняване на грешки въз основа на изходната карта и ако има проблем с новата стъпка на сглобяване, винаги можете да се върнете към старата си.

1. Въведете уебпакет заедно със съществуващата система за изграждане

Започнете с репликирането на основните функции на старата система за изграждане, необходими за изграждането на приложението ви:

  • Създаване на пакет от JavaScript
  • Създаване на CSS пакет
  • Предоставяне на пътища на JS / CSS актив към вашия HTML шаблон

Обърнете внимание, че можете да изключите по-напреднали изисквания от този списък, като минификация, групиране за карма тестове или групиране на преведени езикови низове. Те могат да бъдат обработени по време на стъпка №2.

Създаване на пакет от JavaScript

Съществуващата ви система за изграждане вероятно включва стъпка за обединяване, за да комбинирате много скриптове в един, например с grunt-contrib-concat:

grunt.initConfig ({
  concat: {
    js: {
      файлове: [{
        src: [
          "Продавач / lodash.js"
          "продавач / jquery.js",
          "Продавач / angular.js"
          "Продавач / ъглово-cookies.js ',
          "APP / скриптове / ** / *. JS"
        ],
        dest: 'build / js /'
      }]
    }
  }
});

За щастие, уебпакетът е достатъчно гъвкав, за да възпроизведе това поведение, като използва импорт-товарач, експорт-товарач и контекст:

За да накарате своя уеб пакет JS да се държи идентично със стария си пакет за свързване на скриптове, създайте нов .js файл, който да служи като входна точка за вашия уебпакет, и използвайте loader-loader и Export-loader, за да импортирате зависимости и стойности за експортиране за вашите доставчици скриптове, напр

// app / app.js
// Импортирайте наследени скриптове на доставчици в правилния ред
window._ = изисквам (
  "../Vendor/lodash"
);
прозорец. $ = window.jQuery = изисквам (
  "../Vendor/jquery"
);
window.angular = изисквам (
  "Износ? Window.angular! ../ продавач / ъглов"
);
изисква (
  "Внос? Ъглов => window.angular! +
  "../vendor/angular-cookies"
);
// ... скриптове за приложение

Тъй като всеки скрипт на доставчик има различни зависимости и експортирани стойности, всеки трябва да бъде проверен ръчно, за да се определи дали и как да се използва импорт-товарач и експорт-товарач. Не забравяйте да присвоите глобални променливи на „прозорец“, за да се уверите, че те са налични във вашия код на приложение.

Ако вашият код на приложение също трябва да бъде изпълнен в определен ред, можете просто да „изискате“ всеки файл в последователност, напр.

// app / app.js
// ... скриптове на доставчици
изискват ( "./ скриптове / moduleA ');
изискват ( "./ скриптове / moduleB ');
изискват ( "./ скриптове / moduleC ');
// ...
изискват ( "./ скриптове / главен ');

Или, ако вашият код на приложение може да бъде изпълнен в произволен ред (например, ако използвате модули AngularJS), можете да използвате контекста на уебпакет, за да "изисквате" всички тези файлове наведнъж:

// app / app.js
// ... скриптове на доставчици
/ **
 * "изискват" всички модули в дадения контекст на уебпакета
 * /
функция RequAll (контекст) {
  context.keys () forEach (контекст).
}
// Съберете всички ъглови модули
requireAll (require.context (
  "./scripts",
  / * използвайте поддиректории: * / true,
));

За работа с вашите JS файлове това е всичко! Не са необходими промени в скриптовете на доставчика или кода на приложението; трябва само да промените входната точка на уебпакета. Важно е да не променяте самия код на приложението, за да гарантирате, че можете да продължите да изграждате с помощта на предишната си система за изграждане.

Създаване на CSS пакет

Вашата стъпка за изграждане на CSS вероятно включва препроцесорна стъпка, например със Stylus чрез grunt-contrib-stylus:

grunt.initConfig ({
  стилус: {
    компилиране: {
      файлове: {
        src: 'app / css / main.styl',
        dest: 'build / css / main.css'
      }
    }
  }
});

webpack предлага набор от зареждащи устройства за обработка и извеждане на CSS:

  • stylus-loader / sass-loader / less-loader: изпълнява дадения препроцесор във вашите CSS файлове (файлове), връщайки обикновения CSS
  • css-loader: решава `@ import` /` url (...) `и връща получения CSS
  • url-loader / file-loader: вмъква или излъчва съдържанието на файлове в изхода на уебпакета, като шрифт или изображение `url (...)` s в CSS
  • extract-text-webpack-plugin: премества вашия CSS в отделен изходен файл, вместо да го вгражда в HTML

Конфигурирането на уебпакет с тези зареждащи устройства се оставя като упражнение за четеца, но след като бъде конфигурирано, добавянето на вашия стилов лист към съставянето на уебпакет е толкова просто, колкото добавянето на „изисквам (…)“ към вашата входна точка:

// app / app.js
изискват ( "./ CSS / main.styl ');
// ... скриптове на доставчици
// ... скриптове за приложение

Забележка: Стъпката за изграждане на CSS не е задължително да е част от изграждането на уеб пакета; например, бихме могли да изберете да преминем към обикновен скрипт npm, извикващ командата `stylus`. Но ние получаваме някои предимства, като използваме webpack:

  • Необходимо е да се стартира само уебпакет за изграждане на JS и CSS; няма нужда да стартирате отделна команда за изграждане на CSS.
  • Активите за изображение / шрифт, посочени в CSS, автоматично се включват в изхода на уебпакета; няма нужда да ги копирате във вашата изходна папка и да управлявате пътищата на активите чрез някакъв друг метод.
  • file-loader ще генерира автоматично хеширани имена на файлове за дългосрочно кеширане на CSS файла и включените шрифтове / изображения.

Предоставяне на пътища на JS / CSS актив към вашия HTML шаблон

Последната стъпка, за да можете да стартирате както уебпакет, така и старата си система за изграждане на една и съща кодова база, е да преведете новите JS / CSS активи на уебпакет в HTML шаблон на вашия сайт.

Можете да заснемате пътищата на всички изходни активи на уебпакета, като използвате обекта `Stats`, който се връща, когато изграждането завърши. Един прост начин да предадете тези данни във вашия HTML шаблон е чрез stats-webpack-plugin:

// webpack.config.js
const StatsPlugin = изисквам ('stats-webpack-plugin');
module.exports = {
  // ...
  приставки: [
    // ...
    нов StatsPlugin ('webpack-stats.json', {
      парчета: неверни,
      модули: false,
      деца: лъжливо,
      кеширано: невярно,
      причини: неверни,
      източник: невярно,
      errorDetails: false,
      chunkOrigins: невярно,
    })
  ]
};

За лесно превключване назад и назад между уебпакет и старата ви система за изграждане, можете просто да рендерирате пътищата на активите на уебпакета, ако webpack-stats.json съществува във вашата изходна папка, в противен случай да се върнете към пътищата на активите на старата ви система за изграждане.

Например, използвайки PHP:

Това са всички парчета, необходими, за да се получи минимална изработка на уебпакет! На този етап вашият проект трябва да бъде в това състояние:

  • Изпълнете старата си стъпка на сглобяване (напр. „Grunt build“), която ще създаде JS / CSS активи в папката ви за изграждане, което кара HTML шаблона на вашия сайт да рендира пътищата на активите по стария начин.
  • Изпълнете `webpack`, който ще създаде JS / CSS активи и webpack-stats.json в папката ви за изграждане, което кара HTML шаблона на вашия сайт да изобразява пътища на активи, използвайки webpack-stats.json.

2. Използвайте webpack по време на разработка и оттегляйте използването на старата система за изграждане

По време на този етап кажете на другите разработчици на проекта да използват webpack вместо старата система за изграждане. Ако възникнат някакви проблеми (като неправилно конфигуриран товарач), можете да ги разрешите безопасно, без да засягате производството, тъй като производството продължава да използва старата система за изграждане.

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

Ако използвате изпълнител на задачи като Grunt или Gulp, тогава npm скриптовете често са по-проста алтернатива на Grunt / Gulp задачите.

Ето някои алтернативи на Grunt, които използваме:

  • grunt-karma: Интерфейсът на командния ред на Karma (`karma start`)
  • grunt-angular-gettext: angular-gettext-cli + angular-gettext-loader
  • grunt-angular-templates: ngtemplate-l0ader

В края на този етап трябва да имате:

  • Скрипт npm за замяна на всяка задача за изграждане, напр. `npm run bundle: watch` за групиране и гледане по време на развитие,` npm run bundle: production` за групиране и минимизиране с езикови преводи, `npm run karma` за изпълнение на тестове на Karma
  • Тествайте внимателно цялото си приложение, за да се уверите, че работи правилно: внимавайте за липсващи скриптове или таблици стилове, тъй като те могат да причинят разрушаване на приложението ви.

3. Премахнете остарелата система за изграждане, оставяйки само уебпакет

Тази част е лесна: просто конфигурирайте своя скрипт за изграждане на CI, за да стартирате вашите нови скриптове за сглобяване на npm (като `npm test && npm run bundle: production`), изтрийте старата си конфигурация на изпълнителя на задачи (Gruntfile.js / gulpfile.js / и т.н.) , и премахнете сега неизползваните зависимости от package.json.

Също така ще искате да изтриете кода във вашия HTML шаблон, който се връща към старата ви система за изграждане, ако webpack-stats.json не съществува.

Ако старателно сте тествали приложението си в предишния етап, този етап трябва да излезе без проблем. Разбира се, първо трябва да се внедрите в тестова среда, подобна на производство, за да сте в безопасност.

4. Актуализирайте кодовата база с подобрения, активирани от webpack

Сега, когато webpack е единствената система за изграждане, можем да се справим с проблемите, първоначално описани в Why We Switched to webpack:

Разрешаване на зависимости

Спомнете ли си как настройвате входната точка на уебпакета, за да импортирате скриптове в световен мащаб, в зависимост от първия ред?

// app / app.js
изискват ( "./ CSS / main.styl ');
// Импортирайте наследени скриптове на доставчици в правилния ред
window._ = изисквам (
  "../Vendor/lodash"
);
// ...
изискват ( "./ скриптове / moduleA ');
изискват ( "./ скриптове / moduleB ');
изискват ( "./ скриптове / moduleC ');
// ...
изискват ( "./ скриптове / главен ');

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

Вместо това вече можете да импортирате зависимости в модула, където се използват, напр. ако main.js зависи от lodash.js, moduleA.js и moduleC.js:

// приложение / скриптове / main.js
var _ = изисквам ('../../ продавач / квартира');
var A = изисквам ('./ moduleA');
var C = изисквам ('./ moduleC');
// ...

И ако moduleB.js зависи само от moduleA.js:

// приложение / скриптове / moduleB.js
var A = изисквам ('./ moduleA');
// ...

След като един модул се импортира изрично от всички негови зависими, той може да бъде премахнат от точката за въвеждане на уебпакет: преход по един модул наведнъж и в крайна сметка вашата точка за въвеждане в уебпакет ще остане само с:

// app / app.js
изискват ( "./ CSS / main.styl ');
изискват ( "./ скриптове / главен ');

Използване на npm пакети

Сега можете да започнете да използвате npm пакети, вместо да копирате модули на доставчици на трети страни в хранилището: обновяването на пакети става по-лесно, споделените транзитивни зависимости намаляват дублирането на кода и вече не е необходимо да създавате потребителски UMD пакети.

Трябва да е толкова лесно, колкото да направите npm install ', след това да актуализирате препратки към модула, напр. променете това:

var _ = изисквам ('../../ продавач / квартира');

До това:

var _ = изисквам ('lodash');

Сега, когато зависимостите са изрични и използваме npm пакети, постигнахме (поне донякъде) целта да улесним разбирането на кодовата база. И ние подобрихме dev-prod паритета също, тъй като webpack сега обработва зависимостите на нашите модули по един и същи начин както в разработката, така и в производството: единствената разлика е, че изграждането на производството е опростено.

Разбира се, ние също направихме кодовата база готова за бъдеще, където е по-лесно да започнете да използвате ES2015 +, като включите babel-loader, а използването на React и Redux става по-лесно с възможността да използвате JSX и npm пакети.

Това беше преходът, който основната база данни за събитие на EventMobi наскоро направи успешно. Ако вашият проект е в подобна форма, надявам се това да даде някаква представа как да го подобрите!

[Ако тази статия ви е харесала, щракнете върху малкото отляво, за да знаят другите хора. Ако искате още публикации като тази, следвайте публикацията на EventMobi с бутона (Следване) вдясно!

И накрая, ако решаването на проблеми като това изглежда е вашата алея, ние се наемаме! Проверете нашите текущи открити позиции на http://www.eventmobi.com/careers/]