@flatjs/evolve 1.8.1-next.66 → 1.8.1-next.68

Sign up to get free protection for your applications and to get access to all the features.
Files changed (114) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/dist/constants.js +17 -1
  3. package/dist/create-webpack/create-externals.js +6 -1
  4. package/dist/create-webpack/create-optimization.js +29 -1
  5. package/dist/create-webpack/create-output.js +35 -1
  6. package/dist/create-webpack/create-performance.js +7 -1
  7. package/dist/create-webpack/create-plugins.js +78 -1
  8. package/dist/create-webpack/create-resolve.js +31 -1
  9. package/dist/create-webpack/create-rule-sets.js +16 -1
  10. package/dist/create-webpack/load-webpack-config.js +55 -1
  11. package/dist/create-webpack/rule-sets/constants.js +3 -1
  12. package/dist/create-webpack/rule-sets/rule-assets.js +44 -1
  13. package/dist/create-webpack/rule-sets/rule-css.js +84 -1
  14. package/dist/create-webpack/rule-sets/rule-less.js +45 -1
  15. package/dist/create-webpack/rule-sets/rule-scripts.js +27 -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 +79 -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 +47 -1
  23. package/dist/dev-server/create-app-page-route.js +11 -1
  24. package/dist/dev-server/create-dev-server-compiler-tasks.js +51 -1
  25. package/dist/dev-server/create-dev-server-entries.js +27 -1
  26. package/dist/dev-server/create-dev-server.js +23 -1
  27. package/dist/dev-server/index.js +6 -1
  28. package/dist/dev-server/middlewares/create-page-middleware.js +164 -1
  29. package/dist/dev-server/middlewares/create-public-assets-middleware.js +25 -1
  30. package/dist/dev-server/middlewares/index.js +2 -1
  31. package/dist/errors/evolve-build-error.js +10 -1
  32. package/dist/helpers/allow-px2rem-for-module.js +6 -1
  33. package/dist/helpers/assert-only-single-entry-item.js +23 -1
  34. package/dist/helpers/chunk-entry-map.js +21 -1
  35. package/dist/helpers/enable-bundle-hashname-for-module.js +6 -1
  36. package/dist/helpers/filter-actived-entries.d.ts +1 -1
  37. package/dist/helpers/filter-actived-entries.js +41 -1
  38. package/dist/helpers/get-bundle-file-name.js +23 -1
  39. package/dist/helpers/get-git-root.js +4 -1
  40. package/dist/helpers/get-html-plugin-config.d.ts +9 -1
  41. package/dist/helpers/get-html-plugin-config.js +47 -1
  42. package/dist/helpers/get-max-process-tasks.d.ts +1 -0
  43. package/dist/helpers/get-max-process-tasks.js +7 -0
  44. package/dist/helpers/get-pacakge-dir.js +13 -1
  45. package/dist/helpers/index.js +15 -1
  46. package/dist/helpers/merge-babel-options.js +45 -1
  47. package/dist/helpers/normalize-entry-map.js +38 -1
  48. package/dist/helpers/open-page.js +15 -1
  49. package/dist/helpers/print-log.js +49 -1
  50. package/dist/helpers/refresh-evolve-mock-options.js +23 -1
  51. package/dist/helpers/resolve-entry-map-input-files.js +20 -1
  52. package/dist/helpers/script-injects.js +39 -1
  53. package/dist/helpers/should-enable-react-fast-refresh.js +8 -1
  54. package/dist/helpers/split-to-multi-compiler.js +22 -1
  55. package/dist/index.js +5 -1
  56. package/dist/load-config/index.js +1 -1
  57. package/dist/load-config/load-evolve-config.js +35 -1
  58. package/dist/main/env-verify.js +21 -1
  59. package/dist/main/index.js +4 -1
  60. package/dist/main/prepare-build.d.ts +4 -8
  61. package/dist/main/prepare-build.js +38 -1
  62. package/dist/main/prepare-serve.js +36 -1
  63. package/dist/main/prepare-static.js +28 -1
  64. package/dist/main/start-build-dynamic.d.ts +2 -1
  65. package/dist/main/start-build-dynamic.js +144 -1
  66. package/dist/main/start-build-worker.d.ts +14 -0
  67. package/dist/main/start-build-worker.js +41 -0
  68. package/dist/main/start-build.d.ts +1 -8
  69. package/dist/main/start-build.js +49 -1
  70. package/dist/main/start-one-entry-build.d.ts +13 -0
  71. package/dist/main/start-one-entry-build.js +35 -0
  72. package/dist/main/start-serve.js +32 -1
  73. package/dist/main/start-static.js +16 -1
  74. package/dist/minimizer/create-minimizers.js +25 -1
  75. package/dist/minimizer/default-options.js +14 -1
  76. package/dist/minimizer/image-minimizer.js +56 -1
  77. package/dist/minimizer/index.js +1 -1
  78. package/dist/minimizer/terser-minimizer.js +15 -3
  79. package/dist/minimizer/types.js +1 -1
  80. package/dist/plugins/clean-webpack/clean-webpack-plugin.js +173 -1
  81. package/dist/plugins/clean-webpack/index.js +22 -1
  82. package/dist/plugins/define-variable/define-variable-plugin.js +21 -1
  83. package/dist/plugins/define-variable/index.js +1 -1
  84. package/dist/plugins/html-inject-scripts/plugin-html-inject-script.js +27 -1
  85. package/dist/plugins/module-federation/external-template-remotes.js +92 -1
  86. package/dist/plugins/module-federation/index.js +1 -1
  87. package/dist/plugins/module-federation/module-federation.js +98 -1
  88. package/dist/plugins/multi-html/index.js +15 -1
  89. package/dist/plugins/multi-html/multi-html-cdn-plugin.js +84 -1
  90. package/dist/plugins/multi-html/multi-html-plugin.js +70 -1
  91. package/dist/types/index.js +8 -1
  92. package/dist/types/types-ci.js +1 -1
  93. package/dist/types/types-dev-server.js +1 -1
  94. package/dist/types/types-entry-map.js +1 -1
  95. package/dist/types/types-federation.js +1 -1
  96. package/dist/types/types-loader-options.js +1 -1
  97. package/dist/types/types-modular-import.js +1 -1
  98. package/dist/types/types-multi-html.d.ts +6 -5
  99. package/dist/types/types-multi-html.js +1 -1
  100. package/dist/types/types-options.js +1 -1
  101. package/dist/types/types-plugin-options.js +1 -1
  102. package/dist/types/types-webpack.d.ts +1 -1
  103. package/dist/types/types-webpack.js +1 -1
  104. package/package.json +14 -12
  105. package/templates/html-plugin/index-dev.html +31 -38
  106. package/templates/html-plugin/index-inte.html +31 -38
  107. package/templates/html-plugin/index-inte2.html +31 -38
  108. package/templates/html-plugin/index-inte3.html +31 -38
  109. package/templates/html-plugin/index-inte4.html +31 -38
  110. package/templates/html-plugin/index-me.html +31 -38
  111. package/templates/html-plugin/index-prod.html +31 -38
  112. package/templates/html-plugin/index-rc.html +31 -38
  113. package/templates/html-plugin/index-uat.html +31 -38
  114. package/templates/module.html +40 -55
