@modern-js/app-tools 1.3.2 → 1.4.2

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 (37) hide show
  1. package/CHANGELOG.md +69 -0
  2. package/dist/js/modern/commands/build.js +24 -8
  3. package/dist/js/modern/commands/dev.js +32 -12
  4. package/dist/js/modern/index.js +29 -5
  5. package/dist/js/modern/locale/en.js +2 -1
  6. package/dist/js/modern/locale/zh.js +2 -1
  7. package/dist/js/modern/utils/createServer.js +8 -1
  8. package/dist/js/modern/utils/getSpecifiedEntries.js +36 -0
  9. package/dist/js/modern/utils/printInstructions.js +4 -1
  10. package/dist/js/modern/utils/routes.js +15 -0
  11. package/dist/js/modern/utils/types.js +0 -0
  12. package/dist/js/node/commands/build.js +24 -7
  13. package/dist/js/node/commands/dev.js +36 -11
  14. package/dist/js/node/index.js +31 -4
  15. package/dist/js/node/locale/en.js +2 -1
  16. package/dist/js/node/locale/zh.js +2 -1
  17. package/dist/js/node/utils/createServer.js +15 -2
  18. package/dist/js/node/utils/getSpecifiedEntries.js +48 -0
  19. package/dist/js/node/utils/printInstructions.js +4 -1
  20. package/dist/js/node/utils/routes.js +25 -0
  21. package/dist/js/node/utils/types.js +0 -0
  22. package/dist/types/commands/dev.d.ts +2 -1
  23. package/dist/types/index.d.ts +2 -0
  24. package/dist/types/locale/en.d.ts +1 -0
  25. package/dist/types/locale/index.d.ts +2 -0
  26. package/dist/types/locale/zh.d.ts +1 -0
  27. package/dist/types/utils/createServer.d.ts +2 -0
  28. package/dist/types/utils/getSpecifiedEntries.d.ts +2 -0
  29. package/dist/types/utils/routes.d.ts +3 -0
  30. package/dist/types/utils/types.d.ts +3 -0
  31. package/lib/types.d.ts +0 -10
  32. package/package.json +15 -11
  33. package/tests/commands/build.test.ts +37 -0
  34. package/tests/commands/dev.test.ts +7 -0
  35. package/tests/routes.test.ts +27 -0
  36. package/tests/tsconfig.json +13 -0
  37. package/tests/utils.test.ts +67 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,74 @@
1
1
  # @modern-js/app-tools
2
2
 
3
+ ## 1.4.2
4
+
5
+ ### Patch Changes
6
+
7
+ - fab92861: fix: @modern-js/core phantom dep
8
+ - Updated dependencies [deeaa602]
9
+ - Updated dependencies [54786e58]
10
+ - Updated dependencies [6668a1bf]
11
+ - Updated dependencies [fab92861]
12
+ - Updated dependencies [3da3bf48]
13
+ - @modern-js/plugin-analyze@1.3.3
14
+ - @modern-js/server@1.4.3
15
+ - @modern-js/types@1.3.3
16
+ - @modern-js/utils@1.3.2
17
+ - @modern-js/webpack@1.4.0
18
+ - @modern-js/core@1.4.3
19
+ - @modern-js/new-action@1.3.2
20
+
21
+ ## 1.4.1
22
+
23
+ ### Patch Changes
24
+
25
+ - 78279953: compiler entry bug fix and dev build console
26
+ - c78400c7: fix: remove stylus support
27
+ - 4d72edea: support dev compiler by entry
28
+ - Updated dependencies [75f4eeb8]
29
+ - Updated dependencies [b7a9eeba]
30
+ - Updated dependencies [2cfc4235]
31
+ - Updated dependencies [8d55e234]
32
+ - Updated dependencies [53aca274]
33
+ - Updated dependencies [78279953]
34
+ - Updated dependencies [e116ace5]
35
+ - Updated dependencies [4d72edea]
36
+ - @modern-js/webpack@1.3.1
37
+ - @modern-js/plugin-analyze@1.3.1
38
+ - @modern-js/server@1.4.1
39
+ - @modern-js/core@1.4.1
40
+ - @modern-js/types@1.3.1
41
+ - @modern-js/utils@1.3.1
42
+
43
+ ## 1.4.0
44
+
45
+ ### Minor Changes
46
+
47
+ - ec4dbffb: feat: support as a pure api service
48
+
49
+ ### Patch Changes
50
+
51
+ - bd819a8d: fix: file route changed not trigger hot reload
52
+ - 62cd58c6: fix: create route.json failure
53
+ - d099e5c5: fix error when modify modern.config.js
54
+ - Updated dependencies [816fd721]
55
+ - Updated dependencies [d9cc5ea9]
56
+ - Updated dependencies [ddf0c3a6]
57
+ - Updated dependencies [bfbea9a7]
58
+ - Updated dependencies [bd819a8d]
59
+ - Updated dependencies [ec4dbffb]
60
+ - Updated dependencies [d099e5c5]
61
+ - Updated dependencies [bada2879]
62
+ - Updated dependencies [24f616ca]
63
+ - Updated dependencies [bd819a8d]
64
+ - Updated dependencies [272cab15]
65
+ - @modern-js/server@1.4.0
66
+ - @modern-js/types@1.3.0
67
+ - @modern-js/core@1.4.0
68
+ - @modern-js/plugin-analyze@1.3.0
69
+ - @modern-js/webpack@1.3.0
70
+ - @modern-js/utils@1.3.0
71
+
3
72
  ## 1.3.2
4
73
 
5
74
  ### Patch Changes
