@modern-js/core 1.2.1-rc.0 → 1.4.0

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 (53) hide show
  1. package/CHANGELOG.md +57 -5
  2. package/dist/js/modern/cli.js +29 -0
  3. package/dist/js/modern/config/index.js +11 -5
  4. package/dist/js/modern/context.js +28 -16
  5. package/dist/js/modern/index.js +27 -12
  6. package/dist/js/modern/initWatcher.js +19 -3
  7. package/dist/js/modern/loadPlugins.js +21 -6
  8. package/dist/js/node/cli.js +35 -0
  9. package/dist/js/node/config/index.js +11 -5
  10. package/dist/js/node/context.js +28 -16
  11. package/dist/js/node/index.js +36 -39
  12. package/dist/js/node/initWatcher.js +18 -2
  13. package/dist/js/node/loadPlugins.js +22 -5
  14. package/dist/types/cli.d.ts +1 -0
  15. package/dist/types/config/index.d.ts +20 -14
  16. package/dist/types/context.d.ts +6 -1
  17. package/dist/types/index.d.ts +22 -7
  18. package/dist/types/initWatcher.d.ts +2 -1
  19. package/dist/types/loadPlugins.d.ts +8 -1
  20. package/jest.config.js +8 -0
  21. package/modern.config.js +0 -7
  22. package/package.json +17 -10
  23. package/tests/btsm.test.ts +20 -0
  24. package/tests/config.test.ts +137 -0
  25. package/tests/context.test.ts +68 -0
  26. package/tests/fixtures/index-test/package.json +3 -0
  27. package/tests/index.test.ts +74 -0
  28. package/tests/initWatcher.test.ts +63 -0
  29. package/tests/loadEnv.test.ts +1 -1
  30. package/tests/loadPlugin.test.ts +36 -2
  31. package/tests/mergeConfig.test.ts +1 -1
  32. package/tests/repeatKeyWarning.test.ts +2 -2
  33. package/tests/schema.test.ts +1 -1
  34. package/tests/tsconfig.json +1 -3
  35. package/tests/utils.test.ts +8 -0
  36. package/tsconfig.json +1 -3
  37. package/src/config/defaults.ts +0 -101
  38. package/src/config/index.ts +0 -297
  39. package/src/config/mergeConfig.ts +0 -69
  40. package/src/config/schema/deploy.ts +0 -17
  41. package/src/config/schema/index.ts +0 -116
  42. package/src/config/schema/output.ts +0 -65
  43. package/src/config/schema/server.ts +0 -106
  44. package/src/config/schema/source.ts +0 -34
  45. package/src/config/schema/tools.ts +0 -15
  46. package/src/context.ts +0 -46
  47. package/src/index.ts +0 -277
  48. package/src/initWatcher.ts +0 -77
  49. package/src/loadEnv.ts +0 -23
  50. package/src/loadPlugins.ts +0 -91
  51. package/src/types.d.ts +0 -0
  52. package/src/utils/commander.ts +0 -22
  53. package/src/utils/repeatKeyWarning.ts +0 -29
package/CHANGELOG.md CHANGED
@@ -1,13 +1,65 @@
1
1
  # @modern-js/core
2
2
 
3
- ## 1.2.1-rc.0
3
+ ## 1.4.0
4
+
5
+ ### Minor Changes
6
+
7
+ - bada2879: refactor plugin-garfish:
8
+ - change @modern-js/plugin-micro-frontend => @modern-js/plugin-garfish
9
+ - remove disableCustomerRouter logic
10
+ - adding unit test
11
+ - fix plugin-garfish type error
4
12
 
5
13
  ### Patch Changes
6
14
 
