@modern-js/module-tools 1.0.0-alpha.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (187) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/LICENSE +21 -0
  3. package/README.md +32 -0
  4. package/bin/modern.js +3 -0
  5. package/dist/js/modern/cli/build.js +9 -0
  6. package/dist/js/modern/cli/dev.js +8 -0
  7. package/dist/js/modern/cli/index.js +3 -0
  8. package/dist/js/modern/cli/new.js +16 -0
  9. package/dist/js/modern/commands/build.js +56 -0
  10. package/dist/js/modern/commands/dev.js +29 -0
  11. package/dist/js/modern/commands/index.js +2 -0
  12. package/dist/js/modern/features/build/build-platform.js +70 -0
  13. package/dist/js/modern/features/build/build-watch.js +96 -0
  14. package/dist/js/modern/features/build/build.js +110 -0
  15. package/dist/js/modern/features/build/constants.js +66 -0
  16. package/dist/js/modern/features/build/index.js +29 -0
  17. package/dist/js/modern/features/build/logger/index.js +2 -0
  18. package/dist/js/modern/features/build/logger/logText.js +63 -0
  19. package/dist/js/modern/features/build/logger/loggerManager.js +101 -0
  20. package/dist/js/modern/features/build/utils.js +198 -0
  21. package/dist/js/modern/features/dev/index.js +41 -0
  22. package/dist/js/modern/index.js +46 -0
  23. package/dist/js/modern/locale/en.js +23 -0
  24. package/dist/js/modern/locale/index.js +10 -0
  25. package/dist/js/modern/locale/zh.js +23 -0
  26. package/dist/js/modern/schema/index.js +3 -0
  27. package/dist/js/modern/schema/output.js +29 -0
  28. package/dist/js/modern/schema/source.js +15 -0
  29. package/dist/js/modern/tasks/build-source-code.js +213 -0
  30. package/dist/js/modern/tasks/build-style.js +152 -0
  31. package/dist/js/modern/tasks/build-watch-source-code.js +144 -0
  32. package/dist/js/modern/tasks/build-watch-style.js +213 -0
  33. package/dist/js/modern/tasks/constants.js +1 -0
  34. package/dist/js/modern/tasks/copy-assets.js +108 -0
  35. package/dist/js/modern/tasks/generator-dts.js +220 -0
  36. package/dist/js/modern/types.js +0 -0
  37. package/dist/js/modern/utils/babel.js +85 -0
  38. package/dist/js/modern/utils/color.js +2 -0
  39. package/dist/js/modern/utils/copy.js +80 -0
  40. package/dist/js/modern/utils/json.js +13 -0
  41. package/dist/js/modern/utils/language.js +6 -0
  42. package/dist/js/modern/utils/logger.js +110 -0
  43. package/dist/js/modern/utils/readline.js +19 -0
  44. package/dist/js/modern/utils/tsconfig.js +15 -0
  45. package/dist/js/modern/utils/tspaths-transform/constants.js +3 -0
  46. package/dist/js/modern/utils/tspaths-transform/index.js +130 -0
  47. package/dist/js/modern/utils/tspaths-transform/utils.js +21 -0
  48. package/dist/js/modern/utils/valide.js +28 -0
  49. package/dist/js/node/cli/build.js +21 -0
  50. package/dist/js/node/cli/dev.js +20 -0
  51. package/dist/js/node/cli/index.js +44 -0
  52. package/dist/js/node/cli/new.js +28 -0
  53. package/dist/js/node/commands/build.js +76 -0
  54. package/dist/js/node/commands/dev.js +49 -0
  55. package/dist/js/node/commands/index.js +21 -0
  56. package/dist/js/node/features/build/build-platform.js +84 -0
  57. package/dist/js/node/features/build/build-watch.js +118 -0
  58. package/dist/js/node/features/build/build.js +133 -0
  59. package/dist/js/node/features/build/constants.js +79 -0
  60. package/dist/js/node/features/build/index.js +41 -0
  61. package/dist/js/node/features/build/logger/index.js +31 -0
  62. package/dist/js/node/features/build/logger/logText.js +79 -0
  63. package/dist/js/node/features/build/logger/loggerManager.js +111 -0
  64. package/dist/js/node/features/build/utils.js +231 -0
  65. package/dist/js/node/features/dev/index.js +60 -0
  66. package/dist/js/node/index.js +64 -0
  67. package/dist/js/node/locale/en.js +30 -0
  68. package/dist/js/node/locale/index.js +22 -0
  69. package/dist/js/node/locale/zh.js +30 -0
  70. package/dist/js/node/schema/index.js +14 -0
  71. package/dist/js/node/schema/output.js +36 -0
  72. package/dist/js/node/schema/source.js +22 -0
  73. package/dist/js/node/tasks/build-source-code.js +240 -0
  74. package/dist/js/node/tasks/build-style.js +168 -0
  75. package/dist/js/node/tasks/build-watch-source-code.js +156 -0
  76. package/dist/js/node/tasks/build-watch-style.js +231 -0
  77. package/dist/js/node/tasks/constants.js +8 -0
  78. package/dist/js/node/tasks/copy-assets.js +126 -0
  79. package/dist/js/node/tasks/generator-dts.js +243 -0
  80. package/dist/js/node/types.js +0 -0
  81. package/dist/js/node/utils/babel.js +99 -0
  82. package/dist/js/node/utils/color.js +12 -0
  83. package/dist/js/node/utils/copy.js +99 -0
  84. package/dist/js/node/utils/json.js +22 -0
  85. package/dist/js/node/utils/language.js +15 -0
  86. package/dist/js/node/utils/logger.js +133 -0
  87. package/dist/js/node/utils/readline.js +33 -0
  88. package/dist/js/node/utils/tsconfig.js +30 -0
  89. package/dist/js/node/utils/tspaths-transform/constants.js +10 -0
  90. package/dist/js/node/utils/tspaths-transform/index.js +155 -0
  91. package/dist/js/node/utils/tspaths-transform/utils.js +32 -0
  92. package/dist/js/node/utils/valide.js +41 -0
  93. package/dist/types/cli/build.d.ts +2 -0
  94. package/dist/types/cli/dev.d.ts +2 -0
  95. package/dist/types/cli/index.d.ts +3 -0
  96. package/dist/types/cli/new.d.ts +2 -0
  97. package/dist/types/commands/build.d.ts +16 -0
  98. package/dist/types/commands/dev.d.ts +4 -0
  99. package/dist/types/commands/index.d.ts +2 -0
  100. package/dist/types/features/build/build-platform.d.ts +6 -0
  101. package/dist/types/features/build/build-watch.d.ts +3 -0
  102. package/dist/types/features/build/build.d.ts +3 -0
  103. package/dist/types/features/build/constants.d.ts +14 -0
  104. package/dist/types/features/build/index.d.ts +3 -0
  105. package/dist/types/features/build/logger/index.d.ts +2 -0
  106. package/dist/types/features/build/logger/logText.d.ts +39 -0
  107. package/dist/types/features/build/logger/loggerManager.d.ts +39 -0
  108. package/dist/types/features/build/utils.d.ts +58 -0
  109. package/dist/types/features/dev/index.d.ts +7 -0
  110. package/dist/types/index.d.ts +17 -0
  111. package/dist/types/locale/en.d.ts +23 -0
  112. package/dist/types/locale/index.d.ts +47 -0
  113. package/dist/types/locale/zh.d.ts +23 -0
  114. package/dist/types/schema/index.d.ts +36 -0
  115. package/dist/types/schema/output.d.ts +22 -0
  116. package/dist/types/schema/source.d.ts +15 -0
  117. package/dist/types/tasks/build-source-code.d.ts +42 -0
  118. package/dist/types/tasks/build-style.d.ts +1 -0
  119. package/dist/types/tasks/build-watch-source-code.d.ts +1 -0
  120. package/dist/types/tasks/build-watch-style.d.ts +1 -0
  121. package/dist/types/tasks/constants.d.ts +1 -0
  122. package/dist/types/tasks/copy-assets.d.ts +1 -0
  123. package/dist/types/tasks/generator-dts.d.ts +1 -0
  124. package/dist/types/types.d.ts +48 -0
  125. package/dist/types/utils/babel.d.ts +8 -0
  126. package/dist/types/utils/color.d.ts +2 -0
  127. package/dist/types/utils/copy.d.ts +5 -0
  128. package/dist/types/utils/json.d.ts +4 -0
  129. package/dist/types/utils/language.d.ts +1 -0
  130. package/dist/types/utils/logger.d.ts +56 -0
  131. package/dist/types/utils/readline.d.ts +9 -0
  132. package/dist/types/utils/tsconfig.d.ts +16 -0
  133. package/dist/types/utils/tspaths-transform/constants.d.ts +1 -0
  134. package/dist/types/utils/tspaths-transform/index.d.ts +15 -0
  135. package/dist/types/utils/tspaths-transform/utils.d.ts +4 -0
  136. package/dist/types/utils/valide.d.ts +12 -0
  137. package/modern.config.js +6 -0
  138. package/package.json +95 -0
  139. package/src/.eslintrc.json +5 -0
  140. package/src/cli/build.ts +39 -0
  141. package/src/cli/dev.ts +24 -0
  142. package/src/cli/index.ts +3 -0
  143. package/src/cli/new.ts +32 -0
  144. package/src/commands/build.ts +81 -0
  145. package/src/commands/dev.ts +41 -0
  146. package/src/commands/index.ts +2 -0
  147. package/src/features/build/build-platform.ts +76 -0
  148. package/src/features/build/build-watch.ts +93 -0
  149. package/src/features/build/build.ts +111 -0
  150. package/src/features/build/constants.ts +52 -0
  151. package/src/features/build/index.ts +36 -0
  152. package/src/features/build/logger/index.ts +2 -0
  153. package/src/features/build/logger/logText.ts +80 -0
  154. package/src/features/build/logger/loggerManager.ts +132 -0
  155. package/src/features/build/utils.ts +250 -0
  156. package/src/features/dev/index.ts +62 -0
  157. package/src/index.ts +55 -0
  158. package/src/locale/en.ts +21 -0
  159. package/src/locale/index.ts +15 -0
  160. package/src/locale/zh.ts +21 -0
  161. package/src/schema/index.ts +4 -0
  162. package/src/schema/output.ts +34 -0
  163. package/src/schema/schema.d.ts +13 -0
  164. package/src/schema/source.ts +16 -0
  165. package/src/tasks/build-source-code.ts +245 -0
  166. package/src/tasks/build-style.ts +175 -0
  167. package/src/tasks/build-watch-source-code.ts +185 -0
  168. package/src/tasks/build-watch-style.ts +260 -0
  169. package/src/tasks/constants.ts +1 -0
  170. package/src/tasks/copy-assets.ts +117 -0
  171. package/src/tasks/generator-dts.ts +277 -0
  172. package/src/type.d.ts +1 -0
  173. package/src/types.ts +63 -0
  174. package/src/utils/babel.ts +100 -0
  175. package/src/utils/color.ts +3 -0
  176. package/src/utils/copy.ts +70 -0
  177. package/src/utils/json.ts +13 -0
  178. package/src/utils/language.ts +9 -0
  179. package/src/utils/logger.ts +144 -0
  180. package/src/utils/readline.ts +28 -0
  181. package/src/utils/tsconfig.ts +37 -0
  182. package/src/utils/tspaths-transform/constants.ts +19 -0
  183. package/src/utils/tspaths-transform/index.ts +139 -0
  184. package/src/utils/tspaths-transform/utils.ts +25 -0
  185. package/src/utils/valide.ts +37 -0
  186. package/tsconfig.json +13 -0
  187. package/types.d.ts +1 -0
