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