@@ -1,6 +1,7 @@
1
1
  import { type PartialDeep } from 'type-fest';
2
2
  import { type ConfigLoaderOptions } from '../load-config/load-evolve-config.js';
3
3
  import { type FlatEvolveOptions } from '../types/types-options.js';
4
+ import { type EvolveBuildResult } from './start-one-entry-build.js';
4
5
  export declare function getBuildEntryFiles(projectCwd: string, diffFiles: string[], allEntryInputs: string[]): Promise<string[]>;
5
6
  /**
6
7
  * Dynamic check which entry modules need to build.
@@ -16,4 +17,4 @@ export declare function dynamicCheckBuildEntryMap(projectCwd: string, earlyCommi
16
17
  * @param earlyCommit The diff based earlier commit hash
17
18
  * @param lastCommit If is omitted, it will have the same effect as using HEAD instead.
18
19
  */
19
- export declare const startDynamicBuild: (projectCwd: string, earlyCommit?: string, lastCommit?: string, overrideEvolveOptions?: PartialDeep<FlatEvolveOptions>, configLoaderOptions?: ConfigLoaderOptions) => Promise<import("./prepare-build.js").EvolveBuildResult[]>;
20
+ export declare const startDynamicBuild: (projectCwd: string, earlyCommit?: string, lastCommit?: string, overrideEvolveOptions?: PartialDeep<FlatEvolveOptions>, configLoaderOptions?: ConfigLoaderOptions) => Promise<EvolveBuildResult[]>;
@@ -1 +1,144 @@
1
- import{isAbsolute,join}from"node:path";import{getDiffFiles,getCommitIdOfBranch}from"@armit/git";import{arraysIntersect,logger}from"@flatjs/common";import{traverseGraph}from"@flatjs/graph";import{filterActivedEntriesByEntryInputs,filterActivedEntriesByModule}from"../helpers/filter-actived-entries.js";import{getGitRoot}from"../helpers/get-git-root.js";import{normalizeEvolveEntryMap}from"../helpers/normalize-entry-map.js";import{resolveEntryMapInputFiles}from"../helpers/resolve-entry-map-input-files.js";import{loadEvolveConfig}from"../load-config/load-evolve-config.js";import{prepareBuild}from"./prepare-build.js";export async function getBuildEntryFiles(e,t,i){const r=[],n=[];for(const e of i)t.includes(e)?r.push(e):n.push(e);if(n.length){const i=await traverseGraph({input:n,projectCwd:e,treeNodeFilter:()=>!0});if(!i)return r;logger.debug(`DependencyGraph:\n${JSON.stringify(i,null,2)}`);for(const e of n){const n=i[e]||[];arraysIntersect(n,t)&&r.push(e)}}return r}export async function dynamicCheckBuildEntryMap(e,t,i,r,n){const o=await loadEvolveConfig({command:"build"},e,r,n);if(o.ci?.fixedBuildModules&&o.ci?.fixedBuildModules.length){logger.info("Use `fixedBuildModules` configuration to build...");return{buildEntries:filterActivedEntriesByModule(o.entryMap,o.ci?.fixedBuildModules),newEvolveOptions:o}}if(logger.info("Dynamicly checking code changed modules ..."),!t){const e=o.ci?.basedBranch||"master";logger.info(`Resolving base branch "${e}" commit hash ...`),t=await getCommitIdOfBranch(e)}let l=t?await getDiffFiles(t,i):[];const s=getGitRoot(e);if(!s)throw new Error(`No .git root (${e}) found`);if(l=l.map((e=>isAbsolute(e)?e:join(s,e))),logger.debug(`Diff files: \n${JSON.stringify(l,null,2)}`),!l.length)return logger.warn("It seems that there are no code files changed."),{buildEntries:{},newEvolveOptions:o};const a=await resolveEntryMapInputFiles(e,o.entryMap),d=await getBuildEntryFiles(e,l,a);logger.debug(`To build entry files: \n${JSON.stringify(d,null,2)}`);return{buildEntries:await filterActivedEntriesByEntryInputs(e,o.entryMap,d),newEvolveOptions:o}}export const startDynamicBuild=async(e,t,i,r={},n)=>{const{buildEntries:o,newEvolveOptions:l}=await dynamicCheckBuildEntryMap(e,t,i,r,n),s=Object.keys(o);if(!s.length)return logger.warn("No build entries providered!"),[];logger.info(`Start dynamic build:\n${JSON.stringify({buildEntries:s},null,2)}`);const a=normalizeEvolveEntryMap(o,l.entryMap);return prepareBuild(e,a,l)};
1
+ import { isAbsolute, join } from 'node:path';
2
+ import { pathToFileURL } from 'node:url';
3
+ import { getDirname } from '@armit/file-utility';
4
+ import { getDiffFiles, getCommitIdOfBranch } from '@armit/git';
5
+ import { createThreadPool } from '@armit/worker-threads';
6
+ import { arraysIntersect, chalk, logger } from '@flatjs/common';
7
+ import { traverseGraph } from '@flatjs/graph';
8
+ import Listr from 'listr';
9
+ import { filterActivedEntriesByEntryInputs, filterActivedEntriesByModule, } from '../helpers/filter-actived-entries.js';
10
+ import { getGitRoot } from '../helpers/get-git-root.js';
11
+ import { getMaxProcessTasks } from '../helpers/get-max-process-tasks.js';
12
+ import { resolveEntryMapInputFiles } from '../helpers/resolve-entry-map-input-files.js';
13
+ import { loadEvolveConfig, } from '../load-config/load-evolve-config.js';
14
+ import { envVerify } from './env-verify.js';
15
+ export async function getBuildEntryFiles(projectCwd, diffFiles, allEntryInputs) {
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 there has pedding entry inputs to check.
28
+ if (entryInputsPendingToCheck.length) {
29
+ const graphDeps = await traverseGraph({
30
+ input: entryInputsPendingToCheck,
31
+ projectCwd,
32
+ treeNodeFilter: () => true,
33
+ });
34
+ if (!graphDeps) {
35
+ return toBuildEntryFiles;
36
+ }
37
+ logger.debug(`DependencyGraph:\n${JSON.stringify(graphDeps, null, 2)}`);
38
+ for (const entryInputToCheck of entryInputsPendingToCheck) {
39
+ const dependsFiles = graphDeps[entryInputToCheck] || [];
40
+ if (arraysIntersect(dependsFiles, diffFiles)) {
41
+ toBuildEntryFiles.push(entryInputToCheck);
42
+ }
43
+ }
44
+ }
45
+ return toBuildEntryFiles;
46
+ }
47
+ /**
48
+ * Dynamic check which entry modules need to build.
49
+ * @returns
50
+ */
51
+ export async function dynamicCheckBuildEntryMap(projectCwd, earlyCommit, lastCommit, overrideEvolveOptions, configLoaderOptions) {
52
+ const command = {
53
+ command: 'build',
54
+ };
55
+ // 1. Try to load evolve configuration from `flatjs-evolve.config.ts`
56
+ const newEvolveOptions = await loadEvolveConfig(command, projectCwd, overrideEvolveOptions, configLoaderOptions);
57
+ // 2. Check if we have fixed build modules.
58
+ if (newEvolveOptions.ci?.fixedBuildModules &&
59
+ newEvolveOptions.ci?.fixedBuildModules.length) {
60
+ logger.info('Use `fixedBuildModules` configuration to build...');
61
+ const buildEntries = filterActivedEntriesByModule(newEvolveOptions.entryMap, newEvolveOptions.ci?.fixedBuildModules);
62
+ return { buildEntries, newEvolveOptions };
63
+ }
64
+ logger.info('Dynamicly checking code changed modules ...');
65
+ // 3. Resolve diff files based on specificed branch.
66
+ // Check if we have fixed `early commit` if no resolve based on `Branch` from evolve config file.
67
+ if (!earlyCommit) {
68
+ const basedBranch = newEvolveOptions.ci?.basedBranch || 'master';
69
+ // Try resolve based branch commit hash.
70
+ logger.info(`Resolving base branch "${basedBranch}" commit hash ...`);
71
+ earlyCommit = await getCommitIdOfBranch(basedBranch);
72
+ }
73
+ // `packages/evolve/tests/main/fixtures/src/home/index.ts` without repo cwd.
74
+ let diffFiles = earlyCommit
75
+ ? await getDiffFiles(earlyCommit, lastCommit)
76
+ : [];
77
+ const gitRoot = getGitRoot(projectCwd);
78
+ if (!gitRoot) {
79
+ throw new Error(`No .git root (${projectCwd}) found`);
80
+ }
81
+ // Hack diff files with git repo root dir.
82
+ diffFiles = diffFiles.map((diffFile) => {
83
+ return isAbsolute(diffFile) ? diffFile : join(gitRoot, diffFile);
84
+ });
85
+ logger.debug(`Diff files: \n${JSON.stringify(diffFiles, null, 2)}`);
86
+ // No code changed here.
87
+ if (!diffFiles.length) {
88
+ logger.warn('It seems that there are no code files changed.');
89
+ return {
90
+ buildEntries: {},
91
+ newEvolveOptions,
92
+ };
93
+ }
94
+ // 4. Resolve entry input files.
95
+ const allEntryInputs = await resolveEntryMapInputFiles(projectCwd, newEvolveOptions.entryMap);
96
+ // 5. Flag changed entries (with absolute filepath)
97
+ const toBuildEntryFiles = await getBuildEntryFiles(projectCwd, diffFiles, allEntryInputs);
98
+ logger.debug(`To build entry files: \n${JSON.stringify(toBuildEntryFiles, null, 2)}`);
99
+ // 6. Filter entry map items which need to build.
100
+ const buildEntries = await filterActivedEntriesByEntryInputs(projectCwd, newEvolveOptions.entryMap, toBuildEntryFiles);
101
+ return { buildEntries, newEvolveOptions };
102
+ }
103
+ /**
104
+ * The main entry to start an evolve `build` with automatically detect modules which have been changed between two commits.
105
+ * @param projectCwd The Root directory (workspace) of this project.
106
+ * @param earlyCommit The diff based earlier commit hash
107
+ * @param lastCommit If is omitted, it will have the same effect as using HEAD instead.
108
+ */
109
+ export const startDynamicBuild = async (projectCwd, earlyCommit, lastCommit, overrideEvolveOptions = {}, configLoaderOptions) => {
110
+ // 1. Fetch all changed files betwwen two `commit`
111
+ const { buildEntries, newEvolveOptions } = await dynamicCheckBuildEntryMap(projectCwd, earlyCommit, lastCommit, overrideEvolveOptions, configLoaderOptions);
112
+ await envVerify(projectCwd, newEvolveOptions);
113
+ const buildEntryKeys = Object.keys(buildEntries);
114
+ // Make sure that we have at least one build entry module.
115
+ if (!buildEntryKeys.length) {
116
+ logger.warn(`No build entries providered!`);
117
+ return [];
118
+ }
119
+ logger.info(`Start dynamic build:\n${JSON.stringify({ buildEntries: buildEntryKeys }, null, 2)}`);
120
+ const workerSize = getMaxProcessTasks(buildEntryKeys.length, newEvolveOptions.maxProcesses);
121
+ const workerPath = pathToFileURL(getDirname(import.meta.url, './start-build-worker.js')).toString();
122
+ const worker = await createThreadPool(workerPath, {
123
+ size: workerSize,
124
+ });
125
+ const buildTasks = new Listr([], {
126
+ concurrent: workerSize,
127
+ exitOnError: true,
128
+ });
129
+ const buildResults = [];
130
+ for (const [entryKey] of Object.entries(buildEntries)) {
131
+ buildTasks.add({
132
+ title: `Build module ${chalk(['magenta'])(entryKey)} ...`,
133
+ task: async () => {
134
+ const buildResult = await worker.startBuildWorker(projectCwd, entryKey, overrideEvolveOptions, configLoaderOptions);
135
+ buildResults.push(buildResult);
136
+ },
137
+ });
138
+ }
139
+ if (buildTasks.tasks.length) {
140
+ await buildTasks.run();
141
+ }
142
+ worker.pool.terminate();
143
+ return buildResults;
144
+ };
@@ -0,0 +1,14 @@
1
+ import { type PartialDeep } from 'type-fest';
2
+ import { type ConfigLoaderOptions } from '../load-config/load-evolve-config.js';
3
+ import { type FlatEvolveOptions } from '../types/types-options.js';
4
+ import { type EvolveBuildResult } from './start-one-entry-build.js';
5
+ /**
6
+ * FIXME: The main entry to start an evolve `build`, NOTE: avoid pass configuration with `function` here.
7
+ * If you need to call build api avoid `worker` you can directly call `prepareBuild`
8
+ * @internal
9
+ * @param projectCwd The Root directory (workspace) of this project.
10
+ * @param entryKey The `entryKey` for one entry build task
11
+ * @param overrideEvolveOptions The overrided evolve options, NOTE: avoid pass configuration with `function` here.
12
+ * @param configLoaderOptions Evolve config loader options, NOTE: avoid pass configuration with `function` here.
13
+ */
14
+ export declare const startBuildWorker: (projectCwd: string, entryKey: string, overrideEvolveOptions?: PartialDeep<FlatEvolveOptions>, configLoaderOptions?: ConfigLoaderOptions) => Promise<EvolveBuildResult>;
@@ -0,0 +1,41 @@
1
+ import { filterActivedEntriesByModule } from '../helpers/filter-actived-entries.js';
2
+ import { normalizeEvolveEntryMap } from '../helpers/normalize-entry-map.js';
3
+ import { loadEvolveConfig, } from '../load-config/load-evolve-config.js';
4
+ import { prepareBuild } from './prepare-build.js';
5
+ /**
6
+ * FIXME: The main entry to start an evolve `build`, NOTE: avoid pass configuration with `function` here.
7
+ * If you need to call build api avoid `worker` you can directly call `prepareBuild`
8
+ * @internal
9
+ * @param projectCwd The Root directory (workspace) of this project.
10
+ * @param entryKey The `entryKey` for one entry build task
11
+ * @param overrideEvolveOptions The overrided evolve options, NOTE: avoid pass configuration with `function` here.
12
+ * @param configLoaderOptions Evolve config loader options, NOTE: avoid pass configuration with `function` here.
13
+ */
14
+ export const startBuildWorker = async (projectCwd, entryKey, overrideEvolveOptions = {}, configLoaderOptions) => {
15
+ const command = {
16
+ command: 'build',
17
+ };
18
+ // Try to load evolve configuration from `flatjs-evolve.config.ts`
19
+ // FIXME: Cause of `worker-theads` do not support pass configuration with `function` reference.
20
+ const newEvolveOptions = await loadEvolveConfig(command, projectCwd, overrideEvolveOptions, configLoaderOptions);
21
+ // FIXME: Cause of `worker threads` we need avoid pass entryItem config directly
22
+ // because we have some config node item with `function`
23
+ // It will break `worker threads` comunication, e.g below shown.
24
+ // DataCloneError: function (url) {
25
+ // if (url.indexOf('dev.flatjs.com') > 0) return 'me';
26
+ // if (url.indexOf('.qa.') > 0) retur...<omitted>... } could not be cloned.
27
+ // at new DOMException (node:internal/per_context/domexception:53:5)
28
+ // So we need to re cacalculate the build entry via `entryKey`
29
+ const buildOneEntry = filterActivedEntriesByModule(newEvolveOptions.entryMap, [
30
+ // Make sure that the entryKey is correct match.
31
+ new RegExp(`^${entryKey}$`),
32
+ ]);
33
+ const buildEntryKeys = Object.keys(buildOneEntry);
34
+ // Make sure that we have at least one build entry module.
35
+ if (!buildEntryKeys.length) {
36
+ throw new Error(`No build entry resolved via "${entryKey}" on "startBuildWorker"!`);
37
+ }
38
+ const normalizedBuildOneEntry = normalizeEvolveEntryMap(buildOneEntry, newEvolveOptions.entryMap);
39
+ const buildEntryConfig = normalizedBuildOneEntry[entryKey];
40
+ return prepareBuild([entryKey, buildEntryConfig], newEvolveOptions);
41
+ };
@@ -1,12 +1,5 @@
1
1
  import { type PartialDeep } from 'type-fest';