7
- - Updated dependencies [b7fb82ec]
8
- - @modern-js/utils@1.1.6-rc.0
9
- - @modern-js/load-config@1.1.2-rc.0
10
- - @modern-js/plugin@1.1.2
15
+ - d9cc5ea9: support resatrt options transfer
16
+ - bd819a8d: fix: file route changed not trigger hot reload
17
+ - d099e5c5: fix error when modify modern.config.js
18
+ - 24f616ca: feat: support custom meta info
19
+ - Updated dependencies [ec4dbffb]
20
+ - Updated dependencies [d099e5c5]
21
+ - Updated dependencies [bada2879]
22
+ - Updated dependencies [24f616ca]
23
+ - Updated dependencies [bd819a8d]
24
+ - @modern-js/utils@1.3.0
25
+
26
+ ## 1.3.2
27
+
28
+ ### Patch Changes
29
+
30
+ - 83166714: change .npmignore
31
+ - c3de9882: fix: internalDirectory path
32
+ - 33ff48af: feat: extend CoreOptions
33
+ - Updated dependencies [83166714]
34
+ - @modern-js/load-config@1.2.1
35
+ - @modern-js/plugin@1.2.1
36
+ - @modern-js/utils@1.2.2
37
+
38
+ ## 1.3.1
39
+
40
+ ### Patch Changes
41
+
42
+ - 4584cc04: export DeployConfig interface
43
+ - 7c19fd94: use existing port number for AppContext when dev server is restarted
44
+ - Updated dependencies [823809c6]
45
+ - @modern-js/utils@1.2.1
46
+
47
+ ## 1.3.0
48
+
49
+ ### Minor Changes
50
+
51
+ - fc71e36f: support custom property name for the config in package.json
52
+ - cfe11628: Make Modern.js self bootstraping
53
+
54
+ ### Patch Changes
55
+
56
+ - Updated dependencies [2da09c69]
57
+ - Updated dependencies [fc71e36f]
58
+ - Updated dependencies [c3d46ee4]
59
+ - Updated dependencies [cfe11628]
60
+ - @modern-js/utils@1.2.0
61
+ - @modern-js/load-config@1.2.0
62
+ - @modern-js/plugin@1.2.0
11
63
 
12
64
  ## 1.2.0
13
65
 
@@ -0,0 +1,29 @@
1
+ // 这个文件跟 bin/modern-js.js 基本一样
2
+ // 在开发阶段,因为 package.json 的 exports['./bin']['jsnext:source'] 配置
3
+ // 了这个文件,所以需要保留, 后续如果找到更好的方式之后会移除这个文件
4
+ import path from 'path';
5
+ import { cli } from ".";
6
+
7
+ const {
8
+ version
9
+ } = require("../../package.json"); // XXX: 通过这个方式去掉了 package.json 里面对于 @modern-js/module-tools 的 devDependencies 依赖
10
+ // 然后可以正常的执行 modern build
11
+
12
+
13
+ const kModuleToolsCliPath = path.resolve(__dirname, '../../../solutions/module-tools/src/index.ts');
14
+ process.env.MODERN_JS_VERSION = version;
15
+
16
+ if (!process.env.NODE_ENV) {
17
+ process.env.NODE_ENV = // eslint-disable-next-line no-nested-ternary
18
+ ['build', 'start', 'deploy'].includes(process.argv[2]) ? 'production' : process.argv[2] === 'test' ? 'test' : 'development';
19
+ }
20
+
21
+ cli.run(process.argv.slice(2), {
22
+ plugins: {
23
+ '@modern-js/module-tools': {
24
+ cli: kModuleToolsCliPath,
25
+ // 是否需要强制加载这个组件,跳过 loadPlugins 里面 filter 的检测逻辑
26
+ forced: true
27
+ }
28
+ }
29
+ });
@@ -20,8 +20,8 @@ const debug = createDebugger('resolve-config');
20
20
  export { defaults as defaultsConfig };
21
21
  export { mergeConfig };
22
22
  export const defineConfig = config => config;
