@flatjs/evolve 2.1.0-next.3 → 2.1.0-next.5
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 +26 -1
- package/dist/create-webpack/create-externals.js +6 -1
- package/dist/create-webpack/create-optimization.js +41 -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 +77 -1
- package/dist/create-webpack/create-resolve.js +37 -1
- package/dist/create-webpack/create-rule-sets.js +19 -1
- package/dist/create-webpack/load-webpack-config.js +56 -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 +50 -1
- package/dist/create-webpack/rule-sets/rule-css.js +101 -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 +84 -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-tasks.js +52 -1
- package/dist/dev-server/create-dev-server-entries.js +27 -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 +42 -1
- package/dist/dev-server/middlewares/get-page-module-html.js +120 -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-only-single-entry-item.js +23 -1
- package/dist/helpers/chunk-entry-map.js +21 -1
- package/dist/helpers/enable-bundle-hashname-for-module.js +6 -1
- package/dist/helpers/filter-actived-entries.js +42 -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/index.js +17 -1
- package/dist/helpers/json-serializer.js +52 -1
- package/dist/helpers/merge-babel-options.js +45 -1
- package/dist/helpers/normalize-entry-map.js +38 -1
- package/dist/helpers/normalize-page-proxy.js +9 -1
- package/dist/helpers/normalize-resolve-alias.js +7 -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 +10 -1
- package/dist/helpers/split-to-multi-compiler.js +32 -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 +42 -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 +38 -1
- package/dist/main/prepare-serve.js +45 -1
- package/dist/main/prepare-static.js +30 -1
- package/dist/main/start-build-dynamic.js +157 -1
- package/dist/main/start-build-worker.js +46 -1
- package/dist/main/start-build.js +53 -1
- package/dist/main/start-one-entry-build.js +35 -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 +98 -1
- package/dist/plugins/multi-html/index.js +15 -1
- package/dist/plugins/multi-html/multi-html-cdn-plugin.js +84 -1
- package/dist/plugins/multi-html/multi-html-plugin.js +70 -1
- package/dist/plugins/ts-checker/index.d.ts +1 -0
- package/dist/plugins/ts-checker/index.js +1 -0
- package/dist/plugins/ts-checker/ts-checker-plugin.d.ts +4 -0
- package/dist/plugins/ts-checker/ts-checker-plugin.js +18 -0
- 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.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-webpack.js +1 -1
- package/package.json +5 -5
|
@@ -1 +1,32 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { join } from 'path';
|
|
2
|
+
import { mergeOptions } from '@flatjs/common';
|
|
3
|
+
import { devReactFastRefresh } from '../constants.js';
|
|
4
|
+
import { normalizeEvolveEntryName } from './normalize-entry-map.js';
|
|
5
|
+
/**
|
|
6
|
+
* Split the `webpack` to make sure that we have separated compiler process for each module
|
|
7
|
+
* @param webpackConfig `Omit<Configuration, 'entry'>` webpack final configuration
|
|
8
|
+
*/
|
|
9
|
+
export function splitToMultiCompilerConfigs(servedEntries, webpackConfig, evolveOptions, enabledHmr = false) {
|
|
10
|
+
const result = [];
|
|
11
|
+
for (const [entryName, entryItem] of Object.entries(servedEntries)) {
|
|
12
|
+
// Make sure that we have correct `virtualPath` for each webpack `entry`
|
|
13
|
+
const normalizedEntryName = normalizeEvolveEntryName(entryName, evolveOptions.projectVirtualPath);
|
|
14
|
+
result.push({
|
|
15
|
+
[normalizedEntryName]: entryItem.entry,
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
return result.map((newEntry) => {
|
|
19
|
+
const entryName = Object.keys(newEntry)[0];
|
|
20
|
+
if (enabledHmr) {
|
|
21
|
+
// `${virtualPath}/module/reactRefreshSetup`
|
|
22
|
+
const fastRefreshEntryName = join(entryName, devReactFastRefresh.reactRefreshSetup);
|
|
23
|
+
newEntry[fastRefreshEntryName] = [
|
|
24
|
+
'@pmmmwh/react-refresh-webpack-plugin/client/ReactRefreshEntry.js',
|
|
25
|
+
];
|
|
26
|
+
}
|
|
27
|
+
return mergeOptions(webpackConfig, {
|
|
28
|
+
name: entryName,
|
|
29
|
+
entry: newEntry,
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -1 +1,5 @@
|
|
|
1
|
-
export*from
|
|
1
|
+
export * from './define-config/index.js';
|
|
2
|
+
export * from './load-config/index.js';
|
|
3
|
+
export * from './main/index.js';
|
|
4
|
+
export * from './types/types-options.js';
|
|
5
|
+
export * from './types/types-entry-map.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export*from
|
|
1
|
+
export * from './load-evolve-config.js';
|
|
@@ -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,42 @@
|
|
|
1
|
-
import EventEmitter from
|
|
1
|
+
import EventEmitter from 'events';
|
|
2
|
+
import { createThreadPool, } from '@armit/worker-threads';
|
|
3
|
+
import { getWorkerPath } from './get-worker-path.js';
|
|
4
|
+
import { startBuildWorker } from './start-build-worker.js';
|
|
5
|
+
class ThreadPoolForUnittest {
|
|
6
|
+
constructor(workerSize) {
|
|
7
|
+
this.workerSize = workerSize;
|
|
8
|
+
}
|
|
9
|
+
startBuildWorker(...args) {
|
|
10
|
+
return startBuildWorker(...args);
|
|
11
|
+
}
|
|
12
|
+
get pool() {
|
|
13
|
+
const puddleInterface = new EventEmitter();
|
|
14
|
+
const pool = {
|
|
15
|
+
terminate() {
|
|
16
|
+
console.warn(`[WARNING] Using fake "terminate" for unittest!`);
|
|
17
|
+
},
|
|
18
|
+
refill() {
|
|
19
|
+
console.warn(`[WARNING] Using fake "refill" for unittest!`);
|
|
20
|
+
},
|
|
21
|
+
async drain() {
|
|
22
|
+
console.warn(`[WARNING] Using fake "drain" for unittest!`);
|
|
23
|
+
},
|
|
24
|
+
size: this.workerSize,
|
|
25
|
+
isTerminated: false,
|
|
26
|
+
threads: new Map(),
|
|
27
|
+
};
|
|
28
|
+
return Object.assign(puddleInterface, pool);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
export const createThreadWorker = async (workerSize) => {
|
|
32
|
+
const workerPath = getWorkerPath();
|
|
33
|
+
// FIXME: Is safe to remove `worker thread` while `test` environment, cause of we need to run UT using `source code`
|
|
34
|
+
const isTestEnv = process.env.NODE_ENV === 'test';
|
|
35
|
+
if (isTestEnv) {
|
|
36
|
+
console.warn(`[WARNING] Using fake thread pool worker for unittest!`);
|
|
37
|
+
return new ThreadPoolForUnittest(workerSize);
|
|
38
|
+
}
|
|
39
|
+
return await createThreadPool(workerPath, {
|
|
40
|
+
size: workerSize,
|
|
41
|
+
});
|
|
42
|
+
};
|
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,38 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { ensureSlash, mergeOptions } from '@flatjs/common';
|
|
2
|
+
import { EvolveBuildError } from '../errors/evolve-build-error.js';
|
|
3
|
+
import { printCompilerError } from '../helpers/print-log.js';
|
|
4
|
+
import { startOneEntryBuild, } from './start-one-entry-build.js';
|
|
5
|
+
/**
|
|
6
|
+
* The main entry to start an evolve `build`
|
|
7
|
+
* @param entryMapItem The `entryMapItem` for one entry build task
|
|
8
|
+
* @param evolveOptions FlatEvolveOptions
|
|
9
|
+
*/
|
|
10
|
+
export const prepareBuild = async (entryMapItem, evolveOptions) => {
|
|
11
|
+
const [entryKey, entryConfig] = entryMapItem;
|
|
12
|
+
// Fetch all configuration cdn
|
|
13
|
+
const cdnPath = evolveOptions.multiHtmlCdn?.prod || [];
|
|
14
|
+
if (!cdnPath.length) {
|
|
15
|
+
throw new Error(`No CDN config for env:"prod", moduleName: ${entryKey}`);
|
|
16
|
+
}
|
|
17
|
+
// Random choose one to publicPath
|
|
18
|
+
const cdnPublicPath = ensureSlash(cdnPath[Math.floor(Math.random() * cdnPath.length)], true);
|
|
19
|
+
// Construct single entry map item to build.
|
|
20
|
+
const toBuildEntryMapItem = {
|
|
21
|
+
[entryKey]: entryConfig,
|
|
22
|
+
};
|
|
23
|
+
try {
|
|
24
|
+
const useRelativeAssetPath = entryConfig.options?.useRelativeAssetPath;
|
|
25
|
+
const buildEvolveOptions = mergeOptions(evolveOptions, {
|
|
26
|
+
webpack: {
|
|
27
|
+
// Only for `assets` used at styling files (e.g.`xxx.less`)
|
|
28
|
+
publicPath: useRelativeAssetPath ? 'auto' : cdnPublicPath,
|
|
29
|
+
},
|
|
30
|
+
});
|
|
31
|
+
return await startOneEntryBuild(toBuildEntryMapItem, buildEvolveOptions);
|
|
32
|
+
}
|
|
33
|
+
catch (err) {
|
|
34
|
+
const formattedErrors = printCompilerError(err);
|
|
35
|
+
// Need re-throw error, in order to third API can capture this error.
|
|
36
|
+
throw new EvolveBuildError(`BUILD_ERROR`, formattedErrors);
|
|
37
|
+
}
|
|
38
|
+
};
|
|
@@ -1 +1,45 @@
|
|
|
1
|
-
import{arrayUnique,urlJoin}from
|
|
1
|
+
import { arrayUnique, urlJoin } from '@flatjs/common';
|
|
2
|
+
import { attachMockMiddlewares } from '@flatjs/mock';
|
|
3
|
+
import { createAppPageRoute, createDevServer, createDevServerCompilerTasks, createDevServerEntries, } from '../dev-server/index.js';
|
|
4
|
+
import { openPage } from '../helpers/index.js';
|
|
5
|
+
import { normalizePageProxy } from '../helpers/normalize-page-proxy.js';
|
|
6
|
+
import { envVerify } from './env-verify.js';
|
|
7
|
+
/**
|
|
8
|
+
* The main entry to start evolve serve
|
|
9
|
+
* @param projectCwd The Root directory (workspace) of this project.
|
|
10
|
+
* @param servedEntries All normalized webpack entries we have served.
|
|
11
|
+
* @param evolveOptions FlatEvolveOptions
|
|
12
|
+
*/
|
|
13
|
+
export const prepareServe = async (projectCwd, servedEntries, evolveOptions) => {
|
|
14
|
+
// Verify if we have an correct project local environment.
|
|
15
|
+
await envVerify(projectCwd, evolveOptions);
|
|
16
|
+
// Create pure dev server.
|
|
17
|
+
const { app, devPort, devHostUri, publicIp } = await createDevServer(evolveOptions);
|
|
18
|
+
// Extract all the mock filters of served entries.
|
|
19
|
+
const mockFilters = evolveOptions.devServer?.mockOptions?.mockFilters || [];
|
|
20
|
+
// Loop all entries gather all mock files definition from each entry item.
|
|
21
|
+
for (const [, value] of Object.entries(servedEntries)) {
|
|
22
|
+
mockFilters.push(...(value.options?.mockFilters || []));
|
|
23
|
+
}
|
|
24
|
+
// Attach core handlers for mock
|
|
25
|
+
await attachMockMiddlewares(app, {
|
|
26
|
+
...evolveOptions.devServer?.mockOptions,
|
|
27
|
+
mockFilters: arrayUnique(mockFilters),
|
|
28
|
+
projectCwd,
|
|
29
|
+
});
|
|
30
|
+
// Create dev-server configurationn for all servedEntries.
|
|
31
|
+
const servedDevServerEntries = await createDevServerEntries(devPort, servedEntries, evolveOptions);
|
|
32
|
+
// Create new route `/pages*`,`*` to pure dev server
|
|
33
|
+
createAppPageRoute(projectCwd, app, devHostUri, servedDevServerEntries, evolveOptions);
|
|
34
|
+
const pageProxy = normalizePageProxy(evolveOptions.devServer?.pageProxy || '/pages');
|
|
35
|
+
const mainPage = urlJoin(devHostUri, [pageProxy]);
|
|
36
|
+
// Open page via browser
|
|
37
|
+
if (evolveOptions.devServer?.autoOpen) {
|
|
38
|
+
openPage(mainPage);
|
|
39
|
+
}
|
|
40
|
+
// Create dev-server compiler tasks
|
|
41
|
+
const serveTasks = await createDevServerCompilerTasks(projectCwd, mainPage, publicIp, servedDevServerEntries, evolveOptions);
|
|
42
|
+
return Promise.all(serveTasks).then(() => {
|
|
43
|
+
return app;
|
|
44
|
+
});
|
|
45
|
+
};
|
|
@@ -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,157 @@
|
|
|
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 { 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 { resolveEntryMapInputFiles } from '../helpers/resolve-entry-map-input-files.js';
|
|
12
|
+
import { loadEvolveConfig } from '../load-config/load-evolve-config.js';
|
|
13
|
+
import { createThreadWorker } from './create-thread-worker.js';
|
|
14
|
+
import { envVerify } from './env-verify.js';
|
|
15
|
+
export async function getBuildEntryFiles(projectCwd, diffFiles, allEntryInputs, resolveAlias, graphTreeNodeFilter) {
|
|
16
|
+
const toBuildEntryFiles = [];
|
|
17
|
+
const entryInputsPendingToCheck = [];
|
|
18
|
+
for (const entryInput of allEntryInputs) {
|
|
19
|
+
// If entry have been existed in diff files, need to rebuild.
|
|
20
|
+
if (diffFiles.includes(entryInput)) {
|
|
21
|
+
toBuildEntryFiles.push(entryInput);
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
entryInputsPendingToCheck.push(entryInput);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
if (graphTreeNodeFilter) {
|
|
28
|
+
logger.info(`Use custom graph traverse filter`, moduleName);
|
|
29
|
+
}
|
|
30
|
+
// If there has pedding entry inputs to check.
|
|
31
|
+
if (entryInputsPendingToCheck.length) {
|
|
32
|
+
const graphDeps = await traverseGraph({
|
|
33
|
+
input: entryInputsPendingToCheck,
|
|
34
|
+
projectCwd,
|
|
35
|
+
treeNodeFilter: graphTreeNodeFilter || (() => true),
|
|
36
|
+
lessImportOptions: {
|
|
37
|
+
projectCwd,
|
|
38
|
+
aliases: resolveAlias,
|
|
39
|
+
},
|
|
40
|
+
});
|
|
41
|
+
if (!graphDeps) {
|
|
42
|
+
return toBuildEntryFiles;
|
|
43
|
+
}
|
|
44
|
+
logger.debug(`DependencyGraph:\n${JSON.stringify(graphDeps, null, 2)}`);
|
|
45
|
+
for (const entryInputToCheck of entryInputsPendingToCheck) {
|
|
46
|
+
const dependsFiles = graphDeps[entryInputToCheck] || [];
|
|
47
|
+
if (arraysIntersect(dependsFiles, diffFiles)) {
|
|
48
|
+
toBuildEntryFiles.push(entryInputToCheck);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return toBuildEntryFiles;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Dynamic check which entry modules need to build.
|
|
56
|
+
* @returns
|
|
57
|
+
*/
|
|
58
|
+
export async function dynamicCheckBuildEntryMap(projectCwd, earlyCommit, lastCommit, overrideEvolveOptions, configLoaderOptions) {
|
|
59
|
+
const command = {
|
|
60
|
+
projectCwd,
|
|
61
|
+
command: 'build',
|
|
62
|
+
resolve: requireResolve,
|
|
63
|
+
};
|
|
64
|
+
// 1. Try to load evolve configuration from `flatjs-evolve.config.ts`
|
|
65
|
+
const newEvolveOptions = await loadEvolveConfig(command, projectCwd, overrideEvolveOptions, configLoaderOptions);
|
|
66
|
+
// 2. Check if we have fixed build modules.
|
|
67
|
+
if (newEvolveOptions.ci?.fixedBuildModules &&
|
|
68
|
+
newEvolveOptions.ci?.fixedBuildModules.length) {
|
|
69
|
+
logger.info('Use `fixedBuildModules` configuration to build...');
|
|
70
|
+
const buildEntries = filterActivedEntriesByModule(newEvolveOptions.entryMap, newEvolveOptions.ci?.fixedBuildModules);
|
|
71
|
+
return { buildEntries, newEvolveOptions };
|
|
72
|
+
}
|
|
73
|
+
logger.info('Dynamicly checking code changed modules ...');
|
|
74
|
+
// 3. Resolve diff files based on specificed branch.
|
|
75
|
+
// Check if we have fixed `early commit` if no resolve based on `Branch` from evolve config file.
|
|
76
|
+
if (!earlyCommit) {
|
|
77
|
+
const basedBranch = newEvolveOptions.ci?.basedBranch || 'origin/master';
|
|
78
|
+
earlyCommit = await getCommitIdOfBranch(basedBranch);
|
|
79
|
+
// Try resolve based branch commit hash.
|
|
80
|
+
logger.info(`Resolving base branch "${basedBranch}" commit hash "${earlyCommit}" ...`);
|
|
81
|
+
}
|
|
82
|
+
// `packages/evolve/tests/main/fixtures/src/home/index.ts` without repo cwd.
|
|
83
|
+
let diffFiles = earlyCommit
|
|
84
|
+
? await getDiffFiles(earlyCommit, lastCommit)
|
|
85
|
+
: [];
|
|
86
|
+
const gitRoot = getGitRoot(projectCwd);
|
|
87
|
+
if (!gitRoot) {
|
|
88
|
+
throw new Error(`No .git root (${projectCwd}) found`);
|
|
89
|
+
}
|
|
90
|
+
// Hack diff files with git repo root dir.
|
|
91
|
+
diffFiles = diffFiles.map((diffFile) => {
|
|
92
|
+
return isAbsolute(diffFile) ? diffFile : join(gitRoot, diffFile);
|
|
93
|
+
});
|
|
94
|
+
logger.debug(`Diff files: \n${JSON.stringify(diffFiles, null, 2)}`);
|
|
95
|
+
// No code changed here.
|
|
96
|
+
if (!diffFiles.length) {
|
|
97
|
+
logger.warn('It seems that there are no code files changed.');
|
|
98
|
+
return {
|
|
99
|
+
buildEntries: {},
|
|
100
|
+
newEvolveOptions,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
// 4. Resolve entry input files.
|
|
104
|
+
const allEntryInputs = await resolveEntryMapInputFiles(projectCwd, newEvolveOptions.entryMap);
|
|
105
|
+
// 5. Flag changed entries (with absolute filepath)
|
|
106
|
+
const toBuildEntryFiles = await getBuildEntryFiles(projectCwd, diffFiles, allEntryInputs, newEvolveOptions.webpack?.resolve?.alias, newEvolveOptions.ci?.graphTreeNodeFilter);
|
|
107
|
+
logger.debug(`To build entry files: \n${JSON.stringify(toBuildEntryFiles, null, 2)}`);
|
|
108
|
+
// 6. Filter entry map items which need to build.
|
|
109
|
+
const buildEntries = await filterActivedEntriesByEntryInputs(projectCwd, newEvolveOptions.entryMap, toBuildEntryFiles);
|
|
110
|
+
return { buildEntries, newEvolveOptions };
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* The main entry to start an evolve `build` with automatically detect modules which have been changed between two commits.
|
|
114
|
+
* @param projectCwd The Root directory (workspace) of this project.
|
|
115
|
+
* @param earlyCommit The diff based earlier commit hash
|
|
116
|
+
* @param lastCommit If is omitted, it will have the same effect as using HEAD instead.
|
|
117
|
+
*/
|
|
118
|
+
export const startDynamicBuild = async (projectCwd, earlyCommit, lastCommit, overrideEvolveOptions = {}, configLoaderOptions) => {
|
|
119
|
+
// 1. Fetch all changed files betwwen two `commit`
|
|
120
|
+
const { buildEntries, newEvolveOptions } = await dynamicCheckBuildEntryMap(projectCwd, earlyCommit, lastCommit, overrideEvolveOptions, configLoaderOptions);
|
|
121
|
+
await envVerify(projectCwd, newEvolveOptions);
|
|
122
|
+
const buildEntryKeys = Object.keys(buildEntries);
|
|
123
|
+
// Make sure that we have at least one build entry module.
|
|
124
|
+
if (!buildEntryKeys.length) {
|
|
125
|
+
logger.warn(`No build entries providered!`);
|
|
126
|
+
return [];
|
|
127
|
+
}
|
|
128
|
+
const workerSize = getMaxProcessTasks(buildEntryKeys.length, newEvolveOptions.maxProcesses);
|
|
129
|
+
logger.info(`Start dynamic build with (${chalk(['magenta'])(String(workerSize))}) workers:\n${JSON.stringify({ buildEntries: buildEntryKeys }, null, 2)}`);
|
|
130
|
+
const worker = await createThreadWorker(workerSize);
|
|
131
|
+
const buildTasks = new Listr([], {
|
|
132
|
+
concurrent: workerSize,
|
|
133
|
+
exitOnError: true,
|
|
134
|
+
});
|
|
135
|
+
const buildResults = [];
|
|
136
|
+
for (const [entryKey] of Object.entries(buildEntries)) {
|
|
137
|
+
buildTasks.add({
|
|
138
|
+
title: `Build module ${chalk(['magenta'])(entryKey)} ...`,
|
|
139
|
+
task: async () => {
|
|
140
|
+
const buildResult = await worker.startBuildWorker(projectCwd, entryKey, jsonSerializer.stringify(overrideEvolveOptions), configLoaderOptions);
|
|
141
|
+
buildResults.push(buildResult);
|
|
142
|
+
},
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
if (buildTasks.tasks.length) {
|
|
146
|
+
try {
|
|
147
|
+
await buildTasks.run();
|
|
148
|
+
}
|
|
149
|
+
catch (err) {
|
|
150
|
+
worker.pool.terminate();
|
|
151
|
+
// we need to catch the error here, makesure the `worker` can be terminated.
|
|
152
|
+
throw err;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
worker.pool.terminate();
|
|
156
|
+
return buildResults;
|
|
157
|
+
};
|
|
@@ -1 +1,46 @@
|
|
|
1
|
-
import{requireResolve}from
|
|
1
|
+
import { requireResolve } from '@flatjs/common';
|
|
2
|
+
import { filterActivedEntriesByModule } from '../helpers/filter-actived-entries.js';
|
|
3
|
+
import { jsonSerializer } from '../helpers/json-serializer.js';
|
|
4
|
+
import { normalizeEvolveEntryMap } from '../helpers/normalize-entry-map.js';
|
|
5
|
+
import { loadEvolveConfig } from '../load-config/load-evolve-config.js';
|
|
6
|
+
import { prepareBuild } from './prepare-build.js';
|
|
7
|
+
/**
|
|
8
|
+
* FIXME: The main entry to start an evolve `build`, NOTE: avoid pass configuration with `function` here.
|
|
9
|
+
* If you need to call build api avoid `worker` you can directly call `prepareBuild`
|
|
10
|
+
* @internal
|
|
11
|
+
* @param projectCwd The Root directory (workspace) of this project.
|
|
12
|
+
* @param entryKey The `entryKey` for one entry build task
|
|
13
|
+
* @param serializedEvolveOptions The overrided evolve options, NOTE: we will serialize `function` property here first
|
|
14
|
+
* @param configLoaderOptions Evolve config loader options, NOTE: avoid pass configuration with `function` here.
|
|
15
|
+
*/
|
|
16
|
+
export const startBuildWorker = async (projectCwd, entryKey, serializedEvolveOptions, configLoaderOptions) => {
|
|
17
|
+
const command = {
|
|
18
|
+
projectCwd,
|
|
19
|
+
command: 'build',
|
|
20
|
+
resolve: requireResolve,
|
|
21
|
+
};
|
|
22
|
+
const overrideEvolveOptions = jsonSerializer.parse(serializedEvolveOptions) || {};
|
|
23
|
+
// Try to load evolve configuration from `flatjs-evolve.config.ts`
|
|
24
|
+
// FIXME: Cause of `worker-theads` do not support pass configuration with `function` reference.
|
|
25
|
+
const newEvolveOptions = await loadEvolveConfig(command, projectCwd, overrideEvolveOptions, configLoaderOptions);
|
|
26
|
+
// FIXME: Cause of `worker threads` we need avoid pass entryItem config directly
|
|
27
|
+
// because we have some config node item with `function`
|
|
28
|
+
// It will break `worker threads` comunication, e.g below shown.
|
|
29
|
+
// DataCloneError: function (url) {
|
|
30
|
+
// if (url.indexOf('dev.flatjs.com') > 0) return 'me';
|
|
31
|
+
// if (url.indexOf('.qa.') > 0) retur...<omitted>... } could not be cloned.
|
|
32
|
+
// at new DOMException (node:internal/per_context/domexception:53:5)
|
|
33
|
+
// So we need to re cacalculate the build entry via `entryKey`
|
|
34
|
+
const buildOneEntry = filterActivedEntriesByModule(newEvolveOptions.entryMap, [
|
|
35
|
+
// Make sure that the entryKey is correct match.
|
|
36
|
+
new RegExp(`^${entryKey}$`),
|
|
37
|
+
]);
|
|
38
|
+
const buildEntryKeys = Object.keys(buildOneEntry);
|
|
39
|
+
// Make sure that we have at least one build entry module.
|
|
40
|
+
if (!buildEntryKeys.length) {
|
|
41
|
+
throw new Error(`No build entry resolved via "${entryKey}" on "startBuildWorker"!`);
|
|
42
|
+
}
|
|
43
|
+
const normalizedBuildOneEntry = normalizeEvolveEntryMap(buildOneEntry, newEvolveOptions.entryMap);
|
|
44
|
+
const buildEntryConfig = normalizedBuildOneEntry[entryKey];
|
|
45
|
+
return prepareBuild([entryKey, buildEntryConfig], newEvolveOptions);
|
|
46
|
+
};
|
package/dist/main/start-build.js
CHANGED
|
@@ -1 +1,53 @@
|
|
|
1
|
-
import{chalk,logger,requireResolve}from
|
|
1
|
+
import { chalk, logger, requireResolve } from '@flatjs/common';
|
|
2
|
+
import Listr from 'listr';
|
|
3
|
+
import { filterActivedEntriesByModule } from '../helpers/filter-actived-entries.js';
|
|
4
|
+
import { getMaxProcessTasks } from '../helpers/get-max-process-tasks.js';
|
|
5
|
+
import { jsonSerializer } from '../helpers/json-serializer.js';
|
|
6
|
+
import { loadEvolveConfig } from '../load-config/load-evolve-config.js';
|
|
7
|
+
import { createThreadWorker } from './create-thread-worker.js';
|
|
8
|
+
import { envVerify } from './env-verify.js';
|
|
9
|
+
export const startBuild = async (projectCwd, buildModules, overrideEvolveOptions = {}, configLoaderOptions) => {
|
|
10
|
+
const command = {
|
|
11
|
+
projectCwd,
|
|
12
|
+
command: 'build',
|
|
13
|
+
resolve: requireResolve,
|
|
14
|
+
};
|
|
15
|
+
// Try to load evolve configuration from `flatjs-evolve.config.ts`
|
|
16
|
+
const newEvolveOptions = await loadEvolveConfig(command, projectCwd, overrideEvolveOptions, configLoaderOptions);
|
|
17
|
+
await envVerify(projectCwd, newEvolveOptions);
|
|
18
|
+
const buildEntries = filterActivedEntriesByModule(newEvolveOptions.entryMap, buildModules);
|
|
19
|
+
const buildEntryKeys = Object.keys(buildEntries);
|
|
20
|
+
// Make sure that we have at least one build entry module.
|
|
21
|
+
if (!buildEntryKeys.length) {
|
|
22
|
+
logger.warn(`No build entries providered!`);
|
|
23
|
+
return [];
|
|
24
|
+
}
|
|
25
|
+
const workerSize = getMaxProcessTasks(buildEntryKeys.length, newEvolveOptions.maxProcesses);
|
|
26
|
+
logger.info(`Start standard build with (${chalk(['magenta'])(String(workerSize))}) workers:\n${JSON.stringify({ buildEntries: buildEntryKeys }, null, 2)}`);
|
|
27
|
+
const worker = await createThreadWorker(workerSize);
|
|
28
|
+
const buildTasks = new Listr([], {
|
|
29
|
+
concurrent: workerSize,
|
|
30
|
+
exitOnError: true,
|
|
31
|
+
});
|
|
32
|
+
const buildResults = [];
|
|
33
|
+
for (const [entryKey] of Object.entries(buildEntries)) {
|
|
34
|
+
buildTasks.add({
|
|
35
|
+
title: `Build module ${chalk(['magenta'])(entryKey)} ...`,
|
|
36
|
+
task: async () => {
|
|
37
|
+
const buildResult = await worker.startBuildWorker(projectCwd, entryKey, jsonSerializer.stringify(overrideEvolveOptions), configLoaderOptions);
|
|
38
|
+
buildResults.push(buildResult);
|
|
39
|
+
},
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
if (buildTasks.tasks.length) {
|
|
43
|
+
try {
|
|
44
|
+
await buildTasks.run();
|
|
45
|
+
}
|
|
46
|
+
catch (err) {
|
|
47
|
+
worker.pool.terminate();
|
|
48
|
+
// we need to catch the error here, makesure the `worker` can be terminated.
|
|
49
|
+
throw err;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return buildResults;
|
|
53
|
+
};
|
|
@@ -1 +1,35 @@
|
|
|
1
|
-
import webpack from
|
|
1
|
+
import webpack from 'webpack';
|
|
2
|
+
import { loadWebpackConfig } from '../create-webpack/load-webpack-config.js';
|
|
3
|
+
import { splitToMultiCompilerConfigs } from '../helpers/split-to-multi-compiler.js';
|
|
4
|
+
/**
|
|
5
|
+
* The helpers to build one entry at a time
|
|
6
|
+
* @param singleBuildEntry The single entry
|
|
7
|
+
* @param buildPublicPath
|
|
8
|
+
* @param evolveOptions
|
|
9
|
+
*/
|
|
10
|
+
export const startOneEntryBuild = async (singleBuildEntry, evolveOptions) => {
|
|
11
|
+
// Try to load webpack configuration
|
|
12
|
+
const webpackConfig = await loadWebpackConfig('production', singleBuildEntry, evolveOptions);
|
|
13
|
+
const compilerConfigs = splitToMultiCompilerConfigs(singleBuildEntry, webpackConfig, evolveOptions, false);
|
|
14
|
+
if (compilerConfigs.length > 1) {
|
|
15
|
+
throw new Error('startOneEntryBuild() only support `compiler` at a time');
|
|
16
|
+
}
|
|
17
|
+
const currCompiler = compilerConfigs[0];
|
|
18
|
+
// Run the single build.
|
|
19
|
+
return new Promise((resolve, reject) => {
|
|
20
|
+
webpack(currCompiler, (err, stats) => {
|
|
21
|
+
if (err) {
|
|
22
|
+
// Handle errors here
|
|
23
|
+
return reject(err);
|
|
24
|
+
}
|
|
25
|
+
const statsJson = stats?.toJson();
|
|
26
|
+
if (statsJson?.errors?.length) {
|
|
27
|
+
return reject(statsJson.errors);
|
|
28
|
+
}
|
|
29
|
+
if (evolveOptions.rejectWarnings && statsJson?.warnings?.length) {
|
|
30
|
+
return reject(statsJson.warnings);
|
|
31
|
+
}
|
|
32
|
+
resolve({ name: currCompiler.name, warningStats: statsJson?.warnings });
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
};
|