@gravity-ui/app-builder 0.14.0-beta.2 → 0.14.0-beta.4
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/README.md +5 -2
- package/dist/commands/dev/client.js +42 -16
- package/dist/commands/dev/index.js +1 -1
- package/dist/common/babel/index.d.ts +4 -0
- package/dist/common/babel/index.js +5 -1
- package/dist/common/models/index.d.ts +8 -0
- package/dist/common/paths.d.ts +2 -0
- package/dist/common/paths.js +2 -0
- package/dist/common/typescript/compile.js +10 -18
- package/dist/common/typescript/utils.d.ts +2 -1
- package/dist/common/typescript/utils.js +20 -2
- package/dist/common/typescript/watch.js +1 -1
- package/dist/common/webpack/compile.js +7 -2
- package/dist/common/webpack/config.d.ts +6 -2
- package/dist/common/webpack/config.js +200 -138
- package/dist/common/webpack/public-path.js +2 -1
- package/dist/common/webpack/storybook.js +4 -0
- package/dist/common/webpack/utils.d.ts +6 -3
- package/dist/common/webpack/utils.js +24 -22
- package/package.json +3 -1
package/README.md
CHANGED
|
@@ -192,8 +192,11 @@ With this `{rootDir}/src/ui/tsconfig.json`:
|
|
|
192
192
|
- `forkTsCheker` (`false | ForkTsCheckerWebpackPluginOptions`) - config for ForkTsCheckerWebpackPlugin [more](https://github.com/TypeStrong/fork-ts-checker-webpack-plugin#options). If `false`, ForkTsCheckerWebpackPlugin will be disabled.
|
|
193
193
|
- `cache` (`boolean | FileCacheOptions | MemoryCacheOptions`) — Cache the generated webpack modules and chunks to improve build speed. [more](https://webpack.js.org/configuration/cache/)
|
|
194
194
|
- `babelCacheDirectory` (`boolean | string`) — Set directory for babel-loader cache (`default: node_modules/.cache/babel-loader``)
|
|
195
|
-
- `babel` (`(config: babel.TransformOptions, options: {configType: 'development' | 'production'}) => babel.TransformOptions | Promise<babel.TransformOptions>`) - Allow override the default babel transform options.
|
|
196
|
-
- `webpack` (`(config: webpack.Configuration, options: {configType: 'development' | 'production'}) => webpack.Configuration | Promise<webpack.Configuration>`) - Allow override the default configuration.
|
|
195
|
+
- `babel` (`(config: babel.TransformOptions, options: {configType: 'development' | 'production'; isSsr: boolean}) => babel.TransformOptions | Promise<babel.TransformOptions>`) - Allow override the default babel transform options.
|
|
196
|
+
- `webpack` (`(config: webpack.Configuration, options: {configType: 'development' | 'production'; isSsr: boolean}) => webpack.Configuration | Promise<webpack.Configuration>`) - Allow override the default configuration.
|
|
197
|
+
- `ssr` - build SSR bundle. The SSR entries should be inside `src/ui/ssr` directory and match the client entries.
|
|
198
|
+
- `noExternal` (`string | RegExp | (string | RegExp)[] | true`) - prevent listed dependencies from being externalized for SSR. By default, all dependencies are externalized.
|
|
199
|
+
- `moduleType`: (`'commonjs' | 'esm'`) - library type for the SSR bundle, by default `commonjs`.
|
|
197
200
|
|
|
198
201
|
##### Dev build
|
|
199
202
|
|
|
@@ -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}`]
|
|
@@ -5,7 +5,11 @@ function babelPreset(config) {
|
|
|
5
5
|
return [
|
|
6
6
|
require.resolve('./ui-preset'),
|
|
7
7
|
{
|
|
8
|
-
env: {
|
|
8
|
+
env: {
|
|
9
|
+
modules: false,
|
|
10
|
+
bugfixes: true,
|
|
11
|
+
targets: config.isSsr ? { node: 'current' } : undefined,
|
|
12
|
+
},
|
|
9
13
|
runtime: { version: '^7.13.10' },
|
|
10
14
|
typescript: true,
|
|
11
15
|
react: {
|
|
@@ -180,17 +180,23 @@ export interface ClientConfig {
|
|
|
180
180
|
*/
|
|
181
181
|
webpack?: (config: Configuration, options: {
|
|
182
182
|
configType: `${WebpackMode}`;
|
|
183
|
+
isSsr?: boolean;
|
|
183
184
|
}) => Configuration | Promise<Configuration>;
|
|
184
185
|
/**
|
|
185
186
|
* Modify or return a custom Babel config.
|
|
186
187
|
*/
|
|
187
188
|
babel?: (config: Babel.TransformOptions, options: {
|
|
188
189
|
configType: `${WebpackMode}`;
|
|
190
|
+
isSsr: boolean;
|
|
189
191
|
}) => Babel.TransformOptions | Promise<Babel.TransformOptions>;
|
|
190
192
|
/**
|
|
191
193
|
* Modify or return a custom [Terser options](https://github.com/terser/terser#minify-options).
|
|
192
194
|
*/
|
|
193
195
|
terser?: (options: TerserOptions) => TerserOptions;
|
|
196
|
+
ssr?: {
|
|
197
|
+
noExternal?: string | RegExp | (string | RegExp)[] | true;
|
|
198
|
+
moduleType?: 'commonjs' | 'esm';
|
|
199
|
+
};
|
|
194
200
|
}
|
|
195
201
|
export interface CdnUploadConfig {
|
|
196
202
|
bucket: string;
|
|
@@ -230,10 +236,12 @@ export type NormalizedClientConfig = Omit<ClientConfig, 'publicPathPrefix' | 'hi
|
|
|
230
236
|
verbose?: boolean;
|
|
231
237
|
webpack: (config: Configuration, options: {
|
|
232
238
|
configType: `${WebpackMode}`;
|
|
239
|
+
isSsr: boolean;
|
|
233
240
|
}) => Configuration | Promise<Configuration>;
|
|
234
241
|
debugWebpack?: boolean;
|
|
235
242
|
babel: (config: Babel.TransformOptions, options: {
|
|
236
243
|
configType: `${WebpackMode}`;
|
|
244
|
+
isSsr: boolean;
|
|
237
245
|
}) => Babel.TransformOptions | Promise<Babel.TransformOptions>;
|
|
238
246
|
reactRefresh: NonNullable<ClientConfig['reactRefresh']>;
|
|
239
247
|
};
|
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,24 +10,11 @@ function compile(ts, { projectPath, configFileName = 'tsconfig.json', optionsToE
|
|
|
10
10
|
logger.message('Start compilation');
|
|
11
11
|
logger.message(`Typescript v${ts.version}`);
|
|
12
12
|
logger.verbose(`Searching for the ${configFileName} in ${projectPath}`);
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
};
|
|
19
|
-
const parseConfigFileHost = {
|
|
20
|
-
getCurrentDirectory: ts.sys.getCurrentDirectory,
|
|
21
|
-
useCaseSensitiveFileNames: ts.sys.useCaseSensitiveFileNames,
|
|
22
|
-
readDirectory: ts.sys.readDirectory,
|
|
23
|
-
fileExists: ts.sys.fileExists,
|
|
24
|
-
readFile: ts.sys.readFile,
|
|
25
|
-
onUnRecoverableConfigFileDiagnostic: reportDiagnostic,
|
|
26
|
-
};
|
|
27
|
-
const parsedConfig = ts.getParsedCommandLineOfConfigFile(configPath, { noEmit: false, noEmitOnError: true, ...optionsToExtend }, parseConfigFileHost);
|
|
28
|
-
if (!parsedConfig) {
|
|
29
|
-
throw new Error(`Invalid '${configFileName}'`);
|
|
30
|
-
}
|
|
13
|
+
const parsedConfig = (0, utils_1.getTsProjectConfig)(ts, projectPath, configFileName, {
|
|
14
|
+
noEmit: false,
|
|
15
|
+
noEmitOnError: true,
|
|
16
|
+
...optionsToExtend,
|
|
17
|
+
});
|
|
31
18
|
logger.verbose('Config found and parsed');
|
|
32
19
|
logger.verbose("We're about to create the program");
|
|
33
20
|
const compilerHost = ts.createCompilerHost(parsedConfig.options);
|
|
@@ -57,6 +44,11 @@ function compile(ts, { projectPath, configFileName = 'tsconfig.json', optionsToE
|
|
|
57
44
|
else {
|
|
58
45
|
logger.success(`Compiled successfully in ${(0, pretty_time_1.elapsedTime)(start)}`);
|
|
59
46
|
}
|
|
47
|
+
const formatHost = {
|
|
48
|
+
getCanonicalFileName: (path) => path,
|
|
49
|
+
getCurrentDirectory: ts.sys.getCurrentDirectory,
|
|
50
|
+
getNewLine: () => ts.sys.newLine,
|
|
51
|
+
};
|
|
60
52
|
function reportDiagnostic(diagnostic) {
|
|
61
53
|
if (logger.isVerbose) {
|
|
62
54
|
logger.message(ts.formatDiagnosticsWithColorAndContext([diagnostic], formatHost));
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type Typescript from 'typescript';
|
|
2
2
|
import type { Logger } from '../logger';
|
|
3
|
-
export declare function
|
|
3
|
+
export declare function getTsProjectConfigPath(ts: typeof Typescript, projectPath: string, filename?: string): string;
|
|
4
|
+
export declare function getTsProjectConfig(ts: typeof Typescript, projectPath: string, filename?: string, optionsToExtend?: Typescript.CompilerOptions): Typescript.ParsedCommandLine;
|
|
4
5
|
export declare function displayFilename(originalFunc: (path: string, encoding?: string) => string | undefined, operationName: string, logger: Logger): {
|
|
5
6
|
(path: string, encoding?: string | undefined): string | undefined;
|
|
6
7
|
originalFunc: (path: string, encoding?: string) => string | undefined;
|
|
@@ -3,19 +3,37 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.
|
|
6
|
+
exports.getTsProjectConfigPath = getTsProjectConfigPath;
|
|
7
|
+
exports.getTsProjectConfig = getTsProjectConfig;
|
|
7
8
|
exports.displayFilename = displayFilename;
|
|
8
9
|
exports.onHostEvent = onHostEvent;
|
|
9
10
|
exports.resolveTypescript = resolveTypescript;
|
|
10
11
|
const node_path_1 = __importDefault(require("node:path"));
|
|
11
12
|
const paths_1 = __importDefault(require("../paths"));
|
|
12
|
-
function
|
|
13
|
+
function getTsProjectConfigPath(ts, projectPath, filename = 'tsconfig.json') {
|
|
13
14
|
const configPath = ts.findConfigFile(projectPath, ts.sys.fileExists, filename);
|
|
14
15
|
if (!configPath) {
|
|
15
16
|
throw new Error(`Could not find a valid '${filename}'.`);
|
|
16
17
|
}
|
|
17
18
|
return configPath;
|
|
18
19
|
}
|
|
20
|
+
function getTsProjectConfig(ts, projectPath, filename = 'tsconfig.json', optionsToExtend) {
|
|
21
|
+
const configPath = getTsProjectConfigPath(ts, projectPath, filename);
|
|
22
|
+
const parseConfigFileHost = {
|
|
23
|
+
getCurrentDirectory: ts.sys.getCurrentDirectory,
|
|
24
|
+
useCaseSensitiveFileNames: ts.sys.useCaseSensitiveFileNames,
|
|
25
|
+
readDirectory: ts.sys.readDirectory,
|
|
26
|
+
fileExists: ts.sys.fileExists,
|
|
27
|
+
readFile: ts.sys.readFile,
|
|
28
|
+
// this is required in types but not used
|
|
29
|
+
onUnRecoverableConfigFileDiagnostic: () => { },
|
|
30
|
+
};
|
|
31
|
+
const parsedConfig = ts.getParsedCommandLineOfConfigFile(configPath, optionsToExtend, parseConfigFileHost);
|
|
32
|
+
if (!parsedConfig) {
|
|
33
|
+
throw new Error(`Invalid config file '${configPath}'`);
|
|
34
|
+
}
|
|
35
|
+
return parsedConfig;
|
|
36
|
+
}
|
|
19
37
|
function displayFilename(originalFunc, operationName, logger) {
|
|
20
38
|
let displayEnabled = false;
|
|
21
39
|
let count = 0;
|
|
@@ -7,7 +7,7 @@ const diagnostic_1 = require("./diagnostic");
|
|
|
7
7
|
function watch(ts, projectPath, { logger, onAfterFilesEmitted, enableSourceMap, }) {
|
|
8
8
|
logger.message('Start compilation in watch mode');
|
|
9
9
|
logger.message(`Typescript v${ts.version}`);
|
|
10
|
-
const configPath = (0, utils_1.
|
|
10
|
+
const configPath = (0, utils_1.getTsProjectConfigPath)(ts, projectPath);
|
|
11
11
|
const createProgram = ts.createEmitAndSemanticDiagnosticsBuilderProgram;
|
|
12
12
|
const formatHost = {
|
|
13
13
|
getCanonicalFileName: (path) => path,
|
|
@@ -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/],
|
|
@@ -92,7 +107,7 @@ async function webpackConfigFactory(webpackMode, config, { logger } = {}) {
|
|
|
92
107
|
},
|
|
93
108
|
cache: config.cache,
|
|
94
109
|
};
|
|
95
|
-
webpackConfig = await config.webpack(webpackConfig, { configType: webpackMode });
|
|
110
|
+
webpackConfig = await config.webpack(webpackConfig, { configType: webpackMode, isSsr });
|
|
96
111
|
if (config.debugWebpack) {
|
|
97
112
|
(0, log_config_1.logConfig)('Preview webpack config', webpackConfig);
|
|
98
113
|
}
|
|
@@ -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
|
}
|
|
@@ -174,7 +192,7 @@ function configureResolve({ isEnvProduction, config }) {
|
|
|
174
192
|
alias['react-dom$'] = 'react-dom/profiling';
|
|
175
193
|
alias['scheduler/tracing'] = 'scheduler/tracing-profiling';
|
|
176
194
|
}
|
|
177
|
-
const { aliases, modules = [] } = (0, utils_1.
|
|
195
|
+
const { aliases, modules = [] } = (0, utils_1.resolveTsConfigPathsToAlias)(paths_1.default.appClient);
|
|
178
196
|
return {
|
|
179
197
|
alias: {
|
|
180
198
|
...aliases,
|
|
@@ -190,61 +208,74 @@ 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
|
-
presets: [(0, babel_1.babelPreset)(config)],
|
|
276
|
+
presets: [(0, babel_1.babelPreset)({ newJsxTransform: config.newJsxTransform, isSsr })],
|
|
246
277
|
plugins,
|
|
247
|
-
}, { configType });
|
|
278
|
+
}, { configType, isSsr });
|
|
248
279
|
return {
|
|
249
280
|
loader: require.resolve('babel-loader'),
|
|
250
281
|
options: {
|
|
@@ -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,38 @@ function getCssLoaders({ isEnvDevelopment, isEnvProduction, config }, additional
|
|
|
362
393
|
loaders.unshift({
|
|
363
394
|
loader: require.resolve('css-loader'),
|
|
364
395
|
options: {
|
|
365
|
-
|
|
396
|
+
url: {
|
|
397
|
+
filter: (url) => {
|
|
398
|
+
// ignore data uri
|
|
399
|
+
return !url.startsWith('data:');
|
|
400
|
+
},
|
|
401
|
+
},
|
|
366
402
|
sourceMap: !config.disableSourceMapGeneration,
|
|
367
403
|
importLoaders,
|
|
368
404
|
modules: {
|
|
369
405
|
auto: true,
|
|
370
406
|
localIdentName: '[name]__[local]--[hash:base64:5]',
|
|
371
407
|
exportLocalsConvention: 'camelCase',
|
|
408
|
+
exportOnlyLocals: isSsr,
|
|
372
409
|
},
|
|
373
410
|
},
|
|
374
411
|
});
|
|
375
412
|
if (isEnvProduction) {
|
|
376
|
-
loaders.unshift(mini_css_extract_plugin_1.default.loader);
|
|
413
|
+
loaders.unshift({ loader: mini_css_extract_plugin_1.default.loader, options: { emit: !isSsr } });
|
|
377
414
|
}
|
|
378
415
|
if (isEnvDevelopment) {
|
|
379
|
-
|
|
380
|
-
loader:
|
|
381
|
-
}
|
|
416
|
+
if (isSsr || config.ssr) {
|
|
417
|
+
loaders.unshift({ loader: mini_css_extract_plugin_1.default.loader, options: { emit: !isSsr } });
|
|
418
|
+
}
|
|
419
|
+
else {
|
|
420
|
+
loaders.unshift({
|
|
421
|
+
loader: require.resolve('style-loader'),
|
|
422
|
+
});
|
|
423
|
+
}
|
|
382
424
|
}
|
|
383
425
|
return loaders;
|
|
384
426
|
}
|
|
385
|
-
function createIconsRule({ isEnvProduction, config }, jsLoader) {
|
|
427
|
+
function createIconsRule({ isEnvProduction, config, isSsr }, jsLoader) {
|
|
386
428
|
const iconIncludes = config.icons || [];
|
|
387
429
|
return {
|
|
388
430
|
// eslint-disable-next-line security/detect-unsafe-regex
|
|
@@ -419,11 +461,12 @@ function createIconsRule({ isEnvProduction, config }, jsLoader) {
|
|
|
419
461
|
generator: {
|
|
420
462
|
filename: 'assets/images/[name].[contenthash:8][ext]',
|
|
421
463
|
publicPath: isEnvProduction ? '../' : undefined,
|
|
464
|
+
emit: !isSsr,
|
|
422
465
|
},
|
|
423
466
|
}),
|
|
424
467
|
};
|
|
425
468
|
}
|
|
426
|
-
function createAssetsRules({ isEnvProduction, config }) {
|
|
469
|
+
function createAssetsRules({ isEnvProduction, config, isSsr }) {
|
|
427
470
|
const imagesRule = {
|
|
428
471
|
test: /\.(ico|bmp|gif|jpe?g|png|svg)$/,
|
|
429
472
|
include: [paths_1.default.appClient, ...(config.images || [])],
|
|
@@ -435,6 +478,7 @@ function createAssetsRules({ isEnvProduction, config }) {
|
|
|
435
478
|
},
|
|
436
479
|
generator: {
|
|
437
480
|
filename: 'assets/images/[name].[contenthash:8][ext]',
|
|
481
|
+
emit: !isSsr,
|
|
438
482
|
},
|
|
439
483
|
};
|
|
440
484
|
const fontsRule = {
|
|
@@ -448,6 +492,7 @@ function createAssetsRules({ isEnvProduction, config }) {
|
|
|
448
492
|
},
|
|
449
493
|
generator: {
|
|
450
494
|
filename: 'assets/fonts/[name].[contenthash:8][ext]',
|
|
495
|
+
emit: !isSsr,
|
|
451
496
|
},
|
|
452
497
|
};
|
|
453
498
|
const rules = [imagesRule, fontsRule];
|
|
@@ -467,6 +512,7 @@ function createAssetsRules({ isEnvProduction, config }) {
|
|
|
467
512
|
generator: {
|
|
468
513
|
filename: 'assets/images/[name].[contenthash:8][ext]',
|
|
469
514
|
publicPath: '../',
|
|
515
|
+
emit: !isSsr,
|
|
470
516
|
},
|
|
471
517
|
}, {
|
|
472
518
|
test: /\.(ttf|eot|woff2?)$/,
|
|
@@ -481,17 +527,19 @@ function createAssetsRules({ isEnvProduction, config }) {
|
|
|
481
527
|
generator: {
|
|
482
528
|
filename: 'assets/fonts/[name].[contenthash:8][ext]',
|
|
483
529
|
publicPath: '../',
|
|
530
|
+
emit: !isSsr,
|
|
484
531
|
},
|
|
485
532
|
});
|
|
486
533
|
}
|
|
487
534
|
return rules;
|
|
488
535
|
}
|
|
489
|
-
function createFallbackRules({ isEnvProduction }) {
|
|
536
|
+
function createFallbackRules({ isEnvProduction, isSsr }) {
|
|
490
537
|
const rules = [
|
|
491
538
|
{
|
|
492
539
|
type: 'asset/resource',
|
|
493
540
|
generator: {
|
|
494
541
|
filename: 'assets/[name].[contenthash:8][ext]',
|
|
542
|
+
emit: !isSsr,
|
|
495
543
|
},
|
|
496
544
|
exclude: [/\.[jt]sx?$/, /\.json$/, /\.[cm]js$/, /\.ejs$/],
|
|
497
545
|
},
|
|
@@ -506,6 +554,7 @@ function createFallbackRules({ isEnvProduction }) {
|
|
|
506
554
|
generator: {
|
|
507
555
|
filename: 'assets/[name].[contenthash:8][ext]',
|
|
508
556
|
publicPath: '../',
|
|
557
|
+
emit: !isSsr,
|
|
509
558
|
},
|
|
510
559
|
});
|
|
511
560
|
}
|
|
@@ -520,7 +569,7 @@ function createMomentTimezoneDataPlugin(options = {}) {
|
|
|
520
569
|
return new moment_timezone_data_webpack_plugin_1.default({ ...options, startYear, endYear });
|
|
521
570
|
}
|
|
522
571
|
function configurePlugins(options) {
|
|
523
|
-
const { isEnvDevelopment, isEnvProduction, config } = options;
|
|
572
|
+
const { isEnvDevelopment, isEnvProduction, config, isSsr } = options;
|
|
524
573
|
const excludeFromClean = config.excludeFromClean || [];
|
|
525
574
|
const manifestFile = 'assets-manifest.json';
|
|
526
575
|
const plugins = [
|
|
@@ -544,11 +593,11 @@ function configurePlugins(options) {
|
|
|
544
593
|
: {
|
|
545
594
|
entrypoints: true,
|
|
546
595
|
writeToDisk: true,
|
|
547
|
-
output: path.resolve(
|
|
596
|
+
output: path.resolve(options.buildDirectory, manifestFile),
|
|
548
597
|
}),
|
|
549
|
-
createMomentTimezoneDataPlugin(config.momentTz),
|
|
550
598
|
new webpack.DefinePlugin({
|
|
551
599
|
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV),
|
|
600
|
+
'process.env.IS_SSR': JSON.stringify(isSsr),
|
|
552
601
|
...config.definitions,
|
|
553
602
|
}),
|
|
554
603
|
];
|
|
@@ -558,51 +607,12 @@ function configurePlugins(options) {
|
|
|
558
607
|
if (process.env.WEBPACK_PROFILE === 'true') {
|
|
559
608
|
plugins.push(new webpack.debug.ProfilingPlugin());
|
|
560
609
|
}
|
|
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
610
|
if (config.forkTsChecker !== false) {
|
|
601
611
|
plugins.push(new fork_ts_checker_webpack_plugin_1.default({
|
|
602
612
|
...config.forkTsChecker,
|
|
603
613
|
typescript: {
|
|
604
614
|
typescriptPath: (0, utils_2.resolveTypescript)(),
|
|
605
|
-
configFile: path.resolve(paths_1.default.
|
|
615
|
+
configFile: path.resolve(paths_1.default.appClient, 'tsconfig.json'),
|
|
606
616
|
diagnosticOptions: {
|
|
607
617
|
syntactic: true,
|
|
608
618
|
},
|
|
@@ -611,19 +621,17 @@ function configurePlugins(options) {
|
|
|
611
621
|
},
|
|
612
622
|
}));
|
|
613
623
|
}
|
|
614
|
-
if (config.
|
|
615
|
-
|
|
624
|
+
if (config.detectCircularDependencies) {
|
|
625
|
+
let circularPluginOptions = {
|
|
626
|
+
exclude: /node_modules/,
|
|
627
|
+
allowAsyncCycles: true,
|
|
628
|
+
};
|
|
629
|
+
if (typeof config.detectCircularDependencies === 'object') {
|
|
630
|
+
circularPluginOptions = config.detectCircularDependencies;
|
|
631
|
+
}
|
|
632
|
+
plugins.push(new circular_dependency_plugin_1.default(circularPluginOptions));
|
|
616
633
|
}
|
|
617
634
|
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
635
|
if (config.analyzeBundle === 'true') {
|
|
628
636
|
plugins.push(new webpack_bundle_analyzer_1.BundleAnalyzerPlugin({
|
|
629
637
|
openAnalyzer: false,
|
|
@@ -634,8 +642,8 @@ function configurePlugins(options) {
|
|
|
634
642
|
if (config.analyzeBundle === 'statoscope') {
|
|
635
643
|
const customStatoscopeConfig = config.statoscopeConfig || {};
|
|
636
644
|
plugins.push(new webpack_plugin_1.default({
|
|
637
|
-
saveReportTo: path.resolve(
|
|
638
|
-
saveStatsTo: path.resolve(
|
|
645
|
+
saveReportTo: path.resolve(options.buildDirectory, 'report.html'),
|
|
646
|
+
saveStatsTo: path.resolve(options.buildDirectory, 'stats.json'),
|
|
639
647
|
open: false,
|
|
640
648
|
statsOptions: {
|
|
641
649
|
all: true,
|
|
@@ -644,50 +652,104 @@ function configurePlugins(options) {
|
|
|
644
652
|
}));
|
|
645
653
|
}
|
|
646
654
|
}
|
|
647
|
-
if (config.
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
655
|
+
if (isEnvProduction || isSsr || config.ssr) {
|
|
656
|
+
plugins.push(new mini_css_extract_plugin_1.default({
|
|
657
|
+
filename: isEnvProduction ? 'css/[name].[contenthash:8].css' : 'css/[name].css',
|
|
658
|
+
chunkFilename: isEnvProduction
|
|
659
|
+
? 'css/[name].[contenthash:8].chunk.css'
|
|
660
|
+
: 'css/[name].chunk.css',
|
|
661
|
+
ignoreOrder: true,
|
|
662
|
+
}));
|
|
663
|
+
}
|
|
664
|
+
if (!isSsr) {
|
|
665
|
+
if (config.monaco) {
|
|
666
|
+
const MonacoEditorWebpackPlugin = require('monaco-editor-webpack-plugin');
|
|
667
|
+
plugins.push(new MonacoEditorWebpackPlugin({
|
|
668
|
+
filename: isEnvProduction ? '[name].[hash:8].worker.js' : undefined,
|
|
669
|
+
...config.monaco,
|
|
670
|
+
// currently, workers located on cdn are not working properly, so we are enforcing loading workers from
|
|
671
|
+
// service instead
|
|
672
|
+
publicPath: path.normalize(config.publicPathPrefix + '/build/'),
|
|
673
|
+
}));
|
|
674
|
+
}
|
|
675
|
+
const contextReplacement = config.contextReplacement || {};
|
|
676
|
+
plugins.push(createMomentTimezoneDataPlugin(config.momentTz));
|
|
677
|
+
plugins.push(new webpack.ContextReplacementPlugin(/moment[\\/]locale$/,
|
|
678
|
+
// eslint-disable-next-line security/detect-non-literal-regexp
|
|
679
|
+
new RegExp(`^\\./(${(contextReplacement.locale || ['ru']).join('|')})$`)));
|
|
680
|
+
plugins.push(new webpack.ContextReplacementPlugin(/dayjs[\\/]locale$/,
|
|
681
|
+
// eslint-disable-next-line security/detect-non-literal-regexp
|
|
682
|
+
new RegExp(`^\\./(${(contextReplacement.locale || ['ru']).join('|')})\\.js$`)));
|
|
683
|
+
if (contextReplacement['highlight.js']) {
|
|
684
|
+
plugins.push(new webpack.ContextReplacementPlugin(/highlight\.js[\\/]lib[\\/]languages$/,
|
|
685
|
+
// eslint-disable-next-line security/detect-non-literal-regexp
|
|
686
|
+
new RegExp(`^\\./(${contextReplacement['highlight.js'].join('|')})$`)));
|
|
654
687
|
}
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
688
|
+
if (isEnvDevelopment && config.reactRefresh !== false) {
|
|
689
|
+
const { webSocketPath = path.normalize(`/${config.publicPathPrefix}/build/sockjs-node`), } = config.devServer || {};
|
|
690
|
+
plugins.push(new react_refresh_webpack_plugin_1.default(config.reactRefresh({
|
|
691
|
+
overlay: { sockPath: webSocketPath },
|
|
692
|
+
exclude: [/node_modules/, /\.worker\.[jt]sx?$/],
|
|
693
|
+
})));
|
|
694
|
+
}
|
|
695
|
+
if (config.polyfill?.process) {
|
|
696
|
+
plugins.push(new webpack.ProvidePlugin({ process: 'process/browser.js' }));
|
|
697
|
+
}
|
|
698
|
+
if (isEnvProduction) {
|
|
699
|
+
if (config.sentryConfig) {
|
|
700
|
+
const sentryPlugin = require('@sentry/webpack-plugin').sentryWebpackPlugin;
|
|
701
|
+
plugins.push(sentryPlugin({ ...config.sentryConfig }));
|
|
660
702
|
}
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
if (
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
703
|
+
}
|
|
704
|
+
if (config.cdn) {
|
|
705
|
+
let credentialsGlobal;
|
|
706
|
+
if (process.env.FRONTEND_S3_ACCESS_KEY_ID &&
|
|
707
|
+
process.env.FRONTEND_S3_SECRET_ACCESS_KEY) {
|
|
708
|
+
credentialsGlobal = {
|
|
709
|
+
accessKeyId: process.env.FRONTEND_S3_ACCESS_KEY_ID,
|
|
710
|
+
secretAccessKey: process.env.FRONTEND_S3_SECRET_ACCESS_KEY,
|
|
668
711
|
};
|
|
669
712
|
}
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
}
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
713
|
+
const cdns = Array.isArray(config.cdn) ? config.cdn : [config.cdn];
|
|
714
|
+
for (let index = 0; index < cdns.length; index++) {
|
|
715
|
+
const cdn = cdns[index];
|
|
716
|
+
if (!cdn) {
|
|
717
|
+
continue;
|
|
718
|
+
}
|
|
719
|
+
let credentials = credentialsGlobal;
|
|
720
|
+
const accessKeyId = process.env[`FRONTEND_S3_ACCESS_KEY_ID_${index}`];
|
|
721
|
+
const secretAccessKey = process.env[`FRONTEND_S3_SECRET_ACCESS_KEY_${index}`];
|
|
722
|
+
if (accessKeyId && secretAccessKey) {
|
|
723
|
+
credentials = {
|
|
724
|
+
accessKeyId,
|
|
725
|
+
secretAccessKey,
|
|
726
|
+
};
|
|
727
|
+
}
|
|
728
|
+
plugins.push(new s3_upload_1.S3UploadPlugin({
|
|
729
|
+
exclude: config.hiddenSourceMap ? /\.map$/ : undefined,
|
|
730
|
+
compress: cdn.compress,
|
|
731
|
+
s3ClientOptions: {
|
|
732
|
+
region: cdn.region,
|
|
733
|
+
endpoint: cdn.endpoint,
|
|
734
|
+
credentials,
|
|
735
|
+
},
|
|
736
|
+
s3UploadOptions: {
|
|
737
|
+
bucket: cdn.bucket,
|
|
738
|
+
targetPath: cdn.prefix,
|
|
739
|
+
cacheControl: cdn.cacheControl,
|
|
740
|
+
},
|
|
741
|
+
additionalPattern: cdn.additionalPattern,
|
|
742
|
+
logger: options.logger,
|
|
743
|
+
}));
|
|
744
|
+
}
|
|
686
745
|
}
|
|
687
746
|
}
|
|
688
747
|
return plugins;
|
|
689
748
|
}
|
|
690
|
-
function configureOptimization({ config }) {
|
|
749
|
+
function configureOptimization({ config, isSsr }) {
|
|
750
|
+
if (isSsr) {
|
|
751
|
+
return {};
|
|
752
|
+
}
|
|
691
753
|
const configVendors = config.vendors ?? [];
|
|
692
754
|
let vendorsList = [
|
|
693
755
|
'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,7 +1,10 @@
|
|
|
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.
|
|
4
|
-
export declare function
|
|
3
|
+
export declare function webpackCompilerHandlerFactory(logger: Logger, onCompilationEnd?: () => void): (err?: Error | null, stats?: webpack.MultiStats) => Promise<void>;
|
|
4
|
+
export declare function resolveTsConfigPathsToAlias(projectPath: string, filename?: string): {
|
|
5
|
+
aliases?: undefined;
|
|
6
|
+
modules?: undefined;
|
|
7
|
+
} | {
|
|
5
8
|
aliases: Record<string, string[]>;
|
|
6
9
|
modules: string[];
|
|
7
|
-
}
|
|
10
|
+
};
|
|
@@ -24,10 +24,11 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
24
24
|
};
|
|
25
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
26
|
exports.webpackCompilerHandlerFactory = webpackCompilerHandlerFactory;
|
|
27
|
-
exports.
|
|
27
|
+
exports.resolveTsConfigPathsToAlias = resolveTsConfigPathsToAlias;
|
|
28
28
|
const path = __importStar(require("node:path"));
|
|
29
|
-
const
|
|
29
|
+
const ts = __importStar(require("typescript"));
|
|
30
30
|
const pretty_time_1 = require("../logger/pretty-time");
|
|
31
|
+
const utils_1 = require("../typescript/utils");
|
|
31
32
|
function webpackCompilerHandlerFactory(logger, onCompilationEnd) {
|
|
32
33
|
return async (err, stats) => {
|
|
33
34
|
if (err) {
|
|
@@ -50,25 +51,37 @@ function webpackCompilerHandlerFactory(logger, onCompilationEnd) {
|
|
|
50
51
|
if (onCompilationEnd) {
|
|
51
52
|
await onCompilationEnd();
|
|
52
53
|
}
|
|
53
|
-
|
|
54
|
-
|
|
54
|
+
const [clientStats, ssrStats] = stats?.stats ?? [];
|
|
55
|
+
if (clientStats) {
|
|
56
|
+
const time = clientStats.endTime - clientStats.startTime;
|
|
55
57
|
logger.success(`Client was successfully compiled in ${(0, pretty_time_1.prettyTime)(BigInt(time) * BigInt(1_000_000))}`);
|
|
56
58
|
}
|
|
57
|
-
|
|
59
|
+
if (ssrStats) {
|
|
60
|
+
const time = ssrStats.endTime - ssrStats.startTime;
|
|
61
|
+
logger.success(`SSR: Client was successfully compiled in ${(0, pretty_time_1.prettyTime)(BigInt(time) * BigInt(1_000_000))}`);
|
|
62
|
+
}
|
|
63
|
+
if (!clientStats && !ssrStats) {
|
|
58
64
|
logger.success(`Client was successfully compiled`);
|
|
59
65
|
}
|
|
60
66
|
};
|
|
61
67
|
}
|
|
62
68
|
const endStarRe = /\/?\*$/;
|
|
63
|
-
function
|
|
64
|
-
|
|
65
|
-
|
|
69
|
+
function resolveTsConfigPathsToAlias(projectPath, filename = 'tsconfig.json') {
|
|
70
|
+
let parsed;
|
|
71
|
+
try {
|
|
72
|
+
parsed = (0, utils_1.getTsProjectConfig)(ts, projectPath, filename);
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
return {};
|
|
76
|
+
}
|
|
77
|
+
if (parsed.errors.length > 0) {
|
|
78
|
+
return {};
|
|
66
79
|
}
|
|
67
|
-
const { paths = {}, baseUrl } =
|
|
80
|
+
const { paths = {}, baseUrl } = parsed.options;
|
|
68
81
|
if (!baseUrl) {
|
|
69
|
-
return
|
|
82
|
+
return {};
|
|
70
83
|
}
|
|
71
|
-
const basePath = path.resolve(path.dirname(
|
|
84
|
+
const basePath = path.resolve(path.dirname(projectPath), baseUrl);
|
|
72
85
|
const aliases = {};
|
|
73
86
|
const modules = [basePath];
|
|
74
87
|
for (const [key, value] of Object.entries(paths)) {
|
|
@@ -84,14 +97,3 @@ function resolveTsconfigPathsToAlias(tsConfigPath) {
|
|
|
84
97
|
}
|
|
85
98
|
return { aliases, modules };
|
|
86
99
|
}
|
|
87
|
-
function readJsonConfig(pathname) {
|
|
88
|
-
try {
|
|
89
|
-
const json = fs.readFileSync(pathname, 'utf-8');
|
|
90
|
-
return {
|
|
91
|
-
...JSON.parse(json),
|
|
92
|
-
};
|
|
93
|
-
}
|
|
94
|
-
catch {
|
|
95
|
-
throw new Error(`Couldn't read config ${pathname}`);
|
|
96
|
-
}
|
|
97
|
-
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gravity-ui/app-builder",
|
|
3
|
-
"version": "0.14.0-beta.
|
|
3
|
+
"version": "0.14.0-beta.4",
|
|
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",
|