@@ -0,0 +1,277 @@
1
+ import type { ChildProcess } from 'child_process';
2
+ import * as path from 'path';
3
+ import * as os from 'os';
4
+ import { Import, fs } from '@modern-js/utils';
5
+ import type { NormalizedConfig } from '@modern-js/core';
6
+ import type { ITsconfig } from '@/types';
7
+
8
+ const tsPathsTransform: typeof import('../utils/tspaths-transform') =
9
+ Import.lazy('../utils/tspaths-transform', require);
10
+ const babel: typeof import('../utils/babel') = Import.lazy(
11
+ '../utils/babel',
12
+ require,
13
+ );
14
+ const constants: typeof import('./constants') = Import.lazy(
15
+ './constants',
16
+ require,
17
+ );
18
+
19
+ const core: typeof import('@modern-js/core') = Import.lazy(
20
+ '@modern-js/core',
21
+ require,
22
+ );
23
+ const pluginNode: typeof import('@modern-js/plugin/node') = Import.lazy(
24
+ '@modern-js/plugin/node',
25
+ require,
26
+ );
27
+ const execa: typeof import('execa') = Import.lazy('execa', require);
28
+ const JSON5: typeof import('json5') = Import.lazy('json5', require);
29
+ const argv: typeof import('process.argv').default = Import.lazy(
30
+ 'process.argv',
31
+ require,
32
+ );
33
+ const deepMerge: typeof import('lodash.merge') = Import.lazy(
34
+ 'lodash.merge',
35
+ require,
36
+ );
37
+ const glob: typeof import('glob') = Import.lazy('glob', require);
38
+
39
+ let removeTsconfigPath = '';
40
+
41
+ const generatorTsConfig = (
42
+ projectTsconfig: ITsconfig,
43
+ {
44
+ appDirectory,
45
+ distDir,
46
+ sourceDir = 'src',
47
+ }: { appDirectory: string; distDir: string; sourceDir?: string },
48
+ ) => {
49
+ const tempPath = path.resolve(appDirectory, './node_modules');
50
+ const resolvePath = path.relative(tempPath, appDirectory);
51
+ // const rootDir = projectTsconfig.compilerOptions?.rootDir
52
+ // ? path.join(resolvePath, projectTsconfig.compilerOptions?.rootDir)
53
+ // : resolvePath;
54
+ // 目前限制 rootDir 的路径为 sourceDir
55
+ const rootDir = path.join(resolvePath, sourceDir);
56
+ const baseUrl = projectTsconfig.compilerOptions?.baseUrl
57
+ ? path.join(appDirectory, projectTsconfig.compilerOptions?.baseUrl)
58
+ : appDirectory;
59
+ // if include = ['src'], final include should be ['../src']
60
+ const include = projectTsconfig.include?.map(includePath =>
61
+ path.join(resolvePath, includePath),
62
+ );
63
+ const exclude = projectTsconfig.exclude?.map(excludePath =>
64
+ path.join(resolvePath, excludePath),
65
+ );
66
+
67
+ const resetConfig: ITsconfig = {
68
+ compilerOptions: {
69
+ rootDir,
70
+ baseUrl,
71
+ // Ensure that .d.ts files are created by tsc, but not .js files
72
+ declaration: true,
73
+ emitDeclarationOnly: true,
74
+ outDir: distDir,
75
+ },
76
+ include,
77
+ exclude,
78
+ };
79
+
80
+ const recommendOption = {
81
+ // Ensure that Babel can safely transpile files in the TypeScript project
82
+ compilerOptions: {
83
+ isolatedModules: true,
84
+ },
85
+ };
86
+
87
+ const tempTsconfigPath = path.join(tempPath, constants.tempTsconfigName);
88
+ fs.ensureFileSync(tempTsconfigPath);
89
+ fs.writeJSONSync(
90
+ tempTsconfigPath,
91
+ deepMerge(
92
+ recommendOption,
93
+ projectTsconfig,
94
+ // 此处是必须要覆盖用户默认配置
95
+ resetConfig,
96
+ ),
97
+ );
98
+ return tempTsconfigPath;
99
+ };
100
+
101
+ const getProjectTsconfig = (tsconfigPath: string | undefined): ITsconfig => {
102
+ if (!tsconfigPath || !fs.existsSync(tsconfigPath)) {
103
+ return {};
104
+ }
105
+
106
+ return JSON5.parse(fs.readFileSync(tsconfigPath, 'utf-8'));
107
+ };
108
+
109
+ const resolveLog = (
110
+ childProgress: ChildProcess,
111
+ { tsCheck = false, watch = false } = {},
112
+ ) => {
113
+ /**
114
+ * tsc 所有的log信息都是从stdout data 事件中获取
115
+ * 正常模式下,如果有报错信息,交给 resolveLog 后面的逻辑来处理
116
+ * watch 模式下,则使用这里的信息
117
+ */
118
+ childProgress.stdout?.on('data', data => {
119
+ if (!tsCheck) {
120
+ return;
121
+ }
122
+ if (watch) {
123
+ console.info(data.toString());
124
+ }
125
+ });
126
+ // 正常以下内容都不会触发,因为tsc 不会产生以下类型的log信息,不过防止意外情况
127
+ childProgress.stdout?.on('error', error => {
128
+ console.error(error.message);
129
+ });
130
+ childProgress.stderr?.on('data', chunk => {
131
+ console.error(chunk.toString());
132
+ });
133
+ };
134
+
135
+ interface IGeneratorConfig {
136
+ sourceDirName?: string;
137
+ srcDir: string;
138
+ distDir: string;
139
+ projectData: {
140
+ appDirectory: string;
141
+ };
142
+ tsconfigPath?: string;
143
+ tsCheck?: boolean;
144
+ watch?: boolean;
145
+ }
146
+
147
+ const generatorDts = async (_: NormalizedConfig, config: IGeneratorConfig) => {
148
+ const {
149
+ tsconfigPath,
150
+ distDir,
151
+ sourceDirName = 'src',
152
+ projectData: { appDirectory },
153
+ tsCheck = false,
154
+ watch = false,
155
+ } = config;
156
+
157
+ const userTsconfig = getProjectTsconfig(tsconfigPath);
158
+ const willDeleteTsconfigPath = generatorTsConfig(userTsconfig, {
159
+ appDirectory,
160
+ distDir,
161
+ sourceDir: sourceDirName,
162
+ });
163
+ removeTsconfigPath = willDeleteTsconfigPath;
164
+ const tscBinFile = path.join(appDirectory, './node_modules/.bin/tsc');
165
+ const watchParams = watch ? ['-w'] : [];
166
+ const childProgress = execa(
167
+ tscBinFile,
168
+ ['-p', willDeleteTsconfigPath, ...watchParams],
169
+ {
170
+ stdio: 'pipe',
171
+ cwd: appDirectory,
172
+ },
173
+ );
174
+ resolveLog(childProgress, { tsCheck, watch });
175
+ try {
176
+ await childProgress;
177
+ console.info('[Tsc Compiler]: Successfully');
178
+ } catch (e) {
179
+ if (!tsCheck) {
180
+ console.warn(
181
+ `There are some type issues, which can be checked by configuring 'source.enableTsChecker = true' ${os.EOL} in modern.config.js`,
182
+ );
183
+ } else {
184
+ const isRecord = (input: any): input is Record<string, any> =>
185
+ typeof input === 'object';
186
+ // 通过使用 execa,可以将tsc 的 data 类型的报错信息变为异常错误信息
187
+ if (isRecord(e)) {
188
+ console.error(e.stdout);
189
+ }
190
+ }
191
+ }
192
+ fs.removeSync(willDeleteTsconfigPath);
193
+ };
194
+
195
+ const resolveAlias = (
196
+ modernConfig: NormalizedConfig,
197
+ config: IGeneratorConfig,
198
+ watchFilenames: string[] = [],
199
+ ) => {
200
+ const { output } = modernConfig;
201
+ const defaultPaths = { '@': ['./src'] };
202
+ const dtsDistPath = `${config.distDir}/**/*.d.ts`;
203
+ const dtsFilenames =
204
+ watchFilenames.length > 0
205
+ ? watchFilenames
206
+ : glob.sync(dtsDistPath, { absolute: true });
207
+ const alias = babel.getFinalAlias(modernConfig, {
208
+ appDirectory: config.projectData.appDirectory,
209
+ tsconfigPath:
210
+ config.tsconfigPath ||
211
+ path.join(config.projectData.appDirectory, './tsconfig.json'),
212
+ sourceAbsDir: config.distDir,
213
+ });
214
+ const mergedPaths = alias.isTsPath
215
+ ? alias.paths || {}
216
+ : { ...defaultPaths, ...(alias.paths || {}) };
217
+ const result = tsPathsTransform.transformDtsAlias({
218
+ filenames: dtsFilenames,
219
+ baseUrl: path.join(config.projectData.appDirectory, output.path || 'dist'),
220
+ paths: mergedPaths,
221
+ });
222
+ for (const r of result) {
223
+ fs.writeFileSync(r.path, r.content);
224
+ }
225
+ };
226
+
227
+ interface ITaskConfig {
228
+ srcDir: string;
229
+ sourceDirName: string;
230
+ distDir: string;
231
+ appDirectory: string;
232
+ tsconfigPath?: string;
233
+ tsCheck?: boolean;
234
+ watch?: boolean;
235
+ debug?: boolean;
236
+ }
237
+
238
+ const taskMain = async ({
239
+ modernConfig,
240
+ }: {
241
+ modernConfig: NormalizedConfig;
242
+ }) => {
243
+ const processArgv = argv(process.argv.slice(2));
244
+ const config = processArgv<ITaskConfig>({
245
+ appDirectory: process.cwd(),
246
+ srcDir: 'src',
247
+ distDir: 'dist/types',
248
+ tsconfigPath: './tsconfig.json',
249
+ sourceDirName: 'src',
250
+ });
251
+
252
+ const option = {
253
+ srcDir: config.srcDir,
254
+ distDir: config.distDir,
255
+ projectData: { appDirectory: config.appDirectory },
256
+ tsconfigPath: config.tsconfigPath,
257
+ watch: config.watch,
258
+ tsCheck: config.tsCheck,
259
+ sourceDirName: config.sourceDirName,
260
+ };
261
+ await generatorDts(modernConfig, option);
262
+ // TODO: watch 模式下无法转换
263
+ resolveAlias(modernConfig, option);
264
+ };
265
+
266
+ (async () => {
267
+ pluginNode.enable();
268
+ const { resolved } = await core.cli.init();
269
+ await core.manager.run(async () => {
270
+ try {
271
+ await taskMain({ modernConfig: resolved });
272
+ } catch (e: any) {
273
+ console.error(e.message);
274
+ fs.removeSync(removeTsconfigPath);
275
+ }
276
+ });
277
+ })();
package/src/type.d.ts ADDED
@@ -0,0 +1 @@
1
+ /// <reference types="@modern-js/module-tools-hooks" />
package/src/types.ts ADDED
@@ -0,0 +1,63 @@
1
+ import type { OutputConfig, SourceConfig } from '@modern-js/core/config';
2
+ import type { ImportStyleType } from '@modern-js/babel-preset-module';
3
+ import type { NormalizedConfig } from '@modern-js/core';
4
+ import type { LoggerText } from './features/build/logger/logText';
5
+ import type { Platform } from './features/build/build-platform';
6
+
7
+ export type { Platform } from './features/build/build-platform';
8
+ export type { ITsconfig } from './utils/tsconfig';
9
+
10
+ export interface ITaskMapper {
11
+ logger: LoggerText | null;
12
+ taskPath: string;
13
+ params?: string[];
14
+ }
15
+
16
+ export type PackageModeType =
17
+ | 'universal-js'
18
+ | 'universal-js-lite'
19
+ | 'browser-js'
20
+ | 'browser-js-lite'
21
+ | 'node-js';
22
+
23
+ export type JsSyntaxType = 'CJS+ES6' | 'ESM+ES5' | 'ESM+ES6';
24
+
25
+ export interface IPackageFields {
26
+ main?: JsSyntaxType;
27
+ modern?: JsSyntaxType;
28
+ module?: JsSyntaxType;
29
+ }
30
+
31
+ export interface IBuildConfig {
32
+ platform: boolean | Exclude<Platform, 'all'>;
33
+ enableTscCompiler: boolean;
34
+ enableWatchMode?: boolean;
35
+ isTsProject: boolean;
36
+ sourceDir: string;
37
+ tsconfigName?: string;
38
+ }
39
+
40
+ export interface IPackageModeValue {
41
+ type: 'module' | 'commonjs';
42
+ syntax: 'es5' | 'es6+';
43
+ outDir: 'node' | 'treeshaking' | 'modern';
44
+ copyDirs?: ('node' | 'treeshaking' | 'modern')[];
45
+ }
46
+
47
+ export interface ModuleToolsOutput extends OutputConfig {
48
+ assetsPath: string;
49
+ disableTsChecker: boolean;
50
+ enableSourceMap: boolean;
51
+ packageMode: PackageModeType;
52
+ packageFields: IPackageFields;
53
+ importStyle: ImportStyleType;
54
+ }
55
+
56
+ export interface ModuleToolsSource extends SourceConfig {
57
+ jsxTransformRuntime: 'automatic' | 'classic';
58
+ }
59
+
60
+ export type ModuleToolsConfig = NormalizedConfig & {
61
+ output: OutputConfig & ModuleToolsOutput;
62
+ source: NormalizedConfig['source'] & ModuleToolsSource;
63
+ };
@@ -0,0 +1,100 @@
1
+ import {
2
+ getBabelConfig,
3
+ getModuleBabelChain,
4
+ } from '@modern-js/babel-preset-module';
5
+ import { TransformOptions } from '@babel/core';
6
+ import { applyOptionsChain, getAlias } from '@modern-js/utils';
7
+ import { NormalizedConfig } from '@modern-js/core';
8
+ import type { BabelChain } from '@modern-js/babel-chain';
9
+ import { IPackageModeValue, ModuleToolsConfig } from '../types';
10
+
11
+ export const getFinalAlias: any = (
12
+ modernConfig: NormalizedConfig,
13
+ option: { appDirectory: string; tsconfigPath: string; sourceAbsDir: string },
14
+ ) => {
15
+ const aliasConfig = getAlias(modernConfig.source.alias, option);
16
+ // 排除内部别名,因为不需要处理
17
+ const finalPaths: Record<string, string | string[]> = {};
18
+ const internalAliasPrefix = '@modern-js/runtime';
19
+ if (aliasConfig.paths && typeof aliasConfig.paths === 'object') {
20
+ const pathsKey = Object.keys(aliasConfig.paths);
21
+ for (const key of pathsKey) {
22
+ if (!key.includes(internalAliasPrefix)) {
23
+ finalPaths[key] = aliasConfig.paths[key];
24
+ }
25
+ }
26
+ }
27
+
28
+ aliasConfig.paths = finalPaths;
29
+ return aliasConfig;
30
+ };
31
+
32
+ export const resolveBabelConfig = (
33
+ appDirectory: string,
34
+ modernConfig: NormalizedConfig,
35
+ option: Pick<IPackageModeValue, 'syntax' | 'type'> & {
36
+ sourceAbsDir: string;
37
+ tsconfigPath: string;
38
+ },
39
+ ) => {
40
+ const {
41
+ source: { envVars, globalVars, jsxTransformRuntime = 'automatic' },
42
+ output: { importStyle },
43
+ tools: { lodash: userLodashOption },
44
+ } = modernConfig as ModuleToolsConfig;
45
+
46
+ // alias config
47
+ const aliasConfig = getFinalAlias(modernConfig, {
48
+ appDirectory,
49
+ ...option,
50
+ });
51
+
52
+ // lodash config
53
+ const lodashOptions = applyOptionsChain(
54
+ { id: ['lodash', 'ramda'] },
55
+ // TODO: 需要处理类型问题
56
+ userLodashOption as any,
57
+ );
58
+ // babel config
59
+ const internalBabelConfig = getBabelConfig(
60
+ {
61
+ appDirectory,
62
+ enableReactPreset: true,
63
+ enableTypescriptPreset: true,
64
+ alias: aliasConfig,
65
+ envVars,
66
+ globalVars,
67
+ lodashOptions,
68
+ jsxTransformRuntime,
69
+ importStyle,
70
+ },
71
+ {
72
+ type: option.type,
73
+ syntax: option.syntax,
74
+ },
75
+ );
76
+ const babelChain = getModuleBabelChain(
77
+ {
78
+ appDirectory,
79
+ enableReactPreset: true,
80
+ enableTypescriptPreset: true,
81
+ alias: aliasConfig,
82
+ envVars,
83
+ globalVars,
84
+ lodashOptions,
85
+ jsxTransformRuntime,
86
+ importStyle,
87
+ },
88
+ {
89
+ type: option.type,
90
+ syntax: option.syntax,
91
+ },
92
+ );
93
+ const userBabelConfig = modernConfig.tools.babel;
94
+ return applyOptionsChain<TransformOptions, { chain: BabelChain }>(
95
+ internalBabelConfig,
96
+ // TODO: 感觉 userBabelConfig 的类型应该是TransformOptions
97
+ userBabelConfig as any,
98
+ { chain: babelChain },
99
+ );
100
+ };
@@ -0,0 +1,3 @@
1
+ import { chalk } from '@modern-js/utils';
2
+
3
+ export const devMenuTitle = chalk.rgb(255, 153, 0);
@@ -0,0 +1,70 @@
1
+ import * as path from 'path';
2
+ import { fs, Import } from '@modern-js/utils';
3
+ import type { NormalizedConfig, IAppContext } from '@modern-js/core';
4
+
5
+ const globby: typeof import('globby') = Import.lazy('globby', require);
6
+ const fastGlob: typeof import('fast-glob') = Import.lazy('fast-glob', require);
7
+ const normalizePath: typeof import('normalize-path') = Import.lazy(
8
+ 'normalize-path',
9
+ require,
10
+ );
11
+
12
+ // eslint-disable-next-line max-statements
13
+ export const copyTask = async (option: {
14
+ modernConfig: NormalizedConfig;
15
+ appContext: IAppContext;
16
+ }) => {
17
+ const { modernConfig, appContext } = option;
18
+ const { appDirectory } = appContext;
19
+ const {
20
+ output: { copy, path: outputPath = 'dist' },
21
+ } = modernConfig;
22
+
23
+ if (!copy) {
24
+ return;
25
+ }
26
+ try {
27
+ // 类型暂时这样处理,待之后优化copy的逻辑
28
+ for (const copyOption of copy as any) {
29
+ // 在原来的基础上,引入了类似于 copy-webpck-plugin 的 context 属性,可以设置项目根路径
30
+ const {
31
+ context = appDirectory,
32
+ from,
33
+ globOptions,
34
+ to: toOrigin,
35
+ } = copyOption;
36
+ let fromOrigin = from;
37
+ // 获取 glob 规则
38
+ let glob = '';
39
+ let options = {};
40
+ if (fromOrigin !== null && typeof fromOrigin === 'object') {
41
+ ({ glob, ...options } = fromOrigin);
42
+ fromOrigin = glob;
43
+ } else if (globOptions && typeof globOptions === 'object') {
44
+ options = globOptions;
45
+ }
46
+ glob = path.isAbsolute(fromOrigin)
47
+ ? fromOrigin
48
+ : path.posix.join(
49
+ fastGlob.escapePath(normalizePath(path.resolve(context))),
50
+ fromOrigin,
51
+ );
52
+ // 计算 glob,获取目标文件
53
+ const paths = await globby(glob, options);
54
+ if (!paths.length) {
55
+ return;
56
+ }
57
+ const to = path.normalize(toOrigin ? toOrigin : '');
58
+ const isToDirectory = path.extname(to) === '';
59
+ paths.forEach(item => {
60
+ const relativeFrom = path.relative(context, item);
61
+ // 如果 to 是目录,通过相对路径计算完整的产物路径;如果 to 是文件,直接作为最终产物路径
62
+ const fileName = isToDirectory ? path.join(to, relativeFrom) : to;
63
+ const finalToPath = path.resolve(outputPath, fileName);
64
+ fs.copySync(item, finalToPath);
65
+ });
66
+ }
67
+ } catch (e: any) {
68
+ console.error(`copy error: ${e.message}`);
69
+ }
70
+ };
@@ -0,0 +1,13 @@
1
+ export const safeParse = (jsonString: string) => {
2
+ try {
3
+ return {
4
+ code: 0,
5
+ value: JSON.parse(jsonString),
6
+ };
7
+ } catch (e) {
8
+ return {
9
+ code: 1,
10
+ value: jsonString,
11
+ };
12
+ }
13
+ };
@@ -0,0 +1,9 @@
1
+ import { Import } from '@modern-js/utils';
2
+
3
+ const i18n: typeof import('@modern-js/i18n-cli-language-detector') =
4
+ Import.lazy('@modern-js/i18n-cli-language-detector', require);
5
+
6
+ export function getLocaleLanguage() {
7
+ const detector = new i18n.I18CLILanguageDetector();
8
+ return detector.detect();
9
+ }
@@ -0,0 +1,144 @@
1
+ /* eslint-disable max-classes-per-file */
2
+ import type { ChildProcess } from 'child_process';
3
+ import EventEmitter from 'events';
4
+ import { Import } from '@modern-js/utils';
5
+
6
+ const chalk: typeof import('chalk') = Import.lazy('chalk', require);
7
+
8
+ export const clearFlag = '\x1Bc';
9
+
10
+ export const logTemplate = (
11
+ title: string,
12
+ messageStack: string[],
13
+ maxLength: number,
14
+ {
15
+ noBottomBorder = false,
16
+ bottomBorderText = '',
17
+ noLeftBorder = false,
18
+ leftBorder = '│',
19
+ contentColor = (s: string) => s,
20
+ } = {},
21
+ ) => {
22
+ const leftBorderFlag = noLeftBorder ? '' : leftBorder;
23
+ const messageFragments = messageStack
24
+ .map(p => {
25
+ p.trim();
26
+
27
+ return `${leftBorderFlag}${p.replace(clearFlag, '')}`;
28
+ }) // 移除 clearFlag
29
+ .filter(s => s !== leftBorderFlag) // 过滤空字符串
30
+ .slice(0, maxLength) // 控制长度
31
+ .reverse(); // 调换顺序,最新的消息在最后面
32
+ messageFragments[messageFragments.length - 1] =
33
+ messageFragments[messageFragments.length - 1].trim();
34
+ const template = `${title}:
35
+ ${contentColor(messageFragments.join(''))}${
36
+ noBottomBorder ? '' : `\n${bottomBorderText}`
37
+ }`;
38
+ console.info('template', messageFragments);
39
+ return template;
40
+ };
41
+
42
+ export type STDOUT = ChildProcess['stdout'] | NodeJS.ReadStream;
43
+ export type STDERR = ChildProcess['stdout'] | NodeJS.ReadStream;
44
+
45
+ export interface LoggerTextOption {
46
+ title: string;
47
+ maxLength: number;
48
+ contentConfig?: {
49
+ noBottomBorder?: boolean;
50
+ bottomBorderText?: string;
51
+ noLeftBorder?: boolean;
52
+ leftBorder?: string;
53
+ contentColor?: (s: string) => string;
54
+ replace?: string[];
55
+ };
56
+ }
57
+
58
+ export class LoggerText {
59
+ messages: string[];
60
+
61
+ option: LoggerTextOption;
62
+
63
+ constructor(option: LoggerTextOption) {
64
+ this.messages = [];
65
+ this.option = option;
66
+ }
67
+
68
+ append(message: string) {
69
+ const replace = this.option.contentConfig?.replace || [];
70
+ let content = message;
71
+ for (const r of replace) {
72
+ content = content.replace(new RegExp(r, 'g'), '');
73
+ }
74
+ this.messages.push(content);
75
+ }
76
+
77
+ get value() {
78
+ const { title, maxLength, contentConfig } = this.option;
79
+ const messages = [...new Set(this.messages)];
80
+ return logTemplate(title, messages, maxLength, contentConfig);
81
+ }
82
+ }
83
+
84
+ interface IAddStdoutConfig {
85
+ event?: { data?: boolean; error?: boolean };
86
+ colors?: {
87
+ data?: (s: string) => string;
88
+ error?: (s: string) => string;
89
+ warning?: (s: string) => string;
90
+ };
91
+ }
92
+
93
+ export class LoggerManager extends EventEmitter {
94
+ // constructor() {}
95
+
96
+ createLoggerText(option: LoggerTextOption) {
97
+ return new LoggerText(option);
98
+ }
99
+
100
+ addStdout(
101
+ loggerText: LoggerText,
102
+ stdout: STDOUT,
103
+ config: IAddStdoutConfig = {},
104
+ ) {
105
+ const {
106
+ event = { data: true, error: true },
107
+ colors = {
108
+ data: chalk.green,
109
+ error: chalk.red,
110
+ warning: chalk.yellow,
111
+ },
112
+ } = config;
113
+ if (event.data) {
114
+ stdout?.on('data', chunk => {
115
+ const data = chunk.toString();
116
+ const content = colors.data ? colors.data(data) : chalk.green(data);
117
+ loggerText.append(content);
118
+ this.emit('data');
119
+ });
120
+ }
121
+
122
+ if (event.error) {
123
+ stdout?.on('error', error => {
124
+ const data = error.message;
125
+ const content = colors.error ? colors.error(data) : chalk.red(data);
126
+ loggerText.append(content);
127
+ this.emit('data');
128
+ });
129
+ }
130
+ }
131
+
132
+ addStderr(loggerText: LoggerText, stderr: STDERR) {
133
+ stderr?.on('data', chunk => {
134
+ const data = chunk.toString();
135
+ loggerText.append(data);
136
+ });
137
+ }
138
+
139
+ show(loggerText: LoggerText) {
140
+ console.info(loggerText.value);
141
+ }
142
+ }
143
+
144
+ /* eslint-enable max-classes-per-file */