@modern-js/app-tools 1.21.3 → 2.0.0-beta.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 (146) hide show
  1. package/CHANGELOG.md +138 -16
  2. package/dist/js/modern/analyze/constants.js +1 -0
  3. package/dist/js/modern/analyze/generateCode.js +118 -16
  4. package/dist/js/modern/analyze/getBundleEntry.js +3 -2
  5. package/dist/js/modern/analyze/getClientRoutes/getRoutes.js +198 -0
  6. package/dist/js/modern/analyze/{getClientRoutes.js → getClientRoutes/getRoutesLegacy.js} +8 -28
  7. package/dist/js/modern/analyze/getClientRoutes/index.js +2 -0
  8. package/dist/js/modern/analyze/getClientRoutes/utils.js +21 -0
  9. package/dist/js/modern/analyze/getFileSystemEntry.js +31 -12
  10. package/dist/js/modern/analyze/index.js +2 -1
  11. package/dist/js/modern/analyze/nestedRoutes.js +127 -0
  12. package/dist/js/modern/analyze/templates.js +164 -10
  13. package/dist/js/modern/analyze/utils.js +2 -1
  14. package/dist/js/modern/builder/builderPlugins/compatModern.js +226 -0
  15. package/dist/js/modern/builder/createHtmlConfig.js +58 -0
  16. package/dist/js/modern/builder/createOutputConfig.js +67 -0
  17. package/dist/js/modern/builder/createSourceConfig.js +85 -0
  18. package/dist/js/modern/builder/createToolsConfig.js +94 -0
  19. package/dist/js/modern/builder/index.js +106 -0
  20. package/dist/js/modern/builder/share.js +48 -0
  21. package/dist/js/modern/builder/webpackPlugins/htmlAsyncChunkPlugin.js +37 -0
  22. package/dist/js/modern/builder/webpackPlugins/htmlBottomTemplate.js +44 -0
  23. package/dist/js/modern/commands/build.js +41 -95
  24. package/dist/js/modern/commands/dev.js +15 -19
  25. package/dist/js/modern/commands/inspect.js +17 -58
  26. package/dist/js/modern/commands/start.js +2 -1
  27. package/dist/js/modern/index.js +14 -4
  28. package/dist/js/modern/locale/en.js +0 -1
  29. package/dist/js/modern/locale/zh.js +0 -1
  30. package/dist/js/modern/utils/commands.js +5 -0
  31. package/dist/js/modern/utils/createCompiler.js +37 -40
  32. package/dist/js/modern/utils/createServer.js +16 -0
  33. package/dist/js/modern/utils/printInstructions.js +1 -1
  34. package/dist/js/node/analyze/constants.js +3 -1
  35. package/dist/js/node/analyze/generateCode.js +121 -14
  36. package/dist/js/node/analyze/getBundleEntry.js +3 -2
  37. package/dist/js/node/analyze/getClientRoutes/getRoutes.js +221 -0
  38. package/dist/js/node/analyze/{getClientRoutes.js → getClientRoutes/getRoutesLegacy.js} +16 -35
  39. package/dist/js/node/analyze/getClientRoutes/index.js +21 -0
  40. package/dist/js/node/analyze/getClientRoutes/utils.js +42 -0
  41. package/dist/js/node/analyze/getFileSystemEntry.js +30 -11
  42. package/dist/js/node/analyze/index.js +2 -1
  43. package/dist/js/node/analyze/nestedRoutes.js +144 -0
  44. package/dist/js/node/analyze/templates.js +167 -10
  45. package/dist/js/node/analyze/utils.js +6 -2
  46. package/dist/js/node/builder/builderPlugins/compatModern.js +245 -0
  47. package/dist/js/node/builder/createHtmlConfig.js +76 -0
  48. package/dist/js/node/builder/createOutputConfig.js +75 -0
  49. package/dist/js/node/builder/createSourceConfig.js +99 -0
  50. package/dist/js/node/builder/createToolsConfig.js +103 -0
  51. package/dist/js/node/builder/index.js +129 -0
  52. package/dist/js/node/builder/share.js +63 -0
  53. package/dist/js/node/builder/webpackPlugins/htmlAsyncChunkPlugin.js +46 -0
  54. package/dist/js/node/builder/webpackPlugins/htmlBottomTemplate.js +53 -0
  55. package/dist/js/node/commands/build.js +44 -98
  56. package/dist/js/node/commands/dev.js +13 -23
  57. package/dist/js/node/commands/inspect.js +18 -74
  58. package/dist/js/node/commands/start.js +3 -1
  59. package/dist/js/node/index.js +19 -2
  60. package/dist/js/node/locale/en.js +0 -1
  61. package/dist/js/node/locale/zh.js +0 -1
  62. package/dist/js/node/utils/commands.js +14 -0
  63. package/dist/js/node/utils/createCompiler.js +43 -49
  64. package/dist/js/node/utils/createServer.js +21 -2
  65. package/dist/js/node/utils/printInstructions.js +1 -1
  66. package/dist/js/treeshaking/analyze/constants.js +16 -0
  67. package/dist/js/treeshaking/analyze/generateCode.js +412 -0
  68. package/dist/js/treeshaking/analyze/getBundleEntry.js +77 -0
  69. package/dist/js/treeshaking/analyze/getClientRoutes/getRoutes.js +210 -0
  70. package/dist/js/treeshaking/analyze/getClientRoutes/getRoutesLegacy.js +211 -0
  71. package/dist/js/treeshaking/analyze/getClientRoutes/index.js +2 -0
  72. package/dist/js/treeshaking/analyze/getClientRoutes/utils.js +27 -0
  73. package/dist/js/treeshaking/analyze/getFileSystemEntry.js +109 -0
  74. package/dist/js/treeshaking/analyze/getHtmlTemplate.js +153 -0
  75. package/dist/js/treeshaking/analyze/getServerRoutes.js +170 -0
  76. package/dist/js/treeshaking/analyze/index.js +214 -0
  77. package/dist/js/treeshaking/analyze/isDefaultExportFunction.js +32 -0
  78. package/dist/js/treeshaking/analyze/makeLegalIdentifier.js +18 -0
  79. package/dist/js/treeshaking/analyze/nestedRoutes.js +207 -0
  80. package/dist/js/treeshaking/analyze/templates.js +189 -0
  81. package/dist/js/treeshaking/analyze/utils.js +95 -0
  82. package/dist/js/treeshaking/builder/builderPlugins/compatModern.js +231 -0
  83. package/dist/js/treeshaking/builder/createHtmlConfig.js +59 -0
  84. package/dist/js/treeshaking/builder/createOutputConfig.js +67 -0
  85. package/dist/js/treeshaking/builder/createSourceConfig.js +100 -0
  86. package/dist/js/treeshaking/builder/createToolsConfig.js +90 -0
  87. package/dist/js/treeshaking/builder/index.js +172 -0
  88. package/dist/js/treeshaking/builder/share.js +50 -0
  89. package/dist/js/treeshaking/builder/webpackPlugins/htmlAsyncChunkPlugin.js +58 -0
  90. package/dist/js/treeshaking/builder/webpackPlugins/htmlBottomTemplate.js +53 -0
  91. package/dist/js/treeshaking/commands/build.js +168 -0
  92. package/dist/js/treeshaking/commands/deploy.js +29 -0
  93. package/dist/js/treeshaking/commands/dev.js +146 -0
  94. package/dist/js/treeshaking/commands/index.js +3 -0
  95. package/dist/js/treeshaking/commands/inspect.js +52 -0
  96. package/dist/js/treeshaking/commands/start.js +78 -0
  97. package/dist/js/treeshaking/exports/server.js +1 -0
  98. package/dist/js/treeshaking/hooks.js +21 -0
  99. package/dist/js/treeshaking/index.js +304 -0
  100. package/dist/js/treeshaking/locale/en.js +34 -0
  101. package/dist/js/treeshaking/locale/index.js +9 -0
  102. package/dist/js/treeshaking/locale/zh.js +34 -0
  103. package/dist/js/treeshaking/utils/commands.js +5 -0
  104. package/dist/js/treeshaking/utils/config.js +140 -0
  105. package/dist/js/treeshaking/utils/createCompiler.js +117 -0
  106. package/dist/js/treeshaking/utils/createServer.js +83 -0
  107. package/dist/js/treeshaking/utils/getSpecifiedEntries.js +68 -0
  108. package/dist/js/treeshaking/utils/language.js +5 -0
  109. package/dist/js/treeshaking/utils/printInstructions.js +35 -0
  110. package/dist/js/treeshaking/utils/routes.js +33 -0
  111. package/dist/js/treeshaking/utils/types.js +0 -0
  112. package/dist/types/analyze/constants.d.ts +1 -0
  113. package/dist/types/analyze/generateCode.d.ts +1 -1
  114. package/dist/types/analyze/{getClientRoutes.d.ts → getClientRoutes/getRoutes.d.ts} +2 -7
  115. package/dist/types/analyze/getClientRoutes/getRoutesLegacy.d.ts +15 -0
  116. package/dist/types/analyze/getClientRoutes/index.d.ts +2 -0
  117. package/dist/types/analyze/getClientRoutes/utils.d.ts +5 -0
  118. package/dist/types/analyze/index.d.ts +2 -2
  119. package/dist/types/analyze/nestedRoutes.d.ts +5 -0
  120. package/dist/types/analyze/templates.d.ts +17 -3
  121. package/dist/types/analyze/utils.d.ts +2 -1
  122. package/dist/types/builder/builderPlugins/compatModern.d.ts +14 -0
  123. package/dist/types/builder/createHtmlConfig.d.ts +6 -0
  124. package/dist/types/builder/createOutputConfig.d.ts +3 -0
  125. package/dist/types/builder/createSourceConfig.d.ts +5 -0
  126. package/dist/types/builder/createToolsConfig.d.ts +13 -0
  127. package/dist/types/builder/index.d.ts +19 -0
  128. package/dist/types/builder/share.d.ts +26 -0
  129. package/dist/types/builder/webpackPlugins/htmlAsyncChunkPlugin.d.ts +8 -0
  130. package/dist/types/builder/webpackPlugins/htmlBottomTemplate.d.ts +10 -0
  131. package/dist/types/commands/build.d.ts +2 -1
  132. package/dist/types/commands/deploy.d.ts +2 -1
  133. package/dist/types/commands/dev.d.ts +2 -1
  134. package/dist/types/commands/inspect.d.ts +5 -6
  135. package/dist/types/commands/start.d.ts +2 -1
  136. package/dist/types/hooks.d.ts +15 -10
  137. package/dist/types/index.d.ts +4 -2
  138. package/dist/types/locale/en.d.ts +0 -1
  139. package/dist/types/locale/index.d.ts +0 -2
  140. package/dist/types/locale/zh.d.ts +0 -1
  141. package/dist/types/utils/commands.d.ts +1 -0
  142. package/dist/types/utils/createCompiler.d.ts +9 -10
  143. package/dist/types/utils/createServer.d.ts +8 -1
  144. package/dist/types/utils/printInstructions.d.ts +3 -2
  145. package/dist/types/utils/types.d.ts +2 -3
  146. package/package.json +25 -43
