1 | ARUI-scripts
|
2 | ===
|
3 |
|
4 | Приложение на нашем стеке без какой либо конфигурации билдеров.
|
5 |
|
6 | Во многом пакет аналогичен `react-scripts` из `create-react-app`, разница заключается
|
7 | в немного отличающихся настройках для `babel`, поддержки `ts` и возможности работы с серверным кодом.
|
8 |
|
9 | Использование
|
10 | ===
|
11 |
|
12 | 0. Пакет требует версию nodejs 8+.
|
13 |
|
14 | 1. Установите `arui-scripts` в свой проект как dev зависимость
|
15 |
|
16 | ```bash
|
17 | yarn add arui-scripts --dev
|
18 | ```
|
19 | или
|
20 | ```bash
|
21 | npm install arui-scripts --save-dev
|
22 | ```
|
23 |
|
24 | 2. Создайте необходимые файлы
|
25 | - `src/index.{js,jsx,ts,tsx}` - входная точка для клиентского приложения.
|
26 | - `src/server/index.{js,jsx,tsx}` - входная точка для серверного приложения.
|
27 | - `node_modules/arui-feather/polyfills` - полифилы для клиентского приложения.
|
28 |
|
29 | При желании вы можете изменить эти пути с помощью настроек.
|
30 |
|
31 | 3. Используйте команды из `arui-scripts`!
|
32 |
|
33 | Доступные команды
|
34 | ---
|
35 |
|
36 | - `arui-scripts start` - запускает WebpackDevServer для фронтенда и webpack в режиме `--watch` для сервера.
|
37 | - `arui-scripts build` - компилирует клиент и сервер для использования в production
|
38 | - `arui-scripts docker-build` - собирает docker контейнер c production билдом и загружает его в артифактори
|
39 | - `arui-scripts test` - запускает jest тесты.
|
40 | - `arui-scripts archive-build` - собирает архив с production билдом
|
41 |
|
42 |
|
43 | Настройки
|
44 | ---
|
45 |
|
46 | Несмотря на то, что все работает из коробки, вы можете захотеть поменять некоторые настройки сборщиков.
|
47 | Сделать это можно в `package.json`, определив там свойство `aruiScripts`.
|
48 |
|
49 | Доступные настройки:
|
50 |
|
51 | - `dockerRegistry` - адрес используемого docker registry, по умолчанию `''`, то есть используется публичный registry
|
52 | - `baseDockerImage` - имя базового образа, используемого для построения docker образа. По умолчанию `heymdall/alpine-node-nginx:8.9.1`.
|
53 | - `serverEntry` - точка входа для исходников сервера, по умолчанию `src/server/index`.
|
54 | - `serverOutput` - имя файла для компиляции сервера, по умолчанию `server.js`.
|
55 | - `clientPolyfillsEntry` - точка входа для полифилов. Будет подключаться до основной точки входа. По умолчанию подтягивает полифилы из `arui-feather`, если он установлен.
|
56 | - `clientEntry` - точка входа для клиентского приложения. По умолчанию `src/index.js`.
|
57 | - `useServerHMR` - использовать ли HotModuleReplacement для сервера. По умолчанию `false`.
|
58 | - `clientServerPort` - порт WebpackDevServer и nginx итогового контейнера. По умолчанию `8080`.
|
59 | - `serverPort` - порт нодового сервера. Нужен для правильного проксирования запросов от дев сервера и nginx. По умолчанию `3000`.
|
60 | - `additionalBuildPath` - массив путей, которые попадут в архив при использовании команды `archive-build`. По умолчанию `['config']`.
|
61 | - `archiveName` - имя архива, который будет создан при использовании команды `archive-build`. По умолчанию `build.tar`.
|
62 | - `keepPropTypes` - если `true`, пакеты с prop-types не будут удалены из production билда.
|
63 | - `debug` - режим отладки, в котором не выполняются некоторые нежелательные операции и выводится больше сообщений об ошибках, по умолчанию `false`.
|
64 | - `useTscLoader` - использовать ts-loader вместо babel-loader для обработки ts файлов. У babel-loader есть [ряд ограничений](https://blogs.msdn.microsoft.com/typescript/2018/08/27/typescript-and-babel-7/). По умолчанию `false`.
|
65 |
|
66 | В целях отладки все эти настройки можно переопределить не изменяя package.json
|
67 | Просто передайте необходимые настройки в environment переменной ARUI_SCRIPTS_CONFIG
|
68 | ```
|
69 | ARUI_SCRIPTS_CONFIG="{\"serverPort\":3333}" yarn start
|
70 | ```
|
71 |
|
72 | Так же, читаются настройки jest (см. [документацию](https://facebook.github.io/jest/docs/en/configuration.html))
|
73 | и `proxy` (см. [документацию](https://github.com/facebook/create-react-app/blob/master/packages/react-scripts/template/README.md#proxying-api-requests-in-development)).
|
74 |
|
75 | Переопределение настроек компиляторов
|
76 | ---
|
77 |
|
78 | По умолчанию для компиляции используется только Babel, для переопределения конфига можете положить файл `.babelrc` в рут папку своего проекта.
|
79 | TypeScript можно включить, положив `tsconfig.json` в корень проекта.
|
80 |
|
81 | Пути до ассетов
|
82 | ---
|
83 | Во время компиляции продакшн версии билда будет созданно два бандла `vendor.[hash].js` и `main.[hash].js`. Для
|
84 | того, чтобы генерировать правильный html с подключением этих ассетов вы можете использовать файл `webpack-assets.json`
|
85 | который будет автоматически положен в папку со скомпилированным кодом.
|
86 |
|
87 | `vendor.js` будет содержать все используемые вами `node_modules`, за исключением модулей, в названии которых содержится `arui`.
|
88 |
|
89 | `main.js` содержит все остальное.
|
90 |
|
91 | Важно подключать ваши ассеты в правильном порядке, `vendor.js` должен подключаться ДО `main.js`.
|
92 |
|
93 | Пример функции, которая сформирует отсортированные в правильном порядке массивы для js и css файлов:
|
94 | ```js
|
95 | function readAssetsManifest() {
|
96 | // читаем манифест
|
97 | const manifestPath = path.join(process.cwd(), '.build/webpack-assets.json');
|
98 | const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
|
99 |
|
100 | const js = [];
|
101 | const css = [];
|
102 | // vendor должен идти перед main
|
103 | ['vendor', 'main'].forEach((key) => {
|
104 | if (!manifest[key]) { // в дев сборке vendor.js не формируется
|
105 | return;
|
106 | }
|
107 | if (manifest[key].js) {
|
108 | js.push(manifest[key].js);
|
109 | }
|
110 | if (manifest[key].css) {
|
111 | css.push(manifest[key].css);
|
112 | }
|
113 | });
|
114 |
|
115 | return {
|
116 | js, css
|
117 | };
|
118 | }
|
119 | ```
|
120 |
|
121 | Использование hot-module-replacement
|
122 | ---
|
123 | #### Клиент:
|
124 |
|
125 | По умолчанию на клиенте будет подменяться только css. Для правильной работы с react вам надо добавить примерно такой код:
|
126 | ```jsx harmony
|
127 | import React from 'react'
|
128 | import ReactDOM from 'react-dom'
|
129 | import App from './app';
|
130 | import { AppContainer } from 'react-hot-loader';
|
131 |
|
132 | ReactDOM.render(
|
133 | <AppContainer><App /></AppContainer>,
|
134 | document.getElementById('react-app')
|
135 | );
|
136 | if (module.hot) {
|
137 | module.hot.accept('./app', () => {
|
138 | const NextAppAssignments = require('./app').default;
|
139 | ReactDOM.render(
|
140 | <AppContainer><NextAppAssignments /></AppContainer>,
|
141 | document.getElementById('react-app')
|
142 | );
|
143 | });
|
144 | }
|
145 | ```
|
146 |
|
147 | При возникновении в консоли предупреждения `React-Hot-Loader: react-🔥-dom patch is not detected. React 16.6+ features may not work.` убедитесь, что в `webpack.client.dev` не переопределяется настройка `resolve.alias`, в нём должна быть следующая запиcь:
|
148 |
|
149 | ```
|
150 | // ...
|
151 | resolve: {
|
152 | alias: {
|
153 | 'react-dom': '@hot-loader/react-dom'
|
154 | }
|
155 | }
|
156 | ```
|
157 |
|
158 | #### Сервер
|
159 | Серверная часть приложения по умолчанию будет просто перезапускаться после каждого изменения кода,
|
160 | для использования hot module replacement на сервере нужно сделать несколько вещей:
|
161 |
|
162 | В `package.json` добавить:
|
163 | ```json
|
164 | {
|
165 | "aruiScripts": { "useServerHMR": true }
|
166 | }
|
167 | ```
|
168 |
|
169 | Ваша входная точка сервера должна выглядеть примерно так (на примере hapi):
|
170 | ##### server/index.js
|
171 | ```js
|
172 | import server from './server';
|
173 |
|
174 | let currentServer = server;
|
175 |
|
176 | async function startServer() {
|
177 | try {
|
178 | await currentServer.start();
|
179 | } catch (error) {
|
180 | console.error('Failed to start server', error);
|
181 | process.exit(1);
|
182 | }
|
183 | }
|
184 |
|
185 | startServer();
|
186 |
|
187 | if (module.hot) {
|
188 | module.hot.accept(['./server'], async () => {
|
189 | try {
|
190 | await currentServer.stop();
|
191 |
|
192 | currentServer = server; // импорт из сервера заменится самостоятельно
|
193 | await startServer();
|
194 | } catch (error) {
|
195 | console.log('Failed to update server. You probably need to restart application', error);
|
196 | }
|
197 | });
|
198 | }
|
199 | ```
|
200 | ##### server/server.js
|
201 | ```js
|
202 | import hapi from 'hapi';
|
203 | const server = new hapi.Server();
|
204 |
|
205 | server.ext('onPostStart', (_, done) => {
|
206 | console.log(`Server is running: ${server.info.uri}`);
|
207 | done();
|
208 | });
|
209 |
|
210 | (async () => {
|
211 | server.connection({ port: 3000 });
|
212 |
|
213 | // ...
|
214 | // конфигурация вашего сервера
|
215 | // ...
|
216 | })();
|
217 |
|
218 | export default server;
|
219 | ```
|
220 |
|
221 | Таким образом после изменения кода сервер не будет полностью пререзагружаться, что во многих случаях быстрее.
|
222 | В случае изменения входной точки сервера при использовании HMR вам надо будет перезапускать сервер вручную.
|
223 |
|
224 | Тесты
|
225 | ---
|
226 | Команда `arui-scripts test` внутри запускает jest с дополнительной конфигурацией.
|
227 |
|
228 | Конфигурация включает в себя:
|
229 | - Использование `jest-snapshot-serializer-class-name-to-string` для правильной работы с `cn`
|
230 | - Замену всех импортов css файлов на пустые файлы
|
231 | - Компиляцию .js/.jsx файлов используя babel
|
232 | - Компиляцию .ts/.tsx файлов используя tsc
|
233 | - Замену импортов остальных типов файлов на импорт строк с названием файла
|
234 |
|
235 | По умолчанию под маску для поиска тестов попадают все файлы `*test*.(js|jsx|ts|tsx)`, `*spec*.((js|jsx|ts|tsx))`, `*/__test__/*.(js|jsx|ts|tsx)`.
|
236 |
|
237 | Вы можете переопределять любые настройки jest в `package.json`, [документация](https://facebook.github.io/jest/docs/en/configuration.html).
|
238 |
|
239 | Если какие либо из ваших инструментов (например VSСode или WebStorm) не могут запустить тесты поскольку не находят конфигурацию, вы можете так же указать `arui-scripts` как preset для jest.
|
240 | Таким образом будет работать как запуск тестов через arui-script, так и любые сторонние инструменты, запускающие jest.
|
241 |
|
242 | ##### package.json
|
243 | ```json
|
244 | {
|
245 | "jest": {
|
246 | "preset": "arui-scripts"
|
247 | }
|
248 | }
|
249 | ```
|
250 |
|
251 | docker
|
252 | ---
|
253 |
|
254 | Команда `arui-scripts docker-build` запускает компиляцию продакшн версии и сборку докер образа.
|
255 |
|
256 | Образ основан на [alpine-node-nginx](https://github.com/Heymdall/alpine-node-nginx).
|
257 |
|
258 | Имя контейнера определяется как `{configs.dockerRegistry}/{name}:{version}`. Переменные `name` и `version` по умолчанию берутся из package.json,
|
259 | но вы так же можете переопределить их из командной строки, например
|
260 | `arui-scripts docker-build name=container-name version=0.1-beta`
|
261 |
|
262 | Команда предполагает наличие установленных `node_modules` перед сборкой, в процессе работы же очищает дев зависимости используя `yarn` или `npm`.
|
263 | yarn будет использоваться когда в рутовой папке проекта есть `yarn.lock` и `yarn` доступен в системе.
|
264 |
|
265 | Итоговый контейнер будет содержать `nginx` и скрипт для запуска `nginx` одновременно с `nodejs` сервером.
|
266 |
|
267 | В итоге, для корректного запуска вашего докер-контейнера вам надо будет выполнить
|
268 |
|
269 | ```
|
270 | docker run -p 8080:8080 container-name:version ./start.sh
|
271 | ```
|
272 |
|
273 | На `8080` порту будет поднят nginx, который будет раздавать статику и проксировать все остальные запросы к `nodejs`.
|
274 |
|
275 | Вы также можете переопределить полностью процесс сборки docker-образа, создав в корневой директории проекта `Dockerfile` содержащий необходимый набор инструкций. Пример [Dockerfile](https://github.com/alfa-laboratory/arui-scripts/blob/master/commands/docker-build/dockerfile.template.js).
|
276 |
|
277 | archive
|
278 | ---
|
279 |
|
280 | Команда `arui-scripts archive-build` запускает компиляцию продакшн версии и сборку архива со скомпилированным кодом.
|
281 |
|
282 | Этот вариант может быть полезен если вы хотите деплоить ваше приложение через подключение архива в марафоне.
|
283 |
|
284 | Команда предполагает наличие установленных `node_modules` перед сборкой, в процессе работы же очищает дев зависимости используя `yarn` или `npm`.
|
285 | yarn будет использоваться когда в рутовой папке проекта есть `yarn.lock` и `yarn` доступен в системе.
|
286 |
|
287 | Итоговый архив будет содержать в себе `.build`, `node_modules`, `package.json` и `config` папки вашего проекта.
|
288 |
|
289 | Проксирование запросов до бэкенда.
|
290 | ---
|
291 |
|
292 | В случае, если ваш фронт должен обращаться к API, отличному от вашего nodejs сервера, в дев режиме вы можете настроить проксирование запросов.
|
293 | Сделать это можно используя свойство `proxy` в вашем `package.json`.
|
294 |
|
295 | Например:
|
296 |
|
297 | ```json
|
298 | {
|
299 | "proxy": {
|
300 | "/corp-shared-ui": {
|
301 | "target": "http://corpint4",
|
302 | "headers": {
|
303 | "host": "corpint4"
|
304 | }
|
305 | }
|
306 | }
|
307 | }
|
308 | ```
|
309 |
|
310 | Такая конфигурация будет проксировать запросы к `http://localhost:8080/corp-shared-ui/` на `http://corpint4/corp-shared-ui`.
|
311 | Подробнее о конфигурации прокси сервера можно почитать в [документации Webpack](https://webpack.js.org/configuration/dev-server/#devserver-proxy).
|
312 |
|
313 | Конфигурация typescript
|
314 | ---
|
315 |
|
316 | Компиляция TS работает из коробки, если в корне проекта есть файл `tsconfig.json`.
|
317 | За основу можно использовать дефолтный конфиг:
|
318 |
|
319 | ```json
|
320 | {
|
321 | "extends": "./node_modules/arui-scripts/configs/tsconfig.json"
|
322 | }
|
323 | ```
|
324 |
|
325 | По умолчанию TS будет компилироваться через babel, но у этого есть ряд ограничений:
|
326 | - нельзя использовать namespace
|
327 | - Нельзя использовать устаревший синтаксис import/export (`import foo = require(...)`, `export = foo`)
|
328 | - enum merging
|
329 |
|
330 | Если вы используете что-то из вышеперичисленного - вы можете вернуться к использованию tsc для компиляции ts файлов
|
331 |
|
332 | ```json
|
333 | {
|
334 | "aruiScripts": { "useTscLoader": true }
|
335 | }
|
336 | ```
|
337 |
|
338 | Конфигурация nginx
|
339 | ---
|
340 |
|
341 | Несмотря на то, что nginx имеет готовый конфиг с роутингом, иногда возникает необходимость добавлять свои роуты.
|
342 | Для этого вы можете создать `nginx.conf` на уровне проекта со своими роутами. Пример конфига: arui-scripts/commands/docker-build/nginx.conf.template.js
|
343 |
|
344 |
|
345 | Удаление proptypes
|
346 | ---
|
347 |
|
348 | Так как в production режими proptypes не проверяются, их имеет смысл удалить из production сборки.
|
349 |
|
350 | Сами объявления proptypes удаляются с помощью [babel-plugin-transform-react-remove-prop-types](https://www.npmjs.com/package/babel-plugin-transform-react-remove-prop-types).
|
351 | Но импорты пакетов `prop-types` при этом не удаляются. Чтобы это реализовать, используется `webpack.NormalModuleReplacementPlugin`.
|
352 | С помощью него заменяются на пустышку пакеты, попадающие под маску:
|
353 |
|
354 | - `/^react-style-proptype$/`
|
355 | - `/^thrift-services\/proptypes/`
|
356 |
|
357 | Если, по какой то причине, вы не хотите такого поведения - вы можете отключить его, добавив в `package.json`:
|
358 |
|
359 | ```json
|
360 | {
|
361 | "aruiScripts": {
|
362 | "keepPropTypes": true
|
363 | }
|
364 | }
|
365 | ```
|
366 |
|
367 | require не js файлов в node_modules в node.js
|
368 | ---
|
369 | Сборка серверной части устроена таким образом, что большая часть `node_modules` не вкомпиливается
|
370 | в итоговый бандл, а загружается стандартным `require` node.js. Как правило - это нам и нужно.
|
371 | Но в случае react-компонентов, мы зачастую запрашиваем кроме кода компонентов еще и `.css`, `.png` и другие файлы.
|
372 | require node.js на таких местах ломается. Поэтому наши внутренние библиотеки компонентов все же вкомпиливаются
|
373 | в итоговый бандл сервера. Это сделанно с помощью [добавления их в исключение](https://github.com/alfa-laboratory/arui-scripts/blob/master/configs/webpack.server.dev.js#L51)
|
374 | плагина [webpack-node-externals](https://www.npmjs.com/package/webpack-node-externals).
|
375 | В случае, если вам необходима обработка не-js файлов из других внешних модулей - вы можете
|
376 | воспользоваться механизмом `overrides`, описанным ниже.
|
377 | По умолчанию же все не-js файлы из внешних модулей будут проигнорированы.
|
378 |
|
379 |
|
380 |
|
381 | Тонкая настройка
|
382 | ===
|
383 | Если вам не хватает гибкости при использовании `arui-scripts`, например вы хотите добавить свой плагин для вебпака -
|
384 | вы можете воспользоваться механизмом `overrides`.
|
385 |
|
386 | Для этого вам необходимо создать в корне вашего проекта файл `arui-scripts.overrides.js`, из которого вы сможете управлять
|
387 | конфигурацией почти всех инструментов, используемых в `arui-scripts`.
|
388 |
|
389 | Принцип работы тут следующий. Для всех конфигураций определен набор ключей, которые они будут искать в `arui-scripts.overrides.js`,
|
390 | В случае если такой ключ найден и это функция - она будет вызвана, и в качестве аргумента ей будет передана существующая конфигурация.
|
391 | Возвращать такая функция должна так же конфигурацию.
|
392 |
|
393 | Например такое содержимое `arui-scripts.overrides.js`:
|
394 | ```javascript
|
395 | const path = require('path');
|
396 | module.exports = {
|
397 | webpack: (config) => {
|
398 | config.resolve.alias = {
|
399 | components: path.resolve(__dirname, 'src/components')
|
400 | };
|
401 | return config;
|
402 | }
|
403 | };
|
404 | ```
|
405 |
|
406 | С помощью этой конфигурации ко всем настройкам вебпака будет добавлен `alias` *components*.
|
407 |
|
408 | На данный момент можно переопределять следующие конфигурации:
|
409 | - `babel-client` - конфигурация `babel` для клиентского кода. Ключи: `babel`, `babelClient`.
|
410 | - `babel-server` - конфигурация `babel` для серверноого кода. Ключи: `babel`, `babelServer`.
|
411 | - `dev-server` - конфигурация `webpack-dev-server`. Ключи: `devServer`.
|
412 | - `postcss` - конфигурация для `postcss`. Ключи: `postcss`.
|
413 | > `config` postcss содержит массив с уже инициализированными плагинами, параметры которых уже зафиксированны. Если необходимо изменить параметры плагинов можно пересоздать конфиг, таким образом:
|
414 | ```javascript
|
415 | const {
|
416 | createPostcssConfig, // функция для создания конфигурационного файла postcss
|
417 | postcssPlugins, // список плагинов
|
418 | postcssPluginsOptions, // коллекция конфигураций плагинов
|
419 | } = require('arui-scripts/configs/postcss.config');
|
420 |
|
421 | module.exports = {
|
422 | postcss: () => {
|
423 | const newOption = {
|
424 | ...postcssPluginsOptions,
|
425 | 'postcss-import': {
|
426 | ...postcssPluginsOptions['postcss-import'],
|
427 | path: [...postcssPluginsOptions['postcss-import'].path, './src'],
|
428 | },
|
429 | };
|
430 | return createPostcssConfig(postcssPlugins, newOption);
|
431 | },
|
432 | };
|
433 | ```
|
434 | - `stats-options` - конфигурация для [webpack-stats](https://webpack.js.org/configuration/stats/). Ключи: `stats`.
|
435 | - `webpack.client.dev` - конфигурация для клиентского webpack в dev режиме. Ключи: `webpack`, `webpackClient`, `webpackDev`, `webpackClientDev`.
|
436 | - `webpack.client.prod` - конфигурация для клиентского webpack в prod режиме. Ключи: `webpack`, `webpackClient`, `webpackProd`, `webpackClientProd`.
|
437 | - `webpack.server.dev` - конфигурация для серверного webpack в dev режиме. Ключи: `webpack`, `webpackServer`, `webpackDev`, `webpackServerDev`.
|
438 | - `webpack.server.prod` - конфигурация для серверного webpack в prod режиме. Ключи: `webpack`, `webpackServer`, `webpackProd`, `webpackServerProd`.
|
439 |
|
440 | Для некоторых конфигураций определены несколько ключей, они будут применяться в том порядке, в котором они приведены в этом файле.
|