@hitachivantara/app-shell-vite-plugin 0.12.1 → 0.14.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 (51) hide show
  1. package/README.md +0 -15
  2. package/dist/automatic-utils.d.ts +6 -0
  3. package/dist/automatic-utils.d.ts.map +1 -0
  4. package/dist/automatic-utils.js +105 -0
  5. package/dist/automatic-utils.js.map +1 -0
  6. package/dist/config-utils.d.ts +34 -0
  7. package/dist/config-utils.d.ts.map +1 -0
  8. package/dist/config-utils.js +126 -0
  9. package/dist/config-utils.js.map +1 -0
  10. package/dist/esm-externals/react-dom.production.min.js +1 -1
  11. package/dist/esm-externals/react-dom.production.min.js.map +1 -1
  12. package/dist/esm-externals/react.production.min.js +1 -1
  13. package/dist/esm-externals/react.production.min.js.map +1 -1
  14. package/dist/index.d.ts +0 -8
  15. package/dist/index.d.ts.map +1 -1
  16. package/dist/index.js.map +1 -1
  17. package/dist/shared-dependencies.d.ts +8 -0
  18. package/dist/shared-dependencies.d.ts.map +1 -0
  19. package/dist/shared-dependencies.js +87 -0
  20. package/dist/shared-dependencies.js.map +1 -0
  21. package/dist/virtual-entrypoints.d.ts +5 -0
  22. package/dist/virtual-entrypoints.d.ts.map +1 -0
  23. package/dist/virtual-entrypoints.js +37 -0
  24. package/dist/virtual-entrypoints.js.map +1 -0
  25. package/dist/vite-configuration-processor-plugin.d.ts +14 -0
  26. package/dist/vite-configuration-processor-plugin.d.ts.map +1 -0
  27. package/dist/vite-configuration-processor-plugin.js +161 -0
  28. package/dist/vite-configuration-processor-plugin.js.map +1 -0
  29. package/dist/vite-generate-base-plugin.d.ts +8 -0
  30. package/dist/vite-generate-base-plugin.d.ts.map +1 -0
  31. package/dist/vite-generate-base-plugin.js +32 -0
  32. package/dist/vite-generate-base-plugin.js.map +1 -0
  33. package/dist/vite-generate-bash-script-plugin.d.ts +3 -0
  34. package/dist/vite-generate-bash-script-plugin.d.ts.map +1 -0
  35. package/dist/vite-generate-bash-script-plugin.js +122 -0
  36. package/dist/vite-generate-bash-script-plugin.js.map +1 -0
  37. package/dist/vite-importmap-plugin.d.ts +2 -2
  38. package/dist/vite-importmap-plugin.d.ts.map +1 -1
  39. package/dist/vite-importmap-plugin.js +15 -4
  40. package/dist/vite-importmap-plugin.js.map +1 -1
  41. package/dist/vite-metadata-plugin.d.ts.map +1 -1
  42. package/dist/vite-metadata-plugin.js.map +1 -1
  43. package/dist/vite-plugin.d.ts +36 -13
  44. package/dist/vite-plugin.d.ts.map +1 -1
  45. package/dist/vite-plugin.js +49 -525
  46. package/dist/vite-plugin.js.map +1 -1
  47. package/dist/vite-watch-config-plugin.d.ts +4 -0
  48. package/dist/vite-watch-config-plugin.d.ts.map +1 -0
  49. package/dist/vite-watch-config-plugin.js +41 -0
  50. package/dist/vite-watch-config-plugin.js.map +1 -0
  51. package/package.json +2 -2
@@ -1,449 +1,53 @@
1
1
  import fs from "fs";
2
2
  import path from "path";
3
- import { register, createEsmHooks } from "ts-node";
4
3
  import virtual from "@rollup/plugin-virtual";
5
4
  import { viteStaticCopy } from "vite-plugin-static-copy";
6
5
  import generateImportmap from "./vite-importmap-plugin.js";
