@modern-js/app-tools 2.0.0-beta.2 → 2.0.0-beta.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 (60) hide show
  1. package/CHANGELOG.md +251 -0
  2. package/bin/modern.js +10 -1
  3. package/dist/js/modern/analyze/constants.js +2 -0
  4. package/dist/js/modern/analyze/generateCode.js +38 -18
  5. package/dist/js/modern/analyze/getServerRoutes.js +3 -3
  6. package/dist/js/modern/analyze/nestedRoutes.js +17 -6
  7. package/dist/js/modern/analyze/templates.js +59 -27
  8. package/dist/js/modern/analyze/utils.js +30 -4
  9. package/dist/js/modern/builder/builderPlugins/compatModern.js +6 -1
  10. package/dist/js/modern/builder/index.js +3 -5
  11. package/dist/js/modern/builder/loaders/routerLoader.js +20 -0
  12. package/dist/js/modern/builder/loaders/serverModuleLoader.js +4 -0
  13. package/dist/js/modern/commands/dev.js +23 -27
  14. package/dist/js/modern/commands/start.js +0 -1
  15. package/dist/js/modern/config/default.js +0 -1
  16. package/dist/js/modern/config/initial/createOutputConfig.js +3 -0
  17. package/dist/js/modern/utils/createFileWatcher.js +1 -1
  18. package/dist/js/modern/utils/restart.js +1 -1
  19. package/dist/js/node/analyze/constants.js +5 -1
  20. package/dist/js/node/analyze/generateCode.js +36 -16
  21. package/dist/js/node/analyze/getServerRoutes.js +3 -3
  22. package/dist/js/node/analyze/nestedRoutes.js +15 -4
  23. package/dist/js/node/analyze/templates.js +60 -27
  24. package/dist/js/node/analyze/utils.js +31 -3
  25. package/dist/js/node/builder/builderPlugins/compatModern.js +6 -1
  26. package/dist/js/node/builder/index.js +3 -5
  27. package/dist/js/node/builder/loaders/routerLoader.js +27 -0
  28. package/dist/js/node/builder/loaders/serverModuleLoader.js +11 -0
  29. package/dist/js/node/commands/dev.js +23 -27
  30. package/dist/js/node/commands/start.js +0 -1
  31. package/dist/js/node/config/default.js +0 -1
  32. package/dist/js/node/config/initial/createOutputConfig.js +3 -0
  33. package/dist/js/node/utils/createFileWatcher.js +2 -1
  34. package/dist/js/node/utils/restart.js +1 -1
  35. package/dist/js/treeshaking/analyze/constants.js +2 -0
  36. package/dist/js/treeshaking/analyze/generateCode.js +137 -81
  37. package/dist/js/treeshaking/analyze/getServerRoutes.js +4 -3
  38. package/dist/js/treeshaking/analyze/nestedRoutes.js +98 -55
  39. package/dist/js/treeshaking/analyze/templates.js +175 -101
  40. package/dist/js/treeshaking/analyze/utils.js +80 -4
  41. package/dist/js/treeshaking/builder/builderPlugins/compatModern.js +6 -1
  42. package/dist/js/treeshaking/builder/index.js +3 -5
  43. package/dist/js/treeshaking/builder/loaders/routerLoader.js +14 -0
  44. package/dist/js/treeshaking/builder/loaders/serverModuleLoader.js +4 -0
  45. package/dist/js/treeshaking/commands/dev.js +37 -38
  46. package/dist/js/treeshaking/commands/start.js +0 -1
  47. package/dist/js/treeshaking/config/default.js +0 -1
  48. package/dist/js/treeshaking/config/initial/createOutputConfig.js +3 -0
  49. package/dist/js/treeshaking/utils/createFileWatcher.js +1 -1
  50. package/dist/js/treeshaking/utils/restart.js +1 -1
  51. package/dist/types/analyze/constants.d.ts +2 -0
  52. package/dist/types/analyze/templates.d.ts +8 -7
  53. package/dist/types/analyze/utils.d.ts +9 -1
  54. package/dist/types/builder/loaders/routerLoader.d.ts +3 -0
  55. package/dist/types/builder/loaders/serverModuleLoader.d.ts +3 -0
  56. package/dist/types/types/config/tools.d.ts +8 -1
  57. package/dist/types/types/hooks.d.ts +2 -1
  58. package/dist/types/utils/createFileWatcher.d.ts +2 -1
  59. package/lib/types.d.ts +1 -1
  60. package/package.json +25 -22
