@modern-js/core 1.1.5-beta.1 → 1.3.1
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/CHANGELOG.md +43 -0
- package/dist/js/modern/cli.js +29 -0
- package/dist/js/modern/config/index.js +11 -5
- package/dist/js/modern/index.js +18 -9
- package/dist/js/modern/loadPlugins.js +16 -2
- package/dist/js/node/cli.js +35 -0
- package/dist/js/node/config/index.js +11 -5
- package/dist/js/node/index.js +27 -36
- package/dist/js/node/loadPlugins.js +17 -1
- package/dist/types/cli.d.ts +1 -0
- package/dist/types/config/index.d.ts +14 -13
- package/dist/types/index.d.ts +7 -7
- package/dist/types/loadPlugins.d.ts +5 -0
- package/jest.config.js +8 -0
- package/modern.config.js +0 -7
- package/package.json +25 -19
- package/src/cli.ts +36 -0
- package/src/config/index.ts +42 -17
- package/src/index.ts +21 -20
- package/src/loadPlugins.ts +23 -6
- package/tests/btsm.test.ts +20 -0
- package/tests/config.test.ts +137 -0
- package/tests/context.test.ts +28 -0
- package/tests/fixtures/index-test/package.json +3 -0
- package/tests/index.test.ts +74 -0
- package/tests/loadEnv.test.ts +1 -1
- package/tests/loadPlugin.test.ts +36 -1
- package/tests/mergeConfig.test.ts +1 -1
- package/tests/repeatKeyWarning.test.ts +2 -2
- package/tests/schema.test.ts +1 -1
- package/tests/tsconfig.json +1 -3
- package/tests/utils.test.ts +8 -0
- package/tsconfig.json +1 -3
package/package.json
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"modern",
|
|
12
12
|
"modern.js"
|
|
13
13
|
],
|
|
14
|
-
"version": "1.
|
|
14
|
+
"version": "1.3.1",
|
|
15
15
|
"jsnext:source": "./src/index.ts",
|
|
16
16
|
"types": "./dist/types/index.d.ts",
|
|
17
17
|
"main": "./dist/js/node/index.js",
|
|
@@ -20,12 +20,16 @@
|
|
|
20
20
|
"exports": {
|
|
21
21
|
".": {
|
|
22
22
|
"node": {
|
|
23
|
+
"jsnext:source": "./src/index.ts",
|
|
23
24
|
"import": "./dist/js/modern/index.js",
|
|
24
25
|
"require": "./dist/js/node/index.js"
|
|
25
26
|
},
|
|
26
27
|
"default": "./dist/js/treeshaking/index.js"
|
|
27
28
|
},
|
|
28
|
-
"./bin":
|
|
29
|
+
"./bin": {
|
|
30
|
+
"jsnext:source": "./src/cli.ts",
|
|
31
|
+
"default": "./bin/modern-js.js"
|
|
32
|
+
}
|
|
29
33
|
},
|
|
30
34
|
"typesVersions": {
|
|
31
35
|
"*": {
|
|
@@ -35,20 +39,12 @@
|
|
|
35
39
|
}
|
|
36
40
|
},
|
|
37
41
|
"bin": "./bin/modern-js.js",
|
|
38
|
-
"scripts": {
|
|
39
|
-
"prepare": "pnpm build",
|
|
40
|
-
"prepublishOnly": "pnpm build -- --platform",
|
|
41
|
-
"new": "modern new",
|
|
42
|
-
"build": "modern build",
|
|
43
|
-
"dev": "modern build --watch",
|
|
44
|
-
"test": "modern test --passWithNoTests"
|
|
45
|
-
},
|
|
46
42
|
"dependencies": {
|
|
47
43
|
"@babel/code-frame": "^7.14.5",
|
|
48
44
|
"@babel/runtime": "^7",
|
|
49
|
-
"@modern-js/load-config": "^1.
|
|
50
|
-
"@modern-js/plugin": "^1.
|
|
51
|
-
"@modern-js/utils": "^1.1
|
|
45
|
+
"@modern-js/load-config": "^1.2.0",
|
|
46
|
+
"@modern-js/plugin": "^1.2.0",
|
|
47
|
+
"@modern-js/utils": "^1.2.1",
|
|
52
48
|
"address": "^1.1.2",
|
|
53
49
|
"ajv": "^8.6.2",
|
|
54
50
|
"ajv-keywords": "^5.0.0",
|
|
@@ -64,8 +60,9 @@
|
|
|
64
60
|
"v8-compile-cache": "^2.3.0"
|
|
65
61
|
},
|
|
66
62
|
"devDependencies": {
|
|
63
|
+
"btsm": "2.2.2",
|
|
67
64
|
"@types/babel__code-frame": "^7.0.3",
|
|
68
|
-
"@modern-js/types": "^1.
|
|
65
|
+
"@modern-js/types": "^1.2.0",
|
|
69
66
|
"@types/jest": "^26",
|
|
70
67
|
"@types/lodash.clonedeep": "^4.5.6",
|
|
71
68
|
"@types/lodash.mergewith": "^4.6.6",
|
|
@@ -74,8 +71,9 @@
|
|
|
74
71
|
"@types/react-dom": "^17",
|
|
75
72
|
"@types/signale": "^1.4.2",
|
|
76
73
|
"typescript": "^4",
|
|
77
|
-
"
|
|
78
|
-
"@
|
|
74
|
+
"jest": "^27",
|
|
75
|
+
"@scripts/build": "0.0.0",
|
|
76
|
+
"@scripts/jest-config": "0.0.0"
|
|
79
77
|
},
|
|
80
78
|
"sideEffects": false,
|
|
81
79
|
"modernConfig": {
|
|
@@ -85,6 +83,14 @@
|
|
|
85
83
|
},
|
|
86
84
|
"publishConfig": {
|
|
87
85
|
"registry": "https://registry.npmjs.org/",
|
|
88
|
-
"access": "public"
|
|
89
|
-
|
|
90
|
-
}
|
|
86
|
+
"access": "public",
|
|
87
|
+
"types": "./dist/types/index.d.ts"
|
|
88
|
+
},
|
|
89
|
+
"scripts": {
|
|
90
|
+
"new": "modern new",
|
|
91
|
+
"build": "modern build",
|
|
92
|
+
"dev": "modern build --watch",
|
|
93
|
+
"test": "jest"
|
|
94
|
+
},
|
|
95
|
+
"readme": "\n<p align=\"center\">\n <a href=\"https://modernjs.dev\" target=\"blank\"><img src=\"https://lf3-static.bytednsdoc.com/obj/eden-cn/ylaelkeh7nuhfnuhf/modernjs-cover.png\" width=\"300\" alt=\"Modern.js Logo\" /></a>\n</p>\n<p align=\"center\">\n现代 Web 工程体系\n <br/>\n <a href=\"https://modernjs.dev\" target=\"blank\">\n modernjs.dev\n </a>\n</p>\n<p align=\"center\">\n The meta-framework suite designed from scratch for frontend-focused modern web development\n</p>\n\n# Introduction\n\n> The doc site ([modernjs.dev](https://modernjs.dev)) and articles are only available in Chinese for now, we are planning to add English versions soon.\n\n- [Modern.js: Hello, World!](https://zhuanlan.zhihu.com/p/426707646)\n\n## Getting Started\n\n- [Quick Start](https://modernjs.dev/docs/start)\n- [Guides](https://modernjs.dev/docs/guides)\n- [API References](https://modernjs.dev/docs/apis)\n\n## Contributing\n\n- [Contributing Guide](https://github.com/modern-js-dev/modern.js/blob/main/CONTRIBUTING.md)\n"
|
|
96
|
+
}
|
package/src/cli.ts
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// 这个文件跟 bin/modern-js.js 基本一样
|
|
2
|
+
// 在开发阶段,因为 package.json 的 exports['./bin']['jsnext:source'] 配置
|
|
3
|
+
// 了这个文件,所以需要保留, 后续如果找到更好的方式之后会移除这个文件
|
|
4
|
+
|
|
5
|
+
import path from 'path';
|
|
6
|
+
import { cli } from '.';
|
|
7
|
+
|
|
8
|
+
const { version } = require('../package.json');
|
|
9
|
+
|
|
10
|
+
// XXX: 通过这个方式去掉了 package.json 里面对于 @modern-js/module-tools 的 devDependencies 依赖
|
|
11
|
+
// 然后可以正常的执行 modern build
|
|
12
|
+
const kModuleToolsCliPath = path.resolve(
|
|
13
|
+
__dirname,
|
|
14
|
+
'../../../solutions/module-tools/src/index.ts',
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
process.env.MODERN_JS_VERSION = version;
|
|
18
|
+
if (!process.env.NODE_ENV) {
|
|
19
|
+
process.env.NODE_ENV =
|
|
20
|
+
// eslint-disable-next-line no-nested-ternary
|
|
21
|
+
['build', 'start', 'deploy'].includes(process.argv[2])
|
|
22
|
+
? 'production'
|
|
23
|
+
: process.argv[2] === 'test'
|
|
24
|
+
? 'test'
|
|
25
|
+
: 'development';
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
cli.run(process.argv.slice(2), {
|
|
29
|
+
plugins: {
|
|
30
|
+
'@modern-js/module-tools': {
|
|
31
|
+
cli: kModuleToolsCliPath,
|
|
32
|
+
// 是否需要强制加载这个组件,跳过 loadPlugins 里面 filter 的检测逻辑
|
|
33
|
+
forced: true,
|
|
34
|
+
} as any,
|
|
35
|
+
},
|
|
36
|
+
});
|
package/src/config/index.ts
CHANGED
|
@@ -24,7 +24,7 @@ const debug = createDebugger('resolve-config');
|
|
|
24
24
|
export { defaults as defaultsConfig };
|
|
25
25
|
export { mergeConfig };
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
interface SourceConfig {
|
|
28
28
|
entries?: Record<
|
|
29
29
|
string,
|
|
30
30
|
| string
|
|
@@ -49,7 +49,7 @@ export interface SourceConfig {
|
|
|
49
49
|
include?: Array<string | RegExp>;
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
|
|
52
|
+
interface OutputConfig {
|
|
53
53
|
assetPrefix?: string;
|
|
54
54
|
htmlPath?: string;
|
|
55
55
|
jsPath?: string;
|
|
@@ -92,7 +92,7 @@ export interface OutputConfig {
|
|
|
92
92
|
enableTsLoader?: boolean;
|
|
93
93
|
}
|
|
94
94
|
|
|
95
|
-
|
|
95
|
+
interface ServerConfig {
|
|
96
96
|
routes?: Record<
|
|
97
97
|
string,
|
|
98
98
|
| string
|
|
@@ -111,12 +111,12 @@ export interface ServerConfig {
|
|
|
111
111
|
enableMicroFrontendDebug?: boolean;
|
|
112
112
|
}
|
|
113
113
|
|
|
114
|
-
|
|
114
|
+
interface DevConfig {
|
|
115
115
|
assetPrefix?: string | boolean;
|
|
116
116
|
https?: boolean;
|
|
117
117
|
}
|
|
118
118
|
|
|
119
|
-
|
|
119
|
+
interface DeployConfig {
|
|
120
120
|
microFrontend?: boolean & Record<string, unknown>;
|
|
121
121
|
domain?: string | Array<string>;
|
|
122
122
|
domainByEntries?: Record<string, string | Array<string>>;
|
|
@@ -126,7 +126,7 @@ type ConfigFunction =
|
|
|
126
126
|
| Record<string, unknown>
|
|
127
127
|
// eslint-disable-next-line @typescript-eslint/no-invalid-void-type
|
|
128
128
|
| ((config: Record<string, unknown>) => Record<string, unknown> | void);
|
|
129
|
-
|
|
129
|
+
interface ToolsConfig {
|
|
130
130
|
webpack?: ConfigFunction;
|
|
131
131
|
babel?: ConfigFunction;
|
|
132
132
|
autoprefixer?: ConfigFunction;
|
|
@@ -139,13 +139,13 @@ export interface ToolsConfig {
|
|
|
139
139
|
esbuild?: Record<string, unknown>;
|
|
140
140
|
}
|
|
141
141
|
|
|
142
|
-
|
|
142
|
+
type RuntimeConfig = Record<string, any>;
|
|
143
143
|
|
|
144
|
-
|
|
144
|
+
interface RuntimeByEntriesConfig {
|
|
145
145
|
[name: string]: RuntimeConfig;
|
|
146
146
|
}
|
|
147
147
|
|
|
148
|
-
|
|
148
|
+
interface UserConfig {
|
|
149
149
|
source?: SourceConfig;
|
|
150
150
|
output?: OutputConfig;
|
|
151
151
|
server?: ServerConfig;
|
|
@@ -157,12 +157,12 @@ export interface UserConfig {
|
|
|
157
157
|
runtimeByEntries?: RuntimeByEntriesConfig;
|
|
158
158
|
}
|
|
159
159
|
|
|
160
|
-
|
|
160
|
+
type ConfigParam =
|
|
161
161
|
| UserConfig
|
|
162
162
|
| Promise<UserConfig>
|
|
163
163
|
| ((env: any) => UserConfig | Promise<UserConfig>);
|
|
164
164
|
|
|
165
|
-
|
|
165
|
+
interface LoadedConfig {
|
|
166
166
|
config: UserConfig;
|
|
167
167
|
filePath: string | false;
|
|
168
168
|
dependencies: string[];
|
|
@@ -175,8 +175,13 @@ export const defineConfig = (config: ConfigParam): ConfigParam => config;
|
|
|
175
175
|
export const loadUserConfig = async (
|
|
176
176
|
appDirectory: string,
|
|
177
177
|
filePath?: string,
|
|
178
|
+
packageJsonConfig?: string,
|
|
178
179
|
): Promise<LoadedConfig> => {
|
|
179
|
-
const loaded = await loadConfig<ConfigParam>(
|
|
180
|
+
const loaded = await loadConfig<ConfigParam>(
|
|
181
|
+
appDirectory,
|
|
182
|
+
filePath,
|
|
183
|
+
packageJsonConfig,
|
|
184
|
+
);
|
|
180
185
|
|
|
181
186
|
const config = !loaded
|
|
182
187
|
? {}
|
|
@@ -186,7 +191,7 @@ export const loadUserConfig = async (
|
|
|
186
191
|
|
|
187
192
|
return {
|
|
188
193
|
config: mergeWith({}, config || {}, loaded?.pkgConfig || {}),
|
|
189
|
-
jsConfig: config || {},
|
|
194
|
+
jsConfig: (config || {}) as any,
|
|
190
195
|
pkgConfig: (loaded?.pkgConfig || {}) as UserConfig,
|
|
191
196
|
filePath: loaded?.path,
|
|
192
197
|
dependencies: loaded?.dependencies || [],
|
|
@@ -226,7 +231,7 @@ export const resolveConfig = async (
|
|
|
226
231
|
loaded: LoadedConfig,
|
|
227
232
|
configs: UserConfig[],
|
|
228
233
|
schemas: PluginValidateSchema[],
|
|
229
|
-
|
|
234
|
+
restartWithExistingPort: number,
|
|
230
235
|
argv: string[],
|
|
231
236
|
): Promise<NormalizedConfig> => {
|
|
232
237
|
const { config: userConfig, jsConfig, pkgConfig } = loaded;
|
|
@@ -282,12 +287,18 @@ export const resolveConfig = async (
|
|
|
282
287
|
throw new Error(`Validate configuration error.`);
|
|
283
288
|
}
|
|
284
289
|
}
|
|
285
|
-
const resolved = mergeConfig([defaults, ...configs, userConfig]);
|
|
290
|
+
const resolved = mergeConfig([defaults as any, ...configs, userConfig]);
|
|
286
291
|
|
|
287
292
|
resolved._raw = loaded.config;
|
|
288
293
|
|
|
289
|
-
if (isDev() && argv[0] === 'dev'
|
|
290
|
-
|
|
294
|
+
if (isDev() && argv[0] === 'dev') {
|
|
295
|
+
if (restartWithExistingPort > 0) {
|
|
296
|
+
// dev server is restarted, should use existing port number
|
|
297
|
+
resolved.server.port = restartWithExistingPort;
|
|
298
|
+
} else {
|
|
299
|
+
// get port for new dev server
|
|
300
|
+
resolved.server.port = await getPort(resolved.server.port!);
|
|
301
|
+
}
|
|
291
302
|
}
|
|
292
303
|
|
|
293
304
|
debug('resolved %o', resolved);
|
|
@@ -295,3 +306,17 @@ export const resolveConfig = async (
|
|
|
295
306
|
return resolved;
|
|
296
307
|
};
|
|
297
308
|
/* eslint-enable max-statements, max-params */
|
|
309
|
+
|
|
310
|
+
export type {
|
|
311
|
+
SourceConfig,
|
|
312
|
+
OutputConfig,
|
|
313
|
+
ServerConfig,
|
|
314
|
+
DevConfig,
|
|
315
|
+
DeployConfig,
|
|
316
|
+
ToolsConfig,
|
|
317
|
+
RuntimeConfig,
|
|
318
|
+
RuntimeByEntriesConfig,
|
|
319
|
+
UserConfig,
|
|
320
|
+
ConfigParam,
|
|
321
|
+
LoadedConfig,
|
|
322
|
+
};
|
package/src/index.ts
CHANGED
|
@@ -20,13 +20,7 @@ import { enable } from '@modern-js/plugin/node';
|
|
|
20
20
|
|
|
21
21
|
import type { Hooks } from '@modern-js/types';
|
|
22
22
|
import { program, Command } from './utils/commander';
|
|
23
|
-
import {
|
|
24
|
-
resolveConfig,
|
|
25
|
-
defineConfig,
|
|
26
|
-
loadUserConfig,
|
|
27
|
-
UserConfig,
|
|
28
|
-
ToolsConfig,
|
|
29
|
-
} from './config';
|
|
23
|
+
import { resolveConfig, loadUserConfig } from './config';
|
|
30
24
|
import { loadPlugins } from './loadPlugins';
|
|
31
25
|
import {
|
|
32
26
|
AppContext,
|
|
@@ -43,8 +37,7 @@ import { NormalizedConfig } from './config/mergeConfig';
|
|
|
43
37
|
import { loadEnv } from './loadEnv';
|
|
44
38
|
|
|
45
39
|
export type { Hooks };
|
|
46
|
-
export
|
|
47
|
-
|
|
40
|
+
export * from './config';
|
|
48
41
|
export * from '@modern-js/plugin';
|
|
49
42
|
export * from '@modern-js/plugin/node';
|
|
50
43
|
|
|
@@ -117,7 +110,6 @@ export const usePlugins = (plugins: string[]) =>
|
|
|
117
110
|
);
|
|
118
111
|
|
|
119
112
|
export {
|
|
120
|
-
defineConfig,
|
|
121
113
|
AppContext,
|
|
122
114
|
ResolvedConfigContext,
|
|
123
115
|
useAppContext,
|
|
@@ -126,15 +118,17 @@ export {
|
|
|
126
118
|
ConfigContext,
|
|
127
119
|
};
|
|
128
120
|
|
|
129
|
-
export type { NormalizedConfig, IAppContext
|
|
121
|
+
export type { NormalizedConfig, IAppContext };
|
|
130
122
|
|
|
131
|
-
const initAppDir = async (): Promise<string> => {
|
|
132
|
-
|
|
123
|
+
const initAppDir = async (cwd?: string): Promise<string> => {
|
|
124
|
+
if (!cwd) {
|
|
125
|
+
// eslint-disable-next-line no-param-reassign
|
|
126
|
+
cwd = process.cwd();
|
|
127
|
+
}
|
|
128
|
+
const pkg = await pkgUp({ cwd });
|
|
133
129
|
|
|
134
130
|
if (!pkg) {
|
|
135
|
-
throw new Error(
|
|
136
|
-
`no package.json found in current work dir: ${process.cwd()}`,
|
|
137
|
-
);
|
|
131
|
+
throw new Error(`no package.json found in current work dir: ${cwd}`);
|
|
138
132
|
}
|
|
139
133
|
|
|
140
134
|
return path.dirname(pkg);
|
|
@@ -142,8 +136,9 @@ const initAppDir = async (): Promise<string> => {
|
|
|
142
136
|
|
|
143
137
|
export interface CoreOptions {
|
|
144
138
|
configFile?: string;
|
|
139
|
+
packageJsonConfig?: string;
|
|
145
140
|
plugins?: typeof INTERNAL_PLUGINS;
|
|
146
|
-
beforeUsePlugins
|
|
141
|
+
beforeUsePlugins?: (
|
|
147
142
|
plugins: any,
|
|
148
143
|
config: any,
|
|
149
144
|
) => { cli: any; cliPath: any; server: any; serverPath: any }[];
|
|
@@ -152,6 +147,7 @@ export interface CoreOptions {
|
|
|
152
147
|
const createCli = () => {
|
|
153
148
|
let hooksRunner: HooksRunner;
|
|
154
149
|
let isRestart = false;
|
|
150
|
+
let restartWithExistingPort = 0;
|
|
155
151
|
|
|
156
152
|
const init = async (argv: string[] = [], options?: CoreOptions) => {
|
|
157
153
|
enable();
|
|
@@ -162,7 +158,11 @@ const createCli = () => {
|
|
|
162
158
|
|
|
163
159
|
loadEnv(appDirectory);
|
|
164
160
|
|
|
165
|
-
const loaded = await loadUserConfig(
|
|
161
|
+
const loaded = await loadUserConfig(
|
|
162
|
+
appDirectory,
|
|
163
|
+
options?.configFile,
|
|
164
|
+
options?.packageJsonConfig,
|
|
165
|
+
);
|
|
166
166
|
|
|
167
167
|
let plugins = loadPlugins(
|
|
168
168
|
appDirectory,
|
|
@@ -208,7 +208,7 @@ const createCli = () => {
|
|
|
208
208
|
loaded,
|
|
209
209
|
extraConfigs as any,
|
|
210
210
|
extraSchemas as any,
|
|
211
|
-
|
|
211
|
+
restartWithExistingPort,
|
|
212
212
|
argv,
|
|
213
213
|
);
|
|
214
214
|
|
|
@@ -249,6 +249,7 @@ const createCli = () => {
|
|
|
249
249
|
|
|
250
250
|
async function restart() {
|
|
251
251
|
isRestart = true;
|
|
252
|
+
restartWithExistingPort = isRestart ? AppContext.use().value?.port ?? 0 : 0;
|
|
252
253
|
|
|
253
254
|
logger.info('Restart...\n');
|
|
254
255
|
|
|
@@ -274,4 +275,4 @@ const createCli = () => {
|
|
|
274
275
|
|
|
275
276
|
export const cli = createCli();
|
|
276
277
|
|
|
277
|
-
export {
|
|
278
|
+
export { initAppDir, initAppContext };
|
package/src/loadPlugins.ts
CHANGED
|
@@ -49,6 +49,28 @@ const resolvePlugin = (appDirectory: string, plugin: PluginConfigItem) => {
|
|
|
49
49
|
return resolved;
|
|
50
50
|
};
|
|
51
51
|
|
|
52
|
+
export function getAppPlugins(
|
|
53
|
+
appDirectory: string,
|
|
54
|
+
pluginConfig: PluginConfig,
|
|
55
|
+
internalPlugins?: typeof INTERNAL_PLUGINS,
|
|
56
|
+
) {
|
|
57
|
+
const allPlugins = internalPlugins || INTERNAL_PLUGINS;
|
|
58
|
+
const appPlugins = [
|
|
59
|
+
...Object.keys(allPlugins)
|
|
60
|
+
.filter(name => {
|
|
61
|
+
const config: any = allPlugins[name];
|
|
62
|
+
if (config.forced === true) {
|
|
63
|
+
// 参考 packages/cli/core/src/cli.ts 文件
|
|
64
|
+
return true;
|
|
65
|
+
}
|
|
66
|
+
return isDepExists(appDirectory, name);
|
|
67
|
+
})
|
|
68
|
+
.map(name => allPlugins[name]),
|
|
69
|
+
...pluginConfig,
|
|
70
|
+
];
|
|
71
|
+
return appPlugins;
|
|
72
|
+
}
|
|
73
|
+
|
|
52
74
|
/**
|
|
53
75
|
* Load internal plugins which in @modern-js scope and user's custom plugins.
|
|
54
76
|
* @param appDirectory - Application root directory.
|
|
@@ -60,12 +82,7 @@ export const loadPlugins = (
|
|
|
60
82
|
pluginConfig: PluginConfig,
|
|
61
83
|
internalPlugins?: typeof INTERNAL_PLUGINS,
|
|
62
84
|
) => {
|
|
63
|
-
const plugins =
|
|
64
|
-
...Object.keys(internalPlugins || INTERNAL_PLUGINS)
|
|
65
|
-
.filter(name => isDepExists(appDirectory, name))
|
|
66
|
-
.map(name => (internalPlugins || INTERNAL_PLUGINS)[name]),
|
|
67
|
-
...pluginConfig,
|
|
68
|
-
];
|
|
85
|
+
const plugins = getAppPlugins(appDirectory, pluginConfig, internalPlugins);
|
|
69
86
|
|
|
70
87
|
return plugins.map(plugin => {
|
|
71
88
|
const { cli, server } = resolvePlugin(appDirectory, plugin);
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
import { spawnSync } from 'child_process';
|
|
3
|
+
|
|
4
|
+
const kPackageDir = path.resolve(__dirname, '..');
|
|
5
|
+
|
|
6
|
+
describe('jsnext:source', () => {
|
|
7
|
+
test('process exit status is 0', () => {
|
|
8
|
+
const { status, stdout, stderr } = spawnSync(
|
|
9
|
+
process.execPath,
|
|
10
|
+
['--conditions=jsnext:source', '-r', 'btsm', 'src/cli.ts'],
|
|
11
|
+
{
|
|
12
|
+
cwd: kPackageDir,
|
|
13
|
+
encoding: 'utf-8',
|
|
14
|
+
},
|
|
15
|
+
);
|
|
16
|
+
expect(stdout).toBe('');
|
|
17
|
+
expect(stderr.startsWith('Usage: modern <command> [options]')).toBe(true);
|
|
18
|
+
expect(status).toBe(1);
|
|
19
|
+
});
|
|
20
|
+
});
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
// import os from 'os';
|
|
3
|
+
import { isDev, getPort } from '@modern-js/utils';
|
|
4
|
+
import { resolveConfig } from '../src/config';
|
|
5
|
+
import {
|
|
6
|
+
cli,
|
|
7
|
+
loadUserConfig,
|
|
8
|
+
initAppContext,
|
|
9
|
+
initAppDir,
|
|
10
|
+
manager,
|
|
11
|
+
createPlugin,
|
|
12
|
+
registerHook,
|
|
13
|
+
useRunner,
|
|
14
|
+
} from '../src';
|
|
15
|
+
import { defaults } from '../src/config/defaults';
|
|
16
|
+
|
|
17
|
+
jest.mock('@modern-js/utils', () => ({
|
|
18
|
+
__esModule: true,
|
|
19
|
+
...jest.requireActual('@modern-js/utils'),
|
|
20
|
+
isDev: jest.fn(),
|
|
21
|
+
getPort: jest.fn(),
|
|
22
|
+
}));
|
|
23
|
+
|
|
24
|
+
// const kOSRootDir =
|
|
25
|
+
// os.platform() === 'win32' ? process.cwd().split(path.sep)[0] : '/';
|
|
26
|
+
|
|
27
|
+
describe('config', () => {
|
|
28
|
+
/**
|
|
29
|
+
* Typescript Type annotations cannot be used for esbuild-jest
|
|
30
|
+
* test files that use jest.mock('@some/module')
|
|
31
|
+
* refer to this esbuild-jest issue:
|
|
32
|
+
* https://github.com/aelbore/esbuild-jest/issues/57
|
|
33
|
+
* TODO: find a better solution to solve this problem while allowing us
|
|
34
|
+
* to use esbuild, and have good TypeScript support
|
|
35
|
+
*/
|
|
36
|
+
let loaded = {
|
|
37
|
+
config: {},
|
|
38
|
+
filePath: '',
|
|
39
|
+
dependencies: [],
|
|
40
|
+
pkgConfig: {},
|
|
41
|
+
jsConfig: {},
|
|
42
|
+
};
|
|
43
|
+
let schemas: any[] = [];
|
|
44
|
+
let restartWithExistingPort = 0;
|
|
45
|
+
let argv: string[] = ['dev'];
|
|
46
|
+
let configs: any[] = [];
|
|
47
|
+
|
|
48
|
+
const getResolvedConfig = async () =>
|
|
49
|
+
resolveConfig(loaded, configs, schemas, restartWithExistingPort, argv);
|
|
50
|
+
|
|
51
|
+
const resetParams = () => {
|
|
52
|
+
loaded = {
|
|
53
|
+
config: {},
|
|
54
|
+
filePath: '',
|
|
55
|
+
dependencies: [],
|
|
56
|
+
pkgConfig: {},
|
|
57
|
+
jsConfig: {},
|
|
58
|
+
};
|
|
59
|
+
schemas = [];
|
|
60
|
+
restartWithExistingPort = 0;
|
|
61
|
+
argv = ['dev'];
|
|
62
|
+
configs = [];
|
|
63
|
+
};
|
|
64
|
+
const resetMock = () => {
|
|
65
|
+
jest.resetAllMocks();
|
|
66
|
+
(isDev as jest.Mock).mockReturnValue(true);
|
|
67
|
+
(getPort as jest.Mock).mockReturnValue(
|
|
68
|
+
Promise.resolve(defaults.server.port),
|
|
69
|
+
);
|
|
70
|
+
};
|
|
71
|
+
beforeEach(() => {
|
|
72
|
+
resetParams();
|
|
73
|
+
resetMock();
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it('default', () => {
|
|
77
|
+
expect(resolveConfig).toBeDefined();
|
|
78
|
+
expect(cli).toBeDefined();
|
|
79
|
+
expect(loadUserConfig).toBeDefined();
|
|
80
|
+
expect(initAppContext).toBeDefined();
|
|
81
|
+
expect(initAppDir).toBeDefined();
|
|
82
|
+
expect(manager).toBeDefined();
|
|
83
|
+
expect(createPlugin).toBeDefined();
|
|
84
|
+
expect(registerHook).toBeDefined();
|
|
85
|
+
expect(useRunner).toBeDefined();
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
it('initAppDir', async () => {
|
|
89
|
+
expect(await initAppDir(__dirname)).toBe(path.resolve(__dirname, '..'));
|
|
90
|
+
// expect(await initAppDir()).toBe(path.resolve(__dirname, '..'));
|
|
91
|
+
|
|
92
|
+
// FIXME: windows 下面会失败,先忽略这个测试
|
|
93
|
+
// try {
|
|
94
|
+
// await initAppDir(kOSRootDir);
|
|
95
|
+
// expect(true).toBe(false); // SHOULD NOT BE HERE
|
|
96
|
+
// } catch (err: any) {
|
|
97
|
+
// expect(err.message).toMatch(/no package.json found in current work dir/);
|
|
98
|
+
// }
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
test('should use default port if not restarting in dev mode', async () => {
|
|
102
|
+
let resolved = await getResolvedConfig();
|
|
103
|
+
expect(resolved.server.port).toEqual(defaults.server.port);
|
|
104
|
+
expect(getPort).toHaveBeenCalledWith(defaults.server.port);
|
|
105
|
+
|
|
106
|
+
// getResolvedConfig should use the value givin by getPort
|
|
107
|
+
restartWithExistingPort = -1;
|
|
108
|
+
(getPort as jest.Mock).mockClear();
|
|
109
|
+
(getPort as jest.Mock).mockReturnValue(1111);
|
|
110
|
+
resolved = await getResolvedConfig();
|
|
111
|
+
expect(resolved.server.port).toEqual(1111);
|
|
112
|
+
expect(getPort).toHaveBeenCalledWith(defaults.server.port);
|
|
113
|
+
|
|
114
|
+
argv = ['start'];
|
|
115
|
+
(isDev as jest.Mock).mockReturnValue(false);
|
|
116
|
+
restartWithExistingPort = 0;
|
|
117
|
+
resolved = await getResolvedConfig();
|
|
118
|
+
expect(resolved.server.port).toEqual(defaults.server.port);
|
|
119
|
+
|
|
120
|
+
restartWithExistingPort = 1234;
|
|
121
|
+
resolved = await getResolvedConfig();
|
|
122
|
+
expect(resolved.server.port).toEqual(defaults.server.port);
|
|
123
|
+
|
|
124
|
+
restartWithExistingPort = -1;
|
|
125
|
+
resolved = await getResolvedConfig();
|
|
126
|
+
expect(resolved.server.port).toEqual(defaults.server.port);
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
test('should reuse existing port if restarting in dev mode', async () => {
|
|
130
|
+
restartWithExistingPort = 1234;
|
|
131
|
+
const resolved = await getResolvedConfig();
|
|
132
|
+
expect(resolved.server.port).toEqual(1234);
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
// type TEST = Parameters<typeof resolveConfig>;
|
|
137
|
+
// type TypeC = TEST[1];
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import path from 'path';
|
|
2
|
+
import { initAppContext } from '../src/context';
|
|
3
|
+
|
|
4
|
+
describe('context', () => {
|
|
5
|
+
it('initAppContext', () => {
|
|
6
|
+
const appDirectory = path.resolve(
|
|
7
|
+
__dirname,
|
|
8
|
+
'./fixtures/load-plugin/user-plugins',
|
|
9
|
+
);
|
|
10
|
+
const appContext = initAppContext(appDirectory, [], false);
|
|
11
|
+
expect(appContext).toEqual({
|
|
12
|
+
appDirectory,
|
|
13
|
+
configFile: false,
|
|
14
|
+
ip: expect.any(String),
|
|
15
|
+
port: 0,
|
|
16
|
+
packageName: expect.any(String),
|
|
17
|
+
srcDirectory: expect.any(String),
|
|
18
|
+
distDirectory: expect.any(String),
|
|
19
|
+
sharedDirectory: expect.any(String),
|
|
20
|
+
nodeModulesDirectory: expect.any(String),
|
|
21
|
+
internalDirectory: expect.any(String),
|
|
22
|
+
plugins: [],
|
|
23
|
+
htmlTemplates: {},
|
|
24
|
+
serverRoutes: [],
|
|
25
|
+
entrypoints: [],
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
});
|