6
+ import processConfiguration from "./vite-configuration-processor-plugin.js";
7
+ import generateBaseTag from "./vite-generate-base-plugin.js";
7
8
  import injectMetadata from "./vite-metadata-plugin.js";
8
- import { resolveModule, require, getModulePath } from "./nodeModule.js";
9
- createEsmHooks(register({
10
- transpileOnly: true,
11
- moduleTypes: {
12
- "app-shell.config.ts": "cjs"
13
- }
14
- }));
15
- /**
16
- * Return the main app (identified by @self)
17
- * @param appShellConfig The App shell configuration
18
- */
19
- const getMainApp = (appShellConfig) => {
20
- return appShellConfig.apps?.filter(app => app.id === "@self")[0];
21
- };
22
- /**
23
- * Return the public path to be use by vite to launch the application.
24
- * Value is obtained by returning the baseUrl value of the main app {@link #getMainApp}
25
- * @param appShellConfig The App shell configuration
26
- */
27
- const getPublicPath = (appShellConfig) => {
28
- const mainApp = getMainApp(appShellConfig);
29
- if (!mainApp) {
30
- return "/";
31
- }
32
- const url = mainApp.baseUrl;
33
- try {
34
- return new URL(url).pathname;
35
- }
36
- catch {
37
- return url;
38
- }
39
- };
9
+ import serveAppShellConfig from "./vite-watch-config-plugin.js";
10
+ import generateBashScript from "./vite-generate-bash-script-plugin.js";
11
+ import { findAppShellConfigFile, loadConfigFile } from "./config-utils.js";
12
+ import { resolveModule, getModulePath } from "./nodeModule.js";
13
+ import { applyAutomaticMenu, applyAutomaticViewsAndRoutes } from "./automatic-utils.js";
14
+ import getVirtualEntrypoints from "./virtual-entrypoints.js";
15
+ import SHARED_DEPENDENCIES from "./shared-dependencies.js";
40
16
  var ViteBuildMode;
41
17
  (function (ViteBuildMode) {
42
18
  ViteBuildMode["PRODUCTION"] = "production";
43
19
  ViteBuildMode["DEVELOPMENT"] = "development";
44
20
  })(ViteBuildMode || (ViteBuildMode = {}));