23
- export const loadUserConfig = async (appDirectory, filePath) => {
24
- const loaded = await loadConfig(appDirectory, filePath);
23
+ export const loadUserConfig = async (appDirectory, filePath, packageJsonConfig) => {
24
+ const loaded = await loadConfig(appDirectory, filePath, packageJsonConfig);
25
25
  const config = !loaded ? {} : await (typeof loaded.config === 'function' ? loaded.config(0) : loaded.config);
26
26
  return {
27
27
  config: mergeWith({}, config || {}, (loaded === null || loaded === void 0 ? void 0 : loaded.pkgConfig) || {}),
@@ -45,7 +45,7 @@ const showAdditionalPropertiesError = error => {
45
45
  /* eslint-disable max-statements, max-params */
46
46
 
47
47
 
48
- export const resolveConfig = async (loaded, configs, schemas, isRestart, argv) => {
48
+ export const resolveConfig = async (loaded, configs, schemas, restartWithExistingPort, argv) => {
49
49
  var _validate$errors;
50
50
 
51
51
  const {
@@ -95,8 +95,14 @@ export const resolveConfig = async (loaded, configs, schemas, isRestart, argv) =
95
95
  const resolved = mergeConfig([defaults, ...configs, userConfig]);
96
96
  resolved._raw = loaded.config;
97
97
 
98
- if (isDev() && argv[0] === 'dev' && !isRestart) {
99
- resolved.server.port = await getPort(resolved.server.port);
98
+ if (isDev() && argv[0] === 'dev') {
99
+ if (restartWithExistingPort > 0) {
100
+ // dev server is restarted, should use existing port number
101
+ resolved.server.port = restartWithExistingPort;
102
+ } else {
103
+ // get port for new dev server
104
+ resolved.server.port = await getPort(resolved.server.port);
105
+ }
100
106
  }
101
107
 
102
108
  debug('resolved %o', resolved);
@@ -7,19 +7,31 @@ export const ResolvedConfigContext = createContext({});
7
7
  export const useAppContext = () => AppContext.use().value;
8
8
  export const useConfigContext = () => ConfigContext.use().value;
9
9
  export const useResolvedConfigContext = () => ResolvedConfigContext.use().value;
10
- export const initAppContext = (appDirectory, plugins, configFile) => ({
11
- appDirectory,
12
- configFile,
13
- ip: address.ip(),
14
- port: 0,
15
- packageName: require(path.resolve(appDirectory, './package.json')).name,
16
- srcDirectory: path.resolve(appDirectory, './src'),
17
- distDirectory: '',
18
- sharedDirectory: path.resolve(appDirectory, './shared'),
19
- nodeModulesDirectory: path.resolve(appDirectory, './node_modules'),
20
- internalDirectory: path.resolve(appDirectory, './node_modules/.modern-js'),
21
- plugins,
22
- htmlTemplates: {},
23
- serverRoutes: [],
24
- entrypoints: []
25
- });
10
+ export const initAppContext = (appDirectory, plugins, configFile, options) => {
11
+ const {
12
+ metaName = 'modern-js',
13
+ srcDir = 'src',
14
+ distDir = '',
15
+ sharedDir = 'shared'
16
+ } = options || {};
17
+ return {
18
+ metaName,
19
+ appDirectory,
20
+ configFile,
21
+ ip: address.ip(),
22
+ port: 0,
23
+ packageName: require(path.resolve(appDirectory, './package.json')).name,
24
+ srcDirectory: path.resolve(appDirectory, srcDir),
25
+ distDirectory: distDir,
26
+ sharedDirectory: path.resolve(appDirectory, sharedDir),
27
+ nodeModulesDirectory: path.resolve(appDirectory, './node_modules'),
28
+ internalDirectory: path.resolve(appDirectory, `./node_modules/.${metaName}`),
29
+ plugins,
30
+ htmlTemplates: {},
31
+ serverRoutes: [],
32
+ entrypoints: [],
33
+ existSrc: true,
34
+ internalDirAlias: `@_${metaName.replace(/-/g, '_')}_internal`,
35
+ internalSrcAlias: `@_${metaName.replace(/-/g, '_')}_src`
36
+ };
37
+ };
@@ -9,12 +9,12 @@ import { compatRequire, pkgUp, ensureAbsolutePath, logger } from '@modern-js/uti
9
9
  import { createAsyncManager, createAsyncWorkflow, createParallelWorkflow, createAsyncWaterfall } from '@modern-js/plugin';
10
10
  import { enable } from '@modern-js/plugin/node';
11
11
  import { program } from "./utils/commander";
12
- import { resolveConfig, defineConfig, loadUserConfig } from "./config";
12
+ import { resolveConfig, loadUserConfig } from "./config";
13
13
  import { loadPlugins } from "./loadPlugins";
14
14
  import { AppContext, ConfigContext, initAppContext, ResolvedConfigContext, useAppContext, useConfigContext, useResolvedConfigContext } from "./context";
15
15
  import { initWatcher } from "./initWatcher";
16
16
  import { loadEnv } from "./loadEnv";
17
- export { defaultsConfig, mergeConfig } from "./config";
17
+ export * from "./config";
18
18
  export * from '@modern-js/plugin';
19
19
  export * from '@modern-js/plugin/node';
20
20
  program.name('modern').usage('<command> [options]').version(process.env.MODERN_JS_VERSION || '0.1.0');
@@ -28,7 +28,9 @@ const hooksMap = {
28
28
  watchFiles: createParallelWorkflow(),
29
29
  fileChange: createAsyncWorkflow(),
30
30
  // eslint-disable-next-line @typescript-eslint/no-invalid-void-type
31
- beforeExit: createAsyncWorkflow()
31
+ beforeExit: createAsyncWorkflow(),
32
+ // eslint-disable-next-line @typescript-eslint/no-invalid-void-type
33
+ beforeRestart: createAsyncWorkflow()
32
34
  };
33
35
  export const manager = createAsyncManager(hooksMap);
34
36
  export const {
@@ -37,15 +39,20 @@ export const {
37
39
  useRunner: mountHook
38
40
  } = manager;
39
41
  export const usePlugins = plugins => plugins.forEach(plugin => manager.usePlugin(compatRequire(require.resolve(plugin))));
40
- export { defineConfig, AppContext, ResolvedConfigContext, useAppContext, useConfigContext, useResolvedConfigContext, ConfigContext };
42
+ export { AppContext, ResolvedConfigContext, useAppContext, useConfigContext, useResolvedConfigContext, ConfigContext };
43
+
44
+ const initAppDir = async cwd => {
45
+ if (!cwd) {
46
+ // eslint-disable-next-line no-param-reassign
47
+ cwd = process.cwd();
48
+ }
41
49
 
42
- const initAppDir = async () => {
43
50
  const pkg = await pkgUp({
44
- cwd: process.cwd()
51
+ cwd
45
52
  });
46
53
 
47
54
  if (!pkg) {
48
- throw new Error(`no package.json found in current work dir: ${process.cwd()}`);
55
+ throw new Error(`no package.json found in current work dir: ${cwd}`);
49
56
  }
50
57
 
51
58
  return path.dirname(pkg);
@@ -54,13 +61,16 @@ const initAppDir = async () => {
54
61
  const createCli = () => {
55
62
  let hooksRunner;
56
63
  let isRestart = false;
64
+ let restartWithExistingPort = 0;
65
+ let restartOptions;
57
66
 
58
67
  const init = async (argv = [], options) => {
59
68
  enable();
60
69
  manager.clear();
70
+ restartOptions = options;
61
71
  const appDirectory = await initAppDir();
62
72
  loadEnv(appDirectory);
63
- const loaded = await loadUserConfig(appDirectory, options === null || options === void 0 ? void 0 : options.configFile);
73
+ const loaded = await loadUserConfig(appDirectory, options === null || options === void 0 ? void 0 : options.configFile, options === null || options === void 0 ? void 0 : options.packageJsonConfig);
64
74
  let plugins = loadPlugins(appDirectory, loaded.config.plugins || [], options === null || options === void 0 ? void 0 : options.plugins);
65
75
 
66
76
  if (options !== null && options !== void 0 && options.beforeUsePlugins) {
@@ -68,7 +78,7 @@ const createCli = () => {
68
78
  }
69
79
 
70
80
  plugins.forEach(plugin => plugin.cli && manager.usePlugin(plugin.cli));
71
- const appContext = initAppContext(appDirectory, plugins, loaded.filePath);
81
+ const appContext = initAppContext(appDirectory, plugins, loaded.filePath, options === null || options === void 0 ? void 0 : options.options);
72
82
  manager.run(() => {
73
83
  ConfigContext.set(loaded.config);
74
84
  AppContext.set(appContext);
@@ -90,7 +100,7 @@ const createCli = () => {
90
100
  });
91
101
  const extraConfigs = await hooksRunner.config();
92
102
  const extraSchemas = await hooksRunner.validateSchema();
93
- const config = await resolveConfig(loaded, extraConfigs, extraSchemas, isRestart, argv);
103
+ const config = await resolveConfig(loaded, extraConfigs, extraSchemas, restartWithExistingPort, argv);
94
104
  const {
95
105
  resolved
96
106
  } = await hooksRunner.resolvedConfig({
@@ -127,12 +137,17 @@ const createCli = () => {
127
137
  }
128
138
 
129
139
  async function restart() {
140
+ var _AppContext$use$value, _AppContext$use$value2;
141
+
130
142
  isRestart = true;
143
+ restartWithExistingPort = isRestart ? (_AppContext$use$value = (_AppContext$use$value2 = AppContext.use().value) === null || _AppContext$use$value2 === void 0 ? void 0 : _AppContext$use$value2.port) !== null && _AppContext$use$value !== void 0 ? _AppContext$use$value : 0 : 0;
131
144
  logger.info('Restart...\n');
132
145
  let hasGetError = false;
146
+ const runner = manager.useRunner();
147
+ await runner.beforeRestart();
133
148
 
134
149
  try {
135
- await init(process.argv.slice(2));
150
+ await init(process.argv.slice(2), restartOptions);
136
151
  } catch (err) {
137
152
  console.error(err);
138
153
  hasGetError = true;
@@ -151,4 +166,4 @@ const createCli = () => {
151
166
  };
152
167
 
153
168
  export const cli = createCli();
154
- export { loadUserConfig, initAppDir, initAppContext };
169
+ export { initAppDir, initAppContext };
@@ -1,7 +1,7 @@
1
1
  import crypto from 'crypto';
2
2
  import fs from 'fs';
3
3
  import path from 'path';
4
- import { isDev, createDebugger } from '@modern-js/utils';
4
+ import { isDev, createDebugger, isTest } from '@modern-js/utils';
5
5
  import chokidar from 'chokidar';
6
6
  const debug = createDebugger('watch-files');
7
7
 
@@ -10,7 +10,7 @@ const md5 = data => crypto.createHash('md5').update(data).digest('hex');
10
10
  const hashMap = new Map();
11
11
  export const initWatcher = async (loaded, appDirectory, configDir, hooksRunner, argv) => {
12
12
  // only add fs watcher on dev mode.
13
- if (isDev() && argv[0] === 'dev') {
13
+ if ((isDev() || isTest()) && argv[0] === 'dev') {
14
14
  const extraFiles = await hooksRunner.watchFiles();
15
15
  const configPath = path.join(appDirectory, configDir);
16
16
  const watched = [`${configPath}/html`, ...extraFiles, loaded === null || loaded === void 0 ? void 0 : loaded.filePath, ...loaded.dependencies].filter(Boolean);
@@ -28,19 +28,35 @@ export const initWatcher = async (loaded, appDirectory, configDir, hooksRunner,
28
28
  debug(`file change: %s`, changed);
29
29
  hashMap.set(changed, currentHash);
30
30
  hooksRunner.fileChange({
31
- filename: changed
31
+ filename: changed,
32
+ eventType: 'change'
32
33
  });
33
34
  }
34
35
  });
36
+ watcher.on('add', name => {
37
+ debug(`add file: %s`, name);
38
+ const currentHash = md5(fs.readFileSync(path.join(appDirectory, name), 'utf8'));
39
+ hashMap.set(name, currentHash);
40
+ hooksRunner.fileChange({
41
+ filename: name,
42
+ eventType: 'add'
43
+ });
44
+ });
35
45
  watcher.on('unlink', name => {
36
46
  debug(`remove file: %s`, name);
37
47
 
38
48
  if (hashMap.has(name)) {
39
49
  hashMap.delete(name);
40
50
  }
51
+
52
+ hooksRunner.fileChange({
53
+ filename: name,
54
+ eventType: 'unlink'
55
+ });
41
56
  });
42
57
  watcher.on('error', err => {
43
58
  throw err;
44
59
  });
60
+ return watcher;
45
61
  }
46
62
  };
@@ -45,6 +45,21 @@ const resolvePlugin = (appDirectory, plugin) => {
45
45
 
46
46
  return resolved;
47
47
  };
48
+
49
+ export function getAppPlugins(appDirectory, pluginConfig, internalPlugins) {
50
+ const allPlugins = internalPlugins || INTERNAL_PLUGINS;
51
+ const appPlugins = [...Object.keys(allPlugins).filter(name => {
52
+ const config = allPlugins[name];
53
+
54
+ if (config.forced === true) {
55
+ // 参考 packages/cli/core/src/cli.ts 文件
56
+ return true;
57
+ }
58
+
59
+ return isDepExists(appDirectory, name);
60
+ }).map(name => allPlugins[name]), ...pluginConfig];
61
+ return appPlugins;
62
+ }
48
63
  /**
49
64
  * Load internal plugins which in @modern-js scope and user's custom plugins.
50
65
  * @param appDirectory - Application root directory.
@@ -52,9 +67,8 @@ const resolvePlugin = (appDirectory, plugin) => {
52
67
  * @returns Plugin Objects has been required.
53
68
  */
54
69
 
55
-
56
70
  export const loadPlugins = (appDirectory, pluginConfig, internalPlugins) => {
57
- const plugins = [...Object.keys(internalPlugins || INTERNAL_PLUGINS).filter(name => isDepExists(appDirectory, name)).map(name => (internalPlugins || INTERNAL_PLUGINS)[name]), ...pluginConfig];
71
+ const plugins = getAppPlugins(appDirectory, pluginConfig, internalPlugins);
58
72
  return plugins.map(plugin => {
59
73
  const {
60
74
  cli,
@@ -67,12 +81,13 @@ export const loadPlugins = (appDirectory, pluginConfig, internalPlugins) => {
67
81
 
68
82
  const cliPlugin = cli && _objectSpread(_objectSpread({}, compatRequire(cli)), {}, {
69
83
  pluginPath: cli
70
- });
84
+ }); // server plugin should be required by server
71
85
 
72
- const serverPlugin = server && _objectSpread(_objectSpread({}, compatRequire(server)), {}, {
73
- pluginPath: server
74
- });
75
86
 
87
+ const serverPlugin = server && {
88
+ // ...compatRequire(server),
89
+ pluginPath: server
90
+ };
76
91
  return {
77
92
  cli: cliPlugin,
78
93
  cliPath: typeof plugin === 'string' ? plugin : plugin.cli,
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+
3
+ var _path = _interopRequireDefault(require("path"));
4
+
5
+ var _ = require(".");
6
+
7
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
8
+
9
+ // 这个文件跟 bin/modern-js.js 基本一样
10
+ // 在开发阶段,因为 package.json 的 exports['./bin']['jsnext:source'] 配置
11
+ // 了这个文件,所以需要保留, 后续如果找到更好的方式之后会移除这个文件
12
+ const {
13
+ version
14
+ } = require("../../package.json"); // XXX: 通过这个方式去掉了 package.json 里面对于 @modern-js/module-tools 的 devDependencies 依赖
15
+ // 然后可以正常的执行 modern build
16
+
17
+
18
+ const kModuleToolsCliPath = _path.default.resolve(__dirname, '../../../solutions/module-tools/src/index.ts');
19
+
20
+ process.env.MODERN_JS_VERSION = version;
21
+
22
+ if (!process.env.NODE_ENV) {
23
+ process.env.NODE_ENV = // eslint-disable-next-line no-nested-ternary
24
+ ['build', 'start', 'deploy'].includes(process.argv[2]) ? 'production' : process.argv[2] === 'test' ? 'test' : 'development';
25
+ }
26
+
27
+ _.cli.run(process.argv.slice(2), {
28
+ plugins: {
29
+ '@modern-js/module-tools': {
30
+ cli: kModuleToolsCliPath,
31
+ // 是否需要强制加载这个组件,跳过 loadPlugins 里面 filter 的检测逻辑
32
+ forced: true
33
+ }
34
+ }
35
+ });
@@ -56,8 +56,8 @@ const defineConfig = config => config;
56
56
 
57
57
  exports.defineConfig = defineConfig;
58
58
 
59
- const loadUserConfig = async (appDirectory, filePath) => {
60
- const loaded = await (0, _loadConfig.loadConfig)(appDirectory, filePath);
59
+ const loadUserConfig = async (appDirectory, filePath, packageJsonConfig) => {
60
+ const loaded = await (0, _loadConfig.loadConfig)(appDirectory, filePath, packageJsonConfig);
61
61
  const config = !loaded ? {} : await (typeof loaded.config === 'function' ? loaded.config(0) : loaded.config);
62
62
  return {
63
63
  config: (0, _lodash.default)({}, config || {}, (loaded === null || loaded === void 0 ? void 0 : loaded.pkgConfig) || {}),
@@ -83,7 +83,7 @@ const showAdditionalPropertiesError = error => {
83
83
  /* eslint-disable max-statements, max-params */
84
84
 
85
85
 
86
- const resolveConfig = async (loaded, configs, schemas, isRestart, argv) => {
86
+ const resolveConfig = async (loaded, configs, schemas, restartWithExistingPort, argv) => {
87
87
  var _validate$errors;
88
88
 
89
89
  const {
@@ -136,8 +136,14 @@ const resolveConfig = async (loaded, configs, schemas, isRestart, argv) => {
136
136
  const resolved = (0, _mergeConfig.mergeConfig)([_defaults.defaults, ...configs, userConfig]);
137
137
  resolved._raw = loaded.config;
138
138
 
139
- if ((0, _utils.isDev)() && argv[0] === 'dev' && !isRestart) {
140
- resolved.server.port = await (0, _utils.getPort)(resolved.server.port);
139
+ if ((0, _utils.isDev)() && argv[0] === 'dev') {
140
+ if (restartWithExistingPort > 0) {
141
+ // dev server is restarted, should use existing port number
142
+ resolved.server.port = restartWithExistingPort;
143
+ } else {
144
+ // get port for new dev server
145
+ resolved.server.port = await (0, _utils.getPort)(resolved.server.port);
146
+ }
141
147
  }
142
148
 
143
149
  debug('resolved %o', resolved);
@@ -32,21 +32,33 @@ const useResolvedConfigContext = () => ResolvedConfigContext.use().value;
32
32
 
33
33
  exports.useResolvedConfigContext = useResolvedConfigContext;
34
34
 
35
- const initAppContext = (appDirectory, plugins, configFile) => ({
36
- appDirectory,
37
- configFile,
38
- ip: _address.default.ip(),
39
- port: 0,
40
- packageName: require(_path.default.resolve(appDirectory, './package.json')).name,
41
- srcDirectory: _path.default.resolve(appDirectory, './src'),
42
- distDirectory: '',
43
- sharedDirectory: _path.default.resolve(appDirectory, './shared'),
44
- nodeModulesDirectory: _path.default.resolve(appDirectory, './node_modules'),
45
- internalDirectory: _path.default.resolve(appDirectory, './node_modules/.modern-js'),
46
- plugins,
47
- htmlTemplates: {},
48
- serverRoutes: [],
49
- entrypoints: []
50
- });
35
+ const initAppContext = (appDirectory, plugins, configFile, options) => {
36
+ const {
37
+ metaName = 'modern-js',
38
+ srcDir = 'src',
39
+ distDir = '',
40
+ sharedDir = 'shared'
41
+ } = options || {};
42
+ return {
43
+ metaName,
44
+ appDirectory,
45
+ configFile,
46
+ ip: _address.default.ip(),
47
+ port: 0,
48
+ packageName: require(_path.default.resolve(appDirectory, './package.json')).name,
49
+ srcDirectory: _path.default.resolve(appDirectory, srcDir),
50
+ distDirectory: distDir,
51
+ sharedDirectory: _path.default.resolve(appDirectory, sharedDir),
52
+ nodeModulesDirectory: _path.default.resolve(appDirectory, './node_modules'),
53
+ internalDirectory: _path.default.resolve(appDirectory, `./node_modules/.${metaName}`),
54
+ plugins,
55
+ htmlTemplates: {},
56
+ serverRoutes: [],
57
+ entrypoints: [],
58
+ existSrc: true,
59
+ internalDirAlias: `@_${metaName.replace(/-/g, '_')}_internal`,
60
+ internalSrcAlias: `@_${metaName.replace(/-/g, '_')}_src`
61
+ };
62
+ };
51
63
 
52
64
  exports.initAppContext = initAppContext;