arui-scripts

    11.6.5 • Public • Published

    ARUI-scripts

    Приложение на нашем стеке без какой либо конфигурации билдеров.

    Во многом пакет аналогичен react-scripts из create-react-app, разница заключается в немного отличающихся настройках для babel, поддержки ts и возможности работы с серверным кодом.

    Использование

    1. Пакет требует версию nodejs 10+.

    2. Установите arui-scripts в свой проект как dev зависимость

    yarn add arui-scripts --dev

    или

    npm install arui-scripts --save-dev
    1. Создайте необходимые файлы
    • src/index.{js,jsx,ts,tsx} - входная точка для клиентского приложения.
    • src/server/index.{js,jsx,tsx} - входная точка для серверного приложения.
    • node_modules/arui-feather/polyfills - полифилы для клиентского приложения.

    При желании вы можете изменить эти пути с помощью настроек.

    1. Используйте команды из arui-scripts!

    Доступные команды

    • arui-scripts start - запускает WebpackDevServer для фронтенда и webpack в режиме --watch для сервера.
    • arui-scripts build - компилирует клиент и сервер для использования в production
    • arui-scripts docker-build - собирает docker контейнер c production билдом и загружает его в артифактори
    • arui-scripts test - запускает jest тесты.
    • arui-scripts archive-build - собирает архив с production билдом
    • arui-scripts bundle-analyze - запускает webpack-bundle-analyzer для prod версии клиентского кода

    Настройки

    Несмотря на то, что все работает из коробки, вы можете захотеть поменять некоторые настройки сборщиков. Сделать это можно в package.json, определив там свойство aruiScripts.

    Доступные настройки:

    • dockerRegistry - адрес используемого docker registry, по умолчанию '', то есть используется публичный registry
    • baseDockerImage - имя базового образа, используемого для построения docker образа. По умолчанию alfabankui/arui-scripts:latest.
    • serverEntry - точка входа для исходников сервера, по умолчанию src/server/index.
    • serverOutput - имя файла для компиляции сервера, по умолчанию server.js.
    • clientPolyfillsEntry - точка входа для полифилов. Будет подключаться до основной точки входа. По умолчанию подтягивает полифилы из arui-feather, если он установлен.
    • clientEntry - точка входа для клиентского приложения. По умолчанию src/index.js.
    • useServerHMR - использовать ли HotModuleReplacement для сервера. По умолчанию false.
    • clientServerPort - порт WebpackDevServer и nginx итогового контейнера. По умолчанию 8080.
    • serverPort - порт нодового сервера. Нужен для правильного проксирования запросов от дев сервера и nginx. По умолчанию 3000.
    • additionalBuildPath - массив путей, которые попадут в архив при использовании команды archive-build. По умолчанию ['config'].
    • archiveName - имя архива, который будет создан при использовании команды archive-build. По умолчанию build.tar.
    • keepPropTypes - если true, пакеты с prop-types не будут удалены из production билда.
    • debug - режим отладки, в котором не выполняются некоторые нежелательные операции и выводится больше сообщений об ошибках, по умолчанию false.
    • useTscLoader - использовать ts-loader вместо babel-loader для обработки ts файлов. У babel-loader есть ряд ограничений. По умолчанию false.
    • componentsTheme - путь к css файлу с темой для core-components. Используется для настройки postcss-custom-properties.
    • keepCssVars - отключает postcss-custom-properties, css переменные будут оставаться в бандле.

    В целях отладки все эти настройки можно переопределить не изменяя package.json Просто передайте необходимые настройки в environment переменной ARUI_SCRIPTS_CONFIG

    ARUI_SCRIPTS_CONFIG="{\"serverPort\":3333}" yarn start
    

    Так же, читаются настройки jest (см. документацию) и proxy (см. документацию).

    Несколько entry point

    Ключи serverEntry и clientEntry принимают не только строки, но и любые возможные в webpack варианты. Например, package.json:

    {
        "aruiScripts": {
            "clientEntry": { "mobile": "src/mobile/", "desktop": "src/desktop/" },
            "serverEntry": ["src/server-prepare", "src/server"]
        }
    }

    Ко всем клиентским entryPoint так же будут добавлены clientPolyfillsEntry (если задан) и, в dev режиме, необходимые для hot-module-reload файлы.

    Переопределение настроек компиляторов

    По умолчанию для компиляции используется только Babel, для переопределения конфига можете положить файл .babelrc в рут папку своего проекта. TypeScript можно включить, положив tsconfig.json в корень проекта.

    Пути до ассетов

    Во время компиляции продакшн версии билда будет созданно два бандла vendor.[hash].js и main.[hash].js. Для того, чтобы генерировать правильный html с подключением этих ассетов вы можете использовать файл webpack-assets.json который будет автоматически положен в папку со скомпилированным кодом.

    vendor.js будет содержать все используемые вами node_modules, за исключением модулей, в названии которых содержится arui.

    main.js содержит все остальное.

    Важно подключать ваши ассеты в правильном порядке, vendor.js должен подключаться ДО main.js.

    Пример функции, которая сформирует отсортированные в правильном порядке массивы для js и css файлов:

    function readAssetsManifest() {
        // читаем манифест
        const manifestPath = path.join(process.cwd(), '.build/webpack-assets.json');
        const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
    
        const js = [];
        const css = [];
        // vendor должен идти перед main
        ['vendor', 'main'].forEach((key) => {
            if (!manifest[key]) { // в дев сборке vendor.js не формируется
                return;
            }
            if (manifest[key].js) {
                js.push(manifest[key].js);
            }
            if (manifest[key].css) {
                css.push(manifest[key].css);
            }
        });
    
        return {
            js, css
        };
    }

    Использование hot-module-replacement

    Клиент:

    По умолчанию на клиенте будет подменяться только css. Для правильной работы с react вам надо добавить примерно такой код:

    import React from 'react'
    import ReactDOM from 'react-dom'
    import App from './app';
    import { AppContainer } from 'react-hot-loader';
    
    ReactDOM.render(
        <AppContainer><App /></AppContainer>,
        document.getElementById('react-app')
    );
    if (module.hot) {
        module.hot.accept('./app', () => {
            const NextAppAssignments = require('./app').default;
            ReactDOM.render(
                <AppContainer><NextAppAssignments /></AppContainer>,
                document.getElementById('react-app')
            );
        });
    }

    При возникновении в консоли предупреждения React-Hot-Loader: react-🔥-dom patch is not detected. React 16.6+ features may not work. убедитесь, что в webpack.client.dev не переопределяется настройка resolve.alias, в нём должна быть следующая запиcь:

    // ...
      resolve: {
        alias: {
          'react-dom': '@hot-loader/react-dom'
        }
      }
    

    Сервер

    Серверная часть приложения по умолчанию будет просто перезапускаться после каждого изменения кода, для использования hot module replacement на сервере нужно сделать несколько вещей:

    В package.json добавить:

    {
        "aruiScripts": { "useServerHMR": true }
    }

    Ваша входная точка сервера должна выглядеть примерно так (на примере hapi):

    server/index.js
    import server from './server';
    
    let currentServer = server;
    
    async function startServer() {
        try {
            await currentServer.start();
        } catch (error) {
            console.error('Failed to start server', error);
            process.exit(1);
        }
    }
    
    startServer();
    
    if (module.hot) {
        module.hot.accept(['./server'], async () => {
            try {
                await currentServer.stop();
    
                currentServer = server; // импорт из сервера заменится самостоятельно
                await startServer();
            } catch (error) {
                console.log('Failed to update server. You probably need to restart application', error);
            }
        });
    }
    server/server.js
    import hapi from 'hapi';
    const server = new hapi.Server();
    
    server.ext('onPostStart', (_, done) => {
        console.log(`Server is running: ${server.info.uri}`);
        done();
    });
    
    (async () => {
        server.connection({ port: 3000 });
    
        // ...
        // конфигурация вашего сервера
        // ...
    })();
    
    export default server;

    Таким образом после изменения кода сервер не будет полностью пререзагружаться, что во многих случаях быстрее. В случае изменения входной точки сервера при использовании HMR вам надо будет перезапускать сервер вручную.

    Тесты

    Команда arui-scripts test внутри запускает jest с дополнительной конфигурацией.

    Конфигурация включает в себя:

    • Использование jest-snapshot-serializer-class-name-to-string для правильной работы с cn
    • Замену всех импортов css файлов на пустые файлы
    • Компиляцию .js/.jsx файлов используя babel
    • Компиляцию .ts/.tsx файлов используя tsc
    • Замену импортов остальных типов файлов на импорт строк с названием файла

    По умолчанию под маску для поиска тестов попадают все файлы *test*.(js|jsx|ts|tsx), *spec*.((js|jsx|ts|tsx)), */__test__/*.(js|jsx|ts|tsx).

    Вы можете переопределять любые настройки jest в package.json, документация.

    Если какие либо из ваших инструментов (например VSСode или WebStorm) не могут запустить тесты поскольку не находят конфигурацию, вы можете так же указать arui-scripts как preset для jest. Таким образом будет работать как запуск тестов через arui-script, так и любые сторонние инструменты, запускающие jest.

    package.json
    {
        "jest": {
            "preset": "arui-scripts"
        }
    }

    docker

    Команда arui-scripts docker-build запускает компиляцию продакшн версии и сборку докер образа.

    Образ основан на alpine-node-nginx.

    Имя контейнера определяется как {configs.dockerRegistry}/{name}:{version}. Переменные name и version по умолчанию берутся из package.json, но вы так же можете переопределить их из командной строки, например arui-scripts docker-build name=container-name version=0.1-beta

    Команда предполагает наличие установленных node_modules перед сборкой, в процессе работы же очищает дев зависимости используя yarn или npm. yarn будет использоваться когда в рутовой папке проекта есть yarn.lock и yarn доступен в системе.

    Итоговый контейнер будет содержать nginx и скрипт для запуска nginx одновременно с nodejs сервером.

    В итоге, для корректного запуска вашего докер-контейнера вам надо будет выполнить

    docker run -p 8080:8080 container-name:version ./start.sh
    

    На 8080 порту будет поднят nginx, который будет раздавать статику и проксировать все остальные запросы к nodejs.

    Вы также можете переопределить полностью процесс сборки docker-образа используя механизм overrides или создав в корневой директории проекта Dockerfile содержащий необходимый набор инструкций. Пример Dockerfile.

    Dockerfile в корне проекта имеет приоритет над overrides.

    archive

    Команда arui-scripts archive-build запускает компиляцию продакшн версии и сборку архива со скомпилированным кодом.

    Этот вариант может быть полезен если вы хотите деплоить ваше приложение через подключение архива в марафоне.

    Команда предполагает наличие установленных node_modules перед сборкой, в процессе работы же очищает дев зависимости используя yarn или npm. yarn будет использоваться когда в рутовой папке проекта есть yarn.lock и yarn доступен в системе.

    Итоговый архив будет содержать в себе .build, node_modules, package.json и config папки вашего проекта.

    Проксирование запросов до бэкенда.

    В случае, если ваш фронт должен обращаться к API, отличному от вашего nodejs сервера, в дев режиме вы можете настроить проксирование запросов. Сделать это можно используя свойство proxy в вашем package.json.

    Например:

    {
        "proxy": {
            "/corp-shared-ui": {
                "target": "http://corpint4",
                "headers": {
                    "host": "corpint4"
                }
            }
        }
    }

    Такая конфигурация будет проксировать запросы к http://localhost:8080/corp-shared-ui/ на http://corpint4/corp-shared-ui. Подробнее о конфигурации прокси сервера можно почитать в документации Webpack.

    Конфигурация typescript

    Компиляция TS работает из коробки, если в корне проекта есть файл tsconfig.json. За основу можно использовать дефолтный конфиг:

    {
        "extends": "./node_modules/arui-scripts/tsconfig.json"
    }

    По умолчанию TS будет компилироваться через babel, но у этого есть ряд ограничений:

    • нельзя использовать namespace
    • Нельзя использовать устаревший синтаксис import/export (import foo = require(...), export = foo)
    • enum merging

    Если вы используете что-то из вышеперичисленного - вы можете вернуться к использованию tsc для компиляции ts файлов

    {
        "aruiScripts": { "useTscLoader": true }
    }

    Конфигурация nginx

    Несмотря на то, что nginx имеет готовый конфиг с роутингом, иногда возникает необходимость добавлять свои роуты. Вы можете использовать механизм overrides. Так же вы можете создать nginx.conf на уровне проекта со своими роутами. Пример конфига тут. Файл nginx.conf имеет приоритет над оверрайдами.

    Использование env переменных в nginx.conf

    Иногда у вас может возникнуть потребность переопределять какие-то из настроек nginx в зависимости от среды, на которой запущен контейнер. Это можно сделать задав свой nginx.conf и передав ENV переменные в контейнер. По умолчанию конфигурация nginx прогоняется при старте через envsubst.

    Если вы используете свой базовый docker-образ для работы приложения - убедитесь что в нем доступен envsubst. Для alpine он является частью пакета gettext

    Важно. Для того, чтобы сохранить нормальную работу специальных переменных nginx, типа $proxy_add_x_forwarded_for перед запуском envsubst они будут заменены на ~~proxy_add_x_forwarded_for~~, а затем возвращены в исходный вид. envsubst будет заменять переменные записанные только как ${MY_VAR}.

    Вы можете использовать это так:

    server {
        listen 8080;
        server_name ${SERVICE_NAME};
        ...
    }
    
    docker run my-awesome-app --env SERVICE_NAME=my-app

    После запуска nginx будет иметь server_name my-app.

    Удаление proptypes

    Так как в production режими proptypes не проверяются, их имеет смысл удалить из production сборки.

    Сами объявления proptypes удаляются с помощью babel-plugin-transform-react-remove-prop-types. Но импорты пакетов prop-types при этом не удаляются. Чтобы это реализовать, используется webpack.NormalModuleReplacementPlugin. С помощью него заменяются на пустышку пакеты, попадающие под маску:

    • /^react-style-proptype$/
    • /^thrift-services\/proptypes/

    Если, по какой то причине, вы не хотите такого поведения - вы можете отключить его, добавив в package.json:

    {
        "aruiScripts": {
            "keepPropTypes": true
        }
    }

    require не js файлов в node_modules в node.js

    Сборка серверной части устроена таким образом, что большая часть node_modules не вкомпиливается в итоговый бандл, а загружается стандартным require node.js. Как правило - это нам и нужно. Но в случае react-компонентов, мы зачастую запрашиваем кроме кода компонентов еще и .css, .png и другие файлы. require node.js на таких местах ломается. Поэтому наши внутренние библиотеки компонентов все же вкомпиливаются в итоговый бандл сервера. Это сделанно с помощью добавления их в исключение плагина webpack-node-externals. В случае, если вам необходима обработка не-js файлов из других внешних модулей - вы можете воспользоваться механизмом overrides, описанным ниже. По умолчанию же все не-js файлы из внешних модулей будут проигнорированы.

    Тонкая настройка

    Если вам не хватает гибкости при использовании arui-scripts, например вы хотите добавить свой плагин для вебпака - вы можете воспользоваться механизмом overrides.

    Для этого вам необходимо создать в корне вашего проекта файл arui-scripts.overrides.js, из которого вы сможете управлять конфигурацией почти всех инструментов, используемых в arui-scripts.

    Принцип работы тут следующий. Для всех конфигураций определен набор ключей, которые они будут искать в arui-scripts.overrides.js, В случае если такой ключ найден и это функция - она будет вызвана, и в качестве аргументов ей будут переданы существующая конфигурация и полный конфиг приложения (см AppConfig). Возвращать такая функция должна так же конфигурацию.

    Например такое содержимое arui-scripts.overrides.js:

    const path = require('path');
    module.exports = {
        webpack: (config, applicationConfig) => {
            config.resolve.alias = {
                components: path.resolve(__dirname, 'src/components')
            };
            return config;
        }
    };

    С помощью этой конфигурации ко всем настройкам вебпака будет добавлен alias components.

    На данный момент можно переопределять следующие конфигурации:

    • babel-client - конфигурация babel для клиентского кода. Ключи: babel, babelClient.
    • babel-server - конфигурация babel для серверноого кода. Ключи: babel, babelServer.
    • dev-server - конфигурация webpack-dev-server. Ключи: devServer.
    • postcss - конфигурация для postcss. Ключи: postcss.

      config postcss содержит массив с уже инициализированными плагинами, параметры которых уже зафиксированны. Если необходимо изменить параметры плагинов можно пересоздать конфиг, таким образом:

      const {
          createPostcssConfig, // функция для создания конфигурационного файла postcss
          postcssPlugins, // список плагинов
          postcssPluginsOptions, // коллекция конфигураций плагинов
      } = require('arui-scripts/build/configs/postcss.config');
      
      module.exports = {
          postcss: () => {
              const newOption = {
                  ...postcssPluginsOptions,
                  'postcss-import': {
                      ...postcssPluginsOptions['postcss-import'],
                      path: [...postcssPluginsOptions['postcss-import'].path, './src'],
                  },
              };
              return createPostcssConfig(postcssPlugins, newOption);
          },
      };
    • stats-options - конфигурация для webpack-stats. Ключи: stats.
    • webpack.client.dev - конфигурация для клиентского webpack в dev режиме. Ключи: webpack, webpackClient, webpackDev, webpackClientDev.
    • webpack.client.prod - конфигурация для клиентского webpack в prod режиме. Ключи: webpack, webpackClient, webpackProd, webpackClientProd.
    • webpack.server.dev - конфигурация для серверного webpack в dev режиме. Ключи: webpack, webpackServer, webpackDev, webpackServerDev.
    • webpack.server.prod - конфигурация для серверного webpack в prod режиме. Ключи: webpack, webpackServer, webpackProd, webpackServerProd.
    • supporting-browsers - список поддерживаемых браузеров в формате browserslist. Ключи: browsers, supportingBrowsers
    • Dockerfile - докерфайл, который будет использоваться для сборки контейнера. Базовый шаблон тут. Dockerfile в корне проекта имеет приоритет над overrides.
    • nginx - шаблон конфигурации для nginx внутри контейнера. Базовый шаблон тут. Файл nginx.conf в корне имеет приоритет над оверрайдами.
    • start.sh - шаблон entrypoint докер контейнера. Базовый шаблон тут.

    Для некоторых конфигураций определены несколько ключей, они будут применяться в том порядке, в котором они приведены в этом файле.

    Пресеты

    В случае, если вы хотите использовать определенный набор конфигураций и оверрайдов сразу в нескольких проектах - вам может помочь механизм пресетов. Он позволяет выносить конфигурацию и оверрайды в отдельный пакет. Для того чтобы использовать персеты на проекте вы должны указать в package.json:

    {
        "aruiScripts": {
            "presets": "my-company-presets"
        }
    }

    Как пресет должен быть указан путь до папки с общими настройками (для поиска пути будет использоваться require.resolve от папки, содержащей package.json. Так что это может быть как папка в проекте, так и пакет из node_modules).

    Сам пакет с пресетами может содержать два файла:

    • arui-scirpts.config.js
    • arui-scripts.overrides.js

    arui-scripts.config.js

    С помощью этого файла можно задать любые ключи конфигурации.

    module.exports = {
        baseDockerImage: 'my-company-artifactory.com/arui-scripts-base:11.2'
    };

    На проекте конфиурация будет загружаться в следующем порядке:

    1. базовые настройки из arui-scripts
    2. настройки из presets
    3. настройки из package.json проекта
    4. настройки, переданные через env переменную.

    Важно!

    Если вы будете задавать относительные пути через общие конфигурации (например serverEntry, additionalBuildPath и другие) они будут вычисляться относительно корня проекта, а не вашей конфигурации. Вы можете использовать абсолютные пути при необходимости задать путь до файла внутри пакета с пресетами.

    arui-scripts.overrides.js

    С помощью этого файла можно задать базовые оверрайды проекта, аналогично заданию оверрайдов на проекте.

    module.exports = {
        babelClient(config) {
            config.plugins.push('my-awesome-babel-plugin');
            return config;
        }
    };

    На проекте оверрайды из пресетов будут выполняться в первую очередь, после них будут выполняться оверрайды из проекта.

    Keywords

    none

    Install

    npm i arui-scripts

    DownloadsWeekly Downloads

    309

    Version

    11.6.5

    License

    MPL-2.0

    Unpacked Size

    1.03 MB

    Total Files

    61

    Last publish

    Collaborators

    • samoxbal
    • siebensieben
    • heymdall
    • stepain
    • aweppc2
    • luchanso
    • raylyanway
    • ilatovsky
    • inc1uder
    • reme3d2y
    • dmitrsavk
    • madbrozzer
    • igor-alfa-test
    • doyakovlev
    • fenkoalex-org
    • praiz90