@flatjs/evolve 2.1.0-next.11 → 2.1.0-next.12

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.
Files changed (125) hide show
  1. package/dist/constants.js +36 -1
  2. package/dist/create-webpack/create-externals.js +6 -1
  3. package/dist/create-webpack/create-optimization.js +43 -1
  4. package/dist/create-webpack/create-output.js +35 -1
  5. package/dist/create-webpack/create-performance.js +7 -1
  6. package/dist/create-webpack/create-plugins.js +78 -1
  7. package/dist/create-webpack/create-resolve.js +37 -1
  8. package/dist/create-webpack/create-rule-sets.js +20 -1
  9. package/dist/create-webpack/load-webpack-config.js +57 -1
  10. package/dist/create-webpack/resolve-public-path.js +15 -1
  11. package/dist/create-webpack/rule-sets/constants.js +3 -1
  12. package/dist/create-webpack/rule-sets/rule-assets.js +52 -1
  13. package/dist/create-webpack/rule-sets/rule-css.js +111 -1
  14. package/dist/create-webpack/rule-sets/rule-less.js +44 -1
  15. package/dist/create-webpack/rule-sets/rule-scripts.js +34 -1
  16. package/dist/create-webpack/rule-sets/rule-svg-icon.js +25 -1
  17. package/dist/create-webpack/rule-sets/rule-utils.js +10 -1
  18. package/dist/create-webpack/types.js +1 -1
  19. package/dist/default-options.js +83 -1
  20. package/dist/define-config/define-config.js +4 -1
  21. package/dist/define-config/index.js +1 -1
  22. package/dist/dev-server/add-compiler-to-dev-server.js +58 -1
  23. package/dist/dev-server/create-app-page-route.js +13 -1
  24. package/dist/dev-server/create-dev-server-compiler-task.js +55 -1
  25. package/dist/dev-server/create-dev-server-entries.js +25 -1
  26. package/dist/dev-server/create-dev-server.js +24 -1
  27. package/dist/dev-server/index.js +6 -1
  28. package/dist/dev-server/middlewares/create-page-middleware.js +33 -1
  29. package/dist/dev-server/middlewares/create-public-assets-middleware.js +25 -1
  30. package/dist/dev-server/middlewares/get-all-sorted-modules.js +24 -1
  31. package/dist/dev-server/middlewares/get-bundle-asset.js +7 -1
  32. package/dist/dev-server/middlewares/get-dev-server-host-uri.js +5 -1
  33. package/dist/dev-server/middlewares/get-hmr-runtime-chunks.js +14 -1
  34. package/dist/dev-server/middlewares/get-normalized-entry-name.js +14 -1
  35. package/dist/dev-server/middlewares/get-page-main-html.js +49 -1
  36. package/dist/dev-server/middlewares/get-page-module-html.js +123 -1
  37. package/dist/dev-server/middlewares/get-project-virtual-path.js +3 -1
  38. package/dist/dev-server/middlewares/get-runtime-manifest.js +25 -1
  39. package/dist/dev-server/middlewares/index.js +2 -1
  40. package/dist/dev-server/middlewares/types.js +1 -1
  41. package/dist/errors/evolve-build-error.js +10 -1
  42. package/dist/helpers/allow-px2rem-for-module.js +6 -1
  43. package/dist/helpers/assert-group-entry-item.js +19 -1
  44. package/dist/helpers/assert-single-compiler.js +45 -1
  45. package/dist/helpers/chunk-entry-map.js +21 -1
  46. package/dist/helpers/delete-object-keys.js +20 -1
  47. package/dist/helpers/enable-bundle-hashname-for-module.js +6 -1
  48. package/dist/helpers/filter-actived-entries.js +42 -1
  49. package/dist/helpers/flat-entry-map.js +11 -1
  50. package/dist/helpers/get-bundle-file-name.js +23 -1
  51. package/dist/helpers/get-git-root.js +4 -1
  52. package/dist/helpers/get-html-plugin-config.js +47 -1
  53. package/dist/helpers/get-max-process-tasks.js +7 -1
  54. package/dist/helpers/get-pacakge-dir.js +13 -1
  55. package/dist/helpers/get-runtime-cdn-base.js +21 -1
  56. package/dist/helpers/index.js +27 -1
  57. package/dist/helpers/is-deep-equal.js +67 -1
  58. package/dist/helpers/json-serializer.js +52 -1
  59. package/dist/helpers/merge-babel-options.js +45 -1
  60. package/dist/helpers/normalize-check-entry-options.js +28 -1
  61. package/dist/helpers/normalize-entry-map.js +59 -1
  62. package/dist/helpers/normalize-group-name.js +16 -1
  63. package/dist/helpers/normalize-page-proxy.js +9 -1
  64. package/dist/helpers/normalize-resolve-alias.js +7 -1
  65. package/dist/helpers/normalize-template-inject-tokens.js +22 -1
  66. package/dist/helpers/open-page.js +15 -1
  67. package/dist/helpers/print-log.js +49 -1
  68. package/dist/helpers/refresh-evolve-mock-options.js +34 -1
  69. package/dist/helpers/resolve-entry-map-input-files.js +20 -1
  70. package/dist/helpers/script-injects.js +39 -1
  71. package/dist/helpers/should-enable-react-fast-refresh.js +14 -1
  72. package/dist/helpers/split-to-entry-group.js +139 -1
  73. package/dist/helpers/verify-group-entry-options.js +21 -1
  74. package/dist/index.js +5 -1
  75. package/dist/load-config/index.js +1 -1
  76. package/dist/load-config/load-evolve-config.js +41 -1
  77. package/dist/load-config/types.js +1 -1
  78. package/dist/main/create-thread-worker.js +51 -1
  79. package/dist/main/env-verify.js +21 -1
  80. package/dist/main/get-worker-path.js +5 -1
  81. package/dist/main/index.js +4 -1
  82. package/dist/main/prepare-build.js +39 -1
  83. package/dist/main/prepare-serve.js +69 -1
  84. package/dist/main/prepare-static.js +30 -1
  85. package/dist/main/start-build-dynamic.js +171 -1
  86. package/dist/main/start-build-worker.js +44 -1
  87. package/dist/main/start-build.js +69 -1
  88. package/dist/main/start-group-entry-build.js +32 -1
  89. package/dist/main/start-serve.js +34 -1
  90. package/dist/main/start-static.js +19 -1
  91. package/dist/minimizer/create-minimizers.js +25 -1
  92. package/dist/minimizer/default-options.js +14 -1
  93. package/dist/minimizer/image-minimizer.js +65 -1
  94. package/dist/minimizer/index.js +1 -1
  95. package/dist/minimizer/terser-minimizer.js +15 -3
  96. package/dist/minimizer/types.js +1 -1
  97. package/dist/plugins/circular-dependency/circular-dependency-plugin.js +119 -1
  98. package/dist/plugins/circular-dependency/index.js +15 -1
  99. package/dist/plugins/clean-webpack/clean-webpack-plugin.js +173 -1
  100. package/dist/plugins/clean-webpack/index.js +22 -1
  101. package/dist/plugins/define-variable/define-variable-plugin.js +28 -1
  102. package/dist/plugins/define-variable/index.js +1 -1
  103. package/dist/plugins/html-inject-scripts/plugin-html-inject-script.js +27 -1
  104. package/dist/plugins/module-federation/external-template-remotes.js +92 -1
  105. package/dist/plugins/module-federation/index.js +1 -1
  106. package/dist/plugins/module-federation/module-federation.js +100 -1
  107. package/dist/plugins/multi-html/index.js +16 -1
  108. package/dist/plugins/multi-html/multi-html-cdn-plugin.js +83 -1
  109. package/dist/plugins/multi-html/multi-html-plugin.js +65 -1
  110. package/dist/plugins/ts-checker/index.js +1 -1
  111. package/dist/plugins/ts-checker/ts-checker-plugin.js +24 -1
  112. package/dist/types/index.js +8 -1
  113. package/dist/types/types-ci.js +1 -1
  114. package/dist/types/types-dev-server.js +1 -1
  115. package/dist/types/types-entry-map.js +1 -1
  116. package/dist/types/types-federation.js +1 -1
  117. package/dist/types/types-loader-options.d.ts +30 -3
  118. package/dist/types/types-loader-options.js +1 -1
  119. package/dist/types/types-modular-import.js +1 -1
  120. package/dist/types/types-multi-html.js +1 -1
  121. package/dist/types/types-options.js +1 -1
  122. package/dist/types/types-plugin-options.js +1 -1
  123. package/dist/types/types-threads-options.js +1 -1
  124. package/dist/types/types-webpack.js +1 -1
  125. package/package.json +2 -2
