Webpack в Visual Studio для великих солюшенов

КПДВУ нас в солюшене 51 проект. У 10 з них використовується TypeScript. Обсяг мінімізованого JavaScript-коду ~1 MB. TypeScript-код одних проектів залежить від коду інших проектів. Для багатьох React-компонентів використовуються глобальні змінні.
Все разом це призводить до довгих годинах налагодження front-end коду. Щоб спростити собі життя, ми впровадили Webpack. А по дорозі відловили граблі.
TL;DR
  1. Встановлюємо node 7 + npm
  2. Виконуємо в консолі
    npm i -g webpack typescript
  3. Встановлюємо Webpack Task Runner
  4. Додаємо webpack.config.js
    в папку "основного" проекту
  5. Додаємо webpack.config.part.js
    в папку кожного залежного проекту

найпоширеніші проблеми, які виникають у нас при роботі з TypeScript-кодом — «непослідовний» спадкування і велика кількість глобальних змінних. Вони з'являються при дефолтних настройках студії і великому розмірі солюшена.
Проблема — «непослідовний» спадкування
Проблема з успадкуванням виникає, коли базовий клас підключається після дочірнього. Коли в нашому додатку падає помилка
Uncaught TypeError: Cannot read property 'prototype' of undefined
, це швидше за все проблема з «непослідовним» спадкуванням.
Наведу приклад. На "старті" ми написали код нижче.
namespace Sandbox {
export class Base {
protected foo() {
console.log('foo');
}
}

export class Derived extends Base {
public baz() {
this.foo();
console.log('baz');
}
}
}

Ми хочемо, щоб кожен клас лежав в окремому файлі, тому що вважаємо, що так зручніше. І код з лістингу вище ми розділили на два файли:
base.ts
та
derived.ts
.
namespace Sandbox {
export class Base {
protected foo() {
console.log('foo');
}
}
}

namespace Sandbox {
export class Derived extends Base {
public baz() {
this.foo();
console.log('baz');
}
}
}

З'явився файл
derived.ts
, який неявно залежить від файлу
base.ts
. Тепер важливий порядок підключення цих двох файлів: якщо підключити спочатку
derived.js
,
base.js
, то отримаємо повідомлення про помилку.
При налаштуваннях студії "за замовчуванням" важливий порядок підключення залежних скриптів.
Проблема — глобальні змінні
Щоб TypeScript-код з різних проектів використовував загальний код, доводиться оголошувати глобальні змінні.
Наприклад, ми написали корисну функцію
makeSandwich
в просторі імен
Utils
в проекті Administration:
namespace Utils {
...
export function makeSandwich() {
...
}
}

Отримуємо наступний код JavaScript:
var Utils;
(function (Utils) {
function makeSandwich() {
...
}
Utils.makeSandwich = makeSandwich;
})(Utils || (Utils = {}));

Створена глобальна змінна
Utils
. Для того, щоб викликати функцію, доведеться звернутися до глобальної змінної.
Самі по собі глобальні змінні не несуть шкоди, але їх неправильне використання веде до довгих годинах дебага. Наприклад, їх можна перезаписати або перекрити.
При налаштуваннях студії "за замовчуванням" створюються глобальні змінні.
Рішення
«непослідовний» спадкування та глобальні змінні — вирішення проблеми залежностей. У світі JavaScript залежності розрулюють спеціальні інструменти: Webpack, Browserify, RequireJS, SystemJS та інші. Вибрав Webpack, так як я з ним раніше працював.
В Visual Studio починаючи з 13 версії з'явився Task Runner. Це такий інструмент, який прив'язує завдання (task) до моменту життєвого циклу проекту: при відкритті, Clean, перед білдів або після білду. Розширюють Task Runner плагіни для студії.
Щоб вбудувати Webpack в білд студії, використовуйте Task Runner і плагін Webpack Task Runner. Працювати з ними просто. Створіть файл
webpack.config.js
в папці з проектом і повісьте таск "Watch - Development" на відкриття проекту. Детальніше статті.
Кожного разу при запуску "Watch - Development" над файловою системою запускається watch — на кожну зміну в спостережуваних файлах спрацьовує білд. Без додаткових налаштувань все чудово працює, якщо у вас один проект. Якщо ж у вас два і більше проектів, на кожен з них буде запущений watch. У нас 10 проектів з TypeScript. 10 вотчей на моєму комп'ютері працюють 3 хвилини на білд скриптів. І це при зміні одного ts-файлу. Потрібно поліпшити.
Наші проекти влаштовані так, що є "основний" проект з каркасом сайту і "залежні" проекти з плагінами.
Я налаштував наш білд таким чином, що при завантаженні "основного" проекту буде запущена завдання "Watch - Development" за допомогою студійного Task Runner'а. Базові налаштування лежать в
webpack.config.js
: лоадери, tsconfig, плагіни. Всередині
webpack.config.js
також написаний код, який шукає по всіх папок солюшена файли
webpack.config.part.js
. Кожен файл
webpack.config.part.js
містить налаштування білду для конкретного проекту: entry, оверрайды налаштувань tsconfig та інше. Зазвичай, там тільки entry. І "основний" і "залежні" проекти містять файл
webpack.config.part.js
. Таким чином, для білду скриптів у всіх проектах використовується тільки один watch.
Налаштування білд сервера банальна: запускаєте
webpack -p
в папці "основного" проекту.
Ще один нюанс — крім Webpack, студія все ще билдит наш TypeScript. У TypeScript з версії 2.0 в tsconfig.json можна заборонити білд файлів директивою
exclude
з паттерном
./Scripts/*
. Webpack проігнорує цю настройку. Але в TypeScript 2.1 компілятор повинен знайти хоча б один файл для білду, інакше впаде помилка. Довелося залишити один порожній файл для принесення в жертву студії.
Результати
І спадкування і використання глобальних змінних виродилося в директиви імпорту:
import { Base } from '../../../../../BaseProject/Scripts/Base';
import * as from Utils '../../../../../Utils';

export class Derived extends Base {
public baz() {
this.foo();
Utils.makeSandwich();
console.log('baz');
}
}

Зверніть увагу на довгі відносні шляхи. Вони тут навмисне, щоб показати, що таке трапляється. Исплоьзуйте проміжні файли з импортами з інших проектів і "заинкапсулировать" тонну довгих відносних шляхів.
При використанні одного watch замість декількох, білд прискорився з 3 хвилин до декількох секунд.
Продуктом компіляції стане один файл, що містить всі заимпортированные файли. Причому, при запуску з production-настройками, файл буде мінімізований. Детальніше про роботу Webpack можна дізнатися на сайті webpack.js.org.
Переписати весь наш код на використання импортов за один підхід не представляється можливим. Але спосіб описаний у статті дозволяє робити цю роботу частинами.
Висновки
  • У вас один проект — все і так працює, не трожьте
  • У вас один проект, але хочете плюшки Webpack — вам сюди
  • У вас трохи проектів (2-5) — вам все ще сюди
  • У вас більше 5 проектів — спробуйте спосіб, описаний у статті
Посилання
Джерело: Хабрахабр

0 коментарів

Тільки зареєстровані та авторизовані користувачі можуть залишати коментарі.