@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.
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
+ };