@@ -2,7 +2,7 @@ import fs from 'fs';
2
2
  import path from 'path';
3
3
  import { findExists, ensureAbsolutePath } from '@modern-js/utils';
4
4
  import { isDefaultExportFunction } from "./isDefaultExportFunction";
5
- import { JS_EXTENSIONS, INDEX_FILE_NAME, APP_FILE_NAME, PAGES_DIR_NAME, FILE_SYSTEM_ROUTES_GLOBAL_LAYOUT } from "./constants";
5
+ import { JS_EXTENSIONS, INDEX_FILE_NAME, APP_FILE_NAME, PAGES_DIR_NAME, FILE_SYSTEM_ROUTES_GLOBAL_LAYOUT, NESTED_ROUTES_DIR } from "./constants";
6
6
 
7
7
  const hasIndex = dir => findExists(JS_EXTENSIONS.map(ext => path.resolve(dir, `${INDEX_FILE_NAME}${ext}`)));
8
8
 
@@ -10,7 +10,9 @@ const hasApp = dir => findExists(JS_EXTENSIONS.map(ext => path.resolve(dir, `${A
10
10
 
11
11
  const hasPages = dir => fs.existsSync(path.join(dir, PAGES_DIR_NAME));
12
12
 
13
- const isBundleEntry = dir => hasApp(dir) || hasPages(dir) || hasIndex(dir);
13
+ const hasNestedRoutes = dir => fs.existsSync(path.join(dir, NESTED_ROUTES_DIR));
14
+
15
+ const isBundleEntry = dir => hasApp(dir) || hasPages(dir) || hasIndex(dir) || hasNestedRoutes(dir);
14
16
 
15
17
  const scanDir = dirs => dirs.map(dir => {
16
18
  const indexFile = hasIndex(dir);
@@ -25,30 +27,47 @@ const scanDir = dirs => dirs.map(dir => {
25
27
  };
26
28
  }
27
29
 
28
- if (hasApp(dir)) {
30
+ const isHasApp = hasApp(dir);
31
+
32
+ if (isHasApp) {
29
33
  return {
30
34
  entryName,
31
35
  entry: path.join(dir, APP_FILE_NAME),
32
36
  isAutoMount: true,
33
37
  customBootstrap
34
38
  };
35
- } else if (hasPages(dir)) {
36
- return {
39
+ }
40
+
41
+ const isHasNestedRoutes = hasNestedRoutes(dir);
42
+ const isHasPages = hasPages(dir);
43
+
44
+ if (isHasNestedRoutes || isHasPages) {
45
+ const entrypoint = {
37
46
  entryName,
38
- entry: path.join(dir, PAGES_DIR_NAME),
47
+ entry: '',
39
48
  fileSystemRoutes: {
40
49
  globalApp: findExists(JS_EXTENSIONS.map(ext => path.resolve(dir, `./${PAGES_DIR_NAME}/${FILE_SYSTEM_ROUTES_GLOBAL_LAYOUT}${ext}`)))
41
50
  },
42
51
  isAutoMount: true,
43
52
  customBootstrap
44
53
  };
45
- } else {
46
- return {
47
- entryName,
48
- entry: indexFile,
49
- isAutoMount: false
50
- };
54
+
55
+ if (isHasPages) {
56
+ entrypoint.entry = path.join(dir, PAGES_DIR_NAME);
57
+ }
58
+
59
+ if (isHasNestedRoutes) {
60
+ entrypoint.nestedRoutesEntry = path.join(dir, NESTED_ROUTES_DIR);
61
+ }
62
+
63
+ return entrypoint;
51
64
  }
65
+
66
+ return {
67
+ entryName,
68
+ entry: indexFile,
69
+ isAutoMount: false
70
+ };
52
71
  });
53
72
 
54
73
  export const getFileSystemEntry = (appContext, config) => {
@@ -95,7 +95,8 @@ export default (() => ({
95
95
  entrypoints,
96
96
  serverRoutes: routes
97
97
  }));
98
- pagesDir = entrypoints.map(point => point.entry);
98
+ const nestedRouteEntries = entrypoints.map(point => point.nestedRoutesEntry).filter(Boolean);
99
+ pagesDir = entrypoints.map(point => point.entry).filter(Boolean).concat(nestedRouteEntries);
99
100
  originEntrypoints = cloneDeep(entrypoints);
100
101
  await generateCode(appContext, resolvedConfig, entrypoints, api);
101
102
  const htmlTemplates = await getHtmlTemplate(entrypoints, api, {
@@ -0,0 +1,127 @@
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
+
3
+ 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; }
4
+
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
+
7
+ import * as path from 'path';
8
+ import { fs, getRouteId } from '@modern-js/utils';
9
+ import { JS_EXTENSIONS } from "./constants";
10
+ import { replaceWithAlias } from "./utils";
11
+ const LAYOUT_FILE = 'layout';
12
+ const PAGE_FILE = 'page';
13
+ const LOADING_FILE = 'loading';
14
+ const ERROR_FILE = 'error';
15
+ const LOADER_FILE = 'loader';
16
+ const conventionNames = [LAYOUT_FILE, PAGE_FILE, LOADING_FILE, ERROR_FILE, LOADER_FILE];
17
+
18
+ const replaceDynamicPath = routePath => {
19
+ return routePath.replace(/\[(.*?)\]/g, ':$1');
20
+ };
21
+
22
+ const createIndexRoute = (routeInfo, rootDir, filename) => {
23
+ return createRoute(_objectSpread(_objectSpread({}, routeInfo), {}, {
24
+ index: true,
25
+ children: undefined
26
+ }), rootDir, filename);
27
+ };
28
+
29
+ const createRoute = (routeInfo, rootDir, filename) => {
30
+ const id = getRouteId(filename, rootDir);
31
+ return _objectSpread(_objectSpread({}, routeInfo), {}, {
32
+ id,
33
+ type: 'nested'
34
+ });
35
+ };
36
+
37
+ export const walk = async (dirname, rootDir, alias) => {
38
+ if (!(await fs.pathExists(dirname))) {
39
+ return null;
40
+ }
41
+
42
+ const isDirectory = (await fs.stat(dirname)).isDirectory();
43
+
44
+ if (!isDirectory) {
45
+ return null;
46
+ }
47
+
48
+ const relativeDir = path.relative(rootDir, dirname);
49
+ const pathSegments = relativeDir.split(path.sep);
50
+ const lastSegment = pathSegments[pathSegments.length - 1];
51
+ const isRoot = lastSegment === '';
52
+ const isPathlessLayout = lastSegment.startsWith('__');
53
+ const isWithoutLayoutPath = lastSegment.includes('.');
54
+ let routePath = isRoot || isPathlessLayout ? '/' : `${lastSegment}`;
55
+
56
+ if (isWithoutLayoutPath) {
57
+ routePath = lastSegment.split('.').join('/');
58
+ }
59
+
60
+ routePath = replaceDynamicPath(routePath);
61
+ const route = {
62
+ path: routePath,
63
+ children: []
64
+ };
65
+ const items = await fs.readdir(dirname);
66
+
67
+ for (const item of items) {
68
+ const itemPath = path.join(dirname, item);
69
+ const extname = path.extname(item);
70
+ const itemWithoutExt = item.slice(0, -extname.length);
71
+ const isDirectory = (await fs.stat(itemPath)).isDirectory();
72
+
73
+ if (isDirectory) {
74
+ const childRoute = await walk(itemPath, rootDir, alias);
75
+
76
+ if (childRoute) {
77
+ var _route$children;
78
+
79
+ (_route$children = route.children) === null || _route$children === void 0 ? void 0 : _route$children.push(childRoute);
80
+ }
81
+ }
82
+
83
+ if (extname && (!JS_EXTENSIONS.includes(extname) || !conventionNames.includes(itemWithoutExt))) {
84
+ continue;
85
+ }
86
+
87
+ if (itemWithoutExt === LAYOUT_FILE) {
88
+ route._component = replaceWithAlias(alias.basename, itemPath, alias.name);
89
+ }
90
+
91
+ if (itemWithoutExt === PAGE_FILE) {
92
+ var _route$children2;
93
+
94
+ const childRoute = createIndexRoute({
95
+ _component: replaceWithAlias(alias.basename, itemPath, alias.name)
96
+ }, rootDir, itemPath);
97
+ (_route$children2 = route.children) === null || _route$children2 === void 0 ? void 0 : _route$children2.push(childRoute);
98
+ }
99
+
100
+ if (itemWithoutExt === LOADER_FILE) {
101
+ route.loader = replaceWithAlias(alias.basename, itemPath, alias.name);
102
+ }
103
+
104
+ if (itemWithoutExt === LOADING_FILE) {
105
+ route.loading = replaceWithAlias(alias.basename, itemPath, alias.name);
106
+ }
107
+
108
+ if (itemWithoutExt === ERROR_FILE) {
109
+ route.error = replaceWithAlias(alias.basename, itemPath, alias.name);
110
+ }
111
+ }
112
+
113
+ const finalRoute = createRoute(route, rootDir, path.join(dirname, `${LAYOUT_FILE}.ts`));
114
+ /**
115
+ * when the url is /, the __auth/layout.tsx component should not be rendered
116
+ * - routes
117
+ * - __auth
118
+ * - layout.tsx
119
+ * - layout.tsx
120
+ */
121
+
122
+ if (isPathlessLayout) {
123
+ delete finalRoute.path;
124
+ }
125
+
126
+ return finalRoute;
127
+ };
@@ -1,3 +1,9 @@
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
+
3
+ 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; }
4
+
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
+
1
7
  export const index = ({
2
8
  mountId,
3
9
  imports,
@@ -73,16 +79,164 @@ export const html = partials => `
73
79
 
74
80
  </html>
75
81
  `;
76
- export const fileSystemRoutes = ({
77
- routes
78
- }) => `
79
- import loadable from '@modern-js/runtime/loadable';
82
+ export const routesForServer = ({
83
+ routes,
84
+ alias
85
+ }) => {
86
+ const {
87
+ name,
88
+ basename
89
+ } = alias;
90
+ const loaders = [];
91
+
92
+ const traverseRouteTree = route => {
93
+ let children;
94
+
95
+ if ('children' in route && route.children) {
96
+ var _route$children;
97
+
98
+ children = route === null || route === void 0 ? void 0 : (_route$children = route.children) === null || _route$children === void 0 ? void 0 : _route$children.map(traverseRouteTree);
99
+ }
100
+
101
+ let loader;
102
+
103
+ if (route.type === 'nested') {
104
+ if (route.loader) {
105
+ loaders.push(route.loader);
106
+ loader = `loader_${loaders.length - 1}`;
107
+ }
108
+ }
109
+
110
+ const finalRoute = _objectSpread(_objectSpread({}, route), {}, {
111
+ loader,
112
+ children
113
+ });
114
+
115
+ return finalRoute;
116
+ };
117
+
118
+ let routesCode = `
119
+ export const routes = [
120
+ `;
121
+
122
+ for (const route of routes) {
123
+ if ('type' in route) {
124
+ const newRoute = traverseRouteTree(route);
125
+ routesCode += `${JSON.stringify(newRoute, null, 2).replace(/"(loader_[^"])"/g, '$1')},`;
126
+ } else {
127
+ routesCode += `${JSON.stringify(route, null, 2)}`;
128
+ }
129
+ }
80
130
 
81
- ${routes.map(({
82
- component,
83
- _component
84
- }) => `const ${component} = loadable(() => import('${_component}'));`).join('\n\n')}
131
+ routesCode += `\n];`;
132
+ const importLoadersCode = loaders.map((loader, index) => {
133
+ const realLoaderPath = loader.replace(name, basename);
134
+ return `import loader_${index} from '${realLoaderPath}';\n`;
135
+ }).join('');
136
+ return `
137
+ ${importLoadersCode}
138
+ ${routesCode}
139
+ `;
140
+ };
141
+ export const fileSystemRoutes = ({
142
+ routes,
143
+ ssrMode,
144
+ nestedRoutesEntry
145
+ }) => {
146
+ const importLazyCode = ssrMode === 'stream' ? 'import { lazy } from "react";' : `import loadable from '@modern-js/runtime/loadable'`;
147
+ let dataLoaderPath = '';
148
+
149
+ if (ssrMode) {
150
+ dataLoaderPath = require.resolve(`@modern-js/plugin-data-loader/loader`);
151
+
152
+ if (nestedRoutesEntry) {
153
+ dataLoaderPath = `${dataLoaderPath}?routesDir=${nestedRoutesEntry}!`;
154
+ }
155
+ }
85
156
 
157
+ const loadings = [];
158
+ const errors = [];
159
+ const loaders = [];
160
+
161
+ const traverseRouteTree = route => {
162
+ let children;
163
+
164
+ if ('children' in route && route.children) {
165
+ var _route$children2;
166
+
167
+ children = route === null || route === void 0 ? void 0 : (_route$children2 = route.children) === null || _route$children2 === void 0 ? void 0 : _route$children2.map(traverseRouteTree);
168
+ }
169
+
170
+ let loading;
171
+ let error;
172
+ let loader;
173
+
174
+ if (route.type === 'nested') {
175
+ if (route.loading) {
176
+ loadings.push(route.loading);
177
+ loading = `loading_${loadings.length - 1}`;
178
+ }
179
+
180
+ if (route.error) {
181
+ errors.push(route.error);
182
+ error = `error_${errors.length - 1}`;
183
+ }
184
+
185
+ if (route.loader) {
186
+ loaders.push(route.loader);
187
+ loader = `loader_${loaders.length - 1}`;
188
+ }
189
+ }
190
+
191
+ const finalRoute = _objectSpread(_objectSpread({}, route), {}, {
192
+ loading,
193
+ loader,
194
+ error,
195
+ children
196
+ });
197
+
198
+ if (route._component) {
199
+ const component = ssrMode === 'stream' ? `lazy(() => import('${route._component}'))` : `loadable(() => import('${route._component}'))`;
200
+ finalRoute.component = component;
201
+ }
202
+
203
+ return finalRoute;
204
+ };
205
+
206
+ let routeComponentsCode = `
207
+ export const routes = [
208
+ `;
209
+
210
+ for (const route of routes) {
211
+ if ('type' in route) {
212
+ const newRoute = traverseRouteTree(route);
213
+ routeComponentsCode += `${JSON.stringify(newRoute, null, 2).replace(/"(loadable[^"]*)"/g, '$1').replace(/"(lazy[^"]*)"/g, '$1').replace(/"(loading_[^"])"/g, '$1').replace(/"(loader_[^"])"/g, '$1').replace(/"(error_[^"])"/g, '$1')},`;
214
+ } else {
215
+ const component = ssrMode === 'stream' ? `lazy(() => import('${route._component}'))` : `loadable(() => import('${route._component}'))`;
216
+
217
+ const finalRoute = _objectSpread(_objectSpread({}, route), {}, {
218
+ component
219
+ });
220
+
221
+ routeComponentsCode += `${JSON.stringify(finalRoute, null, 2).replace(/"(loadable[^"]*)"/g, '$1').replace(/"(lazy[^"]*)"/g, '$1')},`;
222
+ }
223
+ }
86
224
 
87
- export const routes = ${JSON.stringify(routes, null, 2).replace(/"component"\s*:\s*"(\S+)"/g, '"component": $1')}
88
- `;
225
+ routeComponentsCode += `\n];`;
226
+ const importLoadingCode = loadings.map((loading, index) => {
227
+ return `import loading_${index} from '${loading}';\n`;
228
+ }).join('');
229
+ const importErrorComponentsCode = errors.map((error, index) => {
230
+ return `import error_${index} from '${error}';\n`;
231
+ }).join('');
232
+ const importLoaderComponentsCode = loaders.map((loader, index) => {
233
+ return `import loader_${index} from '${dataLoaderPath}${loader}';\n`;
234
+ }).join('');
235
+ return `
236
+ ${importLazyCode}
237
+ ${importLoadingCode}
238
+ ${importErrorComponentsCode}
239
+ ${importLoaderComponentsCode}
240
+ ${routeComponentsCode}
241
+ `;
242
+ };
@@ -89,4 +89,5 @@ export const isRouteComponentFile = filePath => {
89
89
  }
90
90
 
91
91
  return false;
92
- };
92
+ };
93
+ export const replaceWithAlias = (base, filePath, alias) => normalizeToPosixPath(path.join(alias, path.relative(base, filePath)));
@@ -0,0 +1,226 @@
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
+
3
+ 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; }
4
+
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
+
7
+ import { join } from 'path';
8
+ import { mergeBuilderConfig } from '@modern-js/builder-shared';
9
+ import { template as lodashTemplate } from '@modern-js/utils/lodash';
10
+ import HtmlWebpackPlugin from '@modern-js/builder-webpack-provider/html-webpack-plugin';
11
+ import { getEntryOptions } from '@modern-js/utils';
12
+ import { BottomTemplatePlugin } from "../webpackPlugins/htmlBottomTemplate";
13
+ import { HtmlAsyncChunkPlugin } from "../webpackPlugins/htmlAsyncChunkPlugin";
14
+ import { createCopyPattern } from "../share";
15
+
16
+ /**
17
+ * Provides default configuration consistent with `@modern-js/webpack`
18
+ */
19
+ export const PluginCompatModern = (appContext, modernConfig, options) => ({
20
+ name: 'builder-plugin-compat-modern',
21
+
22
+ setup(api) {
23
+ api.modifyBuilderConfig(config => {
24
+ if (isStreamingSSR(modernConfig)) {
25
+ return mergeBuilderConfig(config, {
26
+ html: {
27
+ inject: 'body'
28
+ }
29
+ });
30
+ }
31
+
32
+ return config;
33
+ });
34
+ api.modifyWebpackChain((chain, {
35
+ target,
36
+ CHAIN_ID,
37
+ isProd
38
+ }) => {
39
+ const builderNormalizedConfig = api.getNormalizedConfig(); // set webpack config name
40
+
41
+ if (target === 'node') {
42
+ chain.name('server');
43
+ } else if (target === 'modern-web') {
44
+ chain.name('modern');
45
+ } else {
46
+ chain.name('client');
47
+ }
48
+
49
+ chain.resolve.modules.add('node_modules').add(join(api.context.rootPath, 'node_modules')); // apply node compat
50
+
51
+ if (target === 'node') {
52
+ applyNodeCompat(chain, modernConfig, isProd);
53
+ }
54
+
55
+ if (isHtmlEnabled(builderNormalizedConfig, target)) {
56
+ applyBottomHtmlWebpackPlugin({
57
+ api,
58
+ chain,
59
+ CHAIN_ID,
60
+ appContext,
61
+ modernConfig
62
+ });
63
+ applyAsyncChunkHtmlPlugin({
64
+ chain,
65
+ CHAIN_ID,
66
+ modernConfig
67
+ });
68
+ } // apply copy plugin
69
+ // const copyPatterns = createCopyPatterns(chain, appContext, modernConfig);
70
+
71
+
72
+ const defaultCopyPattern = createCopyPattern(appContext, modernConfig, 'public', chain);
73
+ chain.plugin(CHAIN_ID.PLUGIN.COPY).tap(args => {
74
+ var _args$;
75
+
76
+ return [{
77
+ patterns: [...(((_args$ = args[0]) === null || _args$ === void 0 ? void 0 : _args$.patterns) || []), defaultCopyPattern]
78
+ }];
79
+ });
80
+
81
+ function isHtmlEnabled(config, target) {
82
+ var _config$tools;
83
+
84
+ return ((_config$tools = config.tools) === null || _config$tools === void 0 ? void 0 : _config$tools.htmlPlugin) !== false && target !== 'node' && target !== 'web-worker';
85
+ }
86
+ });
87
+
88
+ if (options) {
89
+ applyCallbacks(api, options);
90
+ }
91
+ }
92
+
93
+ });
94
+ /**
95
+ * register builder hooks callback
96
+ */
97
+
98
+ function applyCallbacks(api, options) {
99
+ options.onAfterBuild && api.onAfterBuild(options.onAfterBuild);
100
+ options.onAfterCreateCompiler && api.onAfterCreateCompiler(options.onAfterCreateCompiler);
101
+ options.onAfterStartDevServer && api.onAfterStartDevServer(options.onAfterStartDevServer);
102
+ options.onBeforeBuild && api.onBeforeBuild(options.onBeforeBuild);
103
+ options.onBeforeCreateCompiler && api.onBeforeCreateCompiler(options.onBeforeCreateCompiler);
104
+ options.onBeforeStartDevServer && api.onBeforeStartDevServer(options.onBeforeStartDevServer);
105
+ options.onDevCompileDone && api.onDevCompileDone(options.onDevCompileDone);
106
+ options.onExit && api.onExit(options.onExit);
107
+ }
108
+ /**
109
+ * compat some config, if target is `node`
110
+ */
111
+
112
+
113
+ function applyNodeCompat(chain, modernConfig, isProd) {
114
+ // apply node resolve extensions
115
+ for (const ext of ['.node.js', '.node.jsx', '.node.ts', '.node.tsx']) {
116
+ chain.resolve.extensions.prepend(ext);
117
+ } // apply filterEntriesBySSRConfig
118
+
119
+
120
+ filterEntriesBySSRConfig(isProd, chain, modernConfig.server, modernConfig.output);
121
+
122
+ function filterEntriesBySSRConfig(isProd, chain, serverConfig, outputConfig) {
123
+ var _outputConfig$ssg;
124
+
125
+ const entries = chain.entryPoints.entries(); // if prod and ssg config is true or function
126
+
127
+ if (isProd && ((outputConfig === null || outputConfig === void 0 ? void 0 : outputConfig.ssg) === true || typeof (outputConfig === null || outputConfig === void 0 ? void 0 : (_outputConfig$ssg = outputConfig.ssg) === null || _outputConfig$ssg === void 0 ? void 0 : _outputConfig$ssg[0]) === 'function')) {
128
+ return;
129
+ } // if single entry has ssg config
130
+ // `ssg: {}` is not allowed if multi entry
131
+
132
+
133
+ const entryNames = Object.keys(entries);
134
+
135
+ if (isProd && entryNames.length === 1 && outputConfig !== null && outputConfig !== void 0 && outputConfig.ssg) {
136
+ return;
137
+ } // collect all ssg entries
138
+
139
+
140
+ const ssgEntries = [];
141
+
142
+ if (isProd && outputConfig !== null && outputConfig !== void 0 && outputConfig.ssg) {
143
+ const {
144
+ ssg
145
+ } = outputConfig;
146
+ entryNames.forEach(name => {
147
+ if (ssg[name]) {
148
+ ssgEntries.push(name);
149
+ }
150
+ });
151
+ }
152
+
153
+ const {
154
+ ssr,
155
+ ssrByEntries
156
+ } = serverConfig || {};
157
+ entryNames.forEach(name => {
158
+ if (!ssgEntries.includes(name) && (ssr && (ssrByEntries === null || ssrByEntries === void 0 ? void 0 : ssrByEntries[name]) === false || !ssr && !(ssrByEntries !== null && ssrByEntries !== void 0 && ssrByEntries[name]))) {
159
+ chain.entryPoints.delete(name);
160
+ }
161
+ });
162
+ }
163
+ }
164
+ /**
165
+ * inject bottom template
166
+ */
167
+
168
+
169
+ function applyBottomHtmlWebpackPlugin({
170
+ api,
171
+ chain,
172
+ modernConfig,
173
+ appContext,
174
+ CHAIN_ID
175
+ }) {
176
+ // inject bottomTemplate into html-webpack-plugin
177
+ for (const entryName of Object.keys(api.context.entry)) {
178
+ // FIXME: the only need necessary
179
+ const baseTemplateParams = _objectSpread({
180
+ entryName,
181
+ title: getEntryOptions(entryName, modernConfig.output.title, modernConfig.output.titleByEntries, appContext.packageName),
182
+ mountId: modernConfig.output.mountId
183
+ }, getEntryOptions(entryName, modernConfig.output.templateParameters, modernConfig.output.templateParametersByEntries, appContext.packageName));
184
+
185
+ chain.plugin(`${CHAIN_ID.PLUGIN.HTML}-${entryName}`).tap(args => [_objectSpread(_objectSpread({}, args[0] || {}), {}, {
186
+ __internal__: true,
187
+ bottomTemplate: appContext.htmlTemplates[`__${entryName}-bottom__`] && lodashTemplate(appContext.htmlTemplates[`__${entryName}-bottom__`])(baseTemplateParams)
188
+ })]);
189
+ }
190
+
191
+ chain.plugin(CHAIN_ID.PLUGIN.BOTTOM_TEMPLATE).use(BottomTemplatePlugin, [HtmlWebpackPlugin]);
192
+ }
193
+
194
+ const isStreamingSSR = userConfig => {
195
+ const isStreaming = ssr => ssr && typeof ssr === 'object' && ssr.mode === 'stream';
196
+
197
+ const {
198
+ server
199
+ } = userConfig;
200
+
201
+ if (isStreaming(server.ssr)) {
202
+ return true;
203
+ } // Since we cannot apply different plugins for different entries,
204
+ // we regard the whole app as streaming ssr only if one entry meets the requirement.
205
+
206
+
207
+ if (server !== null && server !== void 0 && server.ssrByEntries && typeof server.ssrByEntries === 'object') {
208
+ for (const name of Object.keys(server.ssrByEntries)) {
209
+ if (isStreaming(server.ssrByEntries[name])) {
210
+ return true;
211
+ }
212
+ }
213
+ }
214
+
215
+ return false;
216
+ };
217
+
218
+ function applyAsyncChunkHtmlPlugin({
219
+ chain,
220
+ modernConfig,
221
+ CHAIN_ID
222
+ }) {
223
+ if (isStreamingSSR(modernConfig)) {
224
+ chain.plugin(CHAIN_ID.PLUGIN.HTML_ASYNC_CHUNK).use(HtmlAsyncChunkPlugin, [HtmlWebpackPlugin]);
225
+ }
226
+ }
@@ -0,0 +1,58 @@
1
+ import path from 'path';
2
+ import { findExists } from '@modern-js/utils';
3
+ export function createHtmlConfig(normalizedConfig, appContext) {
4
+ const {
5
+ disableHtmlFolder,
6
+ favicon,
7
+ faviconByEntries,
8
+ inject,
9
+ injectByEntries,
10
+ meta,
11
+ metaByEntries,
12
+ mountId,
13
+ title,
14
+ titleByEntries,
15
+ scriptExt,
16
+ templateParameters,
17
+ templateParametersByEntries
18
+ } = normalizedConfig.output;
19
+ const {
20
+ configDir
21
+ } = normalizedConfig.source; // transform Modernjs `output.scriptExt` to Builder `html.crossorigin` configuration
22
+
23
+ const builderCrossorigin = createBuilderCrossorigin(scriptExt);
24
+ const builderAppIcon = createBuilderAppIcon(configDir, appContext);
25
+ const builderFavicon = createBuilderFavicon(favicon, configDir, appContext);
26
+ return {
27
+ appIcon: builderAppIcon,
28
+ disableHtmlFolder,
29
+ favicon: builderFavicon,
30
+ faviconByEntries,
31
+ inject,
32
+ injectByEntries,
33
+ meta,
34
+ metaByEntries,
35
+ mountId,
36
+ title,
37
+ titleByEntries,
38
+ crossorigin: builderCrossorigin,
39
+ templateByEntries: appContext.htmlTemplates,
40
+ templateParameters,
41
+ templateParametersByEntries: templateParametersByEntries
42
+ };
43
+ }
44
+ const ICON_EXTENSIONS = ['png', 'jpg', 'jpeg', 'svg', 'ico'];
45
+ export function createBuilderAppIcon(configDir, appContext) {
46
+ const appIcon = findExists(ICON_EXTENSIONS.map(ext => path.resolve(appContext.appDirectory, configDir, `icon.${ext}`)));
47
+ return typeof appIcon === 'string' ? appIcon : undefined;
48
+ }
49
+ export function createBuilderCrossorigin(scriptExt) {
50
+ var _scriptExtCustomConfi;
51
+
52
+ const scriptExtCustomConfig = scriptExt === null || scriptExt === void 0 ? void 0 : scriptExt.custom;
53
+ return scriptExtCustomConfig !== null && scriptExtCustomConfig !== void 0 && (_scriptExtCustomConfi = scriptExtCustomConfig.test) !== null && _scriptExtCustomConfi !== void 0 && _scriptExtCustomConfi.test('.js') && (scriptExtCustomConfig === null || scriptExtCustomConfig === void 0 ? void 0 : scriptExtCustomConfig.attribute) === 'crossorigin' ? scriptExtCustomConfig.value : undefined;
54
+ }
55
+ export function createBuilderFavicon(favicon, configDir, appContext) {
56
+ const defaultFavicon = findExists(ICON_EXTENSIONS.map(ext => path.resolve(appContext.appDirectory, configDir, `favicon.${ext}`)));
57
+ return favicon || defaultFavicon || undefined;
58
+ }