@gravity-ui/app-builder 0.13.1 → 0.14.0-beta.0
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/dist/commands/dev/client.js +42 -16
- package/dist/commands/dev/index.js +1 -1
- package/dist/common/models/index.d.ts +4 -0
- package/dist/common/paths.d.ts +2 -0
- package/dist/common/paths.js +2 -0
- package/dist/common/webpack/compile.js +7 -2
- package/dist/common/webpack/config.d.ts +6 -2
- package/dist/common/webpack/config.js +187 -134
- package/dist/common/webpack/public-path.js +2 -1
- package/dist/common/webpack/storybook.js +4 -0
- package/dist/common/webpack/utils.d.ts +1 -1
- package/dist/common/webpack/utils.js +10 -2
- package/package.json +3 -1
|
@@ -40,9 +40,6 @@ const config_1 = require("../../common/webpack/config");
|
|
|
40
40
|
async function watchClientCompilation(config, onManifestReady) {
|
|
41
41
|
const clientCompilation = await buildWebpackServer(config);
|
|
42
42
|
const compiler = clientCompilation.compiler;
|
|
43
|
-
if ('compilers' in compiler) {
|
|
44
|
-
throw new Error('Unexpected multi compiler');
|
|
45
|
-
}
|
|
46
43
|
subscribeToManifestReadyEvent(compiler, onManifestReady);
|
|
47
44
|
return clientCompilation;
|
|
48
45
|
}
|
|
@@ -50,7 +47,14 @@ async function buildWebpackServer(config) {
|
|
|
50
47
|
const logger = new logger_1.Logger('webpack', config.verbose);
|
|
51
48
|
const { webSocketPath = path.normalize(`/${config.client.publicPathPrefix}/build/sockjs-node`), writeToDisk, ...devServer } = config.client.devServer || {};
|
|
52
49
|
const normalizedConfig = { ...config.client, devServer: { ...devServer, webSocketPath } };
|
|
53
|
-
const
|
|
50
|
+
const webpackConfigs = [
|
|
51
|
+
await (0, config_1.webpackConfigFactory)("development" /* WebpackMode.Dev */, normalizedConfig, { logger }),
|
|
52
|
+
];
|
|
53
|
+
const isSsr = Boolean(normalizedConfig.ssr);
|
|
54
|
+
if (isSsr) {
|
|
55
|
+
const logger = new logger_1.Logger('webpack(SSR)', config.verbose);
|
|
56
|
+
webpackConfigs.push(await (0, config_1.webpackConfigFactory)("development" /* WebpackMode.Dev */, normalizedConfig, { logger, isSsr }));
|
|
57
|
+
}
|
|
54
58
|
const publicPath = path.normalize(config.client.publicPathPrefix + '/build/');
|
|
55
59
|
const staticFolder = path.resolve(paths_1.default.appDist, 'public');
|
|
56
60
|
const options = {
|
|
@@ -58,7 +62,18 @@ async function buildWebpackServer(config) {
|
|
|
58
62
|
devMiddleware: {
|
|
59
63
|
publicPath,
|
|
60
64
|
stats: 'errors-warnings',
|
|
61
|
-
writeToDisk
|
|
65
|
+
writeToDisk: (target) => {
|
|
66
|
+
if (writeToDisk === true) {
|
|
67
|
+
return true;
|
|
68
|
+
}
|
|
69
|
+
if (isSsr && target.startsWith(paths_1.default.appSsrBuild)) {
|
|
70
|
+
return true;
|
|
71
|
+
}
|
|
72
|
+
if (typeof writeToDisk === 'function') {
|
|
73
|
+
return writeToDisk(target);
|
|
74
|
+
}
|
|
75
|
+
return false;
|
|
76
|
+
},
|
|
62
77
|
},
|
|
63
78
|
liveReload: false,
|
|
64
79
|
hot: true,
|
|
@@ -116,7 +131,7 @@ async function buildWebpackServer(config) {
|
|
|
116
131
|
});
|
|
117
132
|
}
|
|
118
133
|
options.proxy = proxy;
|
|
119
|
-
const compiler = (0, webpack_1.default)(
|
|
134
|
+
const compiler = (0, webpack_1.default)(webpackConfigs);
|
|
120
135
|
const server = new webpack_dev_server_1.default(options, compiler);
|
|
121
136
|
try {
|
|
122
137
|
await server.start();
|
|
@@ -129,17 +144,28 @@ async function buildWebpackServer(config) {
|
|
|
129
144
|
}
|
|
130
145
|
return server;
|
|
131
146
|
}
|
|
132
|
-
function subscribeToManifestReadyEvent(
|
|
147
|
+
function subscribeToManifestReadyEvent(webpackCompiler, onManifestReady) {
|
|
133
148
|
const promises = [];
|
|
134
|
-
const
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
149
|
+
const options = Array.isArray(webpackCompiler.options)
|
|
150
|
+
? webpackCompiler.options
|
|
151
|
+
: [webpackCompiler.options];
|
|
152
|
+
const compilers = 'compilers' in webpackCompiler ? webpackCompiler.compilers : [webpackCompiler];
|
|
153
|
+
for (let i = 0; i < options.length; i++) {
|
|
154
|
+
const config = options[i];
|
|
155
|
+
const compiler = compilers[i];
|
|
156
|
+
if (!config || !compiler) {
|
|
157
|
+
throw new Error('Something goes wrong!');
|
|
158
|
+
}
|
|
159
|
+
const assetsManifestPlugin = config.plugins.find((plugin) => plugin instanceof webpack_assets_manifest_1.default);
|
|
160
|
+
if (assetsManifestPlugin) {
|
|
161
|
+
const assetsManifestReady = (0, utils_1.deferredPromise)();
|
|
162
|
+
promises.push(assetsManifestReady.promise);
|
|
163
|
+
assetsManifestPlugin.hooks.done.tap('app-builder', assetsManifestReady.resolve);
|
|
164
|
+
}
|
|
165
|
+
const manifestReady = (0, utils_1.deferredPromise)();
|
|
166
|
+
promises.push(manifestReady.promise);
|
|
167
|
+
const { afterEmit } = (0, webpack_manifest_plugin_1.getCompilerHooks)(compiler);
|
|
168
|
+
afterEmit.tap('app-builder', manifestReady.resolve);
|
|
139
169
|
}
|
|
140
|
-
const manifestReady = (0, utils_1.deferredPromise)();
|
|
141
|
-
promises.push(manifestReady.promise);
|
|
142
|
-
const { afterEmit } = (0, webpack_manifest_plugin_1.getCompilerHooks)(compiler);
|
|
143
|
-
afterEmit.tap('app-builder', manifestReady.resolve);
|
|
144
170
|
Promise.all(promises).then(() => onManifestReady());
|
|
145
171
|
}
|
|
@@ -56,7 +56,7 @@ async function default_1(config) {
|
|
|
56
56
|
script: `${serverPath}/index.js`,
|
|
57
57
|
args: ['--dev', config.server.port ? `--port=${config.server.port}` : ''],
|
|
58
58
|
env: {
|
|
59
|
-
...(config.server.port ? { APP_PORT: config.server.port } : undefined),
|
|
59
|
+
...(config.server.port ? { APP_PORT: `${config.server.port}` } : undefined),
|
|
60
60
|
},
|
|
61
61
|
nodeArgs: inspect || inspectBrk
|
|
62
62
|
? [`--${inspect ? 'inspect' : 'inspect-brk'}=:::${inspect || inspectBrk}`]
|
|
@@ -191,6 +191,10 @@ export interface ClientConfig {
|
|
|
191
191
|
* Modify or return a custom [Terser options](https://github.com/terser/terser#minify-options).
|
|
192
192
|
*/
|
|
193
193
|
terser?: (options: TerserOptions) => TerserOptions;
|
|
194
|
+
ssr?: {
|
|
195
|
+
noExternal?: string | RegExp | (string | RegExp)[] | true;
|
|
196
|
+
moduleType?: 'commonjs' | 'esm';
|
|
197
|
+
};
|
|
194
198
|
}
|
|
195
199
|
export interface CdnUploadConfig {
|
|
196
200
|
bucket: string;
|
package/dist/common/paths.d.ts
CHANGED
package/dist/common/paths.js
CHANGED
|
@@ -36,6 +36,8 @@ exports.default = {
|
|
|
36
36
|
appDist: resolveApp('dist'),
|
|
37
37
|
appRun: resolveApp('dist/run'),
|
|
38
38
|
appBuild: resolveApp('dist/public/build'),
|
|
39
|
+
appSsrEntry: resolveApp('src/ui/ssr'),
|
|
40
|
+
appSsrBuild: resolveApp('dist/ssr'),
|
|
39
41
|
src: resolveApp('src'),
|
|
40
42
|
libBuild: resolveApp('build'),
|
|
41
43
|
libBuildEsm: resolveApp('build/esm'),
|
|
@@ -10,10 +10,15 @@ const config_1 = require("./config");
|
|
|
10
10
|
const utils_1 = require("./utils");
|
|
11
11
|
async function webpackCompile(config) {
|
|
12
12
|
const logger = new logger_1.Logger('webpack', config.verbose);
|
|
13
|
-
const
|
|
13
|
+
const webpackConfigs = [await (0, config_1.webpackConfigFactory)("production" /* WebpackMode.Prod */, config, { logger })];
|
|
14
|
+
const isSsr = Boolean(config.ssr);
|
|
15
|
+
if (isSsr) {
|
|
16
|
+
const logger = new logger_1.Logger('webpack(SSR)', config.verbose);
|
|
17
|
+
webpackConfigs.push(await (0, config_1.webpackConfigFactory)("production" /* WebpackMode.Prod */, config, { logger, isSsr }));
|
|
18
|
+
}
|
|
14
19
|
logger.verbose('Config created');
|
|
15
20
|
return new Promise((resolve) => {
|
|
16
|
-
const compiler = (0, webpack_1.default)(
|
|
21
|
+
const compiler = (0, webpack_1.default)(webpackConfigs, (0, utils_1.webpackCompilerHandlerFactory)(logger, async () => {
|
|
17
22
|
resolve();
|
|
18
23
|
}));
|
|
19
24
|
process.on('SIGINT', async () => {
|
|
@@ -7,16 +7,20 @@ export interface HelperOptions {
|
|
|
7
7
|
isEnvDevelopment: boolean;
|
|
8
8
|
isEnvProduction: boolean;
|
|
9
9
|
configType: `${WebpackMode}`;
|
|
10
|
+
buildDirectory: string;
|
|
11
|
+
entriesDirectory: string;
|
|
12
|
+
isSsr: boolean;
|
|
10
13
|
}
|
|
11
14
|
export declare const enum WebpackMode {
|
|
12
15
|
Prod = "production",
|
|
13
16
|
Dev = "development"
|
|
14
17
|
}
|
|
15
|
-
export declare function webpackConfigFactory(webpackMode: WebpackMode, config: NormalizedClientConfig, { logger }?: {
|
|
18
|
+
export declare function webpackConfigFactory(webpackMode: WebpackMode, config: NormalizedClientConfig, { logger, isSsr }?: {
|
|
16
19
|
logger?: Logger;
|
|
20
|
+
isSsr?: boolean;
|
|
17
21
|
}): Promise<webpack.Configuration>;
|
|
18
22
|
export declare function configureModuleRules(helperOptions: HelperOptions, additionalRules?: NonNullable<webpack.RuleSetRule['oneOf']>): webpack.RuleSetRule[];
|
|
19
23
|
export declare function configureResolve({ isEnvProduction, config }: HelperOptions): webpack.ResolveOptions;
|
|
20
24
|
type Optimization = NonNullable<webpack.Configuration['optimization']>;
|
|
21
|
-
export declare function configureOptimization({ config }: HelperOptions): Optimization;
|
|
25
|
+
export declare function configureOptimization({ config, isSsr }: HelperOptions): Optimization;
|
|
22
26
|
export {};
|
|
@@ -44,6 +44,7 @@ const react_refresh_webpack_plugin_1 = __importDefault(require("@pmmmwh/react-re
|
|
|
44
44
|
const moment_timezone_data_webpack_plugin_1 = __importDefault(require("moment-timezone-data-webpack-plugin"));
|
|
45
45
|
const webpack_plugin_1 = __importDefault(require("@statoscope/webpack-plugin"));
|
|
46
46
|
const circular_dependency_plugin_1 = __importDefault(require("circular-dependency-plugin"));
|
|
47
|
+
const webpack_node_externals_1 = __importDefault(require("webpack-node-externals"));
|
|
47
48
|
const paths_1 = __importDefault(require("../paths"));
|
|
48
49
|
const babel_1 = require("../babel");
|
|
49
50
|
const progress_plugin_1 = require("./progress-plugin");
|
|
@@ -53,7 +54,7 @@ const log_config_1 = require("../logger/log-config");
|
|
|
53
54
|
const utils_2 = require("../typescript/utils");
|
|
54
55
|
const imagesSizeLimit = 2048;
|
|
55
56
|
const fontSizeLimit = 8192;
|
|
56
|
-
async function webpackConfigFactory(webpackMode, config, { logger } = {}) {
|
|
57
|
+
async function webpackConfigFactory(webpackMode, config, { logger, isSsr = false } = {}) {
|
|
57
58
|
const isEnvDevelopment = webpackMode === "development" /* WebpackMode.Dev */;
|
|
58
59
|
const isEnvProduction = webpackMode === "production" /* WebpackMode.Prod */;
|
|
59
60
|
const helperOptions = {
|
|
@@ -62,11 +63,25 @@ async function webpackConfigFactory(webpackMode, config, { logger } = {}) {
|
|
|
62
63
|
isEnvDevelopment,
|
|
63
64
|
isEnvProduction,
|
|
64
65
|
configType: webpackMode,
|
|
66
|
+
buildDirectory: isSsr ? paths_1.default.appSsrBuild : paths_1.default.appBuild,
|
|
67
|
+
entriesDirectory: isSsr ? paths_1.default.appSsrEntry : paths_1.default.appEntry,
|
|
68
|
+
isSsr,
|
|
65
69
|
};
|
|
70
|
+
let externals = config.externals;
|
|
71
|
+
if (isSsr) {
|
|
72
|
+
externals =
|
|
73
|
+
config.ssr?.noExternal === true
|
|
74
|
+
? undefined
|
|
75
|
+
: (0, webpack_node_externals_1.default)({
|
|
76
|
+
allowlist: config.ssr?.noExternal,
|
|
77
|
+
importType: config.ssr?.moduleType === 'esm' ? 'module' : 'commonjs',
|
|
78
|
+
});
|
|
79
|
+
}
|
|
66
80
|
let webpackConfig = {
|
|
67
81
|
mode: webpackMode,
|
|
68
82
|
context: paths_1.default.app,
|
|
69
83
|
bail: isEnvProduction,
|
|
84
|
+
target: isSsr ? 'node' : undefined,
|
|
70
85
|
devtool: configureDevTool(helperOptions),
|
|
71
86
|
entry: configureEntry(helperOptions),
|
|
72
87
|
output: configureOutput(helperOptions),
|
|
@@ -76,7 +91,7 @@ async function webpackConfigFactory(webpackMode, config, { logger } = {}) {
|
|
|
76
91
|
},
|
|
77
92
|
plugins: configurePlugins(helperOptions),
|
|
78
93
|
optimization: configureOptimization(helperOptions),
|
|
79
|
-
externals
|
|
94
|
+
externals,
|
|
80
95
|
node: config.node,
|
|
81
96
|
watchOptions: configureWatchOptions(helperOptions),
|
|
82
97
|
ignoreWarnings: [/Failed to parse source map/],
|
|
@@ -135,7 +150,10 @@ function configureWatchOptions({ config }) {
|
|
|
135
150
|
delete watchOptions.watchPackages;
|
|
136
151
|
return watchOptions;
|
|
137
152
|
}
|
|
138
|
-
function configureExperiments({ config, isEnvProduction, }) {
|
|
153
|
+
function configureExperiments({ config, isEnvProduction, isSsr, }) {
|
|
154
|
+
if (isSsr) {
|
|
155
|
+
return config.ssr?.moduleType === 'esm' ? { outputModule: true } : undefined;
|
|
156
|
+
}
|
|
139
157
|
if (isEnvProduction) {
|
|
140
158
|
return undefined;
|
|
141
159
|
}
|
|
@@ -190,56 +208,69 @@ function createEntryArray(entry) {
|
|
|
190
208
|
return [require.resolve('./public-path'), entry];
|
|
191
209
|
}
|
|
192
210
|
function addEntry(entry, file) {
|
|
193
|
-
const newEntry = path.resolve(paths_1.default.appEntry, file);
|
|
194
211
|
return {
|
|
195
212
|
...entry,
|
|
196
|
-
[path.parse(file).name]: createEntryArray(
|
|
213
|
+
[path.parse(file).name]: createEntryArray(file),
|
|
197
214
|
};
|
|
198
215
|
}
|
|
199
|
-
function configureEntry({ config }) {
|
|
200
|
-
let entries = fs.readdirSync(
|
|
216
|
+
function configureEntry({ config, entriesDirectory }) {
|
|
217
|
+
let entries = fs.readdirSync(entriesDirectory).filter((file) => /\.[jt]sx?$/.test(file));
|
|
201
218
|
if (Array.isArray(config.entryFilter) && config.entryFilter.length) {
|
|
202
219
|
entries = entries.filter((entry) => config.entryFilter?.includes(entry.split('.')[0] ?? ''));
|
|
203
220
|
}
|
|
204
221
|
if (!entries.length) {
|
|
205
|
-
throw new Error('No entries were found after applying
|
|
222
|
+
throw new Error('No entries were found after applying entry filter');
|
|
206
223
|
}
|
|
207
|
-
return entries.reduce((entry, file) => addEntry(entry, file), {});
|
|
224
|
+
return entries.reduce((entry, file) => addEntry(entry, path.resolve(entriesDirectory, file)), {});
|
|
208
225
|
}
|
|
209
|
-
function getFileNames({ isEnvProduction }) {
|
|
226
|
+
function getFileNames({ isEnvProduction, isSsr, config }) {
|
|
227
|
+
let ext = 'js';
|
|
228
|
+
if (isSsr) {
|
|
229
|
+
ext = config.ssr?.moduleType === 'esm' ? 'mjs' : 'cjs';
|
|
230
|
+
}
|
|
210
231
|
return {
|
|
211
|
-
filename: isEnvProduction ?
|
|
232
|
+
filename: isEnvProduction ? `js/[name].[contenthash:8].${ext}` : `js/[name].${ext}`,
|
|
212
233
|
chunkFilename: isEnvProduction
|
|
213
234
|
? 'js/[name].[contenthash:8].chunk.js'
|
|
214
235
|
: 'js/[name].chunk.js',
|
|
215
236
|
};
|
|
216
237
|
}
|
|
217
|
-
function configureOutput(
|
|
238
|
+
function configureOutput(options) {
|
|
239
|
+
let ssrOptions;
|
|
240
|
+
if (options.isSsr) {
|
|
241
|
+
ssrOptions = {
|
|
242
|
+
library: { type: options.config.ssr?.moduleType === 'esm' ? 'module' : 'commonjs2' },
|
|
243
|
+
chunkFormat: false,
|
|
244
|
+
};
|
|
245
|
+
}
|
|
218
246
|
return {
|
|
219
|
-
...getFileNames(
|
|
220
|
-
path:
|
|
221
|
-
pathinfo: isEnvDevelopment,
|
|
247
|
+
...getFileNames(options),
|
|
248
|
+
path: options.buildDirectory,
|
|
249
|
+
pathinfo: options.isEnvDevelopment,
|
|
250
|
+
...ssrOptions,
|
|
222
251
|
};
|
|
223
252
|
}
|
|
224
|
-
function createJavaScriptLoader({ isEnvProduction, isEnvDevelopment, configType, config, }) {
|
|
253
|
+
function createJavaScriptLoader({ isEnvProduction, isEnvDevelopment, configType, config, isSsr, }) {
|
|
225
254
|
const plugins = [];
|
|
226
|
-
if (
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
255
|
+
if (!isSsr) {
|
|
256
|
+
if (isEnvDevelopment && config.reactRefresh !== false) {
|
|
257
|
+
plugins.push([
|
|
258
|
+
require.resolve('react-refresh/babel'),
|
|
259
|
+
config.devServer?.webSocketPath
|
|
260
|
+
? {
|
|
261
|
+
overlay: {
|
|
262
|
+
sockPath: config.devServer.webSocketPath,
|
|
263
|
+
},
|
|
264
|
+
}
|
|
265
|
+
: undefined,
|
|
266
|
+
]);
|
|
267
|
+
}
|
|
268
|
+
if (isEnvProduction) {
|
|
269
|
+
plugins.push([
|
|
270
|
+
require.resolve('babel-plugin-import'),
|
|
271
|
+
{ libraryName: 'lodash', libraryDirectory: '', camel2DashComponentName: false },
|
|
272
|
+
]);
|
|
273
|
+
}
|
|
243
274
|
}
|
|
244
275
|
const transformOptions = config.babel({
|
|
245
276
|
presets: [(0, babel_1.babelPreset)(config)],
|
|
@@ -339,7 +370,7 @@ function createStylesRule(options) {
|
|
|
339
370
|
use: loaders,
|
|
340
371
|
};
|
|
341
372
|
}
|
|
342
|
-
function getCssLoaders({ isEnvDevelopment, isEnvProduction, config }, additionalRules) {
|
|
373
|
+
function getCssLoaders({ isEnvDevelopment, isEnvProduction, config, isSsr }, additionalRules) {
|
|
343
374
|
const loaders = [];
|
|
344
375
|
if (!config.transformCssWithLightningCss) {
|
|
345
376
|
loaders.push({
|
|
@@ -362,27 +393,32 @@ function getCssLoaders({ isEnvDevelopment, isEnvProduction, config }, additional
|
|
|
362
393
|
loaders.unshift({
|
|
363
394
|
loader: require.resolve('css-loader'),
|
|
364
395
|
options: {
|
|
365
|
-
esModule: false,
|
|
366
396
|
sourceMap: !config.disableSourceMapGeneration,
|
|
367
397
|
importLoaders,
|
|
368
398
|
modules: {
|
|
369
399
|
auto: true,
|
|
370
400
|
localIdentName: '[name]__[local]--[hash:base64:5]',
|
|
371
401
|
exportLocalsConvention: 'camelCase',
|
|
402
|
+
exportOnlyLocals: isSsr,
|
|
372
403
|
},
|
|
373
404
|
},
|
|
374
405
|
});
|
|
375
406
|
if (isEnvProduction) {
|
|
376
|
-
loaders.unshift(mini_css_extract_plugin_1.default.loader);
|
|
407
|
+
loaders.unshift({ loader: mini_css_extract_plugin_1.default.loader, options: { emit: !isSsr } });
|
|
377
408
|
}
|
|
378
409
|
if (isEnvDevelopment) {
|
|
379
|
-
|
|
380
|
-
loader:
|
|
381
|
-
}
|
|
410
|
+
if (isSsr) {
|
|
411
|
+
loaders.unshift({ loader: mini_css_extract_plugin_1.default.loader, options: { emit: false } });
|
|
412
|
+
}
|
|
413
|
+
else {
|
|
414
|
+
loaders.unshift({
|
|
415
|
+
loader: require.resolve('style-loader'),
|
|
416
|
+
});
|
|
417
|
+
}
|
|
382
418
|
}
|
|
383
419
|
return loaders;
|
|
384
420
|
}
|
|
385
|
-
function createIconsRule({ isEnvProduction, config }, jsLoader) {
|
|
421
|
+
function createIconsRule({ isEnvProduction, config, isSsr }, jsLoader) {
|
|
386
422
|
const iconIncludes = config.icons || [];
|
|
387
423
|
return {
|
|
388
424
|
// eslint-disable-next-line security/detect-unsafe-regex
|
|
@@ -419,11 +455,12 @@ function createIconsRule({ isEnvProduction, config }, jsLoader) {
|
|
|
419
455
|
generator: {
|
|
420
456
|
filename: 'assets/images/[name].[contenthash:8][ext]',
|
|
421
457
|
publicPath: isEnvProduction ? '../' : undefined,
|
|
458
|
+
emit: !isSsr,
|
|
422
459
|
},
|
|
423
460
|
}),
|
|
424
461
|
};
|
|
425
462
|
}
|
|
426
|
-
function createAssetsRules({ isEnvProduction, config }) {
|
|
463
|
+
function createAssetsRules({ isEnvProduction, config, isSsr }) {
|
|
427
464
|
const imagesRule = {
|
|
428
465
|
test: /\.(ico|bmp|gif|jpe?g|png|svg)$/,
|
|
429
466
|
include: [paths_1.default.appClient, ...(config.images || [])],
|
|
@@ -435,6 +472,7 @@ function createAssetsRules({ isEnvProduction, config }) {
|
|
|
435
472
|
},
|
|
436
473
|
generator: {
|
|
437
474
|
filename: 'assets/images/[name].[contenthash:8][ext]',
|
|
475
|
+
emit: !isSsr,
|
|
438
476
|
},
|
|
439
477
|
};
|
|
440
478
|
const fontsRule = {
|
|
@@ -448,6 +486,7 @@ function createAssetsRules({ isEnvProduction, config }) {
|
|
|
448
486
|
},
|
|
449
487
|
generator: {
|
|
450
488
|
filename: 'assets/fonts/[name].[contenthash:8][ext]',
|
|
489
|
+
emit: !isSsr,
|
|
451
490
|
},
|
|
452
491
|
};
|
|
453
492
|
const rules = [imagesRule, fontsRule];
|
|
@@ -467,6 +506,7 @@ function createAssetsRules({ isEnvProduction, config }) {
|
|
|
467
506
|
generator: {
|
|
468
507
|
filename: 'assets/images/[name].[contenthash:8][ext]',
|
|
469
508
|
publicPath: '../',
|
|
509
|
+
emit: !isSsr,
|
|
470
510
|
},
|
|
471
511
|
}, {
|
|
472
512
|
test: /\.(ttf|eot|woff2?)$/,
|
|
@@ -481,17 +521,19 @@ function createAssetsRules({ isEnvProduction, config }) {
|
|
|
481
521
|
generator: {
|
|
482
522
|
filename: 'assets/fonts/[name].[contenthash:8][ext]',
|
|
483
523
|
publicPath: '../',
|
|
524
|
+
emit: !isSsr,
|
|
484
525
|
},
|
|
485
526
|
});
|
|
486
527
|
}
|
|
487
528
|
return rules;
|
|
488
529
|
}
|
|
489
|
-
function createFallbackRules({ isEnvProduction }) {
|
|
530
|
+
function createFallbackRules({ isEnvProduction, isSsr }) {
|
|
490
531
|
const rules = [
|
|
491
532
|
{
|
|
492
533
|
type: 'asset/resource',
|
|
493
534
|
generator: {
|
|
494
535
|
filename: 'assets/[name].[contenthash:8][ext]',
|
|
536
|
+
emit: !isSsr,
|
|
495
537
|
},
|
|
496
538
|
exclude: [/\.[jt]sx?$/, /\.json$/, /\.[cm]js$/, /\.ejs$/],
|
|
497
539
|
},
|
|
@@ -506,6 +548,7 @@ function createFallbackRules({ isEnvProduction }) {
|
|
|
506
548
|
generator: {
|
|
507
549
|
filename: 'assets/[name].[contenthash:8][ext]',
|
|
508
550
|
publicPath: '../',
|
|
551
|
+
emit: !isSsr,
|
|
509
552
|
},
|
|
510
553
|
});
|
|
511
554
|
}
|
|
@@ -520,7 +563,7 @@ function createMomentTimezoneDataPlugin(options = {}) {
|
|
|
520
563
|
return new moment_timezone_data_webpack_plugin_1.default({ ...options, startYear, endYear });
|
|
521
564
|
}
|
|
522
565
|
function configurePlugins(options) {
|
|
523
|
-
const { isEnvDevelopment, isEnvProduction, config } = options;
|
|
566
|
+
const { isEnvDevelopment, isEnvProduction, config, isSsr } = options;
|
|
524
567
|
const excludeFromClean = config.excludeFromClean || [];
|
|
525
568
|
const manifestFile = 'assets-manifest.json';
|
|
526
569
|
const plugins = [
|
|
@@ -544,9 +587,8 @@ function configurePlugins(options) {
|
|
|
544
587
|
: {
|
|
545
588
|
entrypoints: true,
|
|
546
589
|
writeToDisk: true,
|
|
547
|
-
output: path.resolve(
|
|
590
|
+
output: path.resolve(options.buildDirectory, manifestFile),
|
|
548
591
|
}),
|
|
549
|
-
createMomentTimezoneDataPlugin(config.momentTz),
|
|
550
592
|
new webpack.DefinePlugin({
|
|
551
593
|
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV),
|
|
552
594
|
...config.definitions,
|
|
@@ -558,51 +600,12 @@ function configurePlugins(options) {
|
|
|
558
600
|
if (process.env.WEBPACK_PROFILE === 'true') {
|
|
559
601
|
plugins.push(new webpack.debug.ProfilingPlugin());
|
|
560
602
|
}
|
|
561
|
-
const contextReplacement = config.contextReplacement || {};
|
|
562
|
-
plugins.push(new webpack.ContextReplacementPlugin(/moment[\\/]locale$/,
|
|
563
|
-
// eslint-disable-next-line security/detect-non-literal-regexp
|
|
564
|
-
new RegExp(`^\\./(${(contextReplacement.locale || ['ru']).join('|')})$`)));
|
|
565
|
-
plugins.push(new webpack.ContextReplacementPlugin(/dayjs[\\/]locale$/,
|
|
566
|
-
// eslint-disable-next-line security/detect-non-literal-regexp
|
|
567
|
-
new RegExp(`^\\./(${(contextReplacement.locale || ['ru']).join('|')})\\.js$`)));
|
|
568
|
-
if (contextReplacement['highlight.js']) {
|
|
569
|
-
plugins.push(new webpack.ContextReplacementPlugin(/highlight\.js[\\/]lib[\\/]languages$/,
|
|
570
|
-
// eslint-disable-next-line security/detect-non-literal-regexp
|
|
571
|
-
new RegExp(`^\\./(${contextReplacement['highlight.js'].join('|')})$`)));
|
|
572
|
-
}
|
|
573
|
-
if (config.monaco) {
|
|
574
|
-
const MonacoEditorWebpackPlugin = require('monaco-editor-webpack-plugin');
|
|
575
|
-
plugins.push(new MonacoEditorWebpackPlugin({
|
|
576
|
-
filename: isEnvProduction ? '[name].[hash:8].worker.js' : undefined,
|
|
577
|
-
...config.monaco,
|
|
578
|
-
// currently, workers located on cdn are not working properly, so we are enforcing loading workers from
|
|
579
|
-
// service instead
|
|
580
|
-
publicPath: path.normalize(config.publicPathPrefix + '/build/'),
|
|
581
|
-
}));
|
|
582
|
-
}
|
|
583
|
-
if (isEnvDevelopment && config.reactRefresh !== false) {
|
|
584
|
-
const { webSocketPath = path.normalize(`/${config.publicPathPrefix}/build/sockjs-node`) } = config.devServer || {};
|
|
585
|
-
plugins.push(new react_refresh_webpack_plugin_1.default(config.reactRefresh({
|
|
586
|
-
overlay: { sockPath: webSocketPath },
|
|
587
|
-
exclude: [/node_modules/, /\.worker\.[jt]sx?$/],
|
|
588
|
-
})));
|
|
589
|
-
}
|
|
590
|
-
if (config.detectCircularDependencies) {
|
|
591
|
-
let circularPluginOptions = {
|
|
592
|
-
exclude: /node_modules/,
|
|
593
|
-
allowAsyncCycles: true,
|
|
594
|
-
};
|
|
595
|
-
if (typeof config.detectCircularDependencies === 'object') {
|
|
596
|
-
circularPluginOptions = config.detectCircularDependencies;
|
|
597
|
-
}
|
|
598
|
-
plugins.push(new circular_dependency_plugin_1.default(circularPluginOptions));
|
|
599
|
-
}
|
|
600
603
|
if (config.forkTsChecker !== false) {
|
|
601
604
|
plugins.push(new fork_ts_checker_webpack_plugin_1.default({
|
|
602
605
|
...config.forkTsChecker,
|
|
603
606
|
typescript: {
|
|
604
607
|
typescriptPath: (0, utils_2.resolveTypescript)(),
|
|
605
|
-
configFile: path.resolve(paths_1.default.
|
|
608
|
+
configFile: path.resolve(paths_1.default.appClient, 'tsconfig.json'),
|
|
606
609
|
diagnosticOptions: {
|
|
607
610
|
syntactic: true,
|
|
608
611
|
},
|
|
@@ -611,19 +614,17 @@ function configurePlugins(options) {
|
|
|
611
614
|
},
|
|
612
615
|
}));
|
|
613
616
|
}
|
|
614
|
-
if (config.
|
|
615
|
-
|
|
617
|
+
if (config.detectCircularDependencies) {
|
|
618
|
+
let circularPluginOptions = {
|
|
619
|
+
exclude: /node_modules/,
|
|
620
|
+
allowAsyncCycles: true,
|
|
621
|
+
};
|
|
622
|
+
if (typeof config.detectCircularDependencies === 'object') {
|
|
623
|
+
circularPluginOptions = config.detectCircularDependencies;
|
|
624
|
+
}
|
|
625
|
+
plugins.push(new circular_dependency_plugin_1.default(circularPluginOptions));
|
|
616
626
|
}
|
|
617
627
|
if (isEnvProduction) {
|
|
618
|
-
plugins.push(new mini_css_extract_plugin_1.default({
|
|
619
|
-
filename: 'css/[name].[contenthash:8].css',
|
|
620
|
-
chunkFilename: 'css/[name].[contenthash:8].chunk.css',
|
|
621
|
-
ignoreOrder: true,
|
|
622
|
-
}));
|
|
623
|
-
if (config.sentryConfig) {
|
|
624
|
-
const sentryPlugin = require('@sentry/webpack-plugin').sentryWebpackPlugin;
|
|
625
|
-
plugins.push(sentryPlugin({ ...config.sentryConfig }));
|
|
626
|
-
}
|
|
627
628
|
if (config.analyzeBundle === 'true') {
|
|
628
629
|
plugins.push(new webpack_bundle_analyzer_1.BundleAnalyzerPlugin({
|
|
629
630
|
openAnalyzer: false,
|
|
@@ -634,8 +635,8 @@ function configurePlugins(options) {
|
|
|
634
635
|
if (config.analyzeBundle === 'statoscope') {
|
|
635
636
|
const customStatoscopeConfig = config.statoscopeConfig || {};
|
|
636
637
|
plugins.push(new webpack_plugin_1.default({
|
|
637
|
-
saveReportTo: path.resolve(
|
|
638
|
-
saveStatsTo: path.resolve(
|
|
638
|
+
saveReportTo: path.resolve(options.buildDirectory, 'report.html'),
|
|
639
|
+
saveStatsTo: path.resolve(options.buildDirectory, 'stats.json'),
|
|
639
640
|
open: false,
|
|
640
641
|
statsOptions: {
|
|
641
642
|
all: true,
|
|
@@ -644,50 +645,102 @@ function configurePlugins(options) {
|
|
|
644
645
|
}));
|
|
645
646
|
}
|
|
646
647
|
}
|
|
647
|
-
if (
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
648
|
+
if (isEnvProduction || isSsr) {
|
|
649
|
+
plugins.push(new mini_css_extract_plugin_1.default({
|
|
650
|
+
filename: 'css/[name].[contenthash:8].css',
|
|
651
|
+
chunkFilename: 'css/[name].[contenthash:8].chunk.css',
|
|
652
|
+
ignoreOrder: true,
|
|
653
|
+
}));
|
|
654
|
+
}
|
|
655
|
+
if (config.monaco) {
|
|
656
|
+
const MonacoEditorWebpackPlugin = require('monaco-editor-webpack-plugin');
|
|
657
|
+
plugins.push(new MonacoEditorWebpackPlugin({
|
|
658
|
+
filename: isEnvProduction ? '[name].[hash:8].worker.js' : undefined,
|
|
659
|
+
...config.monaco,
|
|
660
|
+
// currently, workers located on cdn are not working properly, so we are enforcing loading workers from
|
|
661
|
+
// service instead
|
|
662
|
+
publicPath: path.normalize(config.publicPathPrefix + '/build/'),
|
|
663
|
+
}));
|
|
664
|
+
}
|
|
665
|
+
if (!isSsr) {
|
|
666
|
+
const contextReplacement = config.contextReplacement || {};
|
|
667
|
+
plugins.push(createMomentTimezoneDataPlugin(config.momentTz));
|
|
668
|
+
plugins.push(new webpack.ContextReplacementPlugin(/moment[\\/]locale$/,
|
|
669
|
+
// eslint-disable-next-line security/detect-non-literal-regexp
|
|
670
|
+
new RegExp(`^\\./(${(contextReplacement.locale || ['ru']).join('|')})$`)));
|
|
671
|
+
plugins.push(new webpack.ContextReplacementPlugin(/dayjs[\\/]locale$/,
|
|
672
|
+
// eslint-disable-next-line security/detect-non-literal-regexp
|
|
673
|
+
new RegExp(`^\\./(${(contextReplacement.locale || ['ru']).join('|')})\\.js$`)));
|
|
674
|
+
if (contextReplacement['highlight.js']) {
|
|
675
|
+
plugins.push(new webpack.ContextReplacementPlugin(/highlight\.js[\\/]lib[\\/]languages$/,
|
|
676
|
+
// eslint-disable-next-line security/detect-non-literal-regexp
|
|
677
|
+
new RegExp(`^\\./(${contextReplacement['highlight.js'].join('|')})$`)));
|
|
678
|
+
}
|
|
679
|
+
if (isEnvDevelopment && config.reactRefresh !== false) {
|
|
680
|
+
const { webSocketPath = path.normalize(`/${config.publicPathPrefix}/build/sockjs-node`), } = config.devServer || {};
|
|
681
|
+
plugins.push(new react_refresh_webpack_plugin_1.default(config.reactRefresh({
|
|
682
|
+
overlay: { sockPath: webSocketPath },
|
|
683
|
+
exclude: [/node_modules/, /\.worker\.[jt]sx?$/],
|
|
684
|
+
})));
|
|
685
|
+
}
|
|
686
|
+
if (config.polyfill?.process) {
|
|
687
|
+
plugins.push(new webpack.ProvidePlugin({ process: 'process/browser.js' }));
|
|
654
688
|
}
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
continue;
|
|
689
|
+
if (isEnvProduction) {
|
|
690
|
+
if (config.sentryConfig) {
|
|
691
|
+
const sentryPlugin = require('@sentry/webpack-plugin').sentryWebpackPlugin;
|
|
692
|
+
plugins.push(sentryPlugin({ ...config.sentryConfig }));
|
|
660
693
|
}
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
if (
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
694
|
+
}
|
|
695
|
+
if (config.cdn) {
|
|
696
|
+
let credentialsGlobal;
|
|
697
|
+
if (process.env.FRONTEND_S3_ACCESS_KEY_ID &&
|
|
698
|
+
process.env.FRONTEND_S3_SECRET_ACCESS_KEY) {
|
|
699
|
+
credentialsGlobal = {
|
|
700
|
+
accessKeyId: process.env.FRONTEND_S3_ACCESS_KEY_ID,
|
|
701
|
+
secretAccessKey: process.env.FRONTEND_S3_SECRET_ACCESS_KEY,
|
|
668
702
|
};
|
|
669
703
|
}
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
}
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
704
|
+
const cdns = Array.isArray(config.cdn) ? config.cdn : [config.cdn];
|
|
705
|
+
for (let index = 0; index < cdns.length; index++) {
|
|
706
|
+
const cdn = cdns[index];
|
|
707
|
+
if (!cdn) {
|
|
708
|
+
continue;
|
|
709
|
+
}
|
|
710
|
+
let credentials = credentialsGlobal;
|
|
711
|
+
const accessKeyId = process.env[`FRONTEND_S3_ACCESS_KEY_ID_${index}`];
|
|
712
|
+
const secretAccessKey = process.env[`FRONTEND_S3_SECRET_ACCESS_KEY_${index}`];
|
|
713
|
+
if (accessKeyId && secretAccessKey) {
|
|
714
|
+
credentials = {
|
|
715
|
+
accessKeyId,
|
|
716
|
+
secretAccessKey,
|
|
717
|
+
};
|
|
718
|
+
}
|
|
719
|
+
plugins.push(new s3_upload_1.S3UploadPlugin({
|
|
720
|
+
exclude: config.hiddenSourceMap ? /\.map$/ : undefined,
|
|
721
|
+
compress: cdn.compress,
|
|
722
|
+
s3ClientOptions: {
|
|
723
|
+
region: cdn.region,
|
|
724
|
+
endpoint: cdn.endpoint,
|
|
725
|
+
credentials,
|
|
726
|
+
},
|
|
727
|
+
s3UploadOptions: {
|
|
728
|
+
bucket: cdn.bucket,
|
|
729
|
+
targetPath: cdn.prefix,
|
|
730
|
+
cacheControl: cdn.cacheControl,
|
|
731
|
+
},
|
|
732
|
+
additionalPattern: cdn.additionalPattern,
|
|
733
|
+
logger: options.logger,
|
|
734
|
+
}));
|
|
735
|
+
}
|
|
686
736
|
}
|
|
687
737
|
}
|
|
688
738
|
return plugins;
|
|
689
739
|
}
|
|
690
|
-
function configureOptimization({ config }) {
|
|
740
|
+
function configureOptimization({ config, isSsr }) {
|
|
741
|
+
if (isSsr) {
|
|
742
|
+
return {};
|
|
743
|
+
}
|
|
691
744
|
const configVendors = config.vendors ?? [];
|
|
692
745
|
let vendorsList = [
|
|
693
746
|
'react',
|
|
@@ -35,6 +35,7 @@ const css_minimizer_webpack_plugin_1 = __importDefault(require("css-minimizer-we
|
|
|
35
35
|
const config_1 = require("./config");
|
|
36
36
|
const config_2 = require("../config");
|
|
37
37
|
const models_1 = require("../models");
|
|
38
|
+
const paths_1 = __importDefault(require("../paths"));
|
|
38
39
|
async function configureServiceWebpackConfig(mode, storybookConfig) {
|
|
39
40
|
const serviceConfig = await (0, config_2.getProjectConfig)(mode === "production" /* WebpackMode.Prod */ ? 'build' : 'dev', {
|
|
40
41
|
storybook: true,
|
|
@@ -104,6 +105,9 @@ async function configureWebpackConfigForStorybook(mode, userConfig = {}, storybo
|
|
|
104
105
|
isEnvProduction,
|
|
105
106
|
config: config.client,
|
|
106
107
|
configType: mode,
|
|
108
|
+
buildDirectory: paths_1.default.appBuild,
|
|
109
|
+
entriesDirectory: paths_1.default.appEntry,
|
|
110
|
+
isSsr: false,
|
|
107
111
|
};
|
|
108
112
|
return {
|
|
109
113
|
module: {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type webpack from 'webpack';
|
|
2
2
|
import type { Logger } from '../logger';
|
|
3
|
-
export declare function webpackCompilerHandlerFactory(logger: Logger, onCompilationEnd?: () => void): (err?: Error | null, stats?: webpack.
|
|
3
|
+
export declare function webpackCompilerHandlerFactory(logger: Logger, onCompilationEnd?: () => void): (err?: Error | null, stats?: webpack.MultiStats) => Promise<void>;
|
|
4
4
|
export declare function resolveTsconfigPathsToAlias(tsConfigPath: string): {
|
|
5
5
|
aliases: Record<string, string[]>;
|
|
6
6
|
modules: string[];
|
|
@@ -50,13 +50,21 @@ function webpackCompilerHandlerFactory(logger, onCompilationEnd) {
|
|
|
50
50
|
if (onCompilationEnd) {
|
|
51
51
|
await onCompilationEnd();
|
|
52
52
|
}
|
|
53
|
-
|
|
54
|
-
|
|
53
|
+
const [clientStats, ssrStats] = stats?.stats ?? [];
|
|
54
|
+
if (clientStats) {
|
|
55
|
+
const time = clientStats.endTime - clientStats.startTime;
|
|
55
56
|
logger.success(`Client was successfully compiled in ${(0, pretty_time_1.prettyTime)(BigInt(time) * BigInt(1_000_000))}`);
|
|
56
57
|
}
|
|
57
58
|
else {
|
|
58
59
|
logger.success(`Client was successfully compiled`);
|
|
59
60
|
}
|
|
61
|
+
if (ssrStats) {
|
|
62
|
+
const time = ssrStats.endTime - ssrStats.startTime;
|
|
63
|
+
logger.success(`SSR: Client was successfully compiled in ${(0, pretty_time_1.prettyTime)(BigInt(time) * BigInt(1_000_000))}`);
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
logger.success(`SSR: Client was successfully compiled`);
|
|
67
|
+
}
|
|
60
68
|
};
|
|
61
69
|
}
|
|
62
70
|
const endStarRe = /\/?\*$/;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gravity-ui/app-builder",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.14.0-beta.0",
|
|
4
4
|
"description": "Develop and build your React client-server projects, powered by typescript and webpack",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "commonjs",
|
|
@@ -129,6 +129,7 @@
|
|
|
129
129
|
"webpack-bundle-analyzer": "^4.10.2",
|
|
130
130
|
"webpack-dev-server": "^5.1.0",
|
|
131
131
|
"webpack-manifest-plugin": "^5.0.0",
|
|
132
|
+
"webpack-node-externals": "^3.0.0",
|
|
132
133
|
"worker-loader": "^3.0.8",
|
|
133
134
|
"yargs": "^17.7.2"
|
|
134
135
|
},
|
|
@@ -152,6 +153,7 @@
|
|
|
152
153
|
"@types/webpack-assets-manifest": "^5.1.4",
|
|
153
154
|
"@types/webpack-bundle-analyzer": "^4.7.0",
|
|
154
155
|
"@types/webpack-manifest-plugin": "^3.0.8",
|
|
156
|
+
"@types/webpack-node-externals": "^3.0.4",
|
|
155
157
|
"@types/yargs": "17.0.11",
|
|
156
158
|
"babel-plugin-tester": "^11.0.4",
|
|
157
159
|
"eslint": "^8.57.0",
|