@@ -1 +1,41 @@
1
- import{searchConfig}from"@armit/config-loader";import{mergeOptions,logger}from"@flatjs/common";import{configFileName,moduleName}from"../constants.js";import{defaultEvolveOptions}from"../default-options.js";import{normalizeResolveAlias}from"../helpers/normalize-resolve-alias.js";import{refreshEvolveMockOptions}from"../helpers/refresh-evolve-mock-options.js";export const loadEvolveConfig=async(o,e,i={},s={configFile:configFileName,esmLoaderOptions:{externals:[/^@flatjs\/.*/]}})=>{const{configFile:r,esmLoaderOptions:l}=s,a=await searchConfig(r,e,{esm:{...l,projectCwd:e}});let n={};n="function"==typeof a?.config?await(a?.config(o)):a?.config||{};const t=mergeOptions(defaultEvolveOptions,n),m=mergeOptions(t,i),f=mergeOptions(m,{projectCwd:e}),c="build"===o.command?f:await refreshEvolveMockOptions(e,f,s);return logger.debug(`Load evolve config:\n${JSON.stringify(c,null,2)}`,moduleName),c.webpack?.resolve?.alias&&(c.webpack.resolve.alias=normalizeResolveAlias(e,c.webpack?.resolve?.alias)),c};
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"tinypool";import{getWorkerPath}from"./get-worker-path.js";import startBuildWorker from"./start-build-worker.js";class ThreadPoolForUnittest{startBuildWorker(r){return startBuildWorker(r)}terminate(){console.warn('[WARNING] Using fake "terminate" for unittest!')}}class ThreadPoolForTinyPool{constructor(r,o){const{runtime:e="worker_threads",idleTimeout:t=6e4,minThreads:n=1,maxThreads:s}=o||{};this.pool=new Tinypool({filename:r,minThreads:n,maxThreads:s,runtime:e,idleTimeout:t})}startBuildWorker(r){return this.pool.run(r)}terminate(){this.pool.destroy()}}export const createThreadWorker=r=>{const o=getWorkerPath();return"test"===process.env.NODE_ENV?(console.warn("[WARNING] Using fake thread pool worker for unittest!"),new ThreadPoolForUnittest):new ThreadPoolForTinyPool(o,r)};
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
+ };
@@ -1 +1,21 @@
1
- import{illegalPackageChecker,keepPackageDepsUpToDateForNonMonoRepo}from"@armit/package";export const envVerify=async(e,a)=>{const{packageInstallChecker:o,needVerifyPackages:r}=a;!1!==o&&o?.enabled&&await illegalPackageChecker({cwd:e,modules:o?.detectModules,throwError:o?.throwError,showAllInstalledGraph:o?.showAllInstalledGraph}),!1!==r&&await keepPackageDepsUpToDateForNonMonoRepo({cwd:e,autoUpgrade:!0,needVerifyPackages:r||{}})};
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"node:url";import{getDirname}from"@armit/file-utility";export const getWorkerPath=()=>pathToFileURL(getDirname(import.meta.url,"./start-build-worker.js")).toString();
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
+ };
@@ -1 +1,4 @@
1
- export*from"./start-build.js";export*from"./start-serve.js";export*from"./start-static.js";export*from"./start-build-dynamic.js";
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"@flatjs/common";import{ignoreEntryOptionKeys}from"../constants.js";import{EvolveBuildError}from"../errors/evolve-build-error.js";import{printCompilerError}from"../helpers/print-log.js";import{verifyGroupEntryOptions}from"../helpers/verify-group-entry-options.js";import{startGroupEntryBuild}from"./start-group-entry-build.js";export const prepareBuild=async(r,o)=>{const t=Object.values(r)[0];if(!verifyGroupEntryOptions(r,ignoreEntryOptionKeys,!0))throw new Error("The entry options in a group must be the same.");const e=o.multiHtmlCdn?.prod||[];if(!e.length)throw new Error(`No CDN config for env:"prod", groupName: ${t.groupName}`);const n=ensureSlash(e[Math.floor(Math.random()*e.length)],!0);try{const e=t.options?.useRelativeAssetPath,i=mergeOptions(o,{webpack:{publicPath:e?"auto":n}});return await startGroupEntryBuild(r,i)}catch(r){const o=printCompilerError(r);throw new EvolveBuildError("BUILD_ERROR",o)}};
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{arrayUnique,logger,urlJoin}from"@flatjs/common";import{attachMockMiddlewares}from"@flatjs/mock";import{ignoreEntryOptionKeys}from"../constants.js";import{createAppPageRoute,createDevServer,createDevServerCompilerTask,createDevServerEntries}from"../dev-server/index.js";import{flatEntryMap,openPage}from"../helpers/index.js";import{normalizePageProxy}from"../helpers/normalize-page-proxy.js";import{splitToEntryGroup}from"../helpers/split-to-entry-group.js";import{verifyGroupEntryOptions}from"../helpers/verify-group-entry-options.js";import{envVerify}from"./env-verify.js";export const prepareServe=async(e,r,o)=>{await envVerify(e,o);const t=splitToEntryGroup(r,o,ignoreEntryOptionKeys,!0);if(!t.length)return void logger.warn("No served entries provided!");const n=[],{app:i,devPort:s,devHostUri:p,publicIp:a}=await createDevServer(o),c=o.devServer?.mockOptions?.mockFilters||[];for(const[,e]of Object.entries(r))c.push(...e.options?.mockFilters||[]);await attachMockMiddlewares(i,{...o.devServer?.mockOptions,mockFilters:arrayUnique(c),projectCwd:e});let v=s;const m=[];for(const e of t){if(!verifyGroupEntryOptions(e,ignoreEntryOptionKeys,!0))throw new Error("The entry options in a group must be the same.");v++;const r=await createDevServerEntries(v,e,o);m.push(r)}const l=flatEntryMap(m);createAppPageRoute(e,i,p,l,o);const y=normalizePageProxy(o.devServer?.pageProxy||"/pages"),f=urlJoin(p,[y]);o.devServer?.autoOpen&&openPage(f);for(const r of m){const t=createDevServerCompilerTask(e,f,a,r,m,o);n.push(t)}return Promise.all(n).then((()=>i))};
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"@flatjs/common";import{attachMockMiddlewares}from"@flatjs/mock";import{createAppPageRoute}from"../dev-server/create-app-page-route.js";import{createDevServer}from"../dev-server/create-dev-server.js";import{normalizePageProxy}from"../helpers/normalize-page-proxy.js";import{openPage}from"../helpers/open-page.js";export const prepareStatic=async(e,r)=>{const{app:a,devHostUri:o}=await createDevServer(r);await attachMockMiddlewares(a,{...r.devServer?.mockOptions,projectCwd:e}),createAppPageRoute(e,a,o,{},r);const t=normalizePageProxy(r.devServer?.pageProxy||"/pages"),p=urlJoin(o,[t]);r.devServer?.autoOpen&&openPage(p),logger.info(`${"static page".padEnd(12," ")} ➩ ${chalk(["cyan"])(p)}`)};
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{isAbsolute,join}from"node:path";import{getDiffFiles,getCommitIdOfBranch}from"@armit/git";import{arraysIntersect,chalk,logger,requireResolve}from"@flatjs/common";import{traverseGraph}from"@flatjs/graph";import Listr from"listr";import{ignoreEntryOptionKeys,moduleName}from"../constants.js";import{filterActivedEntriesByEntryInputs,filterActivedEntriesByModule}from"../helpers/filter-actived-entries.js";import{getGitRoot}from"../helpers/get-git-root.js";import{getMaxProcessTasks}from"../helpers/get-max-process-tasks.js";import{jsonSerializer}from"../helpers/json-serializer.js";import{normalizeEvolveEntryMap}from"../helpers/normalize-entry-map.js";import{resolveEntryMapInputFiles}from"../helpers/resolve-entry-map-input-files.js";import{splitToEntryGroup}from"../helpers/split-to-entry-group.js";import{loadEvolveConfig}from"../load-config/load-evolve-config.js";import{createThreadWorker}from"./create-thread-worker.js";import{envVerify}from"./env-verify.js";export async function getBuildEntryFiles(e,r,t,i,o){const n=[],s=[];for(const e of t)r.includes(e)?n.push(e):s.push(e);if(o&&logger.info("Use custom graph traverse filter",moduleName),s.length){const t=await traverseGraph({input:s,projectCwd:e,treeNodeFilter:o||(()=>!0),lessImportOptions:{projectCwd:e,aliases:i}});if(!t)return n;logger.debug(`DependencyGraph:\n${JSON.stringify(t,null,2)}`);for(const e of s){const i=t[e]||[];arraysIntersect(i,r)&&n.push(e)}}return n}export async function dynamicCheckBuildEntryMap(e,r,t,i,o){const n={projectCwd:e,command:"build",resolve:requireResolve},s=await loadEvolveConfig(n,e,i,o);if(s.ci?.fixedBuildModules&&s.ci?.fixedBuildModules.length){logger.info("Use `fixedBuildModules` configuration to build...");return{buildEntries:filterActivedEntriesByModule(s.entryMap,s.ci?.fixedBuildModules),newEvolveOptions:s}}if(logger.info("Dynamicly checking code changed modules ..."),!r){const e=s.ci?.basedBranch||"origin/master";r=await getCommitIdOfBranch(e),logger.info(`Resolving base branch "${e}" commit hash "${r}" ...`)}let a=r?await getDiffFiles(r,t):[];const l=getGitRoot(e);if(!l)throw new Error(`No .git root (${e}) found`);if(a=a.map((e=>isAbsolute(e)?e:join(l,e))),logger.debug(`Diff files: \n${JSON.stringify(a,null,2)}`),!a.length)return logger.warn("It seems that there are no code files changed."),{buildEntries:{},newEvolveOptions:s};const p=await resolveEntryMapInputFiles(e,s.entryMap),c=await getBuildEntryFiles(e,a,p,s.webpack?.resolve?.alias,s.ci?.graphTreeNodeFilter);logger.debug(`To build entry files: \n${JSON.stringify(c,null,2)}`);return{buildEntries:await filterActivedEntriesByEntryInputs(e,s.entryMap,c),newEvolveOptions:s}}export const startDynamicBuild=async(e,r,t,i={},o)=>{const{buildEntries:n,newEvolveOptions:s}=await dynamicCheckBuildEntryMap(e,r,t,i,o);await envVerify(e,s);const a=normalizeEvolveEntryMap(n,s.entryMap),l=splitToEntryGroup(a,s,ignoreEntryOptionKeys,!1);if(!l.length)return logger.warn("No build entries provided!"),[];const p=l.map((e=>Object.values(e)?.[0]?.groupName)),{threads:c={}}=s,d=getMaxProcessTasks(l.length,c?.maxThreads);logger.info(`Start dynamic build with (${chalk(["magenta"])(String(d))}) workers:\n${JSON.stringify({buildEntriesGroup:p},null,2)}`);const f=createThreadWorker({...c,maxThreads:d}),u=new Listr([],{concurrent:d,exitOnError:!0}),g=[];for(const r of l){const t=Object.values(r)?.[0]?.groupName||"",n=Object.keys(r);u.add({title:`Build group ${t}: ${chalk(["magenta"])(`${JSON.stringify(n,null,2)}`)} ...`,task:async()=>{const r=await f.startBuildWorker({projectCwd:e,entryKeys:n,serializedEvolveOptions:jsonSerializer.stringify(i),configLoaderOptions:o});g.push(r)}})}if(u.tasks.length)try{await u.run()}catch(e){throw f.terminate(),e}return f.terminate(),g};
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"@flatjs/common";import{ignoreEntryOptionKeys}from"../constants.js";import{filterActivedEntriesByModule}from"../helpers/filter-actived-entries.js";import{jsonSerializer}from"../helpers/json-serializer.js";import{normalizeEvolveEntryMap}from"../helpers/normalize-entry-map.js";import{splitToEntryGroup}from"../helpers/split-to-entry-group.js";import{loadEvolveConfig}from"../load-config/load-evolve-config.js";import{prepareBuild}from"./prepare-build.js";export default async e=>{const{projectCwd:r,entryKeys:o,serializedEvolveOptions:i,configLoaderOptions:t}=e,n={projectCwd:r,command:"build",resolve:requireResolve},p=jsonSerializer.parse(i)||{},l=await loadEvolveConfig(n,r,p,t),s=o.map((e=>new RegExp(`^${e}$`))),a=filterActivedEntriesByModule(l.entryMap,s),m=normalizeEvolveEntryMap(a,l.entryMap),d=splitToEntryGroup(m,l,ignoreEntryOptionKeys,!1);return prepareBuild(d[0],l)};
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
+ };
@@ -1 +1,69 @@
1
- import{chalk,logger,requireResolve}from"@flatjs/common";import Listr from"listr";import{ignoreEntryOptionKeys}from"../constants.js";import{filterActivedEntriesByModule}from"../helpers/filter-actived-entries.js";import{getMaxProcessTasks}from"../helpers/get-max-process-tasks.js";import{jsonSerializer}from"../helpers/json-serializer.js";import{normalizeEvolveEntryMap}from"../helpers/normalize-entry-map.js";import{splitToEntryGroup}from"../helpers/split-to-entry-group.js";import{loadEvolveConfig}from"../load-config/load-evolve-config.js";import{createThreadWorker}from"./create-thread-worker.js";import{envVerify}from"./env-verify.js";export const startBuild=async(r,e,t={},o)=>{const i={projectCwd:r,command:"build",resolve:requireResolve},s=await loadEvolveConfig(i,r,t,o);await envVerify(r,s);const n=filterActivedEntriesByModule(s.entryMap,e),a=normalizeEvolveEntryMap(n,s.entryMap),l=splitToEntryGroup(a,s,ignoreEntryOptionKeys,!1);if(!l.length)return logger.warn("No build entries provided!"),[];const p=l.map((r=>Object.values(r)?.[0]?.groupName)),{threads:m={}}=s,c=getMaxProcessTasks(l.length,m?.maxThreads);logger.info(`Start standard build with (${chalk(["magenta"])(String(c))}) workers:\n${JSON.stringify({buildEntriesGroup:p},null,2)}`);const d=createThreadWorker({...m,maxThreads:c}),f=new Listr([],{concurrent:c,exitOnError:!0}),g=[];for(const e of l){const i=Object.values(e)?.[0]?.groupName||"",s=Object.keys(e);f.add({title:`Build group ${i}: ${chalk(["magenta"])(`${JSON.stringify(s,null,2)}`)} ...`,task:async()=>{const e=await d.startBuildWorker({projectCwd:r,entryKeys:s,serializedEvolveOptions:jsonSerializer.stringify(t),configLoaderOptions:o});g.push(e)}})}if(f.tasks.length)try{await f.run()}catch(r){throw d.terminate(),r}return d.terminate(),g};
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"webpack";import{loadWebpackConfig}from"../create-webpack/load-webpack-config.js";import{assertSingleCompiler}from"../helpers/assert-single-compiler.js";export const startGroupEntryBuild=async(r,e)=>{const n=await loadWebpackConfig("production",r,e),o=assertSingleCompiler(r,n,e,!1);return new Promise(((r,n)=>{webpack(o,((a,t)=>{if(a)return n(a);const s=t?.toJson();return s?.errors?.length?n(s.errors):e.rejectWarnings&&s?.warnings?.length?n(s.warnings):void r({name:o.name,warningStats:s?.warnings})}))}))};
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
+ };