@@ -78,6 +78,11 @@ export const PluginCompatModern = (appContext, modernConfig, options) => ({
78
78
  chain.plugin('route-plugin').use(RouterPlugin, [{
79
79
  existNestedRoutes
80
80
  }]);
81
+ if (target !== 'node') {
82
+ const bareServerModuleReg = /\.(server|node)\.[tj]sx?$/;
83
+ chain.module.rule(CHAIN_ID.RULE.JS).exclude.add(bareServerModuleReg);
84
+ chain.module.rule('bare-server-module').test(bareServerModuleReg).use('server-module-loader').loader(require.resolve("../loaders/serverModuleLoader"));
85
+ }
81
86
  function isHtmlEnabled(config, target) {
82
87
  var _config$tools;
83
88
  return ((_config$tools = config.tools) === null || _config$tools === void 0 ? void 0 : _config$tools.htmlPlugin) !== false && target !== 'node' && target !== 'web-worker';
@@ -108,7 +113,7 @@ function applyCallbacks(api, options) {
108
113
  */
109
114
  function applyNodeCompat(chain, modernConfig, isProd) {
110
115
  // apply node resolve extensions
111
- for (const ext of ['.node.js', '.node.jsx', '.node.ts', '.node.tsx']) {
116
+ for (const ext of ['.node.js', '.node.jsx', '.node.ts', '.node.tsx', '.server.js', '.server.ts', '.server.ts', '.server.tsx']) {
112
117
  chain.resolve.extensions.prepend(ext);
113
118
  }
114
119
 
@@ -33,6 +33,7 @@ export async function createBuilderForEdenX({
33
33
  return builder;
34
34
  }
35
35
  export function createBuilderProviderConfig(normalizedConfig, appContext) {
36
+ var _normalizedConfig$ser;
36
37
  const output = createOutputConfig(normalizedConfig, appContext);
37
38
  return _objectSpread(_objectSpread({}, normalizedConfig), {}, {
38
39
  source: _objectSpread(_objectSpread({}, normalizedConfig.source), {}, {
@@ -40,6 +41,7 @@ export function createBuilderProviderConfig(normalizedConfig, appContext) {
40
41
  }),
41
42
  output,
42
43
  dev: {
44
+ port: (_normalizedConfig$ser = normalizedConfig.server) === null || _normalizedConfig$ser === void 0 ? void 0 : _normalizedConfig$ser.port,
43
45
  https: normalizedConfig.dev.https,
44
46
  assetPrefix: normalizedConfig.dev.assetPrefix
45
47
  },
@@ -61,11 +63,7 @@ export function createBuilderProviderConfig(normalizedConfig, appContext) {
61
63
  return _objectSpread(_objectSpread({}, config.output), {}, {
62
64
  copy: builderCopy,
63
65
  // We need to do this in the app-tools prepare hook because some files will be generated into the dist directory in the analyze process
64
- cleanDistPath: false,
65
- // `@modern-js/webpack` used to generate asset manifest by default
66
- enableAssetManifest: true,
67
- // compatible the modern-js with fallback behavior
68
- enableAssetFallback: true
66
+ cleanDistPath: false
69
67
  });
70
68
  }
71
69
  }
@@ -0,0 +1,20 @@
1
+ function loader(source) {
2
+ // eslint-disable-next-line @babel/no-invalid-this
3
+ this.cacheable();
4
+ // eslint-disable-next-line @babel/no-invalid-this
5
+ const {
6
+ target
7
+ } = this._compiler.options;
8
+ if (target === 'node' || Array.isArray(target) && target.includes('node')) {
9
+ return source;
10
+ }
11
+ // eslint-disable-next-line @babel/no-invalid-this
12
+ const {
13
+ resourcePath
14
+ } = this;
15
+ const code = `
16
+ export { default } from "${resourcePath}";
17
+ `;
18
+ return code;
19
+ }
20
+ export default loader;
@@ -0,0 +1,4 @@
1
+ function loader() {
2
+ return `module.exports = {}`;
3
+ }
4
+ export default loader;
@@ -1,7 +1,6 @@
1
1
  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; }
2
2
  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; }
3
3
  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; }
4
- import { logger } from '@modern-js/utils';
5
4
  import { ResolvedConfigContext } from '@modern-js/core';
6
5
  import { createFileWatcher } from "../utils/createFileWatcher";
7
6
  import { printInstructions } from "../utils/printInstructions";
@@ -47,42 +46,39 @@ export const dev = async (api, options) => {
47
46
  }
48
47
  });
49
48
  await hookRunners.beforeDev();
50
- let compiler = null;
49
+ let compiler;
50
+ if (!appContext.builder && !apiOnly) {
51
+ throw new Error('Expect the Builder to have been initialized, But the appContext.builder received `undefined`');
52
+ }
51
53
  if (!apiOnly) {
52
- if (!appContext.builder) {
53
- throw new Error('Expect the Builder to have been initialized, But the appContext.builder received `undefined`');
54
- }
55
54
  compiler = await appContext.builder.createCompiler();
56
55
  }
57
56
  await generateRoutes(appContext);
58
- const app = await createServer({
59
- dev: _objectSpread(_objectSpread({}, {
60
- client: {
61
- port: port.toString()
62
- },
63
- devMiddleware: {
64
- writeToDisk: file => !file.includes('.hot-update.')
65
- },
66
- hot: true,
67
- liveReload: true,
57
+ const serverOptions = {
58
+ dev: _objectSpread({
68
59
  port,
69
60
  https: normalizedConfig.dev.https
70
- }), (_normalizedConfig$too = normalizedConfig.tools) === null || _normalizedConfig$too === void 0 ? void 0 : _normalizedConfig$too.devServer),
71
- compiler,
61
+ }, (_normalizedConfig$too = normalizedConfig.tools) === null || _normalizedConfig$too === void 0 ? void 0 : _normalizedConfig$too.devServer),
62
+ compiler: compiler || null,
72
63
  pwd: appDirectory,
73
64
  config: normalizedConfig,
74
65
  serverConfigFile,
75
66
  internalPlugins: injectDataLoaderPlugin(serverInternalPlugins)
76
- });
77
- app.listen(port, async err => {
78
- if (err) {
79
- throw err;
80
- }
81
- if (!apiOnly) {
82
- logger.info(`Starting dev server...\n`);
83
- } else {
67
+ };
68
+ if (apiOnly) {
69
+ const app = await createServer(serverOptions);
70
+ app.listen(port, async err => {
71
+ if (err) {
72
+ throw err;
73
+ }
84
74
  printInstructions(hookRunners, appContext, normalizedConfig);
85
- }
86
- });
75
+ });
76
+ } else {
77
+ await appContext.builder.startDevServer({
78
+ compiler,
79
+ printURLs: false,
80
+ serverOptions
81
+ });
82
+ }
87
83
  await createFileWatcher(appContext, normalizedConfig.source.configDir, hookRunners);
88
84
  };
@@ -16,7 +16,6 @@ export const start = async api => {
16
16
  const apiOnly = await isApiOnly(appContext.appDirectory, userConfig === null || userConfig === void 0 ? void 0 : (_userConfig$source = userConfig.source) === null || _userConfig$source === void 0 ? void 0 : _userConfig$source.entriesDir);
17
17
  const app = await server({
18
18
  pwd: appDirectory,
19
- // FIXME: remove the `any` type
20
19
  config: userConfig,
21
20
  serverConfigFile,
22
21
  internalPlugins: injectDataLoaderPlugin(appContext.serverInternalPlugins),
@@ -36,7 +36,6 @@ export function createDefaultConfig(appContext) {
36
36
  disableFilenameHash: false,
37
37
  enableLatestDecorators: false,
38
38
  polyfill: 'entry',
39
- dataUriLimit: 10000,
40
39
  cssModuleLocalIdentName: undefined
41
40
  };
42
41
  const html = {
@@ -62,6 +62,9 @@ export function createOutputConfig(config) {
62
62
  css: cssModuleLocalIdentName
63
63
  },
64
64
  ssg,
65
+ // set `true`, only in legacy config
66
+ enableAssetFallback: true,
67
+ enableAssetManifest: true,
65
68
  enableModernMode,
66
69
  disableNodePolyfill
67
70
  };
@@ -13,7 +13,7 @@ const getPackageConfig = (appDirectory, packageJsonConfig) => {
13
13
  const json = JSON.parse(fs.readFileSync(path.resolve(appDirectory, './package.json'), 'utf8'));
14
14
  return json[packageJsonConfig !== null && packageJsonConfig !== void 0 ? packageJsonConfig : PACKAGE_JSON_CONFIG_NAME];
15
15
  };
16
- const addServerConfigToDeps = async (dependencies, appDirectory, serverConfigFile) => {
16
+ export const addServerConfigToDeps = async (dependencies, appDirectory, serverConfigFile) => {
17
17
  const serverConfig = await getServerConfig(appDirectory, serverConfigFile);
18
18
  if (serverConfig) {
19
19
  dependencies.push(serverConfig);
@@ -5,7 +5,7 @@ export async function restart(hooksRunner) {
5
5
  let hasGetError = false;
6
6
  await hooksRunner.beforeRestart();
7
7
  try {
8
- await cli.init(cli.initOptions);
8
+ await cli.init(cli.getPrevInitOptions());
9
9
  } catch (err) {
10
10
  console.error(err);
11
11
  hasGetError = true;
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.PAGES_DIR_NAME = exports.NESTED_ROUTES_DIR = exports.JS_EXTENSIONS = exports.INDEX_FILE_NAME = exports.HTML_PARTIALS_FOLDER = exports.HTML_PARTIALS_EXTENSIONS = exports.FILE_SYSTEM_ROUTES_LAYOUT = exports.FILE_SYSTEM_ROUTES_INDEX = exports.FILE_SYSTEM_ROUTES_IGNORED_REGEX = exports.FILE_SYSTEM_ROUTES_GLOBAL_LAYOUT = exports.FILE_SYSTEM_ROUTES_FILE_NAME = exports.FILE_SYSTEM_ROUTES_DYNAMIC_REGEXP = exports.FILE_SYSTEM_ROUTES_COMPONENTS_DIR = exports.ENTRY_POINT_FILE_NAME = exports.ENTRY_BOOTSTRAP_FILE_NAME = exports.APP_FILE_NAME = void 0;
6
+ exports.TEMP_LOADERS_DIR = exports.PAGES_DIR_NAME = exports.NESTED_ROUTES_DIR = exports.LOADER_EXPORT_NAME = exports.JS_EXTENSIONS = exports.INDEX_FILE_NAME = exports.HTML_PARTIALS_FOLDER = exports.HTML_PARTIALS_EXTENSIONS = exports.FILE_SYSTEM_ROUTES_LAYOUT = exports.FILE_SYSTEM_ROUTES_INDEX = exports.FILE_SYSTEM_ROUTES_IGNORED_REGEX = exports.FILE_SYSTEM_ROUTES_GLOBAL_LAYOUT = exports.FILE_SYSTEM_ROUTES_FILE_NAME = exports.FILE_SYSTEM_ROUTES_DYNAMIC_REGEXP = exports.FILE_SYSTEM_ROUTES_COMPONENTS_DIR = exports.ENTRY_POINT_FILE_NAME = exports.ENTRY_BOOTSTRAP_FILE_NAME = exports.APP_FILE_NAME = void 0;
7
7
  const JS_EXTENSIONS = ['.js', '.ts', '.jsx', '.tsx'];
8
8
  exports.JS_EXTENSIONS = JS_EXTENSIONS;
9
9
  const INDEX_FILE_NAME = 'index';
@@ -16,6 +16,10 @@ const NESTED_ROUTES_DIR = 'routes';
16
16
  exports.NESTED_ROUTES_DIR = NESTED_ROUTES_DIR;
17
17
  const FILE_SYSTEM_ROUTES_FILE_NAME = 'routes.js';
18
18
  exports.FILE_SYSTEM_ROUTES_FILE_NAME = FILE_SYSTEM_ROUTES_FILE_NAME;
19
+ const LOADER_EXPORT_NAME = 'loader';
20
+ exports.LOADER_EXPORT_NAME = LOADER_EXPORT_NAME;
21
+ const TEMP_LOADERS_DIR = '__loaders__';
22
+ exports.TEMP_LOADERS_DIR = TEMP_LOADERS_DIR;
19
23
  const ENTRY_POINT_FILE_NAME = 'index.js';
20
24
  exports.ENTRY_POINT_FILE_NAME = ENTRY_POINT_FILE_NAME;
21
25
  const ENTRY_BOOTSTRAP_FILE_NAME = 'bootstrap.js';
@@ -17,6 +17,11 @@ var _nestedRoutes = require("./nestedRoutes");
17
17
  function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
18
18
  function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
19
19
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
20
+ const loader = {
21
+ '.js': 'jsx',
22
+ '.ts': 'tsx'
23
+ };
24
+ const EXTERNAL_REGEXP = /^[^./]|^\.[^./]|^\.\.[^/]/;
20
25
  const createImportSpecifier = specifiers => {
21
26
  let defaults = '';
22
27
  const named = [];
@@ -73,15 +78,10 @@ const createImportStatements = statements => {
73
78
  };
74
79
  exports.createImportStatements = createImportStatements;
75
80
  const buildLoader = async (entry, outfile) => {
76
- const loader = {
77
- '.js': 'jsx',
78
- '.ts': 'tsx'
79
- };
80
- const EXTERNAL_REGEXP = /^[^./]|^\.[^./]|^\.\.[^/]/;
81
81
  const command = (0, _commands.getCommand)();
82
82
  await _esbuild.default.build({
83
- format: 'cjs',
84
- platform: 'node',
83
+ format: 'esm',
84
+ platform: 'browser',
85
85
  target: 'esnext',
86
86
  loader,
87
87
  watch: command === 'dev' && {},
@@ -110,6 +110,20 @@ const buildLoader = async (entry, outfile) => {
110
110
  }]
111
111
  });
112
112
  };
113
+ const buildServerLoader = async (entry, outfile) => {
114
+ const command = (0, _commands.getCommand)();
115
+ await _esbuild.default.build({
116
+ format: 'cjs',
117
+ platform: 'node',
118
+ target: 'esnext',
119
+ loader,
120
+ watch: command === 'dev' && {},
121
+ bundle: true,
122
+ logLevel: 'error',
123
+ entryPoints: [entry],
124
+ outfile
125
+ });
126
+ };
113
127
  const generateCode = async (appContext, config, entrypoints, api) => {
114
128
  var _config$runtime, _config$runtime$route;
115
129
  const {
@@ -188,28 +202,34 @@ const generateCode = async (appContext, config, entrypoints, api) => {
188
202
  code
189
203
  } = await hookRunners.beforeGenerateRoutes({
190
204
  entrypoint,
191
- code: templates.fileSystemRoutes({
205
+ code: await templates.fileSystemRoutes({
192
206
  routes,
193
207
  ssrMode: mode,
194
208
  nestedRoutesEntry: entrypoint.nestedRoutesEntry,
195
- entryName: entrypoint.entryName
209
+ entryName: entrypoint.entryName,
210
+ internalDirectory
196
211
  })
197
212
  });
198
213
 
199
214
  // extract nested router loaders
200
215
  if (entrypoint.nestedRoutesEntry) {
201
- const routesServerFile = _path.default.join(internalDirectory, entryName, 'routes.server.js');
202
- const outputRoutesServerFile = _path.default.join(distDirectory, 'loader-routes', entryName, 'index.js');
216
+ const routesServerFile = _path.default.join(internalDirectory, entryName, 'route-server-loaders.js');
217
+ const outputRoutesServerFile = _path.default.join(distDirectory, _utils.LOADER_ROUTES_DIR, entryName, 'index.js');
203
218
  const code = templates.routesForServer({
204
219
  routes: routes,
205
- alias: {
206
- name: internalSrcAlias,
207
- basename: srcDirectory
208
- }
220
+ internalDirectory,
221
+ entryName
209
222
  });
210
223
  await _utils.fs.ensureFile(routesServerFile);
211
224
  await _utils.fs.writeFile(routesServerFile, code);
212
- await buildLoader(routesServerFile, outputRoutesServerFile);
225
+ const loaderEntryFile = _path.default.join(internalDirectory, entryName, _constants.TEMP_LOADERS_DIR, 'entry.js');
226
+ const loaderIndexFile = _path.default.join(internalDirectory, entryName, _constants.TEMP_LOADERS_DIR, 'index.js');
227
+ if (await _utils.fs.pathExists(loaderEntryFile)) {
228
+ await buildLoader(loaderEntryFile, loaderIndexFile);
229
+ }
230
+ if (await _utils.fs.pathExists(routesServerFile)) {
231
+ await buildServerLoader(routesServerFile, outputRoutesServerFile);
232
+ }
213
233
  }
214
234
  _utils.fs.outputFileSync(_path.default.resolve(internalDirectory, `./${entryName}/${_constants.FILE_SYSTEM_ROUTES_FILE_NAME}`), code, 'utf8');
215
235
  }
@@ -106,7 +106,8 @@ const collectHtmlRoutes = (entrypoints, appContext, config) => {
106
106
  output: {
107
107
  distPath: {
108
108
  html: htmlPath
109
- } = {}
109
+ } = {},
110
+ enableModernMode
110
111
  },
111
112
  server: {
112
113
  baseUrl,
@@ -133,8 +134,7 @@ const collectHtmlRoutes = (entrypoints, appContext, config) => {
133
134
  isSPA: true,
134
135
  isSSR,
135
136
  responseHeaders: resHeaders,
136
- // FIXME: remove the config.enableModernMode
137
- // enableModernMode: Boolean(enableModernMode),
137
+ enableModernMode: Boolean(enableModernMode),
138
138
  bundle: isSSR ? `${_utils.SERVER_BUNDLE_DIRECTORY}/${entryName}.js` : undefined
139
139
  };
140
140
  if (routes !== null && routes !== void 0 && routes.hasOwnProperty(entryName)) {
@@ -19,6 +19,12 @@ const LOADING_FILE = 'loading';
19
19
  const ERROR_FILE = 'error';
20
20
  const LOADER_FILE = 'loader';
21
21
  const conventionNames = [LAYOUT_FILE, PAGE_FILE, LOADING_FILE, ERROR_FILE, LOADER_FILE];
22
+ const getLoaderPath = async filename => {
23
+ if (await (0, _utils2.hasLoader)(filename)) {
24
+ return (0, _utils.normalizeToPosixPath)(filename);
25
+ }
26
+ return undefined;
27
+ };
22
28
  const replaceDynamicPath = routePath => {
23
29
  return routePath.replace(/\[(.*?)\]/g, ':$1');
24
30
  };
@@ -56,7 +62,8 @@ const walk = async (dirname, rootDir, alias, entryName) => {
56
62
  routePath = replaceDynamicPath(routePath);
57
63
  const route = {
58
64
  path: routePath,
59
- children: []
65
+ children: [],
66
+ isRoot
60
67
  };
61
68
  const items = await _utils.fs.readdir(dirname);
62
69
  for (const item of items) {
@@ -76,17 +83,21 @@ const walk = async (dirname, rootDir, alias, entryName) => {
76
83
  }
77
84
  if (itemWithoutExt === LAYOUT_FILE) {
78
85
  route._component = (0, _utils2.replaceWithAlias)(alias.basename, itemPath, alias.name);
86
+ route.loader = await getLoaderPath(itemPath);
79
87
  }
80
88
  if (itemWithoutExt === PAGE_FILE) {
81
89
  var _route$children2;
82
90
  const childRoute = createIndexRoute({
83
91
  _component: (0, _utils2.replaceWithAlias)(alias.basename, itemPath, alias.name)
84
92
  }, rootDir, itemPath, entryName);
93
+ childRoute.loader = await getLoaderPath(itemPath);
85
94
  (_route$children2 = route.children) === null || _route$children2 === void 0 ? void 0 : _route$children2.push(childRoute);
86
95
  }
87
- if (itemWithoutExt === LOADER_FILE) {
88
- route.loader = (0, _utils2.replaceWithAlias)(alias.basename, itemPath, alias.name);
89
- }
96
+
97
+ // if (itemWithoutExt === LOADER_FILE) {
98
+ // route.loader = replaceWithAlias(alias.basename, itemPath, alias.name);
99
+ // }
100
+
90
101
  if (itemWithoutExt === LOADING_FILE) {
91
102
  route.loading = (0, _utils2.replaceWithAlias)(alias.basename, itemPath, alias.name);
92
103
  }
@@ -4,6 +4,10 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.routesForServer = exports.renderFunction = exports.index = exports.html = exports.fileSystemRoutes = void 0;
7
+ var _path = _interopRequireDefault(require("path"));
8
+ var _utils = require("@modern-js/utils");
9
+ var _constants = require("./constants");
10
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
7
11
  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; }
8
12
  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; }
9
13
  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; }
@@ -87,13 +91,11 @@ const html = partials => `
87
91
  exports.html = html;
88
92
  const routesForServer = ({
89
93
  routes,
90
- alias
94
+ internalDirectory,
95
+ entryName
91
96
  }) => {
92
- const {
93
- name,
94
- basename
95
- } = alias;
96
97
  const loaders = [];
98
+ const loaderIndexFile = _path.default.join(internalDirectory, entryName, _constants.TEMP_LOADERS_DIR, 'index.js');
97
99
  const traverseRouteTree = route => {
98
100
  let children;
99
101
  if ('children' in route && route.children) {
@@ -125,39 +127,44 @@ const routesForServer = ({
125
127
  }
126
128
  }
127
129
  routesCode += `\n];`;
128
- const importLoadersCode = loaders.map((loader, index) => {
129
- const realLoaderPath = loader.replace(name, basename);
130
- return `import loader_${index} from '${realLoaderPath}';\n`;
131
- }).join('');
130
+ let importLoadersCode = '';
131
+ if (loaders.length > 0) {
132
+ importLoadersCode = `
133
+ import { ${loaders.map((loader, index) => `loader_${index}`)} } from "${loaderIndexFile}"`;
134
+ }
132
135
  return `
133
136
  ${importLoadersCode}
134
137
  ${routesCode}
135
138
  `;
136
139
  };
137
140
  exports.routesForServer = routesForServer;
138
- const fileSystemRoutes = ({
141
+ const fileSystemRoutes = async ({
139
142
  routes,
140
143
  ssrMode,
141
144
  nestedRoutesEntry,
142
- entryName
145
+ entryName,
146
+ internalDirectory
143
147
  }) => {
144
- // The legacy mode and pages dir routes should use loadable
145
- // nested routes + renderTostring should use loadable.lazy
146
- // nested routes + renderToStream should use react.lazy
148
+ const loadings = [];
149
+ const errors = [];
150
+ const loaders = [];
151
+ const loadersMap = {};
152
+ const loadersIndexFile = _path.default.join('@_modern_js_internal', entryName, _constants.TEMP_LOADERS_DIR, 'index.js');
153
+ const loadersMapFile = _path.default.join(internalDirectory, entryName, _constants.TEMP_LOADERS_DIR, 'map.json');
147
154
  const importLazyCode = `
148
155
  import { lazy } from "react";
149
156
  import loadable, { lazy as loadableLazy } from "@modern-js/runtime/loadable"
150
157
  `;
158
+ let rootLayoutCode = ``;
151
159
  let dataLoaderPath = '';
160
+ let componentLoaderPath = '';
152
161
  if (ssrMode) {
153
162
  dataLoaderPath = require.resolve(`@modern-js/plugin-data-loader/loader`);
154
163
  if (nestedRoutesEntry) {
155
- dataLoaderPath = `${dataLoaderPath}?routesDir=${nestedRoutesEntry}&entryName=${entryName}!`;
164
+ dataLoaderPath = `${dataLoaderPath}?routesDir=${nestedRoutesEntry}&mapFile=${loadersMapFile}!`;
156
165
  }
166
+ componentLoaderPath = `${_path.default.join(__dirname, '../builder/loaders/routerLoader')}!`;
157
167
  }
158
- const loadings = [];
159
- const errors = [];
160
- const loaders = [];
161
168
  const traverseRouteTree = route => {
162
169
  let children;
163
170
  if ('children' in route && route.children) {
@@ -179,13 +186,19 @@ const fileSystemRoutes = ({
179
186
  }
180
187
  if (route.loader) {
181
188
  loaders.push(route.loader);
182
- loader = `loader_${loaders.length - 1}`;
189
+ const loaderId = loaders.length - 1;
190
+ loader = `loader_${loaderId}`;
191
+ loadersMap[loader] = route.id;
183
192
  }
184
193
  if (route._component) {
185
- if (ssrMode === 'stream') {
186
- component = `lazy(() => import(/* webpackChunkName: "${route.id}" */ /* webpackMode: "lazy-once" */ '${route._component}'))`;
194
+ if (route.isRoot) {
195
+ rootLayoutCode = `import RootLayout from '${route._component}'`;
196
+ component = `RootLayout`;
197
+ } else if (ssrMode === 'string') {
198
+ component = `loadable(() => import(/* webpackChunkName: "${route.id}" */ '${componentLoaderPath}${route._component}'))`;
187
199
  } else {
188
- component = `loadable(() => import(/* webpackChunkName: "${route.id}" */ /* webpackMode: "lazy-once" */ '${route._component}'))`;
200
+ // csr and streaming
201
+ component = `lazy(() => import(/* webpackChunkName: "${route.id}" */ '${componentLoaderPath}${route._component}'))`;
189
202
  }
190
203
  }
191
204
  } else if (route._component) {
@@ -208,7 +221,7 @@ const fileSystemRoutes = ({
208
221
  for (const route of routes) {
209
222
  if ('type' in route) {
210
223
  const newRoute = traverseRouteTree(route);
211
- routeComponentsCode += `${JSON.stringify(newRoute, null, 2).replace(/"(loadable.*\))"/g, '$1').replace(/"(loadableLazy.*\))"/g, '$1').replace(/"(lazy.*\))"/g, '$1').replace(/"(loading_[^"])"/g, '$1').replace(/"(loader_[^"])"/g, '$1').replace(/"(error_[^"])"/g, '$1').replace(/\\"/g, '"')},`;
224
+ routeComponentsCode += `${JSON.stringify(newRoute, null, 2).replace(/"(loadable.*\))"/g, '$1').replace(/"(loadableLazy.*\))"/g, '$1').replace(/"(lazy.*\))"/g, '$1').replace(/"(loading_[^"])"/g, '$1').replace(/"(loader_[^"])"/g, '$1').replace(/"(RootLayout)"/g, '$1').replace(/"(error_[^"])"/g, '$1').replace(/\\"/g, '"')},`;
212
225
  } else {
213
226
  const component = `loadable(() => import('${route._component}'))`;
214
227
  const finalRoute = _objectSpread(_objectSpread({}, route), {}, {
@@ -224,14 +237,34 @@ const fileSystemRoutes = ({
224
237
  const importErrorComponentsCode = errors.map((error, index) => {
225
238
  return `import error_${index} from '${error}';\n`;
226
239
  }).join('');
227
- const importLoaderComponentsCode = loaders.map((loader, index) => {
228
- return `import loader_${index} from '${dataLoaderPath}${loader}';\n`;
229
- }).join('');
240
+ let importLoadersCode = '';
241
+ if (loaders.length > 0) {
242
+ importLoadersCode = `
243
+ import { ${loaders.map((loader, index) => `loader_${index}`)} } from "${dataLoaderPath}${loadersIndexFile}"
244
+ `;
245
+ const loaderEntryCode = loaders.map((loader, index) => {
246
+ return `export * from './loader_${index}.js';`;
247
+ }).join('\n');
248
+ const loaderEntryFile = _path.default.join(internalDirectory, entryName, _constants.TEMP_LOADERS_DIR, 'entry.js');
249
+ await _utils.fs.ensureFile(loaderEntryFile);
250
+ await _utils.fs.writeFile(loaderEntryFile, loaderEntryCode);
251
+ await _utils.fs.writeJSON(loadersMapFile, loadersMap);
252
+ await Promise.all(loaders.map(async (loader, index) => {
253
+ const name = `loader_${index}`;
254
+ const filename = _path.default.join(internalDirectory, entryName, _constants.TEMP_LOADERS_DIR, `${name}.js`);
255
+ const code = `
256
+ export { loader as ${name} } from '${loader}'
257
+ `;
258
+ await _utils.fs.ensureFile(filename);
259
+ await _utils.fs.writeFile(filename, code);
260
+ }));
261
+ }
230
262
  return `
231
263
  ${importLazyCode}
264
+ ${rootLayoutCode}
232
265
  ${importLoadingCode}
233
266
  ${importErrorComponentsCode}
234
- ${importLoaderComponentsCode}
267
+ ${importLoadersCode}
235
268
  ${routeComponentsCode}
236
269
  `;
237
270
  };
@@ -3,10 +3,12 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.walkDirectory = exports.replaceWithAlias = exports.isRouteComponentFile = exports.getDefaultImports = void 0;
6
+ exports.walkDirectory = exports.replaceWithAlias = exports.parseModule = exports.isRouteComponentFile = exports.hasLoader = exports.getDefaultImports = void 0;
7
7
  var _fs = _interopRequireDefault(require("fs"));
8
8
  var _path = _interopRequireDefault(require("path"));
9
9
  var _utils = require("@modern-js/utils");
10
+ var _esbuild = require("esbuild");
11
+ var _esModuleLexer = require("es-module-lexer");
10
12
  var _constants = require("./constants");
11
13
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
12
14
  const walkDirectory = dir => _fs.default.readdirSync(dir).reduce((previous, filename) => {
@@ -59,7 +61,7 @@ const getDefaultImports = ({
59
61
  specifiers: [{
60
62
  imported: 'routes'
61
63
  }],
62
- value: (0, _utils.normalizeToPosixPath)(`${internalDirAlias}/${entryName}/${_constants.FILE_SYSTEM_ROUTES_FILE_NAME}`)
64
+ value: (0, _utils.normalizeToPosixPath)(`${internalDirAlias}/${entryName}/${_constants.FILE_SYSTEM_ROUTES_FILE_NAME.replace('.js', '')}`)
63
65
  };
64
66
  if (fileSystemRoutes.globalApp) {
65
67
  imports.push({
@@ -94,4 +96,30 @@ const isRouteComponentFile = filePath => {
94
96
  };
95
97
  exports.isRouteComponentFile = isRouteComponentFile;
96
98
  const replaceWithAlias = (base, filePath, alias) => (0, _utils.normalizeToPosixPath)(_path.default.join(alias, _path.default.relative(base, filePath)));
97
- exports.replaceWithAlias = replaceWithAlias;
99
+ exports.replaceWithAlias = replaceWithAlias;
100
+ const parseModule = async ({
101
+ source,
102
+ filename
103
+ }) => {
104
+ let content = source;
105
+ if (filename.endsWith('.tsx') || filename.endsWith('.jsx')) {
106
+ const result = await (0, _esbuild.transform)(content, {
107
+ loader: _path.default.extname(filename).slice(1),
108
+ format: 'esm'
109
+ });
110
+ content = result.code;
111
+ }
112
+
113
+ // eslint-disable-next-line @typescript-eslint/await-thenable
114
+ return await (0, _esModuleLexer.parse)(content);
115
+ };
116
+ exports.parseModule = parseModule;
117
+ const hasLoader = async filename => {
118
+ const source = await _utils.fs.readFile(filename);
119
+ const [, moduleExports] = await parseModule({
120
+ source: source.toString(),
121
+ filename
122
+ });
123
+ return moduleExports.some(e => e.n === _constants.LOADER_EXPORT_NAME);
124
+ };
125
+ exports.hasLoader = hasLoader;
@@ -85,6 +85,11 @@ const PluginCompatModern = (appContext, modernConfig, options) => ({
85
85
  chain.plugin('route-plugin').use(_routerPlugin.default, [{
86
86
  existNestedRoutes
87
87
  }]);
88
+ if (target !== 'node') {
89
+ const bareServerModuleReg = /\.(server|node)\.[tj]sx?$/;
90
+ chain.module.rule(CHAIN_ID.RULE.JS).exclude.add(bareServerModuleReg);
91
+ chain.module.rule('bare-server-module').test(bareServerModuleReg).use('server-module-loader').loader(require.resolve("../loaders/serverModuleLoader"));
92
+ }
88
93
  function isHtmlEnabled(config, target) {
89
94
  var _config$tools;
90
95
  return ((_config$tools = config.tools) === null || _config$tools === void 0 ? void 0 : _config$tools.htmlPlugin) !== false && target !== 'node' && target !== 'web-worker';
@@ -116,7 +121,7 @@ function applyCallbacks(api, options) {
116
121
  */
117
122
  function applyNodeCompat(chain, modernConfig, isProd) {
118
123
  // apply node resolve extensions
119
- for (const ext of ['.node.js', '.node.jsx', '.node.ts', '.node.tsx']) {
124
+ for (const ext of ['.node.js', '.node.jsx', '.node.ts', '.node.tsx', '.server.js', '.server.ts', '.server.ts', '.server.tsx']) {
120
125
  chain.resolve.extensions.prepend(ext);
121
126
  }
122
127
 
@@ -43,6 +43,7 @@ async function createBuilderForEdenX({
43
43
  return builder;
44
44
  }
45
45
  function createBuilderProviderConfig(normalizedConfig, appContext) {
46
+ var _normalizedConfig$ser;
46
47
  const output = createOutputConfig(normalizedConfig, appContext);
47
48
  return _objectSpread(_objectSpread({}, normalizedConfig), {}, {
48
49
  source: _objectSpread(_objectSpread({}, normalizedConfig.source), {}, {
@@ -50,6 +51,7 @@ function createBuilderProviderConfig(normalizedConfig, appContext) {
50
51
  }),
51
52
  output,
52
53
  dev: {
54
+ port: (_normalizedConfig$ser = normalizedConfig.server) === null || _normalizedConfig$ser === void 0 ? void 0 : _normalizedConfig$ser.port,
53
55
  https: normalizedConfig.dev.https,
54
56
  assetPrefix: normalizedConfig.dev.assetPrefix
55
57
  },
@@ -71,11 +73,7 @@ function createBuilderProviderConfig(normalizedConfig, appContext) {
71
73
  return _objectSpread(_objectSpread({}, config.output), {}, {
72
74
  copy: builderCopy,
73
75
  // We need to do this in the app-tools prepare hook because some files will be generated into the dist directory in the analyze process
74
- cleanDistPath: false,
75
- // `@modern-js/webpack` used to generate asset manifest by default
76
- enableAssetManifest: true,
77
- // compatible the modern-js with fallback behavior
78
- enableAssetFallback: true
76
+ cleanDistPath: false
79
77
  });
80
78
  }
81
79
  }