@flatjs/evolve 2.1.0-next.11 → 2.1.0-next.12
Sign up to get free protection for your applications and to get access to all the features.
- package/dist/constants.js +36 -1
- package/dist/create-webpack/create-externals.js +6 -1
- package/dist/create-webpack/create-optimization.js +43 -1
- package/dist/create-webpack/create-output.js +35 -1
- package/dist/create-webpack/create-performance.js +7 -1
- package/dist/create-webpack/create-plugins.js +78 -1
- package/dist/create-webpack/create-resolve.js +37 -1
- package/dist/create-webpack/create-rule-sets.js +20 -1
- package/dist/create-webpack/load-webpack-config.js +57 -1
- package/dist/create-webpack/resolve-public-path.js +15 -1
- package/dist/create-webpack/rule-sets/constants.js +3 -1
- package/dist/create-webpack/rule-sets/rule-assets.js +52 -1
- package/dist/create-webpack/rule-sets/rule-css.js +111 -1
- package/dist/create-webpack/rule-sets/rule-less.js +44 -1
- package/dist/create-webpack/rule-sets/rule-scripts.js +34 -1
- package/dist/create-webpack/rule-sets/rule-svg-icon.js +25 -1
- package/dist/create-webpack/rule-sets/rule-utils.js +10 -1
- package/dist/create-webpack/types.js +1 -1
- package/dist/default-options.js +83 -1
- package/dist/define-config/define-config.js +4 -1
- package/dist/define-config/index.js +1 -1
- package/dist/dev-server/add-compiler-to-dev-server.js +58 -1
- package/dist/dev-server/create-app-page-route.js +13 -1
- package/dist/dev-server/create-dev-server-compiler-task.js +55 -1
- package/dist/dev-server/create-dev-server-entries.js +25 -1
- package/dist/dev-server/create-dev-server.js +24 -1
- package/dist/dev-server/index.js +6 -1
- package/dist/dev-server/middlewares/create-page-middleware.js +33 -1
- package/dist/dev-server/middlewares/create-public-assets-middleware.js +25 -1
- package/dist/dev-server/middlewares/get-all-sorted-modules.js +24 -1
- package/dist/dev-server/middlewares/get-bundle-asset.js +7 -1
- package/dist/dev-server/middlewares/get-dev-server-host-uri.js +5 -1
- package/dist/dev-server/middlewares/get-hmr-runtime-chunks.js +14 -1
- package/dist/dev-server/middlewares/get-normalized-entry-name.js +14 -1
- package/dist/dev-server/middlewares/get-page-main-html.js +49 -1
- package/dist/dev-server/middlewares/get-page-module-html.js +123 -1
- package/dist/dev-server/middlewares/get-project-virtual-path.js +3 -1
- package/dist/dev-server/middlewares/get-runtime-manifest.js +25 -1
- package/dist/dev-server/middlewares/index.js +2 -1
- package/dist/dev-server/middlewares/types.js +1 -1
- package/dist/errors/evolve-build-error.js +10 -1
- package/dist/helpers/allow-px2rem-for-module.js +6 -1
- package/dist/helpers/assert-group-entry-item.js +19 -1
- package/dist/helpers/assert-single-compiler.js +45 -1
- package/dist/helpers/chunk-entry-map.js +21 -1
- package/dist/helpers/delete-object-keys.js +20 -1
- package/dist/helpers/enable-bundle-hashname-for-module.js +6 -1
- package/dist/helpers/filter-actived-entries.js +42 -1
- package/dist/helpers/flat-entry-map.js +11 -1
- package/dist/helpers/get-bundle-file-name.js +23 -1
- package/dist/helpers/get-git-root.js +4 -1
- package/dist/helpers/get-html-plugin-config.js +47 -1
- package/dist/helpers/get-max-process-tasks.js +7 -1
- package/dist/helpers/get-pacakge-dir.js +13 -1
- package/dist/helpers/get-runtime-cdn-base.js +21 -1
- package/dist/helpers/index.js +27 -1
- package/dist/helpers/is-deep-equal.js +67 -1
- package/dist/helpers/json-serializer.js +52 -1
- package/dist/helpers/merge-babel-options.js +45 -1
- package/dist/helpers/normalize-check-entry-options.js +28 -1
- package/dist/helpers/normalize-entry-map.js +59 -1
- package/dist/helpers/normalize-group-name.js +16 -1
- package/dist/helpers/normalize-page-proxy.js +9 -1
- package/dist/helpers/normalize-resolve-alias.js +7 -1
- package/dist/helpers/normalize-template-inject-tokens.js +22 -1
- package/dist/helpers/open-page.js +15 -1
- package/dist/helpers/print-log.js +49 -1
- package/dist/helpers/refresh-evolve-mock-options.js +34 -1
- package/dist/helpers/resolve-entry-map-input-files.js +20 -1
- package/dist/helpers/script-injects.js +39 -1
- package/dist/helpers/should-enable-react-fast-refresh.js +14 -1
- package/dist/helpers/split-to-entry-group.js +139 -1
- package/dist/helpers/verify-group-entry-options.js +21 -1
- package/dist/index.js +5 -1
- package/dist/load-config/index.js +1 -1
- package/dist/load-config/load-evolve-config.js +41 -1
- package/dist/load-config/types.js +1 -1
- package/dist/main/create-thread-worker.js +51 -1
- package/dist/main/env-verify.js +21 -1
- package/dist/main/get-worker-path.js +5 -1
- package/dist/main/index.js +4 -1
- package/dist/main/prepare-build.js +39 -1
- package/dist/main/prepare-serve.js +69 -1
- package/dist/main/prepare-static.js +30 -1
- package/dist/main/start-build-dynamic.js +171 -1
- package/dist/main/start-build-worker.js +44 -1
- package/dist/main/start-build.js +69 -1
- package/dist/main/start-group-entry-build.js +32 -1
- package/dist/main/start-serve.js +34 -1
- package/dist/main/start-static.js +19 -1
- package/dist/minimizer/create-minimizers.js +25 -1
- package/dist/minimizer/default-options.js +14 -1
- package/dist/minimizer/image-minimizer.js +65 -1
- package/dist/minimizer/index.js +1 -1
- package/dist/minimizer/terser-minimizer.js +15 -3
- package/dist/minimizer/types.js +1 -1
- package/dist/plugins/circular-dependency/circular-dependency-plugin.js +119 -1
- package/dist/plugins/circular-dependency/index.js +15 -1
- package/dist/plugins/clean-webpack/clean-webpack-plugin.js +173 -1
- package/dist/plugins/clean-webpack/index.js +22 -1
- package/dist/plugins/define-variable/define-variable-plugin.js +28 -1
- package/dist/plugins/define-variable/index.js +1 -1
- package/dist/plugins/html-inject-scripts/plugin-html-inject-script.js +27 -1
- package/dist/plugins/module-federation/external-template-remotes.js +92 -1
- package/dist/plugins/module-federation/index.js +1 -1
- package/dist/plugins/module-federation/module-federation.js +100 -1
- package/dist/plugins/multi-html/index.js +16 -1
- package/dist/plugins/multi-html/multi-html-cdn-plugin.js +83 -1
- package/dist/plugins/multi-html/multi-html-plugin.js +65 -1
- package/dist/plugins/ts-checker/index.js +1 -1
- package/dist/plugins/ts-checker/ts-checker-plugin.js +24 -1
- package/dist/types/index.js +8 -1
- package/dist/types/types-ci.js +1 -1
- package/dist/types/types-dev-server.js +1 -1
- package/dist/types/types-entry-map.js +1 -1
- package/dist/types/types-federation.js +1 -1
- package/dist/types/types-loader-options.d.ts +30 -3
- package/dist/types/types-loader-options.js +1 -1
- package/dist/types/types-modular-import.js +1 -1
- package/dist/types/types-multi-html.js +1 -1
- package/dist/types/types-options.js +1 -1
- package/dist/types/types-plugin-options.js +1 -1
- package/dist/types/types-threads-options.js +1 -1
- package/dist/types/types-webpack.js +1 -1
- package/package.json +2 -2
@@ -1 +1,41 @@
|
|
1
|
-
import{searchConfig}from
|
1
|
+
import { searchConfig } from '@armit/config-loader';
|
2
|
+
import { mergeOptions, logger } from '@flatjs/common';
|
3
|
+
import { configFileName, moduleName } from '../constants.js';
|
4
|
+
import { defaultEvolveOptions } from '../default-options.js';
|
5
|
+
import { normalizeResolveAlias } from '../helpers/normalize-resolve-alias.js';
|
6
|
+
import { refreshEvolveMockOptions } from '../helpers/refresh-evolve-mock-options.js';
|
7
|
+
export const loadEvolveConfig = async (configEnv, projectCwd, overrideOptions = {}, configLoaderOptions = {
|
8
|
+
configFile: configFileName,
|
9
|
+
esmLoaderOptions: {
|
10
|
+
externals: [/^@flatjs\/.*/],
|
11
|
+
},
|
12
|
+
}) => {
|
13
|
+
const { configFile, esmLoaderOptions } = configLoaderOptions;
|
14
|
+
const data = await searchConfig(configFile, projectCwd, {
|
15
|
+
esm: {
|
16
|
+
...esmLoaderOptions,
|
17
|
+
projectCwd,
|
18
|
+
},
|
19
|
+
});
|
20
|
+
let localData = {};
|
21
|
+
if (typeof data?.config === 'function') {
|
22
|
+
localData = await data?.config(configEnv);
|
23
|
+
}
|
24
|
+
else {
|
25
|
+
localData = data?.config || {};
|
26
|
+
}
|
27
|
+
// Merge user local config with default configure options.
|
28
|
+
const localConfigOptions = mergeOptions(defaultEvolveOptions, localData);
|
29
|
+
const mergedConfigOptions = mergeOptions(localConfigOptions, overrideOptions);
|
30
|
+
const finalData = mergeOptions(mergedConfigOptions, { projectCwd });
|
31
|
+
// We don't need to load mocks configuration from `flatjs-mock.config.js` while `build` phase.
|
32
|
+
const latestEvolveOptions = configEnv.command === 'build'
|
33
|
+
? finalData
|
34
|
+
: await refreshEvolveMockOptions(projectCwd, finalData, configLoaderOptions);
|
35
|
+
logger.debug(`Load evolve config:\n${JSON.stringify(latestEvolveOptions, null, 2)}`, moduleName);
|
36
|
+
// Normalize webpack.resolve.alias to make sure convert `alias` to absolute path.
|
37
|
+
if (latestEvolveOptions.webpack?.resolve?.alias) {
|
38
|
+
latestEvolveOptions.webpack.resolve.alias = normalizeResolveAlias(projectCwd, latestEvolveOptions.webpack?.resolve?.alias);
|
39
|
+
}
|
40
|
+
return latestEvolveOptions;
|
41
|
+
};
|
@@ -1 +1 @@
|
|
1
|
-
export{};
|
1
|
+
export {};
|
@@ -1 +1,51 @@
|
|
1
|
-
import Tinypool from
|
1
|
+
import Tinypool from 'tinypool';
|
2
|
+
import { getWorkerPath } from './get-worker-path.js';
|
3
|
+
import startBuildWorker from './start-build-worker.js';
|
4
|
+
/**
|
5
|
+
* Represents a thread pool for unit testing.
|
6
|
+
*/
|
7
|
+
class ThreadPoolForUnittest {
|
8
|
+
startBuildWorker(options) {
|
9
|
+
return startBuildWorker(options);
|
10
|
+
}
|
11
|
+
terminate() {
|
12
|
+
console.warn(`[WARNING] Using fake "terminate" for unittest!`);
|
13
|
+
}
|
14
|
+
}
|
15
|
+
/**
|
16
|
+
* Represents a thread pool for executing tasks using the TinyPool library.
|
17
|
+
*/
|
18
|
+
class ThreadPoolForTinyPool {
|
19
|
+
/**
|
20
|
+
* Creates a new instance of the `ThreadPoolForTinyPool` class.
|
21
|
+
* @param workerPath The path to the worker file.
|
22
|
+
* @param workerSize The number of worker threads to create.
|
23
|
+
* @param options Optional configuration options for the worker pool.
|
24
|
+
*/
|
25
|
+
constructor(workerPath, options) {
|
26
|
+
const { runtime = 'worker_threads', idleTimeout = 60000, minThreads = 1, maxThreads, } = options || {};
|
27
|
+
this.pool = new Tinypool({
|
28
|
+
filename: workerPath,
|
29
|
+
minThreads,
|
30
|
+
maxThreads,
|
31
|
+
runtime,
|
32
|
+
idleTimeout,
|
33
|
+
});
|
34
|
+
}
|
35
|
+
startBuildWorker(options) {
|
36
|
+
return this.pool.run(options);
|
37
|
+
}
|
38
|
+
terminate() {
|
39
|
+
this.pool.destroy();
|
40
|
+
}
|
41
|
+
}
|
42
|
+
export const createThreadWorker = (options) => {
|
43
|
+
const workerPath = getWorkerPath();
|
44
|
+
// FIXME: Is safe to remove `worker thread` while `test` environment, cause of we need to run UT using `source code`
|
45
|
+
const isTestEnv = process.env.NODE_ENV === 'test';
|
46
|
+
if (isTestEnv) {
|
47
|
+
console.warn(`[WARNING] Using fake thread pool worker for unittest!`);
|
48
|
+
return new ThreadPoolForUnittest();
|
49
|
+
}
|
50
|
+
return new ThreadPoolForTinyPool(workerPath, options);
|
51
|
+
};
|
package/dist/main/env-verify.js
CHANGED
@@ -1 +1,21 @@
|
|
1
|
-
import{illegalPackageChecker,keepPackageDepsUpToDateForNonMonoRepo}from
|
1
|
+
import { illegalPackageChecker, keepPackageDepsUpToDateForNonMonoRepo, } from '@armit/package';
|
2
|
+
export const envVerify = async (projectCwd, evolveOptions) => {
|
3
|
+
const { packageInstallChecker, needVerifyPackages } = evolveOptions;
|
4
|
+
if (packageInstallChecker !== false && packageInstallChecker?.enabled) {
|
5
|
+
// Verify local install node modules
|
6
|
+
await illegalPackageChecker({
|
7
|
+
cwd: projectCwd,
|
8
|
+
modules: packageInstallChecker?.detectModules,
|
9
|
+
throwError: packageInstallChecker?.throwError,
|
10
|
+
showAllInstalledGraph: packageInstallChecker?.showAllInstalledGraph,
|
11
|
+
});
|
12
|
+
}
|
13
|
+
if (needVerifyPackages !== false) {
|
14
|
+
// Keep package deps up to date for non-monorepo
|
15
|
+
await keepPackageDepsUpToDateForNonMonoRepo({
|
16
|
+
cwd: projectCwd,
|
17
|
+
autoUpgrade: true,
|
18
|
+
needVerifyPackages: needVerifyPackages || {},
|
19
|
+
});
|
20
|
+
}
|
21
|
+
};
|
@@ -1 +1,5 @@
|
|
1
|
-
import{pathToFileURL}from
|
1
|
+
import { pathToFileURL } from 'node:url';
|
2
|
+
import { getDirname } from '@armit/file-utility';
|
3
|
+
export const getWorkerPath = () => {
|
4
|
+
return pathToFileURL(getDirname(import.meta.url, './start-build-worker.js')).toString();
|
5
|
+
};
|
package/dist/main/index.js
CHANGED
@@ -1 +1,4 @@
|
|
1
|
-
export*from
|
1
|
+
export * from './start-build.js';
|
2
|
+
export * from './start-serve.js';
|
3
|
+
export * from './start-static.js';
|
4
|
+
export * from './start-build-dynamic.js';
|
@@ -1 +1,39 @@
|
|
1
|
-
import{ensureSlash,mergeOptions}from
|
1
|
+
import { ensureSlash, mergeOptions } from '@flatjs/common';
|
2
|
+
import { ignoreEntryOptionKeys } from '../constants.js';
|
3
|
+
import { EvolveBuildError } from '../errors/evolve-build-error.js';
|
4
|
+
import { printCompilerError } from '../helpers/print-log.js';
|
5
|
+
import { verifyGroupEntryOptions } from '../helpers/verify-group-entry-options.js';
|
6
|
+
import { startGroupEntryBuild, } from './start-group-entry-build.js';
|
7
|
+
/**
|
8
|
+
* The main entry to start an evolve `build`
|
9
|
+
* @param entryMapItem The `entryMapItem` for one entry build task
|
10
|
+
* @param evolveOptions FlatEvolveOptions
|
11
|
+
*/
|
12
|
+
export const prepareBuild = async (groupEntries, evolveOptions) => {
|
13
|
+
const firstGroupEntryItem = Object.values(groupEntries)[0];
|
14
|
+
if (!verifyGroupEntryOptions(groupEntries, ignoreEntryOptionKeys, true)) {
|
15
|
+
throw new Error('The entry options in a group must be the same.');
|
16
|
+
}
|
17
|
+
// Fetch all configuration cdn
|
18
|
+
const cdnPath = evolveOptions.multiHtmlCdn?.prod || [];
|
19
|
+
if (!cdnPath.length) {
|
20
|
+
throw new Error(`No CDN config for env:"prod", groupName: ${firstGroupEntryItem.groupName}`);
|
21
|
+
}
|
22
|
+
// Random choose one to publicPath
|
23
|
+
const cdnPublicPath = ensureSlash(cdnPath[Math.floor(Math.random() * cdnPath.length)], true);
|
24
|
+
try {
|
25
|
+
const useRelativeAssetPath = firstGroupEntryItem.options?.useRelativeAssetPath;
|
26
|
+
const buildEvolveOptions = mergeOptions(evolveOptions, {
|
27
|
+
webpack: {
|
28
|
+
// Only for `assets` used at styling files (e.g.`xxx.less`)
|
29
|
+
publicPath: useRelativeAssetPath ? 'auto' : cdnPublicPath,
|
30
|
+
},
|
31
|
+
});
|
32
|
+
return await startGroupEntryBuild(groupEntries, buildEvolveOptions);
|
33
|
+
}
|
34
|
+
catch (err) {
|
35
|
+
const formattedErrors = printCompilerError(err);
|
36
|
+
// Need re-throw error, in order to third API can capture this error.
|
37
|
+
throw new EvolveBuildError(`BUILD_ERROR`, formattedErrors);
|
38
|
+
}
|
39
|
+
};
|
@@ -1 +1,69 @@
|
|
1
|
-
import
|
1
|
+
import { arrayUnique, logger, urlJoin } from '@flatjs/common';
|
2
|
+
import { attachMockMiddlewares } from '@flatjs/mock';
|
3
|
+
import { ignoreEntryOptionKeys } from '../constants.js';
|
4
|
+
import { createAppPageRoute, createDevServer, createDevServerCompilerTask, createDevServerEntries, } from '../dev-server/index.js';
|
5
|
+
import { flatEntryMap, openPage } from '../helpers/index.js';
|
6
|
+
import { normalizePageProxy } from '../helpers/normalize-page-proxy.js';
|
7
|
+
import { splitToEntryGroup } from '../helpers/split-to-entry-group.js';
|
8
|
+
import { verifyGroupEntryOptions } from '../helpers/verify-group-entry-options.js';
|
9
|
+
import { envVerify } from './env-verify.js';
|
10
|
+
/**
|
11
|
+
* The main entry to start evolve serve
|
12
|
+
* @param projectCwd The Root directory (workspace) of this project.
|
13
|
+
* @param servedEntries All normalized webpack entries we have served.
|
14
|
+
* @param evolveOptions FlatEvolveOptions
|
15
|
+
*/
|
16
|
+
export const prepareServe = async (projectCwd, servedEntries, evolveOptions) => {
|
17
|
+
// Verify if we have an correct project local environment.
|
18
|
+
await envVerify(projectCwd, evolveOptions);
|
19
|
+
// Group by entry group name
|
20
|
+
const entryMapGroupList = splitToEntryGroup(servedEntries, evolveOptions, ignoreEntryOptionKeys, true);
|
21
|
+
if (!entryMapGroupList.length) {
|
22
|
+
logger.warn(`No served entries provided!`);
|
23
|
+
return;
|
24
|
+
}
|
25
|
+
const serveTasks = [];
|
26
|
+
// Create pure dev server.
|
27
|
+
const { app, devPort, devHostUri, publicIp } = await createDevServer(evolveOptions);
|
28
|
+
// Extract all the mock filters of served entries.
|
29
|
+
const mockFilters = evolveOptions.devServer?.mockOptions?.mockFilters || [];
|
30
|
+
// Loop all entries gather all mock files definition from each entry item.
|
31
|
+
for (const [, value] of Object.entries(servedEntries)) {
|
32
|
+
mockFilters.push(...(value.options?.mockFilters || []));
|
33
|
+
}
|
34
|
+
// Attach core handlers for mock
|
35
|
+
await attachMockMiddlewares(app, {
|
36
|
+
...evolveOptions.devServer?.mockOptions,
|
37
|
+
mockFilters: arrayUnique(mockFilters),
|
38
|
+
projectCwd,
|
39
|
+
});
|
40
|
+
let lastPort = devPort;
|
41
|
+
const servedDevServerEntryList = [];
|
42
|
+
for (const entryMapGroup of entryMapGroupList) {
|
43
|
+
// Verify that each entry option is the same in a group
|
44
|
+
if (!verifyGroupEntryOptions(entryMapGroup, ignoreEntryOptionKeys, true)) {
|
45
|
+
throw new Error('The entry options in a group must be the same.');
|
46
|
+
}
|
47
|
+
// Create dev-server configuration for all servedEntries.
|
48
|
+
lastPort++;
|
49
|
+
const servedDevServerEntries = await createDevServerEntries(lastPort, entryMapGroup, evolveOptions);
|
50
|
+
servedDevServerEntryList.push(servedDevServerEntries);
|
51
|
+
}
|
52
|
+
// Create new route `/pages*`,`*` to pure dev server
|
53
|
+
const flatServedDevServerEntries = flatEntryMap(servedDevServerEntryList);
|
54
|
+
createAppPageRoute(projectCwd, app, devHostUri, flatServedDevServerEntries, evolveOptions);
|
55
|
+
const pageProxy = normalizePageProxy(evolveOptions.devServer?.pageProxy || '/pages');
|
56
|
+
const mainPage = urlJoin(devHostUri, [pageProxy]);
|
57
|
+
// Open page via browser
|
58
|
+
if (evolveOptions.devServer?.autoOpen) {
|
59
|
+
openPage(mainPage);
|
60
|
+
}
|
61
|
+
for (const servedDevServerEntryItem of servedDevServerEntryList) {
|
62
|
+
// Create dev-server compiler tasks
|
63
|
+
const task = createDevServerCompilerTask(projectCwd, mainPage, publicIp, servedDevServerEntryItem, servedDevServerEntryList, evolveOptions);
|
64
|
+
serveTasks.push(task);
|
65
|
+
}
|
66
|
+
return Promise.all(serveTasks).then(() => {
|
67
|
+
return app;
|
68
|
+
});
|
69
|
+
};
|
@@ -1 +1,30 @@
|
|
1
|
-
import{chalk,logger,urlJoin}from
|
1
|
+
import { chalk, logger, urlJoin } from '@flatjs/common';
|
2
|
+
import { attachMockMiddlewares } from '@flatjs/mock';
|
3
|
+
import { createAppPageRoute } from '../dev-server/create-app-page-route.js';
|
4
|
+
import { createDevServer } from '../dev-server/create-dev-server.js';
|
5
|
+
import { normalizePageProxy } from '../helpers/normalize-page-proxy.js';
|
6
|
+
import { openPage } from '../helpers/open-page.js';
|
7
|
+
/**
|
8
|
+
* The main entry to start evolve serve
|
9
|
+
* @param projectCwd The Root directory (workspace) of this project.
|
10
|
+
* @param evolveOptions FlatEvolveOptions
|
11
|
+
*/
|
12
|
+
export const prepareStatic = async (projectCwd, evolveOptions) => {
|
13
|
+
// Create pure dev server.
|
14
|
+
const { app, devHostUri } = await createDevServer(evolveOptions);
|
15
|
+
// Attach core handlers for mock
|
16
|
+
await attachMockMiddlewares(app, {
|
17
|
+
...evolveOptions.devServer?.mockOptions,
|
18
|
+
projectCwd,
|
19
|
+
});
|
20
|
+
// Create new route `/pages*`,`*` to pure dev server
|
21
|
+
createAppPageRoute(projectCwd, app, devHostUri, {}, evolveOptions);
|
22
|
+
const pageProxy = normalizePageProxy(evolveOptions.devServer?.pageProxy || '/pages');
|
23
|
+
const mainPage = urlJoin(devHostUri, [pageProxy]);
|
24
|
+
// Open page via browser
|
25
|
+
if (evolveOptions.devServer?.autoOpen) {
|
26
|
+
openPage(mainPage);
|
27
|
+
}
|
28
|
+
logger.info(`${'static page'.padEnd(12, ' ')} ➩ ${chalk(['cyan'])(mainPage)}`);
|
29
|
+
};
|
30
|
+
// Start up main page proxy server.
|
@@ -1 +1,171 @@
|
|
1
|
-
import
|
1
|
+
import { isAbsolute, join } from 'node:path';
|
2
|
+
import { getDiffFiles, getCommitIdOfBranch } from '@armit/git';
|
3
|
+
import { arraysIntersect, chalk, logger, requireResolve } from '@flatjs/common';
|
4
|
+
import { traverseGraph } from '@flatjs/graph';
|
5
|
+
import Listr from 'listr';
|
6
|
+
import { ignoreEntryOptionKeys, moduleName } from '../constants.js';
|
7
|
+
import { filterActivedEntriesByEntryInputs, filterActivedEntriesByModule, } from '../helpers/filter-actived-entries.js';
|
8
|
+
import { getGitRoot } from '../helpers/get-git-root.js';
|
9
|
+
import { getMaxProcessTasks } from '../helpers/get-max-process-tasks.js';
|
10
|
+
import { jsonSerializer } from '../helpers/json-serializer.js';
|
11
|
+
import { normalizeEvolveEntryMap } from '../helpers/normalize-entry-map.js';
|
12
|
+
import { resolveEntryMapInputFiles } from '../helpers/resolve-entry-map-input-files.js';
|
13
|
+
import { splitToEntryGroup } from '../helpers/split-to-entry-group.js';
|
14
|
+
import { loadEvolveConfig } from '../load-config/load-evolve-config.js';
|
15
|
+
import { createThreadWorker } from './create-thread-worker.js';
|
16
|
+
import { envVerify } from './env-verify.js';
|
17
|
+
export async function getBuildEntryFiles(projectCwd, diffFiles, allEntryInputs, resolveAlias, graphTreeNodeFilter) {
|
18
|
+
const toBuildEntryFiles = [];
|
19
|
+
const entryInputsPendingToCheck = [];
|
20
|
+
for (const entryInput of allEntryInputs) {
|
21
|
+
// If entry have been existed in diff files, need to rebuild.
|
22
|
+
if (diffFiles.includes(entryInput)) {
|
23
|
+
toBuildEntryFiles.push(entryInput);
|
24
|
+
}
|
25
|
+
else {
|
26
|
+
entryInputsPendingToCheck.push(entryInput);
|
27
|
+
}
|
28
|
+
}
|
29
|
+
if (graphTreeNodeFilter) {
|
30
|
+
logger.info(`Use custom graph traverse filter`, moduleName);
|
31
|
+
}
|
32
|
+
// If there has pedding entry inputs to check.
|
33
|
+
if (entryInputsPendingToCheck.length) {
|
34
|
+
const graphDeps = await traverseGraph({
|
35
|
+
input: entryInputsPendingToCheck,
|
36
|
+
projectCwd,
|
37
|
+
treeNodeFilter: graphTreeNodeFilter || (() => true),
|
38
|
+
lessImportOptions: {
|
39
|
+
projectCwd,
|
40
|
+
aliases: resolveAlias,
|
41
|
+
},
|
42
|
+
});
|
43
|
+
if (!graphDeps) {
|
44
|
+
return toBuildEntryFiles;
|
45
|
+
}
|
46
|
+
logger.debug(`DependencyGraph:\n${JSON.stringify(graphDeps, null, 2)}`);
|
47
|
+
for (const entryInputToCheck of entryInputsPendingToCheck) {
|
48
|
+
const dependsFiles = graphDeps[entryInputToCheck] || [];
|
49
|
+
if (arraysIntersect(dependsFiles, diffFiles)) {
|
50
|
+
toBuildEntryFiles.push(entryInputToCheck);
|
51
|
+
}
|
52
|
+
}
|
53
|
+
}
|
54
|
+
return toBuildEntryFiles;
|
55
|
+
}
|
56
|
+
/**
|
57
|
+
* Dynamic check which entry modules need to build.
|
58
|
+
* @returns
|
59
|
+
*/
|
60
|
+
export async function dynamicCheckBuildEntryMap(projectCwd, earlyCommit, lastCommit, overrideEvolveOptions, configLoaderOptions) {
|
61
|
+
const command = {
|
62
|
+
projectCwd,
|
63
|
+
command: 'build',
|
64
|
+
resolve: requireResolve,
|
65
|
+
};
|
66
|
+
// 1. Try to load evolve configuration from `flatjs-evolve.config.ts`
|
67
|
+
const newEvolveOptions = await loadEvolveConfig(command, projectCwd, overrideEvolveOptions, configLoaderOptions);
|
68
|
+
// 2. Check if we have fixed build modules.
|
69
|
+
if (newEvolveOptions.ci?.fixedBuildModules &&
|
70
|
+
newEvolveOptions.ci?.fixedBuildModules.length) {
|
71
|
+
logger.info('Use `fixedBuildModules` configuration to build...');
|
72
|
+
const buildEntries = filterActivedEntriesByModule(newEvolveOptions.entryMap, newEvolveOptions.ci?.fixedBuildModules);
|
73
|
+
return { buildEntries, newEvolveOptions };
|
74
|
+
}
|
75
|
+
logger.info('Dynamicly checking code changed modules ...');
|
76
|
+
// 3. Resolve diff files based on specificed branch.
|
77
|
+
// Check if we have fixed `early commit` if no resolve based on `Branch` from evolve config file.
|
78
|
+
if (!earlyCommit) {
|
79
|
+
const basedBranch = newEvolveOptions.ci?.basedBranch || 'origin/master';
|
80
|
+
earlyCommit = await getCommitIdOfBranch(basedBranch);
|
81
|
+
// Try resolve based branch commit hash.
|
82
|
+
logger.info(`Resolving base branch "${basedBranch}" commit hash "${earlyCommit}" ...`);
|
83
|
+
}
|
84
|
+
// `packages/evolve/tests/main/fixtures/src/home/index.ts` without repo cwd.
|
85
|
+
let diffFiles = earlyCommit
|
86
|
+
? await getDiffFiles(earlyCommit, lastCommit)
|
87
|
+
: [];
|
88
|
+
const gitRoot = getGitRoot(projectCwd);
|
89
|
+
if (!gitRoot) {
|
90
|
+
throw new Error(`No .git root (${projectCwd}) found`);
|
91
|
+
}
|
92
|
+
// Hack diff files with git repo root dir.
|
93
|
+
diffFiles = diffFiles.map((diffFile) => {
|
94
|
+
return isAbsolute(diffFile) ? diffFile : join(gitRoot, diffFile);
|
95
|
+
});
|
96
|
+
logger.debug(`Diff files: \n${JSON.stringify(diffFiles, null, 2)}`);
|
97
|
+
// No code changed here.
|
98
|
+
if (!diffFiles.length) {
|
99
|
+
logger.warn('It seems that there are no code files changed.');
|
100
|
+
return {
|
101
|
+
buildEntries: {},
|
102
|
+
newEvolveOptions,
|
103
|
+
};
|
104
|
+
}
|
105
|
+
// 4. Resolve entry input files.
|
106
|
+
const allEntryInputs = await resolveEntryMapInputFiles(projectCwd, newEvolveOptions.entryMap);
|
107
|
+
// 5. Flag changed entries (with absolute filepath)
|
108
|
+
const toBuildEntryFiles = await getBuildEntryFiles(projectCwd, diffFiles, allEntryInputs, newEvolveOptions.webpack?.resolve?.alias, newEvolveOptions.ci?.graphTreeNodeFilter);
|
109
|
+
logger.debug(`To build entry files: \n${JSON.stringify(toBuildEntryFiles, null, 2)}`);
|
110
|
+
// 6. Filter entry map items which need to build.
|
111
|
+
const buildEntries = await filterActivedEntriesByEntryInputs(projectCwd, newEvolveOptions.entryMap, toBuildEntryFiles);
|
112
|
+
return { buildEntries, newEvolveOptions };
|
113
|
+
}
|
114
|
+
/**
|
115
|
+
* The main entry to start an evolve `build` with automatically detect modules which have been changed between two commits.
|
116
|
+
* @param projectCwd The Root directory (workspace) of this project.
|
117
|
+
* @param earlyCommit The diff based earlier commit hash
|
118
|
+
* @param lastCommit If is omitted, it will have the same effect as using HEAD instead.
|
119
|
+
*/
|
120
|
+
export const startDynamicBuild = async (projectCwd, earlyCommit, lastCommit, overrideEvolveOptions = {}, configLoaderOptions) => {
|
121
|
+
// 1. Fetch all changed files between two `commit`
|
122
|
+
const { buildEntries, newEvolveOptions } = await dynamicCheckBuildEntryMap(projectCwd, earlyCommit, lastCommit, overrideEvolveOptions, configLoaderOptions);
|
123
|
+
await envVerify(projectCwd, newEvolveOptions);
|
124
|
+
// Make sure that each entry option includes the groupName
|
125
|
+
const normalizedBuildOneEntry = normalizeEvolveEntryMap(buildEntries, newEvolveOptions.entryMap);
|
126
|
+
const entryMapGroupList = splitToEntryGroup(normalizedBuildOneEntry, newEvolveOptions, ignoreEntryOptionKeys, false);
|
127
|
+
if (!entryMapGroupList.length) {
|
128
|
+
logger.warn(`No build entries provided!`);
|
129
|
+
return [];
|
130
|
+
}
|
131
|
+
const buildEntryGroupNames = entryMapGroupList.map((group) => {
|
132
|
+
return Object.values(group)?.[0]?.groupName;
|
133
|
+
});
|
134
|
+
const { threads = {} } = newEvolveOptions;
|
135
|
+
const maxThreads = getMaxProcessTasks(entryMapGroupList.length, threads?.maxThreads);
|
136
|
+
logger.info(`Start dynamic build with (${chalk(['magenta'])(String(maxThreads))}) workers:\n${JSON.stringify({ buildEntriesGroup: buildEntryGroupNames }, null, 2)}`);
|
137
|
+
const worker = createThreadWorker({ ...threads, maxThreads });
|
138
|
+
const buildTasks = new Listr([], {
|
139
|
+
concurrent: maxThreads,
|
140
|
+
exitOnError: true,
|
141
|
+
});
|
142
|
+
const buildResults = [];
|
143
|
+
for (const entryMapGroupItem of entryMapGroupList) {
|
144
|
+
const groupName = Object.values(entryMapGroupItem)?.[0]?.groupName || '';
|
145
|
+
const entryKeys = Object.keys(entryMapGroupItem);
|
146
|
+
buildTasks.add({
|
147
|
+
title: `Build group ${groupName}: ${chalk(['magenta'])(`${JSON.stringify(entryKeys, null, 2)}`)} ...`,
|
148
|
+
task: async () => {
|
149
|
+
const buildResult = await worker.startBuildWorker({
|
150
|
+
projectCwd: projectCwd,
|
151
|
+
entryKeys: entryKeys,
|
152
|
+
serializedEvolveOptions: jsonSerializer.stringify(overrideEvolveOptions),
|
153
|
+
configLoaderOptions: configLoaderOptions,
|
154
|
+
});
|
155
|
+
buildResults.push(buildResult);
|
156
|
+
},
|
157
|
+
});
|
158
|
+
}
|
159
|
+
if (buildTasks.tasks.length) {
|
160
|
+
try {
|
161
|
+
await buildTasks.run();
|
162
|
+
}
|
163
|
+
catch (err) {
|
164
|
+
worker.terminate();
|
165
|
+
// we need to catch the error here, make sure the `worker` can be terminated.
|
166
|
+
throw err;
|
167
|
+
}
|
168
|
+
}
|
169
|
+
worker.terminate();
|
170
|
+
return buildResults;
|
171
|
+
};
|
@@ -1 +1,44 @@
|
|
1
|
-
import{requireResolve}from
|
1
|
+
import { requireResolve } from '@flatjs/common';
|
2
|
+
import { ignoreEntryOptionKeys } from '../constants.js';
|
3
|
+
import { filterActivedEntriesByModule } from '../helpers/filter-actived-entries.js';
|
4
|
+
import { jsonSerializer } from '../helpers/json-serializer.js';
|
5
|
+
import { normalizeEvolveEntryMap } from '../helpers/normalize-entry-map.js';
|
6
|
+
import { splitToEntryGroup } from '../helpers/split-to-entry-group.js';
|
7
|
+
import { loadEvolveConfig } from '../load-config/load-evolve-config.js';
|
8
|
+
import { prepareBuild } from './prepare-build.js';
|
9
|
+
/**
|
10
|
+
* FIXME: The main entry to start an evolve `build`, NOTE: avoid pass configuration with `function` here.
|
11
|
+
* If you need to call build api avoid `worker` you can directly call `prepareBuild`
|
12
|
+
* @internal
|
13
|
+
* @param options.projectCwd The Root directory (workspace) of this project.
|
14
|
+
* @param options.entryKey The `entryKey` for one entry build task
|
15
|
+
* @param options.serializedEvolveOptions The overrided evolve options, NOTE: we will serialize `function` property here first
|
16
|
+
* @param options.configLoaderOptions Evolve config loader options, NOTE: avoid pass configuration with `function` here.
|
17
|
+
*/
|
18
|
+
export default async (options) => {
|
19
|
+
const { projectCwd, entryKeys, serializedEvolveOptions, configLoaderOptions, } = options;
|
20
|
+
const command = {
|
21
|
+
projectCwd,
|
22
|
+
command: 'build',
|
23
|
+
resolve: requireResolve,
|
24
|
+
};
|
25
|
+
const overrideEvolveOptions = jsonSerializer.parse(serializedEvolveOptions) || {};
|
26
|
+
// Try to load evolve configuration from `flatjs-evolve.config.ts`
|
27
|
+
// FIXME: Cause of `worker-theads` do not support pass configuration with `function` reference.
|
28
|
+
const newEvolveOptions = await loadEvolveConfig(command, projectCwd, overrideEvolveOptions, configLoaderOptions);
|
29
|
+
// FIXME: Cause of `worker threads` we need avoid pass entryItem config directly
|
30
|
+
// because we have some config node item with `function`
|
31
|
+
// It will break `worker threads` comunication, e.g below shown.
|
32
|
+
// DataCloneError: function (url) {
|
33
|
+
// if (url.indexOf('dev.flatjs.com') > 0) return 'me';
|
34
|
+
// if (url.indexOf('.qa.') > 0) retur...<omitted>... } could not be cloned.
|
35
|
+
// at new DOMException (node:internal/per_context/domexception:53:5)
|
36
|
+
// So we need to re cacalculate the build entry via `entryKey`
|
37
|
+
const modulesRegList = entryKeys.map((key) => new RegExp(`^${key}$`));
|
38
|
+
const buildGroupEntry = filterActivedEntriesByModule(newEvolveOptions.entryMap,
|
39
|
+
// Make sure that the entryKey is correct match.
|
40
|
+
modulesRegList);
|
41
|
+
const normalizedBuildGroupEntry = normalizeEvolveEntryMap(buildGroupEntry, newEvolveOptions.entryMap);
|
42
|
+
const entryMapGroupList = splitToEntryGroup(normalizedBuildGroupEntry, newEvolveOptions, ignoreEntryOptionKeys, false);
|
43
|
+
return prepareBuild(entryMapGroupList[0], newEvolveOptions);
|
44
|
+
};
|
package/dist/main/start-build.js
CHANGED
@@ -1 +1,69 @@
|
|
1
|
-
import{chalk,logger,requireResolve}from
|
1
|
+
import { chalk, logger, requireResolve } from '@flatjs/common';
|
2
|
+
import Listr from 'listr';
|
3
|
+
import { ignoreEntryOptionKeys } from '../constants.js';
|
4
|
+
import { filterActivedEntriesByModule } from '../helpers/filter-actived-entries.js';
|
5
|
+
import { getMaxProcessTasks } from '../helpers/get-max-process-tasks.js';
|
6
|
+
import { jsonSerializer } from '../helpers/json-serializer.js';
|
7
|
+
import { normalizeEvolveEntryMap } from '../helpers/normalize-entry-map.js';
|
8
|
+
import { splitToEntryGroup } from '../helpers/split-to-entry-group.js';
|
9
|
+
import { loadEvolveConfig } from '../load-config/load-evolve-config.js';
|
10
|
+
import { createThreadWorker } from './create-thread-worker.js';
|
11
|
+
import { envVerify } from './env-verify.js';
|
12
|
+
export const startBuild = async (projectCwd, buildModules, overrideEvolveOptions = {}, configLoaderOptions) => {
|
13
|
+
const command = {
|
14
|
+
projectCwd,
|
15
|
+
command: 'build',
|
16
|
+
resolve: requireResolve,
|
17
|
+
};
|
18
|
+
// Try to load evolve configuration from `flatjs-evolve.config.ts`
|
19
|
+
const newEvolveOptions = await loadEvolveConfig(command, projectCwd, overrideEvolveOptions, configLoaderOptions);
|
20
|
+
await envVerify(projectCwd, newEvolveOptions);
|
21
|
+
const buildEntries = filterActivedEntriesByModule(newEvolveOptions.entryMap, buildModules);
|
22
|
+
// Make sure that each entry option includes the groupName
|
23
|
+
const normalizedBuildOneEntry = normalizeEvolveEntryMap(buildEntries, newEvolveOptions.entryMap);
|
24
|
+
const entryMapGroupList = splitToEntryGroup(normalizedBuildOneEntry, newEvolveOptions, ignoreEntryOptionKeys, false);
|
25
|
+
if (!entryMapGroupList.length) {
|
26
|
+
logger.warn(`No build entries provided!`);
|
27
|
+
return [];
|
28
|
+
}
|
29
|
+
const buildEntryGroupNames = entryMapGroupList.map((group) => {
|
30
|
+
return Object.values(group)?.[0]?.groupName;
|
31
|
+
});
|
32
|
+
const { threads = {} } = newEvolveOptions;
|
33
|
+
const maxThreads = getMaxProcessTasks(entryMapGroupList.length, threads?.maxThreads);
|
34
|
+
logger.info(`Start standard build with (${chalk(['magenta'])(String(maxThreads))}) workers:\n${JSON.stringify({ buildEntriesGroup: buildEntryGroupNames }, null, 2)}`);
|
35
|
+
const worker = createThreadWorker({ ...threads, maxThreads });
|
36
|
+
const buildTasks = new Listr([], {
|
37
|
+
concurrent: maxThreads,
|
38
|
+
exitOnError: true,
|
39
|
+
});
|
40
|
+
const buildResults = [];
|
41
|
+
for (const entryMapGroupItem of entryMapGroupList) {
|
42
|
+
const groupName = Object.values(entryMapGroupItem)?.[0]?.groupName || '';
|
43
|
+
const entryKeys = Object.keys(entryMapGroupItem);
|
44
|
+
buildTasks.add({
|
45
|
+
title: `Build group ${groupName}: ${chalk(['magenta'])(`${JSON.stringify(entryKeys, null, 2)}`)} ...`,
|
46
|
+
task: async () => {
|
47
|
+
const buildResult = await worker.startBuildWorker({
|
48
|
+
projectCwd: projectCwd,
|
49
|
+
entryKeys: entryKeys,
|
50
|
+
serializedEvolveOptions: jsonSerializer.stringify(overrideEvolveOptions),
|
51
|
+
configLoaderOptions: configLoaderOptions,
|
52
|
+
});
|
53
|
+
buildResults.push(buildResult);
|
54
|
+
},
|
55
|
+
});
|
56
|
+
}
|
57
|
+
if (buildTasks.tasks.length) {
|
58
|
+
try {
|
59
|
+
await buildTasks.run();
|
60
|
+
}
|
61
|
+
catch (err) {
|
62
|
+
worker.terminate();
|
63
|
+
// we need to catch the error here, make sure the `worker` can be terminated.
|
64
|
+
throw err;
|
65
|
+
}
|
66
|
+
}
|
67
|
+
worker.terminate();
|
68
|
+
return buildResults;
|
69
|
+
};
|
@@ -1 +1,32 @@
|
|
1
|
-
import webpack from
|
1
|
+
import webpack from 'webpack';
|
2
|
+
import { loadWebpackConfig } from '../create-webpack/load-webpack-config.js';
|
3
|
+
import { assertSingleCompiler } from '../helpers/assert-single-compiler.js';
|
4
|
+
/**
|
5
|
+
* Starts the build process for a group of entry files.
|
6
|
+
*
|
7
|
+
* @param groupBuildEntry - The map of entry files to be built.
|
8
|
+
* @param evolveOptions - The options for the build process.
|
9
|
+
* @returns A promise that resolves to the build result.
|
10
|
+
*/
|
11
|
+
export const startGroupEntryBuild = async (groupBuildEntry, evolveOptions) => {
|
12
|
+
// Try to load webpack configuration
|
13
|
+
const webpackConfig = await loadWebpackConfig('production', groupBuildEntry, evolveOptions);
|
14
|
+
const currCompiler = assertSingleCompiler(groupBuildEntry, webpackConfig, evolveOptions, false);
|
15
|
+
// Run the single build.
|
16
|
+
return new Promise((resolve, reject) => {
|
17
|
+
webpack(currCompiler, (err, stats) => {
|
18
|
+
if (err) {
|
19
|
+
// Handle errors here
|
20
|
+
return reject(err);
|
21
|
+
}
|
22
|
+
const statsJson = stats?.toJson();
|
23
|
+
if (statsJson?.errors?.length) {
|
24
|
+
return reject(statsJson.errors);
|
25
|
+
}
|
26
|
+
if (evolveOptions.rejectWarnings && statsJson?.warnings?.length) {
|
27
|
+
return reject(statsJson.warnings);
|
28
|
+
}
|
29
|
+
resolve({ name: currCompiler.name, warningStats: statsJson?.warnings });
|
30
|
+
});
|
31
|
+
});
|
32
|
+
};
|