2
2
  import { type ConfigLoaderOptions } from '../load-config/load-evolve-config.js';
3
3
  import { type FlatEvolveOptions } from '../types/types-options.js';
4
- import { type EvolveBuildResult } from './prepare-build.js';
5
- /**
6
- * The main entry to start an evolve `build`
7
- * @param projectCwd The Root directory (workspace) of this project.
8
- * @param buildModules The filter pattern to detect modules we want to build.
9
- * @param overrideEvolveOptions The overrided evolve options
10
- * @param configLoaderOptions Evolve config loader options
11
- */
4
+ import { type EvolveBuildResult } from './start-one-entry-build.js';
12
5
  export declare const startBuild: (projectCwd: string, buildModules: string[], overrideEvolveOptions?: PartialDeep<FlatEvolveOptions>, configLoaderOptions?: ConfigLoaderOptions) => Promise<EvolveBuildResult[]>;
@@ -1 +1,49 @@
1
- import{logger}from"@flatjs/common";import{filterActivedEntriesByModule}from"../helpers/filter-actived-entries.js";import{normalizeEvolveEntryMap}from"../helpers/normalize-entry-map.js";import{loadEvolveConfig}from"../load-config/load-evolve-config.js";import{prepareBuild}from"./prepare-build.js";export const startBuild=async(r,e,o={},i)=>{const t=await loadEvolveConfig({command:"build"},r,o,i),l=filterActivedEntriesByModule(t.entryMap,e),n=Object.keys(l);if(!n.length)return logger.warn("No build entries providered!"),[];logger.info(`Start normal build:\n${JSON.stringify({buildEntries:n},null,2)}`);const a=normalizeEvolveEntryMap(l,t.entryMap);return prepareBuild(r,a,t)};
1
+ import { pathToFileURL } from 'node:url';
2
+ import { getDirname } from '@armit/file-utility';
3
+ import { createThreadPool } from '@armit/worker-threads';
4
+ import { chalk, logger } from '@flatjs/common';
5
+ import Listr from 'listr';
6
+ import { filterActivedEntriesByModule } from '../helpers/filter-actived-entries.js';
7
+ import { getMaxProcessTasks } from '../helpers/get-max-process-tasks.js';
8
+ import { loadEvolveConfig, } from '../load-config/load-evolve-config.js';
9
+ import { envVerify } from './env-verify.js';
10
+ export const startBuild = async (projectCwd, buildModules, overrideEvolveOptions = {}, configLoaderOptions) => {
11
+ const command = {
12
+ command: 'build',
13
+ };
14
+ // Try to load evolve configuration from `flatjs-evolve.config.ts`
15
+ const newEvolveOptions = await loadEvolveConfig(command, projectCwd, overrideEvolveOptions, configLoaderOptions);
16
+ await envVerify(projectCwd, newEvolveOptions);
17
+ const buildEntries = filterActivedEntriesByModule(newEvolveOptions.entryMap, buildModules);
18
+ const buildEntryKeys = Object.keys(buildEntries);
19
+ // Make sure that we have at least one build entry module.
20
+ if (!buildEntryKeys.length) {
21
+ logger.warn(`No build entries providered!`);
22
+ return [];
23
+ }
24
+ logger.info(`Start standard build:\n${JSON.stringify({ buildEntries: buildEntryKeys }, null, 2)}`);
25
+ const workerSize = getMaxProcessTasks(buildEntryKeys.length, newEvolveOptions.maxProcesses);
26
+ const workerPath = pathToFileURL(getDirname(import.meta.url, './start-build-worker.js')).toString();
27
+ const worker = await createThreadPool(workerPath, {
28
+ size: workerSize,
29
+ });
30
+ const buildTasks = new Listr([], {
31
+ concurrent: workerSize,
32
+ exitOnError: true,
33
+ });
34
+ const buildResults = [];
35
+ for (const [entryKey] of Object.entries(buildEntries)) {
36
+ buildTasks.add({
37
+ title: `Build module ${chalk(['magenta'])(entryKey)} ...`,
38
+ task: async () => {
39
+ const buildResult = await worker.startBuildWorker(projectCwd, entryKey, overrideEvolveOptions, configLoaderOptions);
40
+ buildResults.push(buildResult);
41
+ },
42
+ });
43
+ }
44
+ if (buildTasks.tasks.length) {
45
+ await buildTasks.run();
46
+ }
47
+ worker.pool.terminate();
48
+ return buildResults;
49
+ };
@@ -0,0 +1,13 @@
1
+ import { type EvolveEntryMap } from '../types/types-entry-map.js';
2
+ import { type FlatEvolveOptions } from '../types/types-options.js';
3
+ export type EvolveBuildResult = {
4
+ name?: string;
5
+ warningStats?: unknown;
6
+ };
7
+ /**
8
+ * The helpers to build one entry at a time
9
+ * @param singleBuildEntry The single entry
10
+ * @param buildPublicPath
11
+ * @param evolveOptions
12
+ */
13
+ export declare const startOneEntryBuild: (singleBuildEntry: EvolveEntryMap, evolveOptions: FlatEvolveOptions) => Promise<EvolveBuildResult>;
@@ -0,0 +1,35 @@
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);
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
+ };
@@ -1 +1,32 @@
1
- import{logger}from"@flatjs/common";import{filterActivedEntriesByModule}from"../helpers/filter-actived-entries.js";import{normalizeEvolveEntryMap}from"../helpers/normalize-entry-map.js";import{loadEvolveConfig}from"../load-config/load-evolve-config.js";import{prepareServe}from"./prepare-serve.js";export const startServe=async(e,r,o={},t)=>{const n=await loadEvolveConfig({command:"serve"},e,o,t),i=filterActivedEntriesByModule(n.entryMap,r),l=Object.keys(i);if(!l.length)return logger.warn("No served entries providered!"),[];logger.info({servedEntries:l});const a=normalizeEvolveEntryMap(i,n.entryMap);return prepareServe(e,a,n)};
1
+ import { logger } from '@flatjs/common';
2
+ import { filterActivedEntriesByModule } from '../helpers/filter-actived-entries.js';
3
+ import { normalizeEvolveEntryMap } from '../helpers/normalize-entry-map.js';
4
+ import { loadEvolveConfig, } from '../load-config/load-evolve-config.js';
5
+ import { prepareServe } from './prepare-serve.js';
6
+ /**
7
+ * The main entry to start evolve serve
8
+ * @param projectCwd The Root directory (workspace) of this project.
9
+ * @param serveModules The filter pattern to detect modules we want to serve.
10
+ * @param overrideEvolveOptions The overrided evolve options
11
+ * @param configLoaderOptions Evolve config loader options
12
+ */
13
+ export const startServe = async (projectCwd, serveModules, overrideEvolveOptions = {}, configLoaderOptions) => {
14
+ const command = {
15
+ command: 'serve',
16
+ };
17
+ // Try to load evolve configuration from `flatjs-evolve.config.ts`
18
+ const evolveOptions = await loadEvolveConfig(command, projectCwd, overrideEvolveOptions, configLoaderOptions);
19
+ const servedEntries = filterActivedEntriesByModule(evolveOptions.entryMap, serveModules);
20
+ const servedEntryKeys = Object.keys(servedEntries);
21
+ // Make sure that we have at least one serve entry module.
22
+ if (!servedEntryKeys.length) {
23
+ logger.warn(`No served entries providered!`);
24
+ return [];
25
+ }
26
+ logger.info({
27
+ servedEntries: servedEntryKeys,
28
+ });
29
+ // Normalized served entries to make sure we have latested entry options.
30
+ const normalizedServedEntries = normalizeEvolveEntryMap(servedEntries, evolveOptions.entryMap);
31
+ return prepareServe(projectCwd, normalizedServedEntries, evolveOptions);
32
+ };
@@ -1 +1,16 @@
1
- import{loadEvolveConfig}from"../load-config/load-evolve-config.js";import{prepareStatic}from"./prepare-static.js";export const startStatic=async(o,t={},a)=>{const r=await loadEvolveConfig({command:"static"},o,t,a);return prepareStatic(o,r)};
1
+ import { loadEvolveConfig, } from '../load-config/load-evolve-config.js';
2
+ import { prepareStatic } from './prepare-static.js';
3
+ /**
4
+ * The main entry to start evolve static server to proxy all modules of `production` build
5
+ * @param projectCwd The Root directory (workspace) of this project.
6
+ * @param overrideEvolveOptions The overrided evolve options
7
+ * @param configLoaderOptions Evolve config loader options
8
+ */
9
+ export const startStatic = async (projectCwd, overrideEvolveOptions = {}, configLoaderOptions) => {
10
+ const command = {
11
+ command: 'static',
12
+ };
13
+ // Try to load evolve configuration from `flatjs-evolve.config.ts`
14
+ const evolveOptions = await loadEvolveConfig(command, projectCwd, overrideEvolveOptions, configLoaderOptions);
15
+ return prepareStatic(projectCwd, evolveOptions);
16
+ };
@@ -1 +1,25 @@
1
- import{logger}from"@flatjs/common";import{moduleName}from"../constants.js";import{printInfo}from"../helpers/print-log.js";import{imageMinimizer}from"./image-minimizer.js";import{terserMinimizer}from"./terser-minimizer.js";export const createMinimizers=(i,r)=>{const e=[];if(i)return logger.debug("Ignore minimizer plugin for `serve` mode",moduleName),e;if(!1===r?.minimizer)return printInfo("Note `minimizer` has been disabled for now"),e;const m=imageMinimizer();m&&r?.minimizer?.imageMin&&e.push(m);const n=terserMinimizer(r?.minimizer?.terserOptions||{});return e.push(n),e};
1
+ import { logger } from '@flatjs/common';
2
+ import { moduleName } from '../constants.js';
3
+ import { printInfo } from '../helpers/print-log.js';
4
+ import { imageMinimizer } from './image-minimizer.js';
5
+ import { terserMinimizer } from './terser-minimizer.js';
6
+ export const createMinimizers = (serveMode, webpackOptions) => {
7
+ const minimizers = [];
8
+ if (serveMode) {
9
+ logger.debug('Ignore minimizer plugin for `serve` mode', moduleName);
10
+ return minimizers;
11
+ }
12
+ if (webpackOptions?.minimizer === false) {
13
+ printInfo('Note `minimizer` has been disabled for now');
14
+ return minimizers;
15
+ }
16
+ if (webpackOptions?.minimizer?.imageMin) {
17
+ const imageMinPlugin = imageMinimizer();
18
+ if (imageMinPlugin) {
19
+ minimizers.push(imageMinPlugin);
20
+ }
21
+ }
22
+ const terserPlugin = terserMinimizer(webpackOptions?.minimizer?.terserOptions || {});
23
+ minimizers.push(terserPlugin);
24
+ return minimizers;
25
+ };
@@ -1 +1,14 @@
1
- export const defaultTerserOptions={ecma:void 0,parse:{},compress:{},mangle:!0,module:!1,output:void 0,toplevel:!1,ie8:!1,keep_classnames:void 0,keep_fnames:!1,safari10:!1};
1
+ export const defaultTerserOptions = {
2
+ ecma: undefined,
3
+ parse: {},
4
+ compress: {},
5
+ // Note `mangle.properties` is `false` by default.
6
+ mangle: true,
7
+ module: false,
8
+ output: undefined,
9
+ toplevel: false,
10
+ ie8: false,
11
+ keep_classnames: undefined,
12
+ keep_fnames: false,
13
+ safari10: false,
14
+ };
@@ -1 +1,56 @@
1
- import{projectHasYarn}from"@armit/package";import{chalk,logger,requireResolve}from"@flatjs/common";import ImageMinimizerPlugin from"image-minimizer-webpack-plugin";import{moduleName}from"../constants.js";const logs=new Map;export const imageMinimizer=()=>{const e=[],i=[["svgo",{}],["gifsicle",{}],["jpegtran",{}],["pngquant",{}]].map((i=>{const n=i[0];try{return requireResolve(`imagemin-${n}`),i}catch(i){if(!logs.get(n)){logs.set(n,!0);const i=chalk(["magenta"])(`"${projectHasYarn()?"yarn add":"npm install"} imagemin-${n} -D"`);e.push(`Execute ${i} for assets optimization`)}return null}})).filter(Boolean);if(e.length)for(const i of e)logger.warn(i,moduleName);return i.length?new ImageMinimizerPlugin({minimizer:{implementation:ImageMinimizerPlugin.imageminMinify,options:{plugins:i}}}):null};
1
+ import { projectHasYarn } from '@armit/package';
2
+ import { chalk, logger, requireResolve } from '@flatjs/common';
3
+ import ImageMinimizerPlugin from 'image-minimizer-webpack-plugin';
4
+ import { moduleName } from '../constants.js';
5
+ const logs = new Map();
6
+ /**
7
+ * brew install libpng
8
+ * brew install gifsicle
9
+ * @returns
10
+ */
11
+ export const imageMinimizer = () => {
12
+ const suggestedPlugins = [
13
+ // Svgo configuration here https://github.com/svg/svgo#configuration
14
+ ['svgo', {}],
15
+ ['gifsicle', {}],
16
+ ['jpegtran', {}],
17
+ ['pngquant', {}],
18
+ ];
19
+ const logMessage = [];
20
+ const availabledPlugins = suggestedPlugins
21
+ .map((item) => {
22
+ const moduleId = item[0];
23
+ try {
24
+ requireResolve(`imagemin-${moduleId}`);
25
+ return item;
26
+ }
27
+ catch (err) {
28
+ if (!logs.get(moduleId)) {
29
+ logs.set(moduleId, true);
30
+ const command = chalk(['magenta'])(`"${projectHasYarn() ? 'yarn add' : 'npm install'} imagemin-${moduleId} -D"`);
31
+ logMessage.push(`Execute ${command} for assets optimization`);
32
+ }
33
+ return null;
34
+ }
35
+ })
36
+ .filter(Boolean);
37
+ if (logMessage.length) {
38
+ for (const msg of logMessage) {
39
+ logger.warn(msg, moduleName);
40
+ }
41
+ }
42
+ if (availabledPlugins.length) {
43
+ return new ImageMinimizerPlugin({
44
+ minimizer: {
45
+ // Recommended squoosh options for lossless optimization
46
+ implementation: ImageMinimizerPlugin.imageminMinify,
47
+ options: {
48
+ // Lossless optimization with custom option
49
+ // Feel free to experiment with options for better result for you
50
+ plugins: availabledPlugins,
51
+ },
52
+ },
53
+ });
54
+ }
55
+ return null;
56
+ };
@@ -1 +1 @@
1
- export*from"./create-minimizers.js";
1
+ export * from './create-minimizers.js';
@@ -1,3 +1,15 @@
1
- import{mergeOptions}from"@flatjs/common";import TerserPlugin from"terser-webpack-plugin";import{defaultTerserOptions}from"./default-options.js";export const terserMinimizer=e=>new TerserPlugin({parallel:!0,
2
- // Disable Extract all or some (use /^\**!|@preserve|@license|@cc_on/i RegExp) comments.
3
- extractComments:!1,terserOptions:mergeOptions(defaultTerserOptions,e)});
1
+ import { mergeOptions } from '@flatjs/common';
2
+ import TerserPlugin from 'terser-webpack-plugin';
3
+ import { defaultTerserOptions } from './default-options.js';
4
+ /**
5
+ * https://github.com/webpack-contrib/terser-webpack-plugin#terseroptions
6
+ */
7
+ export const terserMinimizer = (terserOptions) => {
8
+ return new TerserPlugin({
9
+ parallel: true,
10
+ // Disable Extract all or some (use /^\**!|@preserve|@license|@cc_on/i RegExp) comments.
11
+ extractComments: false,
12
+ // Terser minify options.
13
+ terserOptions: mergeOptions(defaultTerserOptions, terserOptions),
14
+ });
15
+ };
@@ -1 +1 @@
1
- export{};
1
+ export {};