45
- var ViteCommand;
46
- (function (ViteCommand) {
47
- ViteCommand["BUILD"] = "build";
48
- ViteCommand["SERVE"] = "serve";
49
- })(ViteCommand || (ViteCommand = {}));
50
- /**
51
- * Returns the modules to be created by the build of the app.
52
- * The list of modules is defined by the app-shell-config.json file routes ( limited to the @self app)
53
- * The bundles will be created following the original directories structure ( having the src folder path removed)
54
- *
55
- * @param root Project root directory.
56
- * @param appShellConfig The App Shell configuration.
57
- * @param selfAppName The name of the application bundle being built.
58
- */
59
- function getAppModules(root, appShellConfig, selfAppName) {
60
- const appModules = {};
61
- const selfApp = getMainApp(appShellConfig);
62
- if (selfApp != null) {
63
- const selfViews = selfApp.views?.map(view => {
64
- const bundleName = view.bundle.replace(/^src\//, "");
65
- return {
66
- ...view,
67
- bundleName
68
- };
69
- }) ?? [];
70
- selfViews.forEach(view => {
71
- appModules[view.bundleName] = path.resolve(root, view.bundle);
72
- });
73
- const selfModules = selfApp.modules?.map(module => {
74
- const bundleName = module.bundle.replace(/^src\//, "");
75
- return {
76
- ...module,
77
- bundleName
78
- };
79
- }) ?? [];
80
- selfModules.forEach(module => {
81
- appModules[module.bundleName] = path.resolve(root, module.bundle);
82
- });
83
- }
84
- const implicitThemeModules = appShellConfig?.theming?.themes?.map(theme => {
85
- if (theme.startsWith("/src/") ||
86
- theme.startsWith("@self/") ||
87
- theme.startsWith(selfAppName)) {
88
- const bundle = theme
89
- .replace(/^@self\//, "")
90
- .replace(new RegExp(`^${selfAppName}/`), "");
91
- const bundleName = bundle.replace(/^(\/?)src\//, "");
92
- return {
93
- bundle,
94
- bundleName
95
- };
96
- }
97
- return undefined;
98
- }) ?? [];
99
- implicitThemeModules.forEach(module => {
100
- if (module != null && appModules[module.bundleName] == null) {
101
- appModules[module.bundleName] = path.resolve(root, module.bundle);
102
- }
103
- });
104
- console.info("Modules exported by the application bundle:", appModules);
105
- return appModules;
106
- }
107
- /**
108
- * Process configuration, executing several tasks:
109
- * - Create rollup configuration to support module creation
110
- * - Generates final transformed configuration json
111
- * - "base" value is always "./" for build, and main app baseUrl for preview or dev
112
- * - Injects the APP_BASE_PATH env prop, to be used by the apps (if required)
113
- * @param root Project root directory.
114
- * @param appShellConfig The original App Shell configuration json.
115
- * @param selfAppName The name of the application bundle being built.
116
- * @param buildEntryPoint If true, the index.html entry point will be added to the bundle.
117
- */
118
- function processConfiguration(root, appShellConfig, selfAppName, buildEntryPoint) {
119
- const selfApp = getMainApp(appShellConfig);
120
- return {
121
- name: "vite-plugin-appShell-configuration-processor",
122
- config(config, { command }) {
123
- const projectRoot = root ?? config.root;
124
- const publicPath = getPublicPath(appShellConfig);
125
- return {
126
- build: {
127
- rollupOptions: {
128
- preserveEntrySignatures: "strict",
129
- input: {
130
- ...(buildEntryPoint &&
131
- fs.existsSync(path.resolve(projectRoot, "index.html"))
132
- ? { main: path.resolve(projectRoot, "index.html") }
133
- : {}),
134
- ...getAppModules(projectRoot, appShellConfig, selfAppName)
135
- },
136
- output: {
137
- entryFileNames: "[name].js"
138
- }
139
- }
140
- },
141
- // if serve (preview/dev) it uses the baseUrl. Otherwise(build), use ./
142
- base: command === ViteCommand.SERVE ? publicPath : "./",
143
- define: {
144
- ...config.define,
145
- APP_BASE_PATH: JSON.stringify(publicPath)
146
- }
147
- };
148
- },
149
- /**
150
- * Rollup hook with the info for bundle generation
151
- * It will be used to create a new configuration with:
152
- * - bundles replace with the final location (e.g. -> "bundle": "src/pages/Main" transformed to "bundle": "pages/Main.js",
153
- * @param options build options
154
- * @param bundle bundles information
155
- */
156
- async generateBundle(options, bundle) {
157
- // obtain the directory (dist) where the new config file will be placed
158
- let targetDir;
159
- if (options.dir) {
160
- targetDir = options.dir;
161
- }
162
- else if (options.file) {
163
- targetDir = path.dirname(options.file);
164
- }
165
- if (!targetDir) {
166
- throw new Error("Please set outputPath, so we can know where to place the json file");
167
- }
168
- // create the targetDir if it does not exist
169
- if (!fs.existsSync(targetDir)) {
170
- fs.mkdirSync(targetDir, { recursive: true });
171
- }
172
- /**
173
- * Creating a map with each chunk and the final name. Only the bundles with type=chunck are important
174
- * Filename do not include the src path at the value
175
- */
176
- const chunks = {};
177
- Object.keys(bundle).forEach(key => {
178
- const chunk = bundle[key];
179
- if (chunk.type === "chunk") {
180
- const outputChunk = chunk;
181
- if (outputChunk.isEntry) {
182
- const { fileName } = outputChunk;
183
- const { name } = outputChunk;
184
- chunks[name] = fileName;
185
- }
186
- }
187
- });
188
- if (selfApp) {
189
- selfApp.views = selfApp.views?.map(view => {
190
- const bundleName = view.bundle
191
- .replace(/^src\//, "")
192
- .replaceAll(/\$/g, "_");
193
- return {
194
- ...view,
195
- bundle: chunks[bundleName]
196
- };
197
- });
198
- selfApp.modules = selfApp.modules?.map(module => {
199
- const bundleName = module.bundle.replace(/^src\//, "");
200
- return {
201
- ...module,
202
- bundle: chunks[bundleName]
203
- };
204
- });
205
- // replace references to @self with the name of this application bundle
206
- selfApp.id = selfAppName;
207
- // also replace implicit references to selfApp in other parts of the configuration
208
- const { theming } = appShellConfig;
209
- if (theming != null) {
210
- theming.themes = theming.themes?.map(theme => {
211
- if (theme.startsWith("@self/") ||
212
- theme.startsWith(selfAppName) ||
213
- theme.startsWith("/src/")) {
214
- const bundleName = theme
215
- .replace(/^@self\//, "")
216
- .replace(new RegExp(`^${selfAppName}/`), "")
217
- .replace(/^(\/?)src\//, "");
218
- return `${selfAppName}/${chunks[bundleName]}`;
219
- }
220
- return theme;
221
- });
222
- }
223
- }
224
- const finalAppShellConfig = buildEntryPoint
225
- ? { ...appShellConfig }
226
- : {
227
- name: appShellConfig.name,
228
- apps: selfApp != null ? [selfApp] : undefined
229
- };
230
- fs.writeFileSync(path.resolve(targetDir, "app-shell.config.json"), JSON.stringify(finalAppShellConfig));
231
- }
232
- };
233
- }
234
- /**
235
- * Add the <BASE> tag at index.html file. Tag value is obtained by the main app ({@link #getMainApp}) baseUrl ({@link #getPublicPath})‘
236
- * @param appShellConfig The app shell configuration.
237
- */
238
- const generateBaseTag = (appShellConfig) => {
239
- const publicPath = getPublicPath(appShellConfig);
240
- return {
241
- name: "vite-plugin-generate-base",
242
- enforce: "pre",
243
- transformIndexHtml: {
244
- enforce: "post",
245
- transform: (html) => ({
246
- html,
247
- tags: [
248
- {
249
- tag: "base",
250
- attrs: { href: publicPath },
251
- injectTo: "head-prepend"
252
- }
253
- ]
254
- })
255
- }
256
- };
257
- };
258
- function serveAppShellConfig(appShellConfig, root, appShellConfigFile, automaticViewsFolder) {
259
- return {
260
- name: "vite-plugin-watch-app-shell-config",
261
- configureServer(server) {
262
- const restartServer = (file) => {
263
- if (appShellConfigFile != null && file.endsWith(appShellConfigFile)) {
264
- console.info("App Shell configuration file changed. Reloading...");
265
- delete require.cache[require.resolve(path.resolve(root, appShellConfigFile))];
266
- server
267
- .restart()
268
- .catch(e => console.error(`Restart failed with: ${e}`));
269
- }
270
- };
271
- const restartServer2 = (file) => {
272
- if (automaticViewsFolder != null && file.match(/\/index\.[tj]sx?$/)) {
273
- console.info("Automatic views folder changed. Reloading...");
274
- server
275
- .restart()
276
- .catch(e => console.error(`Restart failed with: ${e}`));
277
- }
278
- };
279
- if (appShellConfigFile != null) {
280
- server.watcher.add(path.resolve(root, appShellConfigFile));
281
- server.watcher.on("change", restartServer);
282
- }
283
- if (automaticViewsFolder != null) {
284
- server.watcher.add(path.resolve(root, automaticViewsFolder));
285
- server.watcher.on("unlink", restartServer2);
286
- server.watcher.on("add", restartServer2);
287
- }
288
- const publicPath = getPublicPath(appShellConfig);
289
- server.middlewares.use(`${publicPath}app-shell.config.json`, async (req, res) => {
290
- res.end(JSON.stringify(appShellConfig));
291
- });
292
- }
293
- };
294
- }
295
21
  export var ApplicationBundleType;
296
22
  (function (ApplicationBundleType) {
297
23
  ApplicationBundleType["APP"] = "app";
298
24
  ApplicationBundleType["BUNDLE"] = "bundle";
299
25
  })(ApplicationBundleType || (ApplicationBundleType = {}));
300
- const DEFAULT_CONFIG_FILES = [
301
- "app-shell.config.ts",
302
- "app-shell.config.js",
303
- "app-shell.config.json"
304
- ];
305
- function findIndexFiles(dir) {
306
- const files = [];
307
- fs.readdirSync(dir).forEach(file => {
308
- const filePath = path.join(dir, file);
309
- const stat = fs.statSync(filePath);
310
- if (stat.isDirectory()) {
311
- files.push(...findIndexFiles(filePath));
312
- }
313
- else if (file.match(/^index\.[tj]sx?$/)) {
314
- files.push(filePath);
315
- }
316
- });
317
- return files;
318
- }
319
- function mapIndexFilesToRoutes(files, folder) {
320
- const routes = [];
321
- files.forEach(filePath => {
322
- const bundle = filePath.substring(filePath.lastIndexOf(`/${folder.replace(/^\/|\/$/g, "")}/`) + 1, filePath.lastIndexOf("/"));
323
- const route = bundle
324
- .replace(new RegExp(`^${folder}`), "")
325
- .replace(/index\.[t|j]sx?$/, "")
326
- .replaceAll(/\$/g, ":")
327
- .toLowerCase();
328
- routes.push({ bundle, route });
329
- });
330
- return routes;
331
- }
332
26
  /**
333
27
  * Vite plugin to support App Shell apps setup
334
28
  * @param opts Plugin options
335
29
  */
336
30
  export function appShellVitePlugin(opts = {}, env = {}) {
337
- const { root = process.cwd(), mode = ViteBuildMode.PRODUCTION, externalImportMap = false, type = ApplicationBundleType.APP, viewsFolder = "src/pages", autoViewsAndRoutes = false, autoDevMenu = false } = opts;
338
- const buildEntryPoint = type !== ApplicationBundleType.BUNDLE;
31
+ const { root = process.cwd(), mode = ViteBuildMode.PRODUCTION, externalImportMap = false, type = ApplicationBundleType.APP, viewsFolder = "src/pages", autoViewsAndRoutes = false, autoDevMenu = false, inlineConfig = opts.generateEmptyShell ?? false, generateEmptyShell = false } = opts;
339
32
  console.info(`Vite running in mode: ${mode}`);
340
33
  const devMode = mode === ViteBuildMode.DEVELOPMENT;
34
+ const buildEntryPoint = type !== ApplicationBundleType.BUNDLE;
341
35
  const packageJsonRaw = fs.readFileSync(path.resolve(root, "package.json"), "utf-8");
342
36
  const packageJson = JSON.parse(packageJsonRaw);
343
- const appShellConfigFile = DEFAULT_CONFIG_FILES.find(file => fs.existsSync(path.resolve(root, file)));
344
- let appShellConfiguration;
345
- if (appShellConfigFile) {
346
- if (appShellConfigFile.endsWith(".json")) {
347
- // token replacement is only supported for json files
348
- let appShellConfigRaw = fs.readFileSync(path.resolve(root, "app-shell.config.json"), "utf-8");
349
- opts.configReplacements?.forEach(item => {
350
- appShellConfigRaw = appShellConfigRaw.replaceAll(`@@${item.token}@@`, item.value);
351
- });
352
- appShellConfiguration = JSON.parse(appShellConfigRaw);
353
- }
354
- else {
355
- // using require instead of import to avoid using --experimental-loader ts-node/esm
356
- // eslint-disable-next-line import/no-dynamic-require
357
- const loadedAppShellConfig = require(path.resolve(root, appShellConfigFile)).default;
358
- if (typeof loadedAppShellConfig === "function") {
359
- appShellConfiguration = loadedAppShellConfig(opts, env);
360
- }
361
- else {
362
- appShellConfiguration = loadedAppShellConfig;
363
- }
364
- }
365
- }
366
- else {
367
- // an empty configuration is actually valid
368
- // and with the automatic views option, it can even make sense
369
- appShellConfiguration = {};
370
- }
371
- let selfApp = getMainApp(appShellConfiguration);
372
- if (autoViewsAndRoutes != null) {
373
- const folder = path.resolve(root, viewsFolder);
374
- if (fs.existsSync(folder)) {
375
- const views = mapIndexFilesToRoutes(findIndexFiles(folder), viewsFolder);
376
- if (views.length > 0) {
377
- if (selfApp == null) {
378
- selfApp = {
379
- id: "@self",
380
- baseUrl: "/"
381
- };
382
- if (appShellConfiguration.apps == null) {
383
- appShellConfiguration.apps = [];
384
- }
385
- appShellConfiguration.apps.push(selfApp);
386
- }
387
- if (selfApp.views != null && selfApp.views.length > 0) {
388
- const nowOverlappingViews = views.filter(view => {
389
- const exists = selfApp.views.some(existingView => existingView.bundle === view.bundle ||
390
- existingView.route === view.route);
391
- return !exists;
392
- });
393
- selfApp.views.push(...nowOverlappingViews);
394
- }
395
- else {
396
- selfApp.views = views;
397
- }
398
- }
37
+ const appShellConfigFile = !generateEmptyShell
38
+ ? findAppShellConfigFile(root)
39
+ : undefined;
40
+ const appShellConfiguration = loadConfigFile(appShellConfigFile, opts, env);
41
+ if (!generateEmptyShell) {
42
+ if (autoViewsAndRoutes) {
43
+ applyAutomaticViewsAndRoutes(appShellConfiguration, root, viewsFolder);
399
44
  }
400
- }
401
- if (devMode && autoDevMenu) {
402
- if (appShellConfiguration.menu == null ||
403
- appShellConfiguration.menu.length === 0) {
404
- if (selfApp?.views != null && selfApp.views.length > 0) {
405
- const menu = [];
406
- for (let i = 0; i !== selfApp.views.length; i += 1) {
407
- const view = selfApp.views[i];
408
- // skip dynamic routes (e.g. /list/:id))
409
- if (view.route.indexOf(":") === -1) {
410
- let currentMenu = menu;
411
- const bundleParts = view.bundle.split("/");
412
- const numberOfParts = view.route
413
- .split("/")
414
- .filter(part => part !== "").length;
415
- const srcFolderParts = bundleParts.length - numberOfParts;
416
- if (bundleParts.length > srcFolderParts) {
417
- for (let j = srcFolderParts; j !== bundleParts.length - 1; j += 1) {
418
- const part = bundleParts[j];
419
- let submenu = currentMenu.find(item => item.label === part);
420
- if (submenu == null) {
421
- submenu = {
422
- label: part,
423
- submenus: []
424
- };
425
- currentMenu.push(submenu);
426
- }
427
- currentMenu = submenu.submenus;
428
- }
429
- const label = bundleParts[bundleParts.length - 1];
430
- let menuitem = currentMenu.find(item => item.label === label);
431
- if (menuitem == null) {
432
- menuitem = {
433
- label
434
- };
435
- currentMenu.push(menuitem);
436
- }
437
- menuitem.target = view.route;
438
- }
439
- }
440
- }
441
- appShellConfiguration.menu = menu;
442
- }
45
+ if (devMode && autoDevMenu) {
46
+ applyAutomaticMenu(appShellConfiguration);
443
47
  }
444
48
  }
445
49
  return [
446
- // Copy all the required js bundles to final "bundles" folders, that will be injected by the importmap
50
+ // copy the shared dependencies js bundles to the "bundles" folder
447
51
  (buildEntryPoint || devMode) &&
448
52
  viteStaticCopy({
449
53
  targets: [
@@ -454,110 +58,30 @@ export function appShellVitePlugin(opts = {}, env = {}) {
454
58
  ...(!devMode && buildEntryPoint
455
59
  ? [
456
60
  {
457
- src: [
458
- resolveModule("./esm-externals/react.production.min.js"),
459
- resolveModule("./esm-externals/react.production.min.js.map"),
460
- resolveModule("./esm-externals/react-dom.production.min.js"),
461
- resolveModule("./esm-externals/react-dom.production.min.js.map"),
462
- resolveModule("./esm-externals/react-router-dom.production.min.js"),
463
- resolveModule("./esm-externals/react-router-dom.production.min.js.map"),
464
- resolveModule("./esm-externals/emotion-react.production.min.js"),
465
- resolveModule("./esm-externals/emotion-react.production.min.js.map"),
466
- resolveModule("./esm-externals/emotion-cache.production.min.js"),
467
- resolveModule("./esm-externals/emotion-cache.production.min.js.map"),
468
- resolveModule("@hitachivantara/app-shell-shared/bundles/app-shell-shared.esm.js"),
469
- resolveModule("@hitachivantara/app-shell-shared/bundles/app-shell-shared.esm.js.map"),
470
- resolveModule("@hitachivantara/uikit-react-shared/bundles/uikit-react-shared.esm.js"),
471
- resolveModule("@hitachivantara/uikit-react-shared/bundles/uikit-react-shared.esm.js.map")
472
- ],
61
+ src: SHARED_DEPENDENCIES.flatMap(dep => [
62
+ resolveModule(dep.bundleSrc),
63
+ resolveModule(`${dep.bundleSrc}.map`)
64
+ ]),
473
65
  dest: "bundles"
474
66
  }
475
67
  ]
476
68
  : [])
477
69
  ]
478
70
  }),
479
- // create virtual endpoints to support dev mode
71
+ // create virtual endpoints for shell code and for shared dependencies
480
72
  virtual({
481
- "/virtual/main.tsx": `import React, { Suspense } from "react";
482
- import ReactDOM from "react-dom/client";
483
- import App from "virtual:App.tsx";
484
-
485
- const root = ReactDOM.createRoot(document.getElementById("hv-root"));
486
-
487
- root.render(React.createElement(
488
- Suspense,
489
- { fallback: true },
490
- React.createElement(App, null)
491
- ));`,
492
- "virtual:App.tsx": `import React from "react";
493
- import { HvAppShell } from "@hitachivantara/app-shell";
494
-
495
- const App = () => {
496
- return React.createElement(HvAppShell, {
497
- configUrl: window.location.origin + APP_BASE_PATH + "app-shell.config.json"
498
- });
499
- };
500
-
501
- export default App;`,
502
- "/bundles/react.production.min.js": `import * as React from "react";
503
- export default React;
504
-
505
- export {
506
- Fragment,
507
- StrictMode,
508
- Profiler,
509
- Suspense,
510
- Children,
511
- Component,
512
- PureComponent,
513
- cloneElement,
514
- createContext,
515
- createElement,
516
- createFactory,
517
- createRef,
518
- forwardRef,
519
- isValidElement,
520
- lazy,
521
- memo,
522
- useCallback,
523
- useContext,
524
- useDebugValue,
525
- useEffect,
526
- useImperativeHandle,
527
- useLayoutEffect,
528
- useMemo,
529
- useReducer,
530
- useRef,
531
- useState,
532
- version,
533
- } from "react";`,
534
- "/bundles/react-dom.production.min.js": `export {
535
- default,
536
- flushSync,
537
- createPortal,
538
- findDOMNode,
539
- hydrate,
540
- render,
541
- unmountComponentAtNode,
542
- unstable_batchedUpdates,
543
- unstable_renderSubtreeIntoContainer,
544
- version,
545
- } from "react-dom";`,
546
- "/bundles/react-router-dom.production.min.js": `export * from "react-router-dom";`,
547
- "/bundles/emotion-react.production.min.js": `export * from "@emotion/react";`,
548
- "/bundles/emotion-cache.production.min.js": `import createCache from "@emotion/cache"; export default createCache;`,
549
- "/bundles/app-shell-shared.esm.js": `export * from "@hitachivantara/app-shell-shared";`,
550
- "/bundles/uikit-react-shared.esm.js": `export * from "@hitachivantara/uikit-react-shared";`
73
+ ...getVirtualEntrypoints(inlineConfig),
74
+ ...SHARED_DEPENDENCIES.reduce((acc, dep) => {
75
+ acc[`/bundles/${dep.bundle}`] = dep.virtualSrc;
76
+ return acc;
77
+ }, {})
551
78
  }),
552
- // generation of the importmap to create the link to the js bundles
79
+ // generate the importmap for shared dependencies and for apps referenced in the config file
553
80
  generateImportmap({
554
- react: `./bundles/react.production.min.js`,
555
- "react-dom": `./bundles/react-dom.production.min.js`,
556
- "react-router-dom": `./bundles/react-router-dom.production.min.js`,
557
- "@hitachivantara/app-shell-shared": "./bundles/app-shell-shared.esm.js",
558
- "@emotion/react": "./bundles/emotion-react.production.min.js",
559
- "@emotion/cache": "./bundles/emotion-cache.production.min.js",
560
- "@hitachivantara/uikit-react-shared": "./bundles/uikit-react-shared.esm.js",
81
+ ...SHARED_DEPENDENCIES.reduce((acc, dep) => {
82
+ acc[dep.moduleId] = `./bundles/${dep.bundle}`;
83
+ return acc;
84
+ }, {}),
561
85
  ...appShellConfiguration?.apps?.reduce((acc, app) => {
562
86
  if (app.id === "@self") {
563
87
  acc[`${packageJson.name}/`] = app.baseUrl;
@@ -571,21 +95,21 @@ export function appShellVitePlugin(opts = {}, env = {}) {
571
95
  return acc;
572
96
  }, {})
573
97
  }, [
574
- "react",
575
- "react-dom",
576
- "react-router-dom",
577
- "@hitachivantara/app-shell-shared",
578
- "@hitachivantara/uikit-react-shared",
579
- "@emotion/react",
580
- "@emotion/cache",
98
+ ...SHARED_DEPENDENCIES.map(dep => dep.moduleId),
581
99
  "@self",
582
100
  packageJson.name
583
- ], externalImportMap && buildEntryPoint),
584
- injectMetadata(),
585
- buildEntryPoint && generateBaseTag(appShellConfiguration),
586
- // process configuration
587
- processConfiguration(root, appShellConfiguration, packageJson.name, buildEntryPoint),
588
- serveAppShellConfig(appShellConfiguration, root, appShellConfigFile, autoViewsAndRoutes ? viewsFolder : undefined)
101
+ ], externalImportMap && buildEntryPoint, generateEmptyShell),
102
+ // inject version metadata in the index.html
103
+ buildEntryPoint && injectMetadata(),
104
+ // set the base tag and replace the title in the index.html
105
+ buildEntryPoint &&
106
+ generateBaseTag(appShellConfiguration, generateEmptyShell),
107
+ // configure the build process based on the config file
108
+ processConfiguration(root, appShellConfiguration, packageJson.name, buildEntryPoint, inlineConfig, generateEmptyShell),
109
+ // serve the app shell config file as json and watch for changes
110
+ serveAppShellConfig(appShellConfiguration, root, appShellConfigFile, autoViewsAndRoutes ? viewsFolder : undefined),
111
+ // generate the shell script to replace the placeholders in the index.html
112
+ generateEmptyShell && generateBashScript(externalImportMap, inlineConfig)
589
113
  ];
590
114
  }
591
115
  export default appShellVitePlugin;