@@ -7,11 +7,30 @@ function _defineProperty(obj, key, value) { if (key in obj) { Object.definePrope
7
7
  import { webpack } from 'webpack';
8
8
  import { WebpackConfigTarget, getWebpackConfig } from '@modern-js/webpack';
9
9
  import { useAppContext, useResolvedConfigContext, mountHook, ResolvedConfigContext, manager } from '@modern-js/core';
10
- import { fs, formatWebpackMessages, measureFileSizesBeforeBuild, printFileSizesAfterBuild, printBuildError, logger, isUseSSRBundle } from '@modern-js/utils'; // These sizes are pretty large. We'll warn for bundles exceeding them.
10
+ import { fs, formatWebpackMessages, measureFileSizesBeforeBuild, printFileSizesAfterBuild, printBuildError, logger, isUseSSRBundle } from '@modern-js/utils';
11
+ import { generateRoutes } from "../utils/routes"; // These sizes are pretty large. We'll warn for bundles exceeding them.
11
12
 
12
13
  const WARN_AFTER_BUNDLE_GZIP_SIZE = 512 * 1024;
13
14
  const WARN_AFTER_CHUNK_GZIP_SIZE = 1024 * 1024;
15
+ // eslint-disable-next-line max-statements
14
16
  export const build = async options => {
17
+ /* eslint-disable react-hooks/rules-of-hooks */
18
+ const resolvedConfig = useResolvedConfigContext();
19
+ const appContext = useAppContext();
20
+ const {
21
+ existSrc
22
+ } = appContext;
23
+ /* eslint-enable react-hooks/rules-of-hooks */
24
+
25
+ if (!existSrc) {
26
+ await mountHook().beforeBuild({
27
+ webpackConfigs: []
28
+ });
29
+ await generateRoutes(appContext);
30
+ await mountHook().afterBuild();
31
+ return;
32
+ }
33
+
15
34
  const webpackBuild = async (webpackConfig, type) => {
16
35
  const compiler = webpack(webpackConfig);
17
36
  return new Promise((resolve, reject) => {
@@ -62,12 +81,6 @@ export const build = async options => {
62
81
  });
63
82
  });
64
83
  };
65
- /* eslint-disable react-hooks/rules-of-hooks */
66
-
67
-
68
- const resolvedConfig = useResolvedConfigContext();
69
- const appContext = useAppContext();
70
- /* eslint-enable react-hooks/rules-of-hooks */
71
84
 
72
85
  manager.run(() => {
73
86
  ResolvedConfigContext.set(_objectSpread(_objectSpread({}, resolvedConfig), {}, {
@@ -112,9 +125,12 @@ export const build = async options => {
112
125
  try {
113
126
  await webpackBuild(config, buildType);
114
127
  } catch (error) {
115
- printBuildError(error);
128
+ printBuildError(error); // eslint-disable-next-line no-process-exit
129
+
130
+ process.exit(1);
116
131
  }
117
132
  }
118
133
 
134
+ await generateRoutes(appContext);
119
135
  await mountHook().afterBuild();
120
136
  };
@@ -6,10 +6,13 @@ function _defineProperty(obj, key, value) { if (key in obj) { Object.definePrope
6
6
 
7
7
  import { getWebpackConfig, WebpackConfigTarget } from '@modern-js/webpack';
8
8
  import { fs, logger, HMR_SOCK_PATH, clearConsole, chalk, isSSR } from '@modern-js/utils';
9
- import { useAppContext, useResolvedConfigContext, mountHook } from '@modern-js/core';
9
+ import { useAppContext, useResolvedConfigContext, mountHook, AppContext } from '@modern-js/core';
10
10
  import { createCompiler } from "../utils/createCompiler";
11
11
  import { createServer } from "../utils/createServer";
12
- export const dev = async () => {
12
+ import { generateRoutes } from "../utils/routes";
13
+ import { printInstructions } from "../utils/printInstructions";
14
+ import { getSpecifiedEntries } from "../utils/getSpecifiedEntries";
15
+ export const dev = async options => {
13
16
  /* eslint-disable react-hooks/rules-of-hooks */
14
17
  const appContext = useAppContext();
15
18
  const userConfig = useResolvedConfigContext();
@@ -18,16 +21,29 @@ export const dev = async () => {
18
21
  const {
19
22
  appDirectory,
20
23
  distDirectory,
21
- port
24
+ port,
25
+ existSrc,
26
+ entrypoints
22
27
  } = appContext;
28
+ const checkedEntries = await getSpecifiedEntries(options.entry || false, entrypoints);
29
+ AppContext.set(_objectSpread(_objectSpread({}, appContext), {}, {
30
+ checkedEntries
31
+ }));
32
+ appContext.checkedEntries = checkedEntries;
23
33
  fs.emptyDirSync(distDirectory);
24
34
  await mountHook().beforeDev();
25
- const webpackConfigs = [isSSR(userConfig) && getWebpackConfig(WebpackConfigTarget.NODE), getWebpackConfig(WebpackConfigTarget.CLIENT)].filter(Boolean);
26
- const compiler = await createCompiler({
27
- webpackConfigs,
28
- userConfig,
29
- appContext
30
- });
35
+ let compiler = null;
36
+
37
+ if (existSrc) {
38
+ const webpackConfigs = [isSSR(userConfig) && getWebpackConfig(WebpackConfigTarget.NODE), getWebpackConfig(WebpackConfigTarget.CLIENT)].filter(Boolean);
39
+ compiler = await createCompiler({
40
+ webpackConfigs,
41
+ userConfig,
42
+ appContext
43
+ });
44
+ }
45
+
46
+ await generateRoutes(appContext);
31
47
  const app = await createServer({
32
48
  dev: _objectSpread(_objectSpread({}, {
33
49
  client: {
@@ -50,12 +66,16 @@ export const dev = async () => {
50
66
  config: userConfig,
51
67
  plugins: appContext.plugins.filter(p => p.server).map(p => p.server)
52
68
  });
53
- app.listen(port, err => {
69
+ app.listen(port, async err => {
54
70
  if (err) {
55
71
  throw err;
56
72
  }
57
73
 
58
- clearConsole();
59
- logger.log(chalk.cyan(`Starting the development server...`));
74
+ if (existSrc) {
75
+ clearConsole();
76
+ logger.log(chalk.cyan(`Starting the development server...`));
77
+ } else {
78
+ await printInstructions(appContext, userConfig);
79
+ }
60
80
  });
61
81
  };
@@ -4,12 +4,15 @@ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { va
4
4
 
5
5
  function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
6
6
 
7
- import { createPlugin, defineConfig, usePlugins, cli } from '@modern-js/core';
7
+ import * as path from 'path';
8
+ import { createPlugin, defineConfig, usePlugins, cli, useAppContext } from '@modern-js/core';
9
+ import { cleanRequireCache } from '@modern-js/utils';
8
10
  import { lifecycle } from "./lifecycle";
9
11
  import { i18n, localeKeys } from "./locale";
10
12
  import { getLocaleLanguage } from "./utils/language";
11
13
  import { start } from "./commands/start";
12
14
  import { dev } from "./commands/dev";
15
+ import { closeServer } from "./utils/createServer";
13
16
  export { defineConfig }; // eslint-disable-next-line react-hooks/rules-of-hooks
14
17
 
15
18
  usePlugins([require.resolve('@modern-js/plugin-analyze/cli'), require.resolve('@modern-js/plugin-fast-refresh/cli')]);
@@ -23,8 +26,8 @@ export default createPlugin(() => {
23
26
  commands({
24
27
  program
25
28
  }) {
26
- program.command('dev').usage('[options]').description(i18n.t(localeKeys.command.dev.describe)).option('-c --config <config>', i18n.t(localeKeys.command.dev.config)).action(async () => {
27
- await dev();
29
+ program.command('dev').usage('[options]').description(i18n.t(localeKeys.command.dev.describe)).option('-c --config <config>', i18n.t(localeKeys.command.dev.config)).option('-e --entry [entry...]', i18n.t(localeKeys.command.dev.entry)).action(async options => {
30
+ await dev(options);
28
31
  });
29
32
  program.command('build').usage('[options]').description(i18n.t(localeKeys.command.build.describe)).option('--analyze', i18n.t(localeKeys.command.build.analyze)).action(async options => {
30
33
  const {
@@ -60,11 +63,32 @@ export default createPlugin(() => {
60
63
  });
61
64
  },
62
65
 
63
- async fileChange() {
64
- await cli.restart();
66
+ // 这里会被 core/initWatcher 监听的文件变动触发,如果是 src 目录下的文件变动,则不做 restart
67
+ async fileChange(e) {
68
+ const {
69
+ filename,
70
+ eventType
71
+ } = e; // eslint-disable-next-line react-hooks/rules-of-hooks
72
+
73
+ const appContext = useAppContext();
74
+ const {
75
+ appDirectory,
76
+ srcDirectory
77
+ } = appContext;
78
+ const absolutePath = path.resolve(appDirectory, filename);
79
+
80
+ if (!absolutePath.includes(srcDirectory) && (eventType === 'change' || eventType === 'unlink')) {
81
+ await closeServer();
82
+ await cli.restart();
83
+ }
84
+ },
85
+
86
+ async beforeRestart() {
87
+ cleanRequireCache([require.resolve('@modern-js/plugin-analyze/cli'), require.resolve('@modern-js/plugin-fast-refresh/cli')]);
65
88
  }
66
89
 
67
90
  };
68
91
  }, {
92
+ name: '@modern-js/app-tools',
69
93
  post: ['@modern-js/plugin-analyze', '@modern-js/plugin-fast-refresh', '@modern-js/plugin-ssr', '@modern-js/plugin-state', '@modern-js/plugin-router', '@modern-js/plugin-polyfill']
70
94
  });
@@ -2,7 +2,8 @@ export const EN_LOCALE = {
2
2
  command: {
3
3
  dev: {
4
4
  describe: 'start dev server',
5
- config: 'specify config file'
5
+ config: 'specify config file',
6
+ entry: 'compiler by entry'
6
7
  },
7
8
  build: {
8
9
  describe: 'build application',
@@ -2,7 +2,8 @@ export const ZH_LOCALE = {
2
2
  command: {
3
3
  dev: {
4
4
  describe: '本地开发命令',
5
- config: '制定配置文件路径'
5
+ config: '制定配置文件路径',
6
+ entry: '按入口编译'
6
7
  },
7
8
  build: {
8
9
  describe: '构建应用命令',
@@ -1,5 +1,12 @@
1
1
  import { Server } from '@modern-js/server';
2
- let server;
2
+ let server = null;
3
+ export const getServer = () => server;
4
+ export const closeServer = async () => {
5
+ if (server) {
6
+ await server.close();
7
+ server = null;
8
+ }
9
+ };
3
10
  export const createServer = async options => {
4
11
  if (server) {
5
12
  await server.close();
@@ -0,0 +1,36 @@
1
+ import inquirer from 'inquirer';
2
+ export const getSpecifiedEntries = async (entry, entrypoints) => {
3
+ const entryNames = entrypoints.map(e => e.entryName);
4
+
5
+ if (!entry) {
6
+ return entryNames;
7
+ }
8
+
9
+ if (typeof entry === 'boolean') {
10
+ const {
11
+ selected
12
+ } = await inquirer.prompt([{
13
+ type: 'checkbox',
14
+ name: 'selected',
15
+ choices: entryNames,
16
+ message: '请选择需要构建的入口',
17
+
18
+ validate(answer) {
19
+ if (answer.length < 1) {
20
+ return 'You must choose at least one topping.';
21
+ }
22
+
23
+ return true;
24
+ }
25
+
26
+ }]);
27
+ return selected;
28
+ }
29
+
30
+ entry.forEach(name => {
31
+ if (!entryNames.includes(name)) {
32
+ throw new Error(`can not found entry ${name}, compiler entry should in ${entryNames.join(', ')}`);
33
+ }
34
+ });
35
+ return entry;
36
+ };
@@ -2,8 +2,11 @@ import { prettyInstructions, logger, isDev, chalk } from '@modern-js/utils';
2
2
  import { mountHook } from '@modern-js/core';
3
3
  export const printInstructions = async (appContext, config) => {
4
4
  let message = prettyInstructions(appContext, config);
5
+ const {
6
+ existSrc
7
+ } = appContext;
5
8
 
6
- if (isDev()) {
9
+ if (isDev() && existSrc) {
7
10
  message += `\n${chalk.cyanBright([`Note that the development build is not optimized.`, `To create a production build, execute build command.`].join('\n'))}`;
8
11
  } // call beforePrintInstructions hook.
9
12
 
@@ -0,0 +1,15 @@
1
+ import path from 'path';
2
+ import { fs, ROUTE_SPEC_FILE } from '@modern-js/utils';
3
+
4
+ const generateRoutes = async appContext => {
5
+ const {
6
+ serverRoutes,
7
+ distDirectory
8
+ } = appContext;
9
+ const output = JSON.stringify({
10
+ routes: serverRoutes
11
+ }, null, 2);
12
+ await fs.outputFile(path.join(distDirectory, ROUTE_SPEC_FILE), output);
13
+ };
14
+
15
+ export { generateRoutes };
File without changes
@@ -13,6 +13,8 @@ var _core = require("@modern-js/core");
13
13
 
14
14
  var _utils = require("@modern-js/utils");
15
15
 
16
+ var _routes = require("../utils/routes");
17
+
16
18
  function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
17
19
 
18
20
  function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
@@ -23,7 +25,25 @@ function _defineProperty(obj, key, value) { if (key in obj) { Object.definePrope
23
25
  const WARN_AFTER_BUNDLE_GZIP_SIZE = 512 * 1024;
24
26
  const WARN_AFTER_CHUNK_GZIP_SIZE = 1024 * 1024;
25
27
 
28
+ // eslint-disable-next-line max-statements
26
29
  const build = async options => {
30
+ /* eslint-disable react-hooks/rules-of-hooks */
31
+ const resolvedConfig = (0, _core.useResolvedConfigContext)();
32
+ const appContext = (0, _core.useAppContext)();
33
+ const {
34
+ existSrc
35
+ } = appContext;
36
+ /* eslint-enable react-hooks/rules-of-hooks */
37
+
38
+ if (!existSrc) {
39
+ await (0, _core.mountHook)().beforeBuild({
40
+ webpackConfigs: []
41
+ });
42
+ await (0, _routes.generateRoutes)(appContext);
43
+ await (0, _core.mountHook)().afterBuild();
44
+ return;
45
+ }
46
+
27
47
  const webpackBuild = async (webpackConfig, type) => {
28
48
  const compiler = (0, _webpack.webpack)(webpackConfig);
29
49
  return new Promise((resolve, reject) => {
@@ -77,12 +97,6 @@ const build = async options => {
77
97
  });
78
98
  });
79
99
  };
80
- /* eslint-disable react-hooks/rules-of-hooks */
81
-
82
-
83
- const resolvedConfig = (0, _core.useResolvedConfigContext)();
84
- const appContext = (0, _core.useAppContext)();
85
- /* eslint-enable react-hooks/rules-of-hooks */
86
100
 
87
101
  _core.manager.run(() => {
88
102
  _core.ResolvedConfigContext.set(_objectSpread(_objectSpread({}, resolvedConfig), {}, {
@@ -130,10 +144,13 @@ const build = async options => {
130
144
  try {
131
145
  await webpackBuild(config, buildType);
132
146
  } catch (error) {
133
- (0, _utils.printBuildError)(error);
147
+ (0, _utils.printBuildError)(error); // eslint-disable-next-line no-process-exit
148
+
149
+ process.exit(1);
134
150
  }
135
151
  }
136
152
 
153
+ await (0, _routes.generateRoutes)(appContext);
137
154
  await (0, _core.mountHook)().afterBuild();
138
155
  };
139
156
 
@@ -15,13 +15,19 @@ var _createCompiler = require("../utils/createCompiler");
15
15
 
16
16
  var _createServer = require("../utils/createServer");
17
17
 
18
+ var _routes = require("../utils/routes");
19
+
20
+ var _printInstructions = require("../utils/printInstructions");
21
+
22
+ var _getSpecifiedEntries = require("../utils/getSpecifiedEntries");
23
+
18
24
  function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
19
25
 
20
26
  function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
21
27
 
22
28
  function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
23
29
 
24
- const dev = async () => {
30
+ const dev = async options => {
25
31
  /* eslint-disable react-hooks/rules-of-hooks */
26
32
  const appContext = (0, _core.useAppContext)();
27
33
  const userConfig = (0, _core.useResolvedConfigContext)();
@@ -30,18 +36,33 @@ const dev = async () => {
30
36
  const {
31
37
  appDirectory,
32
38
  distDirectory,
33
- port
39
+ port,
40
+ existSrc,
41
+ entrypoints
34
42
  } = appContext;
43
+ const checkedEntries = await (0, _getSpecifiedEntries.getSpecifiedEntries)(options.entry || false, entrypoints);
44
+
45
+ _core.AppContext.set(_objectSpread(_objectSpread({}, appContext), {}, {
46
+ checkedEntries
47
+ }));
48
+
49
+ appContext.checkedEntries = checkedEntries;
35
50
 
36
51
  _utils.fs.emptyDirSync(distDirectory);
37
52
 
38
53
  await (0, _core.mountHook)().beforeDev();
39
- const webpackConfigs = [(0, _utils.isSSR)(userConfig) && (0, _webpack.getWebpackConfig)(_webpack.WebpackConfigTarget.NODE), (0, _webpack.getWebpackConfig)(_webpack.WebpackConfigTarget.CLIENT)].filter(Boolean);
40
- const compiler = await (0, _createCompiler.createCompiler)({
41
- webpackConfigs,
42
- userConfig,
43
- appContext
44
- });
54
+ let compiler = null;
55
+
56
+ if (existSrc) {
57
+ const webpackConfigs = [(0, _utils.isSSR)(userConfig) && (0, _webpack.getWebpackConfig)(_webpack.WebpackConfigTarget.NODE), (0, _webpack.getWebpackConfig)(_webpack.WebpackConfigTarget.CLIENT)].filter(Boolean);
58
+ compiler = await (0, _createCompiler.createCompiler)({
59
+ webpackConfigs,
60
+ userConfig,
61
+ appContext
62
+ });
63
+ }
64
+
65
+ await (0, _routes.generateRoutes)(appContext);
45
66
  const app = await (0, _createServer.createServer)({
46
67
  dev: _objectSpread(_objectSpread({}, {
47
68
  client: {
@@ -64,14 +85,18 @@ const dev = async () => {
64
85
  config: userConfig,
65
86
  plugins: appContext.plugins.filter(p => p.server).map(p => p.server)
66
87
  });
67
- app.listen(port, err => {
88
+ app.listen(port, async err => {
68
89
  if (err) {
69
90
  throw err;
70
91
  }
71
92
 
72
- (0, _utils.clearConsole)();
93
+ if (existSrc) {
94
+ (0, _utils.clearConsole)();
73
95
 
74
- _utils.logger.log(_utils.chalk.cyan(`Starting the development server...`));
96
+ _utils.logger.log(_utils.chalk.cyan(`Starting the development server...`));
97
+ } else {
98
+ await (0, _printInstructions.printInstructions)(appContext, userConfig);
99
+ }
75
100
  });
76
101
  };
77
102
 
@@ -11,8 +11,12 @@ Object.defineProperty(exports, "defineConfig", {
11
11
  }
12
12
  });
13
13
 
14
+ var path = _interopRequireWildcard(require("path"));
15
+
14
16
  var _core = require("@modern-js/core");
15
17
 
18
+ var _utils = require("@modern-js/utils");
19
+
16
20
  var _lifecycle = require("./lifecycle");
17
21
 
18
22
  var _locale = require("./locale");
@@ -23,6 +27,8 @@ var _start = require("./commands/start");
23
27
 
24
28
  var _dev = require("./commands/dev");
25
29
 
30
+ var _createServer = require("./utils/createServer");
31
+
26
32
  function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
27
33
 
28
34
  function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
@@ -48,8 +54,8 @@ var _default = (0, _core.createPlugin)(() => {
48
54
  commands({
49
55
  program
50
56
  }) {
51
- program.command('dev').usage('[options]').description(_locale.i18n.t(_locale.localeKeys.command.dev.describe)).option('-c --config <config>', _locale.i18n.t(_locale.localeKeys.command.dev.config)).action(async () => {
52
- await (0, _dev.dev)();
57
+ program.command('dev').usage('[options]').description(_locale.i18n.t(_locale.localeKeys.command.dev.describe)).option('-c --config <config>', _locale.i18n.t(_locale.localeKeys.command.dev.config)).option('-e --entry [entry...]', _locale.i18n.t(_locale.localeKeys.command.dev.entry)).action(async options => {
58
+ await (0, _dev.dev)(options);
53
59
  });
54
60
  program.command('build').usage('[options]').description(_locale.i18n.t(_locale.localeKeys.command.build.describe)).option('--analyze', _locale.i18n.t(_locale.localeKeys.command.build.analyze)).action(async options => {
55
61
  const {
@@ -85,12 +91,33 @@ var _default = (0, _core.createPlugin)(() => {
85
91
  });
86
92
  },
87
93
 
88
- async fileChange() {
89
- await _core.cli.restart();
94
+ // 这里会被 core/initWatcher 监听的文件变动触发,如果是 src 目录下的文件变动,则不做 restart
95
+ async fileChange(e) {
96
+ const {
97
+ filename,
98
+ eventType
99
+ } = e; // eslint-disable-next-line react-hooks/rules-of-hooks
100
+
101
+ const appContext = (0, _core.useAppContext)();
102
+ const {
103
+ appDirectory,
104
+ srcDirectory
105
+ } = appContext;
106
+ const absolutePath = path.resolve(appDirectory, filename);
107
+
108
+ if (!absolutePath.includes(srcDirectory) && (eventType === 'change' || eventType === 'unlink')) {
109
+ await (0, _createServer.closeServer)();
110
+ await _core.cli.restart();
111
+ }
112
+ },
113
+
114
+ async beforeRestart() {
115
+ (0, _utils.cleanRequireCache)([require.resolve('@modern-js/plugin-analyze/cli'), require.resolve('@modern-js/plugin-fast-refresh/cli')]);
90
116
  }
91
117
 
92
118
  };
93
119
  }, {
120
+ name: '@modern-js/app-tools',
94
121
  post: ['@modern-js/plugin-analyze', '@modern-js/plugin-fast-refresh', '@modern-js/plugin-ssr', '@modern-js/plugin-state', '@modern-js/plugin-router', '@modern-js/plugin-polyfill']
95
122
  });
96
123
 
@@ -8,7 +8,8 @@ const EN_LOCALE = {
8
8
  command: {
9
9
  dev: {
10
10
  describe: 'start dev server',
11
- config: 'specify config file'
11
+ config: 'specify config file',
12
+ entry: 'compiler by entry'
12
13
  },
13
14
  build: {
14
15
  describe: 'build application',
@@ -8,7 +8,8 @@ const ZH_LOCALE = {
8
8
  command: {
9
9
  dev: {
10
10
  describe: '本地开发命令',
11
- config: '制定配置文件路径'
11
+ config: '制定配置文件路径',
12
+ entry: '按入口编译'
12
13
  },
13
14
  build: {
14
15
  describe: '构建应用命令',
@@ -3,11 +3,24 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.createServer = void 0;
6
+ exports.getServer = exports.createServer = exports.closeServer = void 0;
7
7
 
8
8
  var _server = require("@modern-js/server");
9
9
 
10
- let server;
10
+ let server = null;
11
+
12
+ const getServer = () => server;
13
+
14
+ exports.getServer = getServer;
15
+
16
+ const closeServer = async () => {
17
+ if (server) {
18
+ await server.close();
19
+ server = null;
20
+ }
21
+ };
22
+
23
+ exports.closeServer = closeServer;
11
24
 
12
25
  const createServer = async options => {
13
26
  if (server) {
@@ -0,0 +1,48 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.getSpecifiedEntries = void 0;
7
+
8
+ var _inquirer = _interopRequireDefault(require("inquirer"));
9
+
10
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
11
+
12
+ const getSpecifiedEntries = async (entry, entrypoints) => {
13
+ const entryNames = entrypoints.map(e => e.entryName);
14
+
15
+ if (!entry) {
16
+ return entryNames;
17
+ }
18
+
19
+ if (typeof entry === 'boolean') {
20
+ const {
21
+ selected
22
+ } = await _inquirer.default.prompt([{
23
+ type: 'checkbox',
24
+ name: 'selected',
25
+ choices: entryNames,
26
+ message: '请选择需要构建的入口',
27
+
28
+ validate(answer) {
29
+ if (answer.length < 1) {
30
+ return 'You must choose at least one topping.';
31
+ }
32
+
33
+ return true;
34
+ }
35
+
36
+ }]);
37
+ return selected;
38
+ }
39
+
40
+ entry.forEach(name => {
41
+ if (!entryNames.includes(name)) {
42
+ throw new Error(`can not found entry ${name}, compiler entry should in ${entryNames.join(', ')}`);
43
+ }
44
+ });
45
+ return entry;
46
+ };
47
+
48
+ exports.getSpecifiedEntries = getSpecifiedEntries;
@@ -11,8 +11,11 @@ var _core = require("@modern-js/core");
11
11
 
12
12
  const printInstructions = async (appContext, config) => {
13
13
  let message = (0, _utils.prettyInstructions)(appContext, config);
14
+ const {
15
+ existSrc
16
+ } = appContext;
14
17
 
15
- if ((0, _utils.isDev)()) {
18
+ if ((0, _utils.isDev)() && existSrc) {
16
19
  message += `\n${_utils.chalk.cyanBright([`Note that the development build is not optimized.`, `To create a production build, execute build command.`].join('\n'))}`;
17
20
  } // call beforePrintInstructions hook.
18
21
 
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.generateRoutes = void 0;
7
+
8
+ var _path = _interopRequireDefault(require("path"));
9
+
10
+ var _utils = require("@modern-js/utils");
11
+
12
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
13
+
14
+ const generateRoutes = async appContext => {
15
+ const {
16
+ serverRoutes,
17
+ distDirectory
18
+ } = appContext;
19
+ const output = JSON.stringify({
20
+ routes: serverRoutes
21
+ }, null, 2);
22
+ await _utils.fs.outputFile(_path.default.join(distDirectory, _utils.ROUTE_SPEC_FILE), output);
23
+ };
24
+
25
+ exports.generateRoutes = generateRoutes;
File without changes
@@ -1 +1,2 @@
1
- export declare const dev: () => Promise<void>;
1
+ import { DevOptions } from '../utils/types';
2
+ export declare const dev: (options: DevOptions) => Promise<void>;
@@ -14,8 +14,10 @@ declare const _default: import("@modern-js/core").AsyncPlugin<Partial<import("@m
14
14
  watchFiles: import("@modern-js/core").ParallelWorkflow<void, unknown>;
15
15
  fileChange: import("@modern-js/core").AsyncWorkflow<{
16
16
  filename: string;
17
+ eventType: "add" | "unlink" | "change";
17
18
  }, void>;
18
19
  beforeExit: import("@modern-js/core").AsyncWorkflow<void, void>;
20
+ beforeRestart: import("@modern-js/core").AsyncWorkflow<void, void>;
19
21
  } & import("@modern-js/core").ClearDraftProgress<import("@modern-js/core").Hooks>>>>;
20
22
 
21
23
  export default _default;
@@ -3,6 +3,7 @@ export declare const EN_LOCALE: {
3
3
  dev: {
4
4
  describe: string;
5
5
  config: string;
6
+ entry: string;
6
7
  };
7
8
  build: {
8
9
  describe: string;
@@ -5,6 +5,7 @@ declare const localeKeys: {
5
5
  dev: {
6
6
  describe: string;
7
7
  config: string;
8
+ entry: string;
8
9
  };
9
10
  build: {
10
11
  describe: string;
@@ -29,6 +30,7 @@ declare const localeKeys: {
29
30
  dev: {
30
31
  describe: string;
31
32
  config: string;
33
+ entry: string;
32
34
  };
33
35
  build: {
34
36
  describe: string;
@@ -3,6 +3,7 @@ export declare const ZH_LOCALE: {
3
3
  dev: {
4
4
  describe: string;
5
5
  config: string;
6
+ entry: string;
6
7
  };
7
8
  build: {
8
9
  describe: string;
@@ -1,2 +1,4 @@
1
1
  import { Server, ModernServerOptions } from '@modern-js/server';
2
+ export declare const getServer: () => Server | null;
3
+ export declare const closeServer: () => Promise<void>;
2
4
  export declare const createServer: (options: ModernServerOptions) => Promise<Server>;
@@ -0,0 +1,2 @@
1
+ import { Entrypoint } from '@modern-js/types';
2
+ export declare const getSpecifiedEntries: (entry: string[] | boolean, entrypoints: Entrypoint[]) => Promise<string[]>;
@@ -0,0 +1,3 @@
1
+ import { IAppContext } from '@modern-js/core';
2
+ declare const generateRoutes: (appContext: IAppContext) => Promise<void>;
3
+ export { generateRoutes };
@@ -0,0 +1,3 @@
1
+ export declare type DevOptions = {
2
+ entry: string[] | boolean;
3
+ };
package/lib/types.d.ts CHANGED
@@ -71,11 +71,6 @@ declare module '*.less' {
71
71
  export default classes;
72
72
  }
73
73
 
74
- declare module '*.styl' {
75
- const classes: { readonly [key: string]: string };
76
- export default classes;
77
- }
78
-
79
74
  declare module '*.sass' {
80
75
  const classes: { readonly [key: string]: string };
81
76
  export default classes;
@@ -96,11 +91,6 @@ declare module '*.module.less' {
96
91
  export default classes;
97
92
  }
98
93
 
99
- declare module '*.module.styl' {
100
- const classes: { readonly [key: string]: string };
101
- export default classes;
102
- }
103
-
104
94
  declare module '*.module.sass' {
105
95
  const classes: { readonly [key: string]: string };
106
96
  export default classes;
package/package.json CHANGED
@@ -11,7 +11,7 @@
11
11
  "modern",
12
12
  "modern.js"
13
13
  ],
14
- "version": "1.3.2",
14
+ "version": "1.4.2",
15
15
  "jsnext:source": "./src/index.ts",
16
16
  "types": "./dist/types/index.d.ts",
17
17
  "main": "./dist/js/node/index.js",
@@ -50,20 +50,24 @@
50
50
  },
51
51
  "dependencies": {
52
52
  "@babel/runtime": "^7",
53
- "@modern-js/core": "^1.3.2",
54
- "@modern-js/types": "^1.2.1",
53
+ "@modern-js/types": "^1.3.3",
55
54
  "@modern-js/i18n-cli-language-detector": "^1.2.1",
56
- "@modern-js/new-action": "^1.3.1",
55
+ "@modern-js/new-action": "^1.3.2",
57
56
  "@modern-js/plugin": "^1.2.1",
58
- "@modern-js/plugin-analyze": "^1.2.1",
57
+ "@modern-js/plugin-analyze": "^1.3.3",
59
58
  "@modern-js/plugin-fast-refresh": "^1.2.1",
60
59
  "@modern-js/plugin-i18n": "^1.2.1",
61
- "@modern-js/server": "^1.3.2",
62
- "@modern-js/utils": "^1.2.2",
63
- "@modern-js/webpack": "^1.2.1",
60
+ "@modern-js/server": "^1.4.3",
61
+ "@modern-js/utils": "^1.3.2",
62
+ "@modern-js/webpack": "^1.4.0",
63
+ "inquirer": "^8.2.0",
64
64
  "webpack": "^5.54.0"
65
65
  },
66
+ "peerDependencies": {
67
+ "@modern-js/core": "^1.4.3"
68
+ },
66
69
  "devDependencies": {
70
+ "@modern-js/core": "^1.4.3",
67
71
  "@types/jest": "^26",
68
72
  "@types/node": "^14",
69
73
  "@types/react": "^17",
@@ -71,7 +75,8 @@
71
75
  "typescript": "^4",
72
76
  "@scripts/build": "0.0.0",
73
77
  "jest": "^27",
74
- "@scripts/jest-config": "0.0.0"
78
+ "@scripts/jest-config": "0.0.0",
79
+ "@types/inquirer": "^8.2.0"
75
80
  },
76
81
  "sideEffects": false,
77
82
  "modernConfig": {
@@ -81,8 +86,7 @@
81
86
  },
82
87
  "publishConfig": {
83
88
  "registry": "https://registry.npmjs.org/",
84
- "access": "public",
85
- "types": "./dist/types/index.d.ts"
89
+ "access": "public"
86
90
  },
87
91
  "scripts": {
88
92
  "new": "modern new",
@@ -0,0 +1,37 @@
1
+ import { build } from '../../src/commands/build';
2
+
3
+ const mockBeforeBuild = jest.fn();
4
+ const mockAfterBuild = jest.fn();
5
+ const mockGenerateRoutes = jest.fn();
6
+
7
+ jest.mock('@modern-js/core', () => ({
8
+ __esModule: true,
9
+ mountHook() {
10
+ return {
11
+ beforeBuild: mockBeforeBuild,
12
+ afterBuild: mockAfterBuild,
13
+ };
14
+ },
15
+ useAppContext: jest.fn(() => ({
16
+ existSrc: false,
17
+ })),
18
+ useResolvedConfigContext: jest.fn(),
19
+ }));
20
+
21
+ jest.mock('../../src/utils/routes', () => ({
22
+ __esModule: true,
23
+ generateRoutes: () => mockGenerateRoutes(),
24
+ }));
25
+
26
+ describe('command build', () => {
27
+ afterAll(() => {
28
+ jest.resetAllMocks();
29
+ });
30
+
31
+ test('existSrc is false', async () => {
32
+ await build();
33
+ expect(mockBeforeBuild).toBeCalled();
34
+ expect(mockGenerateRoutes).toBeCalled();
35
+ expect(mockAfterBuild).toBeCalled();
36
+ });
37
+ });
@@ -0,0 +1,7 @@
1
+ import { dev } from '../../src/commands/dev';
2
+
3
+ describe('command', () => {
4
+ test('dev', () => {
5
+ expect(dev).toBeDefined();
6
+ });
7
+ });
@@ -0,0 +1,27 @@
1
+ import { fs } from '@modern-js/utils';
2
+ import { generateRoutes } from '../src/utils/routes';
3
+
4
+ jest.mock('@modern-js/utils', () => {
5
+ const originalModule = jest.requireActual('@modern-js/utils');
6
+ return {
7
+ __esModule: true,
8
+ ...originalModule,
9
+ fs: {
10
+ outputFile: jest.fn((filename: string, output: string) => ({
11
+ filename,
12
+ output,
13
+ })),
14
+ },
15
+ };
16
+ });
17
+
18
+ describe('routes', () => {
19
+ test('generateRoutes', async () => {
20
+ const mockAppContext = {
21
+ serverRoutes: [],
22
+ distDirectory: './dist',
23
+ };
24
+ await generateRoutes(mockAppContext as any);
25
+ expect(fs.outputFile).toHaveBeenCalledTimes(1);
26
+ });
27
+ });
@@ -0,0 +1,13 @@
1
+ {
2
+ "extends": "@modern-js/tsconfig/base",
3
+ "compilerOptions": {
4
+ "declaration": true,
5
+ "jsx": "preserve",
6
+ "baseUrl": "./",
7
+ "outDir": "./out",
8
+ "emitDeclarationOnly": true,
9
+ "isolatedModules": true,
10
+ "paths": {},
11
+ "types": ["node", "jest"]
12
+ }
13
+ }
@@ -0,0 +1,67 @@
1
+ import inquirer from 'inquirer';
2
+ import { Server } from '@modern-js/server';
3
+ import {
4
+ closeServer,
5
+ createServer,
6
+ getServer,
7
+ } from '../src/utils/createServer';
8
+ import { getSpecifiedEntries } from '../src/utils/getSpecifiedEntries';
9
+
10
+ describe('test app-tools utils', () => {
11
+ it('should return all entryNames correctly', async () => {
12
+ const checked = await getSpecifiedEntries(false, [
13
+ { entryName: 'a' },
14
+ { entryName: 'b' },
15
+ ] as any);
16
+
17
+ expect(checked).toEqual(['a', 'b']);
18
+ });
19
+
20
+ it('should return spec entry', async () => {
21
+ const checked = await getSpecifiedEntries(['a'], [
22
+ { entryName: 'a' },
23
+ { entryName: 'b' },
24
+ ] as any);
25
+
26
+ expect(checked).toEqual(['a']);
27
+ });
28
+
29
+ it('should return select entry', async () => {
30
+ inquirer.prompt = jest.fn().mockResolvedValue({ selected: ['b'] }) as any;
31
+ const checked = await getSpecifiedEntries(true, [
32
+ { entryName: 'a' },
33
+ { entryName: 'b' },
34
+ ] as any);
35
+
36
+ expect(checked).toEqual(['b']);
37
+ });
38
+
39
+ it('should get error if entry not allow', resolve => {
40
+ getSpecifiedEntries(['c'], [
41
+ { entryName: 'a' },
42
+ { entryName: 'b' },
43
+ // eslint-disable-next-line promise/prefer-await-to-then
44
+ ] as any).catch(e => {
45
+ expect((e as Error).message).toMatch('can not found entry c');
46
+ resolve();
47
+ });
48
+ });
49
+
50
+ it('should create and close server correctly', async () => {
51
+ const app = await createServer({
52
+ dev: false,
53
+ pwd: '.',
54
+ config: {
55
+ output: {
56
+ path: 'dist',
57
+ },
58
+ },
59
+ } as any);
60
+
61
+ expect(app instanceof Server).toBe(true);
62
+ expect(getServer()).toBe(app);
63
+
64
+ await closeServer();
65
+ expect(getServer()).toBeNull();
66
+ });
67
+ });