arui-scripts 14.5.0-feat-modules.3 → 14.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +4 -21
- package/README.md +0 -2
- package/build/commands/build/build-wrapper.d.ts +2 -2
- package/build/commands/build/client.js +3 -3
- package/build/commands/bundle-analyze/index.js +7 -5
- package/build/commands/changelog/index.js +2 -2
- package/build/commands/start/client.js +2 -2
- package/build/commands/start-prod/client.js +2 -2
- package/build/commands/util/{run-client-dev-derver.d.ts → run-client-dev-server.d.ts} +1 -1
- package/build/commands/util/{run-client-dev-derver.js → run-client-dev-server.js} +4 -1
- package/build/configs/app-configs/available-package-settings.d.ts +8 -0
- package/build/configs/app-configs/available-package-settings.js +32 -0
- package/build/configs/app-configs/calculate-dependent-config.d.ts +8 -49
- package/build/configs/app-configs/calculate-dependent-config.js +13 -11
- package/build/configs/app-configs/get-defaults.d.ts +2 -3
- package/build/configs/app-configs/get-defaults.js +34 -50
- package/build/configs/app-configs/index.d.ts +3 -5
- package/build/configs/app-configs/index.js +7 -13
- package/build/configs/app-configs/types.d.ts +26 -61
- package/build/configs/app-configs/update-with-config-file.d.ts +2 -2
- package/build/configs/app-configs/update-with-config-file.js +7 -5
- package/build/configs/app-configs/update-with-env.js +8 -3
- package/build/configs/app-configs/update-with-package.d.ts +2 -2
- package/build/configs/app-configs/update-with-package.js +10 -5
- package/build/configs/app-configs/update-with-presets.d.ts +2 -2
- package/build/configs/app-configs/update-with-presets.js +15 -8
- package/build/configs/app-configs/validate-settings-keys.d.ts +5 -2
- package/build/configs/app-configs/validate-settings-keys.js +7 -6
- package/build/configs/babel-client.d.ts +1 -33
- package/build/configs/babel-dependencies.d.ts +1 -14
- package/build/configs/babel-server.d.ts +1 -26
- package/build/configs/dev-server.js +4 -11
- package/build/configs/jest/index.d.ts +1 -33
- package/build/configs/postcss.config.d.ts +1 -1
- package/build/configs/server-externals-exemptions.d.ts +1 -1
- package/build/configs/server-externals-exemptions.js +0 -1
- package/build/configs/util/apply-overrides.d.ts +6 -6
- package/build/configs/util/get-entry.d.ts +1 -2
- package/build/configs/webpack.client.d.ts +2 -5
- package/build/configs/webpack.client.dev.d.ts +1 -1
- package/build/configs/webpack.client.js +17 -71
- package/build/configs/webpack.client.prod.d.ts +1 -1
- package/build/index.d.ts +1 -1
- package/build/tsconfig-local.tsbuildinfo +1 -1
- package/package.json +3 -4
- package/build/configs/modules.d.ts +0 -15
- package/build/configs/modules.js +0 -78
- package/docs/modules.md +0 -439
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "arui-scripts",
|
|
3
|
-
"version": "14.5.
|
|
3
|
+
"version": "14.5.1",
|
|
4
4
|
"main": "./build/index.js",
|
|
5
5
|
"typings": "./build/index.d.ts",
|
|
6
6
|
"license": "MPL-2.0",
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
"expose-loader": "3.0.0",
|
|
56
56
|
"file-loader": "6.2.0",
|
|
57
57
|
"filesize": "^6.1.0",
|
|
58
|
-
"fork-ts-checker-webpack-plugin": "6.3
|
|
58
|
+
"fork-ts-checker-webpack-plugin": "6.5.3",
|
|
59
59
|
"fs-extra": "6.0.1",
|
|
60
60
|
"gzip-size": "5.1.1",
|
|
61
61
|
"jest": "28.1.3",
|
|
@@ -79,7 +79,6 @@
|
|
|
79
79
|
"postcss-mixins": "^6.2.0",
|
|
80
80
|
"postcss-nested": "^3.0.0",
|
|
81
81
|
"postcss-omit-import-tilde": "^1.0.1",
|
|
82
|
-
"postcss-prefix-selector": "^1.16.0",
|
|
83
82
|
"postcss-strip-units": "^2.0.1",
|
|
84
83
|
"postcss-url": "7.3.1",
|
|
85
84
|
"react-dev-utils": "11.0.4",
|
|
@@ -123,7 +122,6 @@
|
|
|
123
122
|
"@types/lodash.merge": "^4.6.6",
|
|
124
123
|
"@types/mini-css-extract-plugin": "1.2.2",
|
|
125
124
|
"@types/node": "12",
|
|
126
|
-
"@types/postcss-prefix-selector": "^1.15.0",
|
|
127
125
|
"@types/react-dev-utils": "9.0.8",
|
|
128
126
|
"@types/semver": "^7.3.13",
|
|
129
127
|
"@types/shelljs": "^0.8.11",
|
|
@@ -131,6 +129,7 @@
|
|
|
131
129
|
"@types/strip-ansi": "^5.2.1",
|
|
132
130
|
"@types/tar": "^4.0.3",
|
|
133
131
|
"@types/terser-webpack-plugin": "5.2.0",
|
|
132
|
+
"@types/webpack": "5.28.0",
|
|
134
133
|
"@types/webpack-bundle-analyzer": "4.4.1",
|
|
135
134
|
"@types/webpack-dev-server": "4.3.1",
|
|
136
135
|
"@types/webpack-manifest-plugin": "3.0.3",
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { Assets } from 'assets-webpack-plugin';
|
|
2
|
-
import { EmbeddedModuleConfig } from './app-configs/types';
|
|
3
|
-
export declare function processAssetsPluginOutput(assets: Assets): string;
|
|
4
|
-
export declare function haveExposedMfModules(): Record<string, string> | undefined;
|
|
5
|
-
export declare function getCssPrefixForModule(module: EmbeddedModuleConfig): string | undefined;
|
|
6
|
-
export declare function getChunkNamePrefix(module?: EmbeddedModuleConfig): string;
|
|
7
|
-
export declare function getExposeLoadersFormEmbeddedModules(module?: EmbeddedModuleConfig): {
|
|
8
|
-
test: string;
|
|
9
|
-
use: {
|
|
10
|
-
loader: string;
|
|
11
|
-
options: {
|
|
12
|
-
exposes: string[];
|
|
13
|
-
};
|
|
14
|
-
}[];
|
|
15
|
-
}[];
|
package/build/configs/modules.js
DELETED
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.getExposeLoadersFormEmbeddedModules = exports.getChunkNamePrefix = exports.getCssPrefixForModule = exports.haveExposedMfModules = exports.processAssetsPluginOutput = void 0;
|
|
7
|
-
const app_configs_1 = __importDefault(require("./app-configs"));
|
|
8
|
-
function processAssetsPluginOutput(assets) {
|
|
9
|
-
var _a;
|
|
10
|
-
let adjustedAssets = assets;
|
|
11
|
-
if (haveExposedMfModules()) { // для mf модулей мы делаем publicPath 'auto', но в самом манифесте нам все равно хочется видеть нормальный путь
|
|
12
|
-
Object.keys(adjustedAssets).forEach((key) => {
|
|
13
|
-
adjustedAssets[key] = {
|
|
14
|
-
css: replaceAutoPath(adjustedAssets[key].css),
|
|
15
|
-
js: replaceAutoPath(adjustedAssets[key].js),
|
|
16
|
-
};
|
|
17
|
-
});
|
|
18
|
-
}
|
|
19
|
-
const result = Object.assign(Object.assign({}, adjustedAssets), { __metadata__: {
|
|
20
|
-
version: app_configs_1.default.version,
|
|
21
|
-
name: ((_a = app_configs_1.default.mfModules) === null || _a === void 0 ? void 0 : _a.name) || app_configs_1.default.normalizedName,
|
|
22
|
-
} });
|
|
23
|
-
return JSON.stringify(result);
|
|
24
|
-
}
|
|
25
|
-
exports.processAssetsPluginOutput = processAssetsPluginOutput;
|
|
26
|
-
function replaceAutoPath(assets) {
|
|
27
|
-
if (!assets) {
|
|
28
|
-
return assets;
|
|
29
|
-
}
|
|
30
|
-
if (Array.isArray(assets)) {
|
|
31
|
-
return assets.map((asset) => asset.replace(/^auto\//, app_configs_1.default.publicPath));
|
|
32
|
-
}
|
|
33
|
-
return assets.replace(/^auto\//, app_configs_1.default.publicPath);
|
|
34
|
-
}
|
|
35
|
-
function haveExposedMfModules() {
|
|
36
|
-
var _a;
|
|
37
|
-
return (_a = app_configs_1.default.mfModules) === null || _a === void 0 ? void 0 : _a.exposes;
|
|
38
|
-
}
|
|
39
|
-
exports.haveExposedMfModules = haveExposedMfModules;
|
|
40
|
-
function getCssPrefixForModule(module) {
|
|
41
|
-
if (module.cssPrefix) {
|
|
42
|
-
return module.cssPrefix;
|
|
43
|
-
}
|
|
44
|
-
if (module.cssPrefix === false) {
|
|
45
|
-
return undefined;
|
|
46
|
-
}
|
|
47
|
-
return `.module-${module.name}`;
|
|
48
|
-
}
|
|
49
|
-
exports.getCssPrefixForModule = getCssPrefixForModule;
|
|
50
|
-
function getChunkNamePrefix(module) {
|
|
51
|
-
if (!module) {
|
|
52
|
-
return '';
|
|
53
|
-
}
|
|
54
|
-
return `${module.name}-`;
|
|
55
|
-
}
|
|
56
|
-
exports.getChunkNamePrefix = getChunkNamePrefix;
|
|
57
|
-
function getExposeLoadersFormEmbeddedModules(module) {
|
|
58
|
-
var _a;
|
|
59
|
-
const shared = (_a = app_configs_1.default.embeddedModules) === null || _a === void 0 ? void 0 : _a.shared;
|
|
60
|
-
if (!shared || module) {
|
|
61
|
-
return [];
|
|
62
|
-
}
|
|
63
|
-
return Object.keys(shared).map((libraryName) => {
|
|
64
|
-
const globalVarName = shared[libraryName];
|
|
65
|
-
return {
|
|
66
|
-
test: require.resolve(libraryName),
|
|
67
|
-
use: [
|
|
68
|
-
{
|
|
69
|
-
loader: require.resolve('expose-loader'),
|
|
70
|
-
options: {
|
|
71
|
-
exposes: [globalVarName],
|
|
72
|
-
},
|
|
73
|
-
},
|
|
74
|
-
],
|
|
75
|
-
};
|
|
76
|
-
});
|
|
77
|
-
}
|
|
78
|
-
exports.getExposeLoadersFormEmbeddedModules = getExposeLoadersFormEmbeddedModules;
|
package/docs/modules.md
DELETED
|
@@ -1,439 +0,0 @@
|
|
|
1
|
-
# Что такое модули
|
|
2
|
-
Модули приложений предназначены для решения простой проблемы - переиспользование фронтового кода между приложениями.
|
|
3
|
-
|
|
4
|
-
В целом, для того чтобы переиспользовать код у нас есть много разных способов, например:
|
|
5
|
-
- копировать код из одного приложения в другое. Быстро, но неудобно и неэффективно.
|
|
6
|
-
- выносить код в отдельный пакет и подключать его через npm. Понятный и достаточно удобный вариант,
|
|
7
|
-
но ограничивает нас в скорости изменений. Если мы хотим заменить обновить код в пакете, процесс
|
|
8
|
-
раскатки этого обновления на все приложения может занять много времени.
|
|
9
|
-
- Сделать так, чтобы мы могли подключать код из других приложений в свое. При этом мы получаем
|
|
10
|
-
возможность быстро изменить общий код только в одном месте, а все приложения автоматически получат
|
|
11
|
-
обновления.
|
|
12
|
-
|
|
13
|
-
Модули позволяют реализовать именно последний вариант. Если вы знакомы с концепцией [module federation](https://webpack.js.org/concepts/module-federation/),
|
|
14
|
-
то модули приложений - это его реализация в рамках arui-scripts, с дополнительным уровнем абстракции, который, в том числе,
|
|
15
|
-
позволяет использовать модули без самого module-federation.
|
|
16
|
-
|
|
17
|
-
## Общие принципы работы модулей
|
|
18
|
-
С точки зрения кода модуль представляет собой простой js-объект, который может быть _каким то образом_ подключен в другое приложение.
|
|
19
|
-
|
|
20
|
-
`arui-scripts` предоставляет решение для сборки таких модулей, а также отдельную библиотеку для упрощения их подключения в другие приложения.
|
|
21
|
-
|
|
22
|
-
## Режимы подключения модулей
|
|
23
|
-
|
|
24
|
-
В `arui-scripts` есть два способа сборки модулей:
|
|
25
|
-
- `mf` - Это модули, которые подключаются с помощью [webpack module federation](https://webpack.js.org/concepts/module-federation/).
|
|
26
|
-
- `embedded` - Это модули, которые подключаются просто добавлением нужных скриптов на страницу.
|
|
27
|
-
|
|
28
|
-
Основная проблема, которую решает ModuleFederation - это возможность не загружать на хост-приложение код библиотек уже подключенных в него.
|
|
29
|
-
Например, хост-приложение уже использует `react`, модуль так же написан на `react`. ModuleFederation дает нам легко "переиспользовать"
|
|
30
|
-
уже загруженный в браузер код `react` в модуле, не загружая его еще раз.
|
|
31
|
-
|
|
32
|
-
### Сравнение
|
|
33
|
-
|
|
34
|
-
`mf` модули:
|
|
35
|
-
- **+++** Простой способ для переиспользования библиотек между модулем и приложением-хостом.
|
|
36
|
-
- **+++** Возможность использовать разные версии общих библиотек в разных модулях/хостах (речь про те библиотеки, которые будут шарится).
|
|
37
|
-
- **---** Нет встроенной изоляции стилей. Стили модуля будут применены к хост-приложению.
|
|
38
|
-
- **---** Нет возможности использовать модуль в приложении, которое не использует webpack.
|
|
39
|
-
|
|
40
|
-
Проблема изоляции стилей может быть решена с помощью [shadow dom](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_shadow_DOM),
|
|
41
|
-
или с помощью css modules. Но это накладывает некоторые ограничения либо на поддерживаемые браузеры (shadow dom), либо на
|
|
42
|
-
существующую кодовую базу (css modules должны использоваться везде, если у вас будет две версии arui-feather на странице - будет не очень приятно).
|
|
43
|
-
|
|
44
|
-
`embedded` модули:
|
|
45
|
-
- **+++** Встроенная изоляция стилей. Стили модуля не будут применены к хост-приложению, если только вы не захотите этого.
|
|
46
|
-
- **---** Нет возможности использовать разные версии общих библиотек в разных модулях/хостах, если вы хотите их шарить.
|
|
47
|
-
|
|
48
|
-
## Возможность управления модулями с сервера
|
|
49
|
-
Сами модули используются только на клиентской части приложения. Но, в некоторых случаях, может быть полезно иметь возможность
|
|
50
|
-
управлять тем, какой модуль должен быть подключен на странице с сервера, или же иметь модуль, который будет при загрузке
|
|
51
|
-
иметь доступ к данным, доступным только на сервере (аналогично тому, как мы передаем серверный стейт в приложения при SSR).
|
|
52
|
-
|
|
53
|
-
Поэтому `arui-scripts` предоставляет возможность создать специальный эндпоинт на вашем сервере, из которого вы сможете управлять
|
|
54
|
-
состоянием модуля.
|
|
55
|
-
|
|
56
|
-
Модули с такой возможностью мы называем _серверными модулями_ (обычные модули мы называем _клиентскими_).
|
|
57
|
-
|
|
58
|
-
## Особые типы модулей
|
|
59
|
-
Несмотря на то, что сами по себе модули представляют собой простой js-объект, мы определяем один особый тип модулей - _монтируемые модули_.
|
|
60
|
-
|
|
61
|
-
### Монтируемые модули
|
|
62
|
-
Монтируемые модули - это модули, основное предназначение которых - отрендерить какой-то компонент внутри хост-приложения.
|
|
63
|
-
Монтируемые модули могут быть как клиентскими, так и серверными.
|
|
64
|
-
|
|
65
|
-
Такие модули должны экспортировать две функции:
|
|
66
|
-
|
|
67
|
-
```tsx
|
|
68
|
-
export function mount(targetNode, runParams, serverState): void {
|
|
69
|
-
// здесь происходит монтирование модуля в хост-приложение
|
|
70
|
-
// targetNode - это DOM-нода, в которую нужно отрендерить модуль
|
|
71
|
-
// runParams - это параметры, которые были переданы при запуске модуля
|
|
72
|
-
// serverState - это состояние, которое было передано с сервера
|
|
73
|
-
|
|
74
|
-
// Скорее всего это будет что-то вроде:
|
|
75
|
-
ReactDOM.render(<App preparedState={serverState} runParams={runParams} />, targetNode);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
export function unmount(targetNode): void {
|
|
79
|
-
// здесь происходит демонтирование модуля из хост-приложения
|
|
80
|
-
// Скорее всего это будет что-то вроде:
|
|
81
|
-
ReactDOM.unmountComponentAtNode(targetNode);
|
|
82
|
-
}
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
## Как создать модуль
|
|
86
|
-
|
|
87
|
-
### Описать модуль в настройках arui-scripts
|
|
88
|
-
Для того чтобы ваше приложение начало предоставлять модули, вам необходимо добавить настройки в `arui-scripts.config.ts`:
|
|
89
|
-
|
|
90
|
-
```ts
|
|
91
|
-
import { PackageSettings } from 'arui-scripts';
|
|
92
|
-
|
|
93
|
-
const aruiScriptsConfig: PackageSettings = {
|
|
94
|
-
embeddedModules: {
|
|
95
|
-
exposes: {
|
|
96
|
-
'ClientModuleEmbedded': {
|
|
97
|
-
entry: './src/modules/client-module-embedded/index',
|
|
98
|
-
},
|
|
99
|
-
'ServerModuleEmbedded': {
|
|
100
|
-
entry: './src/modules/server-module-embedded/index',
|
|
101
|
-
// этот модуль будет ожидать на странице глобальные переменные react и reactDOM,
|
|
102
|
-
// он будет использовать их вместо библиотек из своего node_modules
|
|
103
|
-
embeddedConfig: {
|
|
104
|
-
react: 'react',
|
|
105
|
-
'react-dom': 'reactDOM',
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
}
|
|
109
|
-
},
|
|
110
|
-
mfModules: {
|
|
111
|
-
// MF модули тут смогут переиспользовать react и react-dom из хост-приложения,
|
|
112
|
-
// если хост приложение шарит эти библиотеки, и они совпадают по версии
|
|
113
|
-
shared: {
|
|
114
|
-
'react': '^17.0.0',
|
|
115
|
-
'react-dom': '^17.0.0',
|
|
116
|
-
},
|
|
117
|
-
exposes: {
|
|
118
|
-
'ClientModuleMF': './src/modules/client-module-mf/index',
|
|
119
|
-
'ServerModuleMF': './src/modules/server-module-mf/index',
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
export default aruiScriptsConfig;
|
|
125
|
-
```
|
|
126
|
-
|
|
127
|
-
Все параметры конфигурации описаны [ниже](#Конфигурация-модулей).
|
|
128
|
-
|
|
129
|
-
### Создать модуль
|
|
130
|
-
Модуль является простым js/ts файлом. Он может использовать любой код вашего проекта, и любые библиотеки из node_modules.
|
|
131
|
-
|
|
132
|
-
В зависимости от режима подключения модуля, входная точка будет выглядеть по разному.
|
|
133
|
-
|
|
134
|
-
#### Embedded модуль
|
|
135
|
-
Входная точка embedded модуля должна писать в глобальную переменную `window` объект с ключом `{НазваниеМодуля}`.
|
|
136
|
-
Все поля этого объекта по сути и будут являться модулем, ваши потребители смогут использовать их.
|
|
137
|
-
|
|
138
|
-
```ts
|
|
139
|
-
// src/modules/client-module-embedded/index.ts
|
|
140
|
-
|
|
141
|
-
window.ClientModuleEmbedded = {
|
|
142
|
-
doSomething: () => {
|
|
143
|
-
console.log('Hello from embedded module!');
|
|
144
|
-
},
|
|
145
|
-
publicConstant: 3.14,
|
|
146
|
-
// ...
|
|
147
|
-
};
|
|
148
|
-
```
|
|
149
|
-
|
|
150
|
-
<details>
|
|
151
|
-
<summary>Писать в window? Вы что, с дуба рухнулись?</summary>
|
|
152
|
-
Да, конечно, это может создать определенные проблемы (конфликты имен модулей, определенные ограничения на используемые названия),
|
|
153
|
-
но по сути это единственный способ передать код модуля в хост-приложение.
|
|
154
|
-
|
|
155
|
-
Webpack module federation делает абсолютно то же самое, просто прячет работу с глобальными переменными за собой.
|
|
156
|
-
</details>
|
|
157
|
-
|
|
158
|
-
#### MF модуль
|
|
159
|
-
Входная точка MF модуля должна экспортировать все поля модуля через `export`.
|
|
160
|
-
|
|
161
|
-
```ts
|
|
162
|
-
// src/modules/client-module-mf/index.ts
|
|
163
|
-
|
|
164
|
-
export const doSomething = () => {
|
|
165
|
-
console.log('Hello from mf module!');
|
|
166
|
-
};
|
|
167
|
-
|
|
168
|
-
export const publicConstant = 3.14;
|
|
169
|
-
```
|
|
170
|
-
|
|
171
|
-
#### Создание модулей предопределенного типа
|
|
172
|
-
|
|
173
|
-
**Монтируемый модуль, mf**
|
|
174
|
-
|
|
175
|
-
```ts
|
|
176
|
-
// src/modules/client-module-mf/index.ts
|
|
177
|
-
|
|
178
|
-
```
|
|
179
|
-
|
|
180
|
-
### (Опционально) Определить серверный эндпоинт для модуля
|
|
181
|
-
Если вы хотите, чтобы ваш модуль имел серверную часть, которая сможет подготовить данные для модуля, то вам необходимо
|
|
182
|
-
определить серверный эндпоинт для модуля. Для этого вам нужно определить объект, описывающий ваши модули:
|
|
183
|
-
|
|
184
|
-
```ts
|
|
185
|
-
import type { ModulesConfig } from '@alfalab/scripts-server';
|
|
186
|
-
|
|
187
|
-
const modules: ModulesConfig = {
|
|
188
|
-
'ServerModuleEmbedded': {
|
|
189
|
-
mountMode: 'embedded',
|
|
190
|
-
version: '1.0.0',
|
|
191
|
-
getRunParams: async (getResourcesRequest) => ({
|
|
192
|
-
// getResouresRequest - это объект, который будет передан из хост-приложения
|
|
193
|
-
|
|
194
|
-
// данные, которые вернет эта будут доступны при инициализации модуля
|
|
195
|
-
paramFromServer: 'This can be any data from server',
|
|
196
|
-
asyncData: 'It can be constructed from async data, so you may perform some service calls here',
|
|
197
|
-
contextRoot: 'http://localhost:8081',
|
|
198
|
-
}),
|
|
199
|
-
},
|
|
200
|
-
'ServerModuleMF': {
|
|
201
|
-
mountMode: 'mf',
|
|
202
|
-
version: '1.0.0',
|
|
203
|
-
getRunParams: async () => ({
|
|
204
|
-
paramFromServer: 'This can be any data from server',
|
|
205
|
-
asyncData: 'It can be constructed from async data, so you may perform some service calls here',
|
|
206
|
-
contextRoot: 'http://localhost:8081',
|
|
207
|
-
}),
|
|
208
|
-
},
|
|
209
|
-
};
|
|
210
|
-
```
|
|
211
|
-
|
|
212
|
-
Подробнее о `getResourcesRequest` и `getRunParams` рассказано в разделе [Подключение модулей](#Подключение-модулей).
|
|
213
|
-
|
|
214
|
-
Далее, в зависимости от того, какой серверный фреймворк вы используете, вам нужно будет подключить ваши модули в
|
|
215
|
-
соответствующий хендлер. Например, для express это будет выглядеть так:
|
|
216
|
-
|
|
217
|
-
```ts
|
|
218
|
-
import { createGetModulesExpress } from '@alfalab/scripts-server/build/express';
|
|
219
|
-
|
|
220
|
-
const modulesRouter = createGetModulesExpress(modules);
|
|
221
|
-
|
|
222
|
-
app.use(modulesRouter);
|
|
223
|
-
```
|
|
224
|
-
|
|
225
|
-
Для `hapi@16`:
|
|
226
|
-
|
|
227
|
-
```ts
|
|
228
|
-
import { createGetModulesHapi16Plugin } from '@alfalab/scripts-server/build/hapi16';
|
|
229
|
-
|
|
230
|
-
const modulesPlugin = createGetModulesHapi16Plugin(modules);
|
|
231
|
-
|
|
232
|
-
server.register(modulesPlugin);
|
|
233
|
-
```
|
|
234
|
-
|
|
235
|
-
Для `hapi@20`:
|
|
236
|
-
|
|
237
|
-
```ts
|
|
238
|
-
import { createGetModulesHapi20Plugin } from '@alfalab/scripts-server/build/hapi20';
|
|
239
|
-
|
|
240
|
-
const modulesPlugin = createGetModulesHapi20Plugin(modules);
|
|
241
|
-
|
|
242
|
-
server.register(modulesPlugin);
|
|
243
|
-
```
|
|
244
|
-
|
|
245
|
-
Если вы хотите использовать другой серверный фреймворк, вы можете использовать общий хелпер:
|
|
246
|
-
|
|
247
|
-
```ts
|
|
248
|
-
import { createGetModulesMethod } from '@alfalab/scripts-server';
|
|
249
|
-
|
|
250
|
-
const getModules = createGetModulesMethod(modules);
|
|
251
|
-
|
|
252
|
-
// getModules будет иметь следующую сигнатуру:
|
|
253
|
-
type ModulesMethod = {
|
|
254
|
-
method: string; // http метод, который нужно использовать для обработки запроса
|
|
255
|
-
path: string; // путь, который нужно использовать для обработки запроса
|
|
256
|
-
handler: (request: GetResourcesRequest) => Promise<GetResourcesResponse>; // обработчик запроса
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
// далее в зависимости от фреймворка вы можете использовать этот метод
|
|
260
|
-
// для конфигурации вашего сервера
|
|
261
|
-
// вы можете посмотреть примеры реализации тких методов для express, hapi@16 и hapi@20.
|
|
262
|
-
```
|
|
263
|
-
|
|
264
|
-
### (Опционально) Разобраться с изоляцией стилей
|
|
265
|
-
|
|
266
|
-
#### Embedded модули
|
|
267
|
-
В случае с embedded модулями, стили модуля будут применены только к элементам, которые находятся внутри элемента
|
|
268
|
-
с классом `module-{имя модуля}`. Это позволяет изолировать стили модуля от стилей хост-приложения.
|
|
269
|
-
|
|
270
|
-
Вашей ответственностью будет добавить к рут-элементу модуля класс .module-nameOfModule. Вы должны сделать это в самом верхнем компоненте/элементе вашего модуля.
|
|
271
|
-
|
|
272
|
-
Вы можете переопределить префикс для css классов модуля, в `arui-scripts.config.ts`, подробнее в [конфигурации модулей](#Конфигурация-модулей).
|
|
273
|
-
|
|
274
|
-
Если ваше react-приложение использует порталы, вам так же надо не забыть добавить префикс к элементу-порталу.
|
|
275
|
-
|
|
276
|
-
#### MF модули
|
|
277
|
-
Никакого встроенного механизма изоляции стилей для MF модулей нет. Если хост-приложение и модуль используют css-modules,
|
|
278
|
-
то конфликтов возникнуть не должно. Если же это не так - вы можете попробовать решить эту проблему используя shadow-dom.
|
|
279
|
-
|
|
280
|
-
### TODO: тестирование модулей
|
|
281
|
-
|
|
282
|
-
# Подключение модулей
|
|
283
|
-
|
|
284
|
-
## Создание загрузчика
|
|
285
|
-
Базовый способ подключение модулей - это использование `createModuleLoader` из `@alfalab/scripts-modules`. Этот метод
|
|
286
|
-
вернет вам функцию, которая позволит подключить модуль в ваше приложение.
|
|
287
|
-
|
|
288
|
-
```ts
|
|
289
|
-
import { createModuleLoader } from '@alfalab/scripts-modules';
|
|
290
|
-
|
|
291
|
-
const loader = createModuleLoader({
|
|
292
|
-
moduleId: 'test', // id модуля, который вы хотите подключить
|
|
293
|
-
// функция, которая должна вернуть описание модуля.
|
|
294
|
-
getModuleResources: async ({ moduleId, hostAppId, params }) => ({
|
|
295
|
-
scripts: ['http://localhost:8081/static/js/main.js'], // скрипты модуля
|
|
296
|
-
styles: ['http://localhost:8081/static/css/main.css'], // стили модуля
|
|
297
|
-
moduleVersion: '1.0.0', // версия модуля
|
|
298
|
-
appName: 'moduleSourceAppName', // имя приложения, которое является источником модуля
|
|
299
|
-
mountMode: 'embedded', // режим монтирования модуля
|
|
300
|
-
moduleRunParams: { // параметры, которые будут доступны при инициализации модуля
|
|
301
|
-
baseUrl: 'http://localhost:8081',
|
|
302
|
-
},
|
|
303
|
-
}),
|
|
304
|
-
});
|
|
305
|
-
```
|
|
306
|
-
|
|
307
|
-
Вам вовсе не обязательно руками описывать функцию `getModuleResources`. В зависимости от типа модуля, вы можете
|
|
308
|
-
использовать один из готовых хелперов:
|
|
309
|
-
|
|
310
|
-
Для клиентских модулей:
|
|
311
|
-
```ts
|
|
312
|
-
import { createModuleLoader, createClientResourcesFetcher } from '@alfalab/scripts-modules';
|
|
313
|
-
|
|
314
|
-
const loader = createModuleLoader({
|
|
315
|
-
moduleId: 'test',
|
|
316
|
-
getModuleResources: createClientResourcesFetcher({
|
|
317
|
-
baseUrl: 'http://localhost:8081',
|
|
318
|
-
mountMode: 'mf',
|
|
319
|
-
}),
|
|
320
|
-
});
|
|
321
|
-
```
|
|
322
|
-
|
|
323
|
-
`createClientResourcesFetcher` сам сделает запрос за манифестом приложения, и правильным образом сформирует описание модуля.
|
|
324
|
-
|
|
325
|
-
Для серверных модулей:
|
|
326
|
-
```ts
|
|
327
|
-
import { createModuleLoader, createServerResourcesFetcher } from '@alfalab/scripts-modules';
|
|
328
|
-
|
|
329
|
-
const loader = createModuleLoader({
|
|
330
|
-
moduleId: 'test',
|
|
331
|
-
getModuleResources: createServerResourcesFetcher({
|
|
332
|
-
baseUrl: 'http://localhost:8081',
|
|
333
|
-
headers: { 'X-Auth': 'bla-bla' } // опционально вы можете передать дополнительные заголовки для запроса
|
|
334
|
-
}),
|
|
335
|
-
});
|
|
336
|
-
```
|
|
337
|
-
|
|
338
|
-
`createServerResourcesFetcher` сам сделает запрос к ручке, которая отдает описание модуля.
|
|
339
|
-
|
|
340
|
-
В случае же совсем кастомных требований, вы можете реализовать функцию `getModuleResources` самостоятельно.
|
|
341
|
-
|
|
342
|
-
## Использование загрузчика
|
|
343
|
-
После того как вы создали `loader` - вы легко можете получить доступ к модулю:
|
|
344
|
-
|
|
345
|
-
```ts
|
|
346
|
-
const { module, unmount, moduleResources } = await loader({
|
|
347
|
-
getResourcesParams: {}, // параметры, которые будут переданы в getModuleResources
|
|
348
|
-
});
|
|
349
|
-
|
|
350
|
-
console.log(module); // модуль, который вы загрузили. Тут будут доступны всё, что было экспортировано из модуля
|
|
351
|
-
console.log(moduleResources); // полный ответ от getModuleResources
|
|
352
|
-
|
|
353
|
-
// вызов этой функции отмонтирует модуль из вашего приложения - удалит скрипты и стили модуля, а так же удалит
|
|
354
|
-
// все глобальные переменные, которые были определены в модуле.
|
|
355
|
-
unmount();
|
|
356
|
-
```
|
|
357
|
-
|
|
358
|
-
При вызове `loader` вы можете передать параметры, которые попадут в функцию `getModuleResources`. Это может быть полезно,
|
|
359
|
-
если вы хотите передать какие-то параметры на сервер модуля.
|
|
360
|
-
|
|
361
|
-
`getModuleResources` будет вызвана со следующими параметрами:
|
|
362
|
-
```ts
|
|
363
|
-
const getModuleResourcesParams = {
|
|
364
|
-
moduleId: 'test', // id модуля, который вы хотите подключить
|
|
365
|
-
hostAppId: 'hostAppId', // id вашего приложения
|
|
366
|
-
params: {}, // параметры, которые вы передали в loader как `getResourcesParams`
|
|
367
|
-
}
|
|
368
|
-
```
|
|
369
|
-
|
|
370
|
-
На сервер будут отправлены именно эти параметры, они будут доступны как параметр в `getRunParams` в описании вашего модуля.
|
|
371
|
-
|
|
372
|
-
При использовании клиентских модулей, вам не нужно беспокоиться о том, какие параметры вы передаете в `getModuleResources` - они
|
|
373
|
-
никак не используются в клиентских модулях.
|
|
374
|
-
|
|
375
|
-
## Использования загрузчика в реакт-приложении
|
|
376
|
-
|
|
377
|
-
Для того чтобы упростить работу с загрузчиком в реакт-приложении, мы предоставляем хук `useModuleLoader`:
|
|
378
|
-
|
|
379
|
-
```tsx
|
|
380
|
-
import { createModuleLoader, useModuleLoader } from '@alfalab/scripts-modules';
|
|
381
|
-
|
|
382
|
-
const loader = createModuleLoader({
|
|
383
|
-
moduleId: 'test',
|
|
384
|
-
getModuleResources: createClientResourcesFetcher({
|
|
385
|
-
baseUrl: 'http://localhost:8081',
|
|
386
|
-
mountMode: 'mf',
|
|
387
|
-
}),
|
|
388
|
-
});
|
|
389
|
-
|
|
390
|
-
const MyComponent = () => {
|
|
391
|
-
const { loadingState, module, resources } = useModuleLoader(loader); // вторым параметром можно передать параметры, которые будут переданы в getModuleResources
|
|
392
|
-
|
|
393
|
-
return (
|
|
394
|
-
<div>
|
|
395
|
-
{loadingState === 'loading' && <div>Loading...</div>}
|
|
396
|
-
{loadingState === 'error' && <div>Error</div>}
|
|
397
|
-
{loadingState === 'success' && (
|
|
398
|
-
<div>
|
|
399
|
-
<div>Module loaded</div>
|
|
400
|
-
<div>{module}</div> {/* модуль, который вы загрузили. Тут будет доступно всё, что было экспортировано из модуля */}
|
|
401
|
-
<div>{resources}</div>
|
|
402
|
-
</div>
|
|
403
|
-
)}
|
|
404
|
-
</div>
|
|
405
|
-
);
|
|
406
|
-
};
|
|
407
|
-
```
|
|
408
|
-
|
|
409
|
-
### Использование монтируемых модулей
|
|
410
|
-
|
|
411
|
-
Для работы с монтируемыми модулями так же есть готовый хук `useModuleMounter`:
|
|
412
|
-
|
|
413
|
-
```tsx
|
|
414
|
-
import { createModuleLoader, useModuleMounter } from '@alfalab/scripts-modules';
|
|
415
|
-
|
|
416
|
-
const loader = createModuleLoader({
|
|
417
|
-
moduleId: 'test',
|
|
418
|
-
getModuleResources: createClientResourcesFetcher({
|
|
419
|
-
baseUrl: 'http://localhost:8081',
|
|
420
|
-
mountMode: 'embedded',
|
|
421
|
-
}),
|
|
422
|
-
});
|
|
423
|
-
|
|
424
|
-
const MyComponent = () => {
|
|
425
|
-
const { loadingState, targetElementRef } = useModuleMounter({
|
|
426
|
-
loader,
|
|
427
|
-
loaderParams: {}, // параметры, которые будут переданы в getModuleResources, опционально
|
|
428
|
-
runParams: {}, // параметры, которые будут переданы в mount функцию модуля, опционально
|
|
429
|
-
});
|
|
430
|
-
|
|
431
|
-
return (
|
|
432
|
-
<div>
|
|
433
|
-
{loadingState === 'loading' && <div>Loading...</div>}
|
|
434
|
-
{loadingState === 'error' && <div>Error</div>}
|
|
435
|
-
<div ref={targetElementRef} /> {/* сюда будет монтироваться модуль */}
|
|
436
|
-
</div>
|
|
437
|
-
);
|
|
438
|
-
};
|
|
439
|
-
```
|