UNPKG

25.3 kBMarkdownView Raw
1ARUI-scripts
2===
3
4Приложение на нашем стеке без какой либо конфигурации билдеров.
5
6Во многом пакет аналогичен `react-scripts` из `create-react-app`, разница заключается
7в немного отличающихся настройках для `babel`, поддержки `ts` и возможности работы с серверным кодом.
8
9Использование
10===
11
120. Пакет требует версию nodejs 8+.
13
141. Установите `arui-scripts` в свой проект как dev зависимость
15
16```bash
17yarn add arui-scripts --dev
18```
19или
20```bash
21npm install arui-scripts --save-dev
22```
23
242. Создайте необходимые файлы
25- `src/index.{js,jsx,ts,tsx}` - входная точка для клиентского приложения.
26- `src/server/index.{js,jsx,tsx}` - входная точка для серверного приложения.
27- `node_modules/arui-feather/polyfills` - полифилы для клиентского приложения.
28
29При желании вы можете изменить эти пути с помощью настроек.
30
313. Используйте команды из `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```
69ARUI_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` в рут папку своего проекта.
79TypeScript можно включить, положив `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
95function 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
127import React from 'react'
128import ReactDOM from 'react-dom'
129import App from './app';
130import { AppContainer } from 'react-hot-loader';
131
132ReactDOM.render(
133 <AppContainer><App /></AppContainer>,
134 document.getElementById('react-app')
135);
136if (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
172import server from './server';
173
174let currentServer = server;
175
176async 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
185startServer();
186
187if (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
202import hapi from 'hapi';
203const server = new hapi.Server();
204
205server.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
218export 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
251docker
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`.
263yarn будет использоваться когда в рутовой папке проекта есть `yarn.lock` и `yarn` доступен в системе.
264
265Итоговый контейнер будет содержать `nginx` и скрипт для запуска `nginx` одновременно с `nodejs` сервером.
266
267В итоге, для корректного запуска вашего докер-контейнера вам надо будет выполнить
268
269```
270docker 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
277archive
278---
279
280Команда `arui-scripts archive-build` запускает компиляцию продакшн версии и сборку архива со скомпилированным кодом.
281
282Этот вариант может быть полезен если вы хотите деплоить ваше приложение через подключение архива в марафоне.
283
284Команда предполагает наличие установленных `node_modules` перед сборкой, в процессе работы же очищает дев зависимости используя `yarn` или `npm`.
285yarn будет использоваться когда в рутовой папке проекта есть `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
367require не js файлов в node_modules в node.js
368---
369Сборка серверной части устроена таким образом, что большая часть `node_modules` не вкомпиливается
370в итоговый бандл, а загружается стандартным `require` node.js. Как правило - это нам и нужно.
371Но в случае react-компонентов, мы зачастую запрашиваем кроме кода компонентов еще и `.css`, `.png` и другие файлы.
372require 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
395const path = require('path');
396module.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Для некоторых конфигураций определены несколько ключей, они будут применяться в том порядке, в котором они приведены в этом файле.