@hitachivantara/app-shell-vite-plugin 2.3.0 → 2.5.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.
- package/LICENSE +201 -0
- package/dist/automatic-utils.js +7 -3
- package/dist/esm-externals/react-router-dom.production.min.js +7 -7
- package/dist/esm-externals/react-router-dom.production.min.js.map +1 -1
- package/dist/locales-utils.d.ts +0 -9
- package/dist/locales-utils.js +2 -34
- package/dist/nodeModule.d.ts +1 -1
- package/dist/shared-dependencies.js +2 -1
- package/dist/utils.d.ts +9 -0
- package/dist/utils.js +34 -0
- package/dist/vite-plugin-configuration-processor.d.ts +30 -0
- package/dist/{vite-configuration-processor-plugin.js → vite-plugin-configuration-processor.js} +11 -12
- package/dist/{vite-crossorigin-fix-plugin.d.ts → vite-plugin-crossorigin-fix.d.ts} +1 -2
- package/dist/{vite-crossorigin-fix-plugin.js → vite-plugin-crossorigin-fix.js} +4 -5
- package/dist/vite-plugin-dist-package-json.d.ts +5 -0
- package/dist/vite-plugin-dist-package-json.js +271 -0
- package/dist/{vite-generate-base-plugin.d.ts → vite-plugin-generate-base.d.ts} +1 -1
- package/dist/{vite-generate-bash-script-plugin.js → vite-plugin-generate-bash-script.js} +1 -1
- package/dist/{vite-locales-plugin.js → vite-plugin-locales.js} +3 -2
- package/dist/{vite-metadata-plugin.d.ts → vite-plugin-metadata.d.ts} +1 -2
- package/dist/{vite-metadata-plugin.js → vite-plugin-metadata.js} +5 -8
- package/dist/{vite-watch-config-plugin.js → vite-plugin-watch-config.js} +3 -1
- package/dist/vite-plugin.d.ts +36 -0
- package/dist/vite-plugin.js +25 -13
- package/package.json +24 -19
- package/dist/vite-configuration-processor-plugin.d.ts +0 -16
- /package/dist/{vite-generate-base-plugin.js → vite-plugin-generate-base.js} +0 -0
- /package/dist/{vite-generate-bash-script-plugin.d.ts → vite-plugin-generate-bash-script.d.ts} +0 -0
- /package/dist/{vite-importmap-plugin.d.ts → vite-plugin-importmap.d.ts} +0 -0
- /package/dist/{vite-importmap-plugin.js → vite-plugin-importmap.js} +0 -0
- /package/dist/{vite-locales-plugin.d.ts → vite-plugin-locales.d.ts} +0 -0
- /package/dist/{vite-watch-config-plugin.d.ts → vite-plugin-watch-config.d.ts} +0 -0
package/dist/locales-utils.d.ts
CHANGED
|
@@ -1,8 +1,4 @@
|
|
|
1
1
|
export declare const SUPPORTED_LOCALES_FILE = "supported-locales.json";
|
|
2
|
-
/**
|
|
3
|
-
* Deep merge two objects. `override` keys take priority over `base`.
|
|
4
|
-
*/
|
|
5
|
-
export declare function deepMerge(base: Record<string, unknown>, override: Record<string, unknown>): Record<string, unknown>;
|
|
6
2
|
/**
|
|
7
3
|
* Reads a `supported-locales.json` file and returns its contents as an array
|
|
8
4
|
* of locale strings. Returns an empty array if the file doesn't exist or
|
|
@@ -31,11 +27,6 @@ export declare function discoverLanguageDirs(localesDir: string): string[];
|
|
|
31
27
|
* @param appLocalesDir - The app's locales directory (downstream / local).
|
|
32
28
|
*/
|
|
33
29
|
export declare function computeSupportedLocales(shellLocalesDir: string | undefined, appLocalesDir: string | undefined): string[];
|
|
34
|
-
/**
|
|
35
|
-
* Parses a JSON file, wrapping parse errors with the file path for
|
|
36
|
-
* actionable diagnostics.
|
|
37
|
-
*/
|
|
38
|
-
export declare function readJsonFile(filePath: string): unknown;
|
|
39
30
|
/**
|
|
40
31
|
* Recursively merges source directory into destination.
|
|
41
32
|
* JSON files are deep-merged with destination keys taking priority.
|
package/dist/locales-utils.js
CHANGED
|
@@ -1,26 +1,7 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
|
+
import { deepMerge, readJsonFile } from "./utils.js";
|
|
3
4
|
export const SUPPORTED_LOCALES_FILE = "supported-locales.json";
|
|
4
|
-
/**
|
|
5
|
-
* Deep merge two objects. `override` keys take priority over `base`.
|
|
6
|
-
*/
|
|
7
|
-
export function deepMerge(base, override) {
|
|
8
|
-
const result = { ...base };
|
|
9
|
-
for (const [key, value] of Object.entries(override)) {
|
|
10
|
-
if (value != null &&
|
|
11
|
-
typeof value === "object" &&
|
|
12
|
-
!Array.isArray(value) &&
|
|
13
|
-
result[key] != null &&
|
|
14
|
-
typeof result[key] === "object" &&
|
|
15
|
-
!Array.isArray(result[key])) {
|
|
16
|
-
result[key] = deepMerge(result[key], value);
|
|
17
|
-
}
|
|
18
|
-
else {
|
|
19
|
-
result[key] = value;
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
return result;
|
|
23
|
-
}
|
|
24
5
|
/**
|
|
25
6
|
* Reads a `supported-locales.json` file and returns its contents as an array
|
|
26
7
|
* of locale strings. Returns an empty array if the file doesn't exist or
|
|
@@ -30,7 +11,7 @@ export function readSupportedLocales(filePath) {
|
|
|
30
11
|
if (!fs.existsSync(filePath))
|
|
31
12
|
return [];
|
|
32
13
|
try {
|
|
33
|
-
const data =
|
|
14
|
+
const data = readJsonFile(filePath);
|
|
34
15
|
if (Array.isArray(data) && data.every((item) => typeof item === "string")) {
|
|
35
16
|
return data;
|
|
36
17
|
}
|
|
@@ -107,19 +88,6 @@ export function computeSupportedLocales(shellLocalesDir, appLocalesDir) {
|
|
|
107
88
|
}
|
|
108
89
|
return result.toSorted();
|
|
109
90
|
}
|
|
110
|
-
/**
|
|
111
|
-
* Parses a JSON file, wrapping parse errors with the file path for
|
|
112
|
-
* actionable diagnostics.
|
|
113
|
-
*/
|
|
114
|
-
export function readJsonFile(filePath) {
|
|
115
|
-
const raw = fs.readFileSync(filePath, "utf-8");
|
|
116
|
-
try {
|
|
117
|
-
return JSON.parse(raw);
|
|
118
|
-
}
|
|
119
|
-
catch (cause) {
|
|
120
|
-
throw new Error(`[app-shell-locales] Failed to parse ${filePath}: ${cause instanceof Error ? cause.message : cause}`, { cause });
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
91
|
/**
|
|
124
92
|
* Recursively merges source directory into destination.
|
|
125
93
|
* JSON files are deep-merged with destination keys taking priority.
|
package/dist/nodeModule.d.ts
CHANGED
|
@@ -6,4 +6,4 @@ export declare const require: NodeJS.Require;
|
|
|
6
6
|
* @param suffix to be added after the module path
|
|
7
7
|
* @returns The module path normalized
|
|
8
8
|
*/
|
|
9
|
-
export declare function resolveModule(moduleName: string, suffix?: string):
|
|
9
|
+
export declare function resolveModule(moduleName: string, suffix?: string): any;
|
|
@@ -87,7 +87,8 @@ export default [
|
|
|
87
87
|
moduleId: "@hitachivantara/app-shell-services",
|
|
88
88
|
bundle: "app-shell-services.esm.js",
|
|
89
89
|
bundleSrc: "@hitachivantara/app-shell-services/bundles/app-shell-services.esm.js",
|
|
90
|
-
virtualSrc: `export
|
|
90
|
+
virtualSrc: `export { default } from "@hitachivantara/app-shell-services";
|
|
91
|
+
export * from "@hitachivantara/app-shell-services";`,
|
|
91
92
|
},
|
|
92
93
|
{
|
|
93
94
|
moduleId: "@hitachivantara/uikit-react-shared",
|
package/dist/utils.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deep merge two objects. `override` keys take priority over `base`.
|
|
3
|
+
*/
|
|
4
|
+
export declare function deepMerge(base: Record<string, unknown>, override: Record<string, unknown>): Record<string, unknown>;
|
|
5
|
+
/**
|
|
6
|
+
* Parses a JSON file, wrapping parse errors with the file path for
|
|
7
|
+
* actionable diagnostics.
|
|
8
|
+
*/
|
|
9
|
+
export declare function readJsonFile(filePath: string): any;
|
package/dist/utils.js
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
/**
|
|
3
|
+
* Deep merge two objects. `override` keys take priority over `base`.
|
|
4
|
+
*/
|
|
5
|
+
export function deepMerge(base, override) {
|
|
6
|
+
const result = { ...base };
|
|
7
|
+
for (const [key, value] of Object.entries(override)) {
|
|
8
|
+
if (value != null &&
|
|
9
|
+
typeof value === "object" &&
|
|
10
|
+
!Array.isArray(value) &&
|
|
11
|
+
result[key] != null &&
|
|
12
|
+
typeof result[key] === "object" &&
|
|
13
|
+
!Array.isArray(result[key])) {
|
|
14
|
+
result[key] = deepMerge(result[key], value);
|
|
15
|
+
}
|
|
16
|
+
else {
|
|
17
|
+
result[key] = value;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
return result;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Parses a JSON file, wrapping parse errors with the file path for
|
|
24
|
+
* actionable diagnostics.
|
|
25
|
+
*/
|
|
26
|
+
export function readJsonFile(filePath) {
|
|
27
|
+
const raw = readFileSync(filePath, "utf-8");
|
|
28
|
+
try {
|
|
29
|
+
return JSON.parse(raw);
|
|
30
|
+
}
|
|
31
|
+
catch (cause) {
|
|
32
|
+
throw new Error(`Failed to parse ${filePath}: ${cause instanceof Error ? cause.message : cause}`, { cause });
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { PluginOption } from "vite";
|
|
2
|
+
import type { HvAppShellConfig } from "@hitachivantara/app-shell-shared";
|
|
3
|
+
/**
|
|
4
|
+
* Options for the configuration processor plugin.
|
|
5
|
+
*/
|
|
6
|
+
export interface ProcessConfigurationOptions {
|
|
7
|
+
/** Project root directory. */
|
|
8
|
+
root: string;
|
|
9
|
+
/** The original App Shell configuration json. */
|
|
10
|
+
appShellConfig: HvAppShellConfig;
|
|
11
|
+
/** The name of the application bundle being built. */
|
|
12
|
+
selfAppName: string;
|
|
13
|
+
/** The set of modules to be created by the rollup. */
|
|
14
|
+
modules: string[];
|
|
15
|
+
/** If true, the index.html entry point will be added to the bundle. */
|
|
16
|
+
buildEntryPoint: boolean;
|
|
17
|
+
/** Flag to control if config is included at index.html. */
|
|
18
|
+
inlineConfig: boolean;
|
|
19
|
+
/** Flag to control if we are creating an empty AppShell instance. */
|
|
20
|
+
generateEmptyShell: boolean;
|
|
21
|
+
/** If true, always writes app-shell.config.json to dist for dual-use packages. */
|
|
22
|
+
experimentalNewPackageLayout: boolean;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Process configuration, executing several tasks:
|
|
26
|
+
* - Create rollup configuration to support module creation
|
|
27
|
+
* - Generates final transformed configuration json
|
|
28
|
+
* - "base" value is always "./" for build, and main app baseUrl for preview or dev
|
|
29
|
+
*/
|
|
30
|
+
export default function processConfiguration(options: ProcessConfigurationOptions): PluginOption;
|
package/dist/{vite-configuration-processor-plugin.js → vite-plugin-configuration-processor.js}
RENAMED
|
@@ -7,19 +7,13 @@ import sharedDependencies from "./shared-dependencies.js";
|
|
|
7
7
|
* - Create rollup configuration to support module creation
|
|
8
8
|
* - Generates final transformed configuration json
|
|
9
9
|
* - "base" value is always "./" for build, and main app baseUrl for preview or dev
|
|
10
|
-
* @param root Project root directory.
|
|
11
|
-
* @param appShellConfig The original App Shell configuration json.
|
|
12
|
-
* @param selfAppName The name of the application bundle being built.
|
|
13
|
-
* @param buildEntryPoint If true, the index.html entry point will be added to the bundle.
|
|
14
|
-
* @param inlineConfig flag to control if config is included at index.html
|
|
15
|
-
* @param generateEmptyShell flag to control if we are creating an empty AppShell instance
|
|
16
|
-
* @param modules the set of modules to be created by the rollup
|
|
17
10
|
*/
|
|
18
|
-
export default function processConfiguration(
|
|
11
|
+
export default function processConfiguration(options) {
|
|
12
|
+
const { root, appShellConfig, selfAppName, modules, buildEntryPoint, inlineConfig, generateEmptyShell, experimentalNewPackageLayout, } = options;
|
|
19
13
|
let finalAppShellConfig;
|
|
20
14
|
let basePath;
|
|
21
15
|
return {
|
|
22
|
-
name: "vite-plugin-appShell-
|
|
16
|
+
name: "vite-plugin-appShell-config-processor",
|
|
23
17
|
config(config, { command }) {
|
|
24
18
|
const projectRoot = root ?? config.root;
|
|
25
19
|
let appModules = {};
|
|
@@ -58,7 +52,7 @@ export default function processConfiguration(root, appShellConfig, selfAppName,
|
|
|
58
52
|
* @param options build options
|
|
59
53
|
*/
|
|
60
54
|
async generateBundle(options) {
|
|
61
|
-
if (generateEmptyShell
|
|
55
|
+
if (generateEmptyShell) {
|
|
62
56
|
return;
|
|
63
57
|
}
|
|
64
58
|
// obtain the directory (dist) where the new config file will be placed
|
|
@@ -82,11 +76,16 @@ export default function processConfiguration(root, appShellConfig, selfAppName,
|
|
|
82
76
|
finalAppShellConfig.baseUrl = basePath;
|
|
83
77
|
}
|
|
84
78
|
finalAppShellConfig.apps = undefined;
|
|
85
|
-
// Replace all @self references using simple string replacement
|
|
79
|
+
// Replace all $app and @self (deprecated) references using simple string replacement.
|
|
86
80
|
let configString = JSON.stringify(finalAppShellConfig);
|
|
81
|
+
configString = configString.replaceAll(`"$app/`, `"${selfAppName}/`);
|
|
82
|
+
// TODO(major): remove @self/ support in favour of $app/
|
|
87
83
|
configString = configString.replaceAll(`"@self/`, `"${selfAppName}/`);
|
|
88
84
|
finalAppShellConfig = JSON.parse(configString);
|
|
89
|
-
|
|
85
|
+
// Write app-shell.config.json to dist when:
|
|
86
|
+
// - inlineConfig is false (standard flow), OR
|
|
87
|
+
// - experimentalNewPackageLayout is true (ensures dual-use: app shell or app bundle)
|
|
88
|
+
if (!inlineConfig || experimentalNewPackageLayout) {
|
|
90
89
|
fs.writeFileSync(path.resolve(targetDir, "app-shell.config.json"), JSON.stringify(finalAppShellConfig));
|
|
91
90
|
}
|
|
92
91
|
},
|
|
@@ -5,5 +5,4 @@ export declare const isExternalUrl: (url: string) => boolean;
|
|
|
5
5
|
export declare const dataUrlRE: RegExp;
|
|
6
6
|
export declare const isDataUrl: (url: string) => boolean;
|
|
7
7
|
export declare function checkCrossOrigin(html: string): any[];
|
|
8
|
-
|
|
9
|
-
export default fixCrossOrigin;
|
|
8
|
+
export default function fixCrossOrigin(): PluginOption;
|
|
@@ -48,11 +48,11 @@ export function checkCrossOrigin(html) {
|
|
|
48
48
|
}
|
|
49
49
|
return withCredentials;
|
|
50
50
|
}
|
|
51
|
-
|
|
51
|
+
export default function fixCrossOrigin() {
|
|
52
52
|
const withCredentials = {};
|
|
53
53
|
return [
|
|
54
54
|
{
|
|
55
|
-
name: "vite-crossorigin-fix-collect-info
|
|
55
|
+
name: "vite-plugin-crossorigin-fix-collect-info",
|
|
56
56
|
transformIndexHtml: {
|
|
57
57
|
order: "pre",
|
|
58
58
|
handler(html, info) {
|
|
@@ -61,7 +61,7 @@ const fixCrossOrigin = () => {
|
|
|
61
61
|
},
|
|
62
62
|
},
|
|
63
63
|
{
|
|
64
|
-
name: "vite-crossorigin-fix-replace
|
|
64
|
+
name: "vite-plugin-crossorigin-fix-replace",
|
|
65
65
|
transformIndexHtml: {
|
|
66
66
|
order: "post",
|
|
67
67
|
handler(html, context) {
|
|
@@ -79,5 +79,4 @@ const fixCrossOrigin = () => {
|
|
|
79
79
|
},
|
|
80
80
|
},
|
|
81
81
|
];
|
|
82
|
-
}
|
|
83
|
-
export default fixCrossOrigin;
|
|
82
|
+
}
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
import * as fs from "node:fs";
|
|
2
|
+
import * as path from "node:path";
|
|
3
|
+
// ─── Constants ───────────────────────────────────────────────────────────────
|
|
4
|
+
/**
|
|
5
|
+
* Default custom export condition used internally by workspace packages
|
|
6
|
+
* to resolve TypeScript source during development.
|
|
7
|
+
*
|
|
8
|
+
* This condition must never leak into published artifacts because external
|
|
9
|
+
* consumers would not be able to resolve it.
|
|
10
|
+
*/
|
|
11
|
+
const DEFAULT_SOURCE_CONDITION = "@pentaho-apps:source";
|
|
12
|
+
/**
|
|
13
|
+
* Runtime-relevant package.json fields copied into dist output.
|
|
14
|
+
*
|
|
15
|
+
* All other fields are intentionally excluded.
|
|
16
|
+
*/
|
|
17
|
+
const INCLUDED_FIELDS = [
|
|
18
|
+
"name",
|
|
19
|
+
"version",
|
|
20
|
+
"type",
|
|
21
|
+
"license",
|
|
22
|
+
"description",
|
|
23
|
+
"dependencies",
|
|
24
|
+
"peerDependencies",
|
|
25
|
+
"peerDependenciesMeta",
|
|
26
|
+
"optionalDependencies",
|
|
27
|
+
];
|
|
28
|
+
// ─── Helpers ─────────────────────────────────────────────────────────────────
|
|
29
|
+
/**
|
|
30
|
+
* Reads and parses a JSON file.
|
|
31
|
+
*
|
|
32
|
+
* Returns `undefined` if the file does not exist or cannot be parsed.
|
|
33
|
+
*/
|
|
34
|
+
function readJsonFile(filePath) {
|
|
35
|
+
try {
|
|
36
|
+
return JSON.parse(fs.readFileSync(filePath, "utf8"));
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
return undefined;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Extracts the package name from a module specifier.
|
|
44
|
+
*
|
|
45
|
+
* Examples:
|
|
46
|
+
* react-dom/client → react-dom
|
|
47
|
+
* @emotion/react/jsx-dev → @emotion/react
|
|
48
|
+
*/
|
|
49
|
+
function toPackageName(specifier) {
|
|
50
|
+
if (specifier.startsWith("@")) {
|
|
51
|
+
const segments = specifier.split("/");
|
|
52
|
+
return segments.length >= 2 ? `${segments[0]}/${segments[1]}` : segments[0];
|
|
53
|
+
}
|
|
54
|
+
return specifier.split("/")[0];
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Removes the build output prefix from an export path.
|
|
58
|
+
*
|
|
59
|
+
* Example:
|
|
60
|
+
* ./dist/index.js → ./index.js
|
|
61
|
+
*/
|
|
62
|
+
function stripDistPrefix(prefix, value) {
|
|
63
|
+
return value.startsWith(prefix) ? `./${value.slice(prefix.length)}` : value;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Transforms a package export target for dist/package.json.
|
|
67
|
+
*
|
|
68
|
+
* Processing rules:
|
|
69
|
+
*
|
|
70
|
+
* Strings:
|
|
71
|
+
* - Must resolve inside build.outDir
|
|
72
|
+
* - build.outDir prefix is stripped
|
|
73
|
+
*
|
|
74
|
+
* Objects:
|
|
75
|
+
* - Removes dev-only source condition
|
|
76
|
+
* - Recursively transforms nested targets
|
|
77
|
+
* - Removed if empty after transformation
|
|
78
|
+
*
|
|
79
|
+
* Arrays:
|
|
80
|
+
* - Node fallback arrays are eagerly collapsed to the first
|
|
81
|
+
* valid non-null target because import maps do not support
|
|
82
|
+
* Node conditional fallback resolution semantics.
|
|
83
|
+
*
|
|
84
|
+
* null:
|
|
85
|
+
* - Preserved as explicit export exclusion
|
|
86
|
+
*
|
|
87
|
+
* undefined:
|
|
88
|
+
* - Internal sentinel meaning "omit this entry"
|
|
89
|
+
*/
|
|
90
|
+
function transformExportTargetForDist(target, distPrefix, sourceCondition) {
|
|
91
|
+
// Explicit export exclusion must be preserved
|
|
92
|
+
if (target === null) {
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
// Direct export path
|
|
96
|
+
if (typeof target === "string") {
|
|
97
|
+
const stripped = stripDistPrefix(distPrefix, target);
|
|
98
|
+
// Ignore paths outside dist output
|
|
99
|
+
return stripped === target ? undefined : stripped;
|
|
100
|
+
}
|
|
101
|
+
// Fallback array
|
|
102
|
+
if (Array.isArray(target)) {
|
|
103
|
+
for (const entry of target) {
|
|
104
|
+
const resolved = transformExportTargetForDist(entry, distPrefix, sourceCondition);
|
|
105
|
+
if (resolved !== undefined && resolved !== null) {
|
|
106
|
+
return resolved;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return undefined;
|
|
110
|
+
}
|
|
111
|
+
// Conditional exports object
|
|
112
|
+
const result = {};
|
|
113
|
+
for (const [condition, value] of Object.entries(target)) {
|
|
114
|
+
// Remove workspace-only source condition
|
|
115
|
+
if (condition === sourceCondition) {
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
const transformed = transformExportTargetForDist(value, distPrefix, sourceCondition);
|
|
119
|
+
// Omitted targets disappear entirely
|
|
120
|
+
if (transformed === undefined) {
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
123
|
+
result[condition] = transformed;
|
|
124
|
+
}
|
|
125
|
+
return Object.keys(result).length === 0 ? undefined : result;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Normalizes package exports into canonical subpath map form.
|
|
129
|
+
*
|
|
130
|
+
* Converts:
|
|
131
|
+
*
|
|
132
|
+
* "exports": "./index.js"
|
|
133
|
+
* → { ".": "./index.js" }
|
|
134
|
+
*
|
|
135
|
+
* "exports": { "import": "./index.js" }
|
|
136
|
+
* → { ".": { "import": "./index.js" } }
|
|
137
|
+
*
|
|
138
|
+
* Leaves already-normalized subpath maps untouched.
|
|
139
|
+
*/
|
|
140
|
+
function normalizeExportsToSubpathMap(exportsField) {
|
|
141
|
+
if (exportsField == null) {
|
|
142
|
+
throw new Error(`[App Shell]: package.json is missing "exports".`);
|
|
143
|
+
}
|
|
144
|
+
// Sugar form:
|
|
145
|
+
// "exports": "./index.js"
|
|
146
|
+
// "exports": ["./a.js", "./b.js"]
|
|
147
|
+
if (typeof exportsField === "string" || Array.isArray(exportsField)) {
|
|
148
|
+
return { ".": exportsField };
|
|
149
|
+
}
|
|
150
|
+
const keys = Object.keys(exportsField);
|
|
151
|
+
// Already a subpath map
|
|
152
|
+
if (keys.every((key) => key.startsWith("."))) {
|
|
153
|
+
return exportsField;
|
|
154
|
+
}
|
|
155
|
+
// Root conditional exports sugar
|
|
156
|
+
return { ".": exportsField };
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Appends standard metadata exports required at runtime.
|
|
160
|
+
*/
|
|
161
|
+
function appendStandardExports(exportsMap, outDir) {
|
|
162
|
+
exportsMap["./package.json"] = "./package.json";
|
|
163
|
+
exportsMap["./app-shell.config.json"] = "./app-shell.config.json";
|
|
164
|
+
if (fs.existsSync(path.join(outDir, "locales"))) {
|
|
165
|
+
exportsMap["./locales/*"] = "./locales/*";
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
// ─── Dist package.json generation ────────────────────────────────────────────
|
|
169
|
+
/**
|
|
170
|
+
* Generates dist/package.json from the source package.
|
|
171
|
+
*
|
|
172
|
+
* The generated package:
|
|
173
|
+
* - strips dev-only export conditions
|
|
174
|
+
* - rewrites export paths relative to dist/
|
|
175
|
+
* - preserves explicit null exclusions
|
|
176
|
+
* - supports nested conditional exports
|
|
177
|
+
*/
|
|
178
|
+
function generateDistPackageJson(root, outDir, buildOutDir, sourceCondition, externalizedPackages) {
|
|
179
|
+
const pkgPath = path.join(root, "package.json");
|
|
180
|
+
const pkg = readJsonFile(pkgPath);
|
|
181
|
+
if (!pkg || !fs.existsSync(outDir)) {
|
|
182
|
+
return false;
|
|
183
|
+
}
|
|
184
|
+
const rawExports = pkg.exports;
|
|
185
|
+
const distPrefix = `./${buildOutDir}/`;
|
|
186
|
+
const transformedExports = transformExportTargetForDist(normalizeExportsToSubpathMap(rawExports), distPrefix, sourceCondition);
|
|
187
|
+
/**
|
|
188
|
+
* The entire exports tree may collapse after removing dev-only
|
|
189
|
+
* conditions and invalid dist targets.
|
|
190
|
+
*/
|
|
191
|
+
if (transformedExports === undefined) {
|
|
192
|
+
throw new Error(`[App Shell] ${pkg.name}: exports resolved to empty after transformation.`);
|
|
193
|
+
}
|
|
194
|
+
appendStandardExports(transformedExports, outDir);
|
|
195
|
+
const distPkg = {};
|
|
196
|
+
// Copy runtime-relevant fields. The "dependencies" and "optionalDependencies"
|
|
197
|
+
// fields are narrowed to only the modules that Rollup actually externalized,
|
|
198
|
+
// so the published package declares exactly the runtime modules it expects the
|
|
199
|
+
// host to provide.
|
|
200
|
+
for (const field of INCLUDED_FIELDS) {
|
|
201
|
+
if (pkg[field] == null) {
|
|
202
|
+
continue;
|
|
203
|
+
}
|
|
204
|
+
if (field === "dependencies" || field === "optionalDependencies") {
|
|
205
|
+
const filtered = filterExternalizedDependencies(pkg[field], externalizedPackages);
|
|
206
|
+
if (Object.keys(filtered).length > 0) {
|
|
207
|
+
distPkg[field] = filtered;
|
|
208
|
+
}
|
|
209
|
+
continue;
|
|
210
|
+
}
|
|
211
|
+
distPkg[field] = pkg[field];
|
|
212
|
+
}
|
|
213
|
+
distPkg.exports = transformedExports;
|
|
214
|
+
fs.writeFileSync(path.join(outDir, "package.json"), JSON.stringify(distPkg, null, 2) + "\n");
|
|
215
|
+
console.info(`[App Shell] Generated ${buildOutDir}/package.json for ${pkg.name}`);
|
|
216
|
+
return true;
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Keeps only the declared dependencies whose package was externalized by the
|
|
220
|
+
* bundle (i.e. expected to be resolved by the host at runtime).
|
|
221
|
+
*/
|
|
222
|
+
function filterExternalizedDependencies(dependencies, externalizedPackages) {
|
|
223
|
+
const filtered = {};
|
|
224
|
+
for (const [name, range] of Object.entries(dependencies)) {
|
|
225
|
+
if (externalizedPackages.has(name)) {
|
|
226
|
+
filtered[name] = range;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
return filtered;
|
|
230
|
+
}
|
|
231
|
+
// ─── Plugin ──────────────────────────────────────────────────────────────────
|
|
232
|
+
/**
|
|
233
|
+
* Generates a cleaned dist/package.json during Vite builds.
|
|
234
|
+
*/
|
|
235
|
+
export default function distPackageJsonPlugin(root, sourceCondition = DEFAULT_SOURCE_CONDITION) {
|
|
236
|
+
let config;
|
|
237
|
+
const externalizedPackages = new Set();
|
|
238
|
+
return {
|
|
239
|
+
name: "vite-plugin-dist-package-json",
|
|
240
|
+
apply: "build",
|
|
241
|
+
configResolved(resolved) {
|
|
242
|
+
config = resolved;
|
|
243
|
+
},
|
|
244
|
+
buildStart() {
|
|
245
|
+
// Reset per build so stale externalized packages from a previous build
|
|
246
|
+
// (e.g. in watch mode, where the plugin instance is reused) don't leak
|
|
247
|
+
// into the next dist/package.json.
|
|
248
|
+
externalizedPackages.clear();
|
|
249
|
+
},
|
|
250
|
+
generateBundle(_options, bundle) {
|
|
251
|
+
const emittedFiles = new Set(Object.keys(bundle));
|
|
252
|
+
for (const file of Object.values(bundle)) {
|
|
253
|
+
if (file.type !== "chunk") {
|
|
254
|
+
continue;
|
|
255
|
+
}
|
|
256
|
+
// Imports that do not point to an emitted file are external modules
|
|
257
|
+
// that Rollup left for the host runtime to resolve.
|
|
258
|
+
for (const imported of [...file.imports, ...file.dynamicImports]) {
|
|
259
|
+
if (!emittedFiles.has(imported)) {
|
|
260
|
+
externalizedPackages.add(toPackageName(imported));
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
},
|
|
265
|
+
closeBundle() {
|
|
266
|
+
const packageRoot = root ?? config.root;
|
|
267
|
+
const outDir = path.resolve(packageRoot, config.build.outDir);
|
|
268
|
+
generateDistPackageJson(packageRoot, outDir, config.build.outDir, sourceCondition, externalizedPackages);
|
|
269
|
+
},
|
|
270
|
+
};
|
|
271
|
+
}
|
|
@@ -8,7 +8,7 @@ import type { HvAppShellConfig } from "@hitachivantara/app-shell-shared";
|
|
|
8
8
|
* @param appShellConfig App shell config values
|
|
9
9
|
* @returns The app title
|
|
10
10
|
*/
|
|
11
|
-
export declare const getAppTitle: (generateEmptyShell: boolean, appShellConfig: HvAppShellConfig) =>
|
|
11
|
+
export declare const getAppTitle: (generateEmptyShell: boolean, appShellConfig: HvAppShellConfig) => string;
|
|
12
12
|
/**
|
|
13
13
|
* Add the <BASE> tag and icons preload in the index.html file.
|
|
14
14
|
* @param appShellConfig The app shell configuration.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import SHARED_DEPENDENCIES from "./shared-dependencies.js";
|
|
4
|
-
import { getExtraDependenciesString } from "./vite-importmap
|
|
4
|
+
import { getExtraDependenciesString } from "./vite-plugin-importmap.js";
|
|
5
5
|
export default function generateBashScript(externalImportMap, inlineConfig) {
|
|
6
6
|
let config;
|
|
7
7
|
let targetDir;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import { createRequire } from "node:module";
|
|
3
3
|
import path from "node:path";
|
|
4
|
-
import { computeSupportedLocales,
|
|
4
|
+
import { computeSupportedLocales, mergeDirs, SUPPORTED_LOCALES_FILE, } from "./locales-utils.js";
|
|
5
|
+
import { deepMerge, readJsonFile } from "./utils.js";
|
|
5
6
|
/**
|
|
6
7
|
* Resolves the app-shell-ui's locales directory path via its `./locales/*` export.
|
|
7
8
|
*/
|
|
@@ -63,7 +64,7 @@ export default function copyAppShellLocales(mergeUpstream = true) {
|
|
|
63
64
|
let resolvedOutDir;
|
|
64
65
|
let isBuild = false;
|
|
65
66
|
return {
|
|
66
|
-
name: "vite-plugin-
|
|
67
|
+
name: "vite-plugin-copy-appShell-locales",
|
|
67
68
|
// Capture the resolved output directory from Vite's config
|
|
68
69
|
configResolved(config) {
|
|
69
70
|
resolvedOutDir = path.resolve(config.root, config.build.outDir);
|
|
@@ -4,5 +4,4 @@ import type { PluginOption } from "vite";
|
|
|
4
4
|
* The metadata is used to help any troubleshoot activity by referencing
|
|
5
5
|
* the version of the app-shell-vite-plugin and app-shell-ui packages used by the app.
|
|
6
6
|
*/
|
|
7
|
-
|
|
8
|
-
export default injectMetadata;
|
|
7
|
+
export default function injectMetadata(): PluginOption;
|
|
@@ -1,20 +1,18 @@
|
|
|
1
|
-
import fs from "node:fs";
|
|
2
1
|
import { resolveModule } from "./nodeModule.js";
|
|
2
|
+
import { readJsonFile } from "./utils.js";
|
|
3
3
|
const extractVersion = (packageJsonFile) => {
|
|
4
|
-
|
|
5
|
-
const packageObject = JSON.parse(packageJson);
|
|
6
|
-
return packageObject.version;
|
|
4
|
+
return readJsonFile(packageJsonFile).version;
|
|
7
5
|
};
|
|
8
6
|
/**
|
|
9
7
|
* This plugin injects metadata into the index.html file.
|
|
10
8
|
* The metadata is used to help any troubleshoot activity by referencing
|
|
11
9
|
* the version of the app-shell-vite-plugin and app-shell-ui packages used by the app.
|
|
12
10
|
*/
|
|
13
|
-
|
|
11
|
+
export default function injectMetadata() {
|
|
14
12
|
const appShellUIVersion = extractVersion(resolveModule("@hitachivantara/app-shell-ui/package.json"));
|
|
15
13
|
const appShellVitePluginVersion = extractVersion(resolveModule("@hitachivantara/app-shell-vite-plugin/package.json"));
|
|
16
14
|
return {
|
|
17
|
-
name: "vite-metadata
|
|
15
|
+
name: "vite-plugin-metadata",
|
|
18
16
|
transformIndexHtml() {
|
|
19
17
|
return [
|
|
20
18
|
{
|
|
@@ -34,5 +32,4 @@ const injectMetadata = () => {
|
|
|
34
32
|
];
|
|
35
33
|
},
|
|
36
34
|
};
|
|
37
|
-
}
|
|
38
|
-
export default injectMetadata;
|
|
35
|
+
}
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
2
|
const prepareConfigForDevMode = (config, selfAppName) => {
|
|
3
3
|
let configString = JSON.stringify(config);
|
|
4
|
+
configString = configString.replaceAll(`"$app/`, `"${selfAppName}/`);
|
|
5
|
+
// TODO(major): remove @self/ support in favour of $app/
|
|
4
6
|
configString = configString.replaceAll(`"@self/`, `"${selfAppName}/`);
|
|
5
7
|
return JSON.parse(configString);
|
|
6
8
|
};
|
|
7
9
|
export default function serveAppShellConfig(appShellConfig, root, selfAppName, appShellConfigFile, automaticViewsFolder) {
|
|
8
10
|
return {
|
|
9
|
-
name: "vite-plugin-watch-
|
|
11
|
+
name: "vite-plugin-watch-appShell-config",
|
|
10
12
|
apply: "serve",
|
|
11
13
|
configureServer(server) {
|
|
12
14
|
const restartServer = (file) => {
|