@salesforce/vite-plugin-ui-bundle 11.55.1 → 11.56.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/README.md +49 -0
- package/dist/core/createCorePlugins.d.ts +26 -0
- package/dist/core/createCorePlugins.d.ts.map +1 -0
- package/dist/core/design.d.ts +26 -0
- package/dist/core/design.d.ts.map +1 -0
- package/dist/core/env.d.ts +42 -0
- package/dist/core/env.d.ts.map +1 -0
- package/dist/createCorePlugins-C2ODv7o-.js +308 -0
- package/dist/index.d.ts +15 -20
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -294
- package/dist/site/index.d.ts +21 -0
- package/dist/site/index.d.ts.map +1 -0
- package/dist/site/index.js +58 -0
- package/dist/site/languages.d.ts +35 -0
- package/dist/site/languages.d.ts.map +1 -0
- package/dist/site/site-plugin.d.ts +23 -0
- package/dist/site/site-plugin.d.ts.map +1 -0
- package/package.json +7 -3
package/README.md
CHANGED
|
@@ -1,3 +1,52 @@
|
|
|
1
1
|
# @salesforce/vite-plugin-ui-bundle
|
|
2
2
|
|
|
3
3
|
Vite plugin for Salesforce UI Bundles
|
|
4
|
+
|
|
5
|
+
## Entry points
|
|
6
|
+
|
|
7
|
+
This package ships two plugins from one versioned artifact:
|
|
8
|
+
|
|
9
|
+
| Import | Use for | basePath / language |
|
|
10
|
+
| ---------------------------------------- | ----------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------- |
|
|
11
|
+
| `@salesforce/vite-plugin-ui-bundle` | **the default** — every bundle, unless something below applies | `basePath` always `/`; no language folding |
|
|
12
|
+
| `@salesforce/vite-plugin-ui-bundle/site` | site bundles that need site-specific local-dev handling (today: the language-switcher feature is installed) | per-request `basePath = /<lang>` + `SFDC_ENV.language`, driven by `languages` |
|
|
13
|
+
|
|
14
|
+
Most bundles use the generic import. The language-switcher feature's setup swaps
|
|
15
|
+
a bundle to `./site` and passes its `LANGUAGES`; you rarely edit this by hand.
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
// Generic bundle
|
|
19
|
+
import uiBundlePlugin from "@salesforce/vite-plugin-ui-bundle";
|
|
20
|
+
export default defineConfig({ plugins: [uiBundlePlugin()] });
|
|
21
|
+
|
|
22
|
+
// Site bundle (language switching in local preview)
|
|
23
|
+
import siteUiBundlePlugin from "@salesforce/vite-plugin-ui-bundle/site";
|
|
24
|
+
export default defineConfig({
|
|
25
|
+
plugins: [siteUiBundlePlugin({ languages: ["en_US", "zh_CN", "fr"] })],
|
|
26
|
+
});
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
The site plugin composes the same core as the generic plugin (proxying, org
|
|
30
|
+
info, API-version bake-in, design mode, HMR are identical); it only adds
|
|
31
|
+
site-specific base-path management. With no `languages` (or an empty array) the
|
|
32
|
+
site plugin behaves identically to the generic one.
|
|
33
|
+
|
|
34
|
+
### How the site entry works (local dev only)
|
|
35
|
+
|
|
36
|
+
On a deployed Experience site the platform injects `globalThis.SFDC_ENV.language`
|
|
37
|
+
and folds the active language into `SFDC_ENV.basePath` (e.g. `/shop/fr`),
|
|
38
|
+
recomputed from the request URL on every load. The generic dev server does
|
|
39
|
+
neither. The site entry mirrors this for local dev, per request:
|
|
40
|
+
|
|
41
|
+
- A leading URL segment matching a **non-default** supported language is stripped
|
|
42
|
+
before Vite's router sees it, so `/fr/property/1` is served exactly like
|
|
43
|
+
`/property/1` (SPA fallback).
|
|
44
|
+
- `SFDC_ENV.language` and `basePath` are recomputed from the URL: a non-default
|
|
45
|
+
segment → `language="<lang>"`, `basePath="/<lang>"`; no segment (or the
|
|
46
|
+
default, which is the **first** entry of `languages`) → `language="<default>"`,
|
|
47
|
+
`basePath="/"`.
|
|
48
|
+
- `apiPath` stays `/` (never folded), so the `/services/*` GraphQL proxy still
|
|
49
|
+
resolves — the language lives in `basePath` only.
|
|
50
|
+
|
|
51
|
+
All of this is gated to non-production, non-CodeBuilder, and a non-empty
|
|
52
|
+
`languages` list, so a deployed build and every generic bundle are untouched.
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { Plugin } from 'vite';
|
|
2
|
+
import { DesignPluginOptions } from './design';
|
|
3
|
+
import { BasePathResolver } from './env';
|
|
4
|
+
export interface CorePluginOptions extends DesignPluginOptions {
|
|
5
|
+
/** Salesforce org alias */
|
|
6
|
+
orgAlias?: string;
|
|
7
|
+
/** Enable verbose logging */
|
|
8
|
+
debug?: boolean;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Optional hooks a specialized entry (e.g. `./site`) can inject into the shared
|
|
12
|
+
* core. `resolveBasePath` runs per index.html request to fold a language into
|
|
13
|
+
* `basePath` and inject `SFDC_ENV.language`; the generic entry omits it and the
|
|
14
|
+
* core uses the identity resolver (today's behavior, byte-for-byte).
|
|
15
|
+
*/
|
|
16
|
+
export interface CoreHooks {
|
|
17
|
+
resolveBasePath?: BasePathResolver;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Assemble the shared UI-bundle plugins ([design, core]) both the generic and
|
|
21
|
+
* site entries build on. All plumbing — proxy handler, org info, API-version
|
|
22
|
+
* bake-in, design mode, HMR, and the `<base href>` + `SFDC_ENV` injection —
|
|
23
|
+
* lives here. The only seam is {@link CoreHooks.resolveBasePath}.
|
|
24
|
+
*/
|
|
25
|
+
export declare function createCorePlugins(options?: CorePluginOptions, hooks?: CoreHooks): Plugin[];
|
|
26
|
+
//# sourceMappingURL=createCorePlugins.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"createCorePlugins.d.ts","sourceRoot":"","sources":["../../src/core/createCorePlugins.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAMH,OAAO,KAAK,EAA6B,MAAM,EAAiB,MAAM,MAAM,CAAC;AAU7E,OAAO,EAAsB,KAAK,mBAAmB,EAAE,MAAM,UAAU,CAAC;AACxE,OAAO,EAAkC,KAAK,gBAAgB,EAAoB,MAAM,OAAO,CAAC;AAEhG,MAAM,WAAW,iBAAkB,SAAQ,mBAAmB;IAC7D,2BAA2B;IAC3B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,6BAA6B;IAC7B,KAAK,CAAC,EAAE,OAAO,CAAC;CAChB;AAED;;;;;GAKG;AACH,MAAM,WAAW,SAAS;IACzB,eAAe,CAAC,EAAE,gBAAgB,CAAC;CACnC;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAChC,OAAO,GAAE,iBAAsB,EAC/B,KAAK,GAAE,SAAc,GACnB,MAAM,EAAE,CAuKV"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { Plugin } from 'vite';
|
|
2
|
+
/** Options consumed by the design-mode plugin. */
|
|
3
|
+
export interface DesignPluginOptions {
|
|
4
|
+
/**
|
|
5
|
+
* Enable design-time features (inject `data-source-file`, serve & inject
|
|
6
|
+
* design interactions script).
|
|
7
|
+
*
|
|
8
|
+
* Defaults to enabled when Vite `mode` is `"design"` (e.g. `vite --mode design`).
|
|
9
|
+
*/
|
|
10
|
+
designMode?: boolean;
|
|
11
|
+
/**
|
|
12
|
+
* File path segments to exclude from design-time `data-source-file` injection.
|
|
13
|
+
* Files whose path contains any of these strings will be skipped entirely.
|
|
14
|
+
*
|
|
15
|
+
* @default ["/components/ui/"]
|
|
16
|
+
*/
|
|
17
|
+
designModeExcludePaths?: string[];
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* The design-mode plugin: injects source-locator attributes into JSX/TSX,
|
|
21
|
+
* serves the design-mode interactions runtime script, and injects a `<script>`
|
|
22
|
+
* to load it. Moved verbatim from the original single plugin — shared by both
|
|
23
|
+
* the generic and site entries.
|
|
24
|
+
*/
|
|
25
|
+
export declare function createDesignPlugin(options?: DesignPluginOptions): Plugin;
|
|
26
|
+
//# sourceMappingURL=design.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"design.d.ts","sourceRoot":"","sources":["../../src/core/design.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAKH,OAAO,KAAK,EAAqB,MAAM,EAAiB,MAAM,MAAM,CAAC;AAErE,kDAAkD;AAClD,MAAM,WAAW,mBAAmB;IACnC;;;;;OAKG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;;;OAKG;IACH,sBAAsB,CAAC,EAAE,MAAM,EAAE,CAAC;CAClC;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,GAAE,mBAAwB,GAAG,MAAM,CAwG5E"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { HtmlTagDescriptor } from 'vite';
|
|
2
|
+
/**
|
|
3
|
+
* The local-dev runtime environment injected into the page as
|
|
4
|
+
* `globalThis.SFDC_ENV` (and mirrored by the `<base href>` tag). Populated only
|
|
5
|
+
* in non-production; see the `config` / `configResolved` hooks in
|
|
6
|
+
* {@link createCorePlugins}.
|
|
7
|
+
*/
|
|
8
|
+
export interface Environment {
|
|
9
|
+
basePath: string;
|
|
10
|
+
apiPath: string;
|
|
11
|
+
orgUrl?: string;
|
|
12
|
+
namespace?: string;
|
|
13
|
+
appName?: string;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Per-request resolution of the effective `basePath` (+ optional `language`)
|
|
17
|
+
* from the request URL.
|
|
18
|
+
*
|
|
19
|
+
* The generic entry passes the {@link identityResolver}, which returns the
|
|
20
|
+
* configured `basePath` unchanged and no language — today's behavior. The site
|
|
21
|
+
* entry supplies a resolver that folds a supported language segment into
|
|
22
|
+
* `basePath`. Returning a `language` causes `SFDC_ENV.language` to be injected,
|
|
23
|
+
* matching the platform, which always sets it on a deployed site.
|
|
24
|
+
*/
|
|
25
|
+
export type BasePathResolver = (originalUrl: string | undefined, env: Environment) => {
|
|
26
|
+
basePath: string;
|
|
27
|
+
language?: string;
|
|
28
|
+
};
|
|
29
|
+
/** The generic resolver: configured `basePath`, no language. */
|
|
30
|
+
export declare const identityResolver: BasePathResolver;
|
|
31
|
+
/**
|
|
32
|
+
* Build the `<base href>` + `SFDC_ENV` tags for a single index.html request.
|
|
33
|
+
*
|
|
34
|
+
* `resolveBasePath` runs per request so the site entry can recompute `basePath`
|
|
35
|
+
* and `language` from `originalUrl` on every reload; the generic entry passes
|
|
36
|
+
* {@link identityResolver} and this collapses to today's behavior.
|
|
37
|
+
*/
|
|
38
|
+
export declare function buildEnvTags(html: string, env: Environment, originalUrl: string | undefined, resolveBasePath?: BasePathResolver): {
|
|
39
|
+
html: string;
|
|
40
|
+
tags: HtmlTagDescriptor[];
|
|
41
|
+
};
|
|
42
|
+
//# sourceMappingURL=env.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env.d.ts","sourceRoot":"","sources":["../../src/core/env.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,MAAM,CAAC;AAE9C;;;;;GAKG;AACH,MAAM,WAAW,WAAW;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;;GASG;AACH,MAAM,MAAM,gBAAgB,GAAG,CAC9B,WAAW,EAAE,MAAM,GAAG,SAAS,EAC/B,GAAG,EAAE,WAAW,KACZ;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAE7C,gEAAgE;AAChE,eAAO,MAAM,gBAAgB,EAAE,gBAA8D,CAAC;AAE9F;;;;;;GAMG;AACH,wBAAgB,YAAY,CAC3B,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,WAAW,EAChB,WAAW,EAAE,MAAM,GAAG,SAAS,EAC/B,eAAe,GAAE,gBAAmC,GAClD;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,iBAAiB,EAAE,CAAA;CAAE,CAoC7C"}
|
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
import { loadManifest, getOrgInfo } from "@salesforce/ui-bundle/app";
|
|
2
|
+
import { injectLivePreviewScript, createProxyHandler } from "@salesforce/ui-bundle/proxy";
|
|
3
|
+
import fs, { existsSync, readFileSync, readdirSync } from "node:fs";
|
|
4
|
+
import { dirname, join, basename } from "node:path";
|
|
5
|
+
import { getRuntimeScriptContent } from "@salesforce/ui-design-mode/runtime";
|
|
6
|
+
import reactDesignTimeLocatorBabelPlugin from "@salesforce/ui-design-mode/source-locator/react";
|
|
7
|
+
const DEFAULT_PORT = 5173;
|
|
8
|
+
const DEFAULT_API_VERSION = "65.0";
|
|
9
|
+
const DEFAULT_NAMESPACE = "c";
|
|
10
|
+
function getAppName(rootPath) {
|
|
11
|
+
try {
|
|
12
|
+
const files = readdirSync(rootPath);
|
|
13
|
+
const metaFile = files.find((f) => f.endsWith(".uibundle-meta.xml"));
|
|
14
|
+
if (metaFile) {
|
|
15
|
+
return metaFile.replace(".uibundle-meta.xml", "");
|
|
16
|
+
}
|
|
17
|
+
} catch {
|
|
18
|
+
}
|
|
19
|
+
return basename(rootPath);
|
|
20
|
+
}
|
|
21
|
+
function getNamespace(startDir) {
|
|
22
|
+
let dir = startDir;
|
|
23
|
+
for (let parent = dirname(dir); ; dir = parent, parent = dirname(dir)) {
|
|
24
|
+
const sfdxProjectPath = join(dir, "sfdx-project.json");
|
|
25
|
+
if (existsSync(sfdxProjectPath)) {
|
|
26
|
+
try {
|
|
27
|
+
const namespace = JSON.parse(readFileSync(sfdxProjectPath, "utf-8")).namespace;
|
|
28
|
+
if (typeof namespace === "string" && namespace.trim()) {
|
|
29
|
+
return namespace.trim();
|
|
30
|
+
}
|
|
31
|
+
} catch {
|
|
32
|
+
}
|
|
33
|
+
return DEFAULT_NAMESPACE;
|
|
34
|
+
}
|
|
35
|
+
if (parent === dir) {
|
|
36
|
+
break;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return DEFAULT_NAMESPACE;
|
|
40
|
+
}
|
|
41
|
+
function getCodeBuilderBasePath(proxyUri, port) {
|
|
42
|
+
try {
|
|
43
|
+
const url = new URL(proxyUri.replace("{{port}}", port.toString()));
|
|
44
|
+
return url.pathname;
|
|
45
|
+
} catch (error) {
|
|
46
|
+
console.error("Failed to parse CODE_BUILDER_FRAMEWORK_PROXY_URI:", error);
|
|
47
|
+
return `/absproxy/${port}`;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
function getDevServerTarget(codeBuilderProxyUrl, port) {
|
|
51
|
+
if (codeBuilderProxyUrl) {
|
|
52
|
+
return getCodeBuilderBasePath(codeBuilderProxyUrl, port);
|
|
53
|
+
}
|
|
54
|
+
return `http://localhost:${port}`;
|
|
55
|
+
}
|
|
56
|
+
function getPort() {
|
|
57
|
+
return parseInt(process.env.SF_UIBUNDLE_PORT || DEFAULT_PORT.toString(), 10);
|
|
58
|
+
}
|
|
59
|
+
function createDesignPlugin(options = {}) {
|
|
60
|
+
let designModeEnabled = options.designMode ?? false;
|
|
61
|
+
return {
|
|
62
|
+
name: "@salesforce/vite-plugin-ui-bundle:design",
|
|
63
|
+
enforce: "pre",
|
|
64
|
+
config(_config, env) {
|
|
65
|
+
designModeEnabled = options.designMode ?? env.mode === "design";
|
|
66
|
+
},
|
|
67
|
+
configureServer(server) {
|
|
68
|
+
server.middlewares.use(async (req, res, next) => {
|
|
69
|
+
if (!designModeEnabled) {
|
|
70
|
+
next();
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
const urlPath = stripUrlQuery(req.url);
|
|
74
|
+
if (urlPath.endsWith("/_sfdc/design-mode-interactions.js")) {
|
|
75
|
+
try {
|
|
76
|
+
const script = getRuntimeScriptContent();
|
|
77
|
+
if (script !== null) {
|
|
78
|
+
res.setHeader("Content-Type", "application/javascript");
|
|
79
|
+
res.setHeader("Cache-Control", "no-cache");
|
|
80
|
+
res.end(script);
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
console.error(
|
|
84
|
+
`[ui-bundle-plugin] Design mode runtime script not found. Run 'npm run build' in @salesforce/ui-design-mode.`
|
|
85
|
+
);
|
|
86
|
+
res.writeHead(404);
|
|
87
|
+
res.end("Design mode script not found");
|
|
88
|
+
return;
|
|
89
|
+
} catch (error) {
|
|
90
|
+
console.error("[ui-bundle-plugin] Error serving design mode script:", error);
|
|
91
|
+
res.writeHead(500);
|
|
92
|
+
res.end("Error loading design mode script");
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
next();
|
|
97
|
+
});
|
|
98
|
+
},
|
|
99
|
+
async transform(code, id) {
|
|
100
|
+
if (!designModeEnabled) return null;
|
|
101
|
+
const filepath = id.split("?", 1)[0] ?? id;
|
|
102
|
+
const isTsx = filepath.endsWith(".tsx");
|
|
103
|
+
const isJsx = filepath.endsWith(".jsx");
|
|
104
|
+
if (!isTsx && !isJsx) return null;
|
|
105
|
+
if (filepath.includes("node_modules")) return null;
|
|
106
|
+
const excludePaths = options.designModeExcludePaths ?? ["/components/ui/"];
|
|
107
|
+
if (excludePaths.some((p) => filepath.includes(p))) return null;
|
|
108
|
+
let originalSource;
|
|
109
|
+
try {
|
|
110
|
+
originalSource = fs.readFileSync(filepath, "utf-8");
|
|
111
|
+
} catch {
|
|
112
|
+
}
|
|
113
|
+
const { transformAsync } = await import("@babel/core");
|
|
114
|
+
const result = await transformAsync(code, {
|
|
115
|
+
filename: filepath,
|
|
116
|
+
babelrc: false,
|
|
117
|
+
configFile: false,
|
|
118
|
+
sourceMaps: true,
|
|
119
|
+
parserOpts: {
|
|
120
|
+
sourceType: "module",
|
|
121
|
+
plugins: isTsx ? ["jsx", "typescript"] : ["jsx"]
|
|
122
|
+
},
|
|
123
|
+
plugins: [[reactDesignTimeLocatorBabelPlugin, { excludePaths, originalSource }]]
|
|
124
|
+
});
|
|
125
|
+
if (!result?.code) return null;
|
|
126
|
+
return { code: result.code, map: result.map };
|
|
127
|
+
},
|
|
128
|
+
transformIndexHtml: {
|
|
129
|
+
order: "pre",
|
|
130
|
+
handler(html) {
|
|
131
|
+
const tags = [];
|
|
132
|
+
if (designModeEnabled) {
|
|
133
|
+
tags.push({
|
|
134
|
+
tag: "script",
|
|
135
|
+
attrs: { src: "/_sfdc/design-mode-interactions.js" },
|
|
136
|
+
injectTo: "body"
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
return { html, tags };
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
function stripUrlQuery(url) {
|
|
145
|
+
if (!url) return "";
|
|
146
|
+
const queryIndex = url.indexOf("?");
|
|
147
|
+
return queryIndex === -1 ? url : url.slice(0, queryIndex);
|
|
148
|
+
}
|
|
149
|
+
const identityResolver = (_url, env) => ({ basePath: env.basePath });
|
|
150
|
+
function buildEnvTags(html, env, originalUrl, resolveBasePath = identityResolver) {
|
|
151
|
+
html = injectLivePreviewScript(html);
|
|
152
|
+
const { basePath, language } = resolveBasePath(originalUrl, env);
|
|
153
|
+
const tags = [];
|
|
154
|
+
const baseHref = basePath.endsWith("/") ? basePath : `${basePath}/`;
|
|
155
|
+
tags.push({
|
|
156
|
+
tag: "base",
|
|
157
|
+
attrs: { href: baseHref },
|
|
158
|
+
injectTo: "head-prepend"
|
|
159
|
+
});
|
|
160
|
+
const sfdcEnv = {
|
|
161
|
+
basePath,
|
|
162
|
+
apiPath: env.apiPath
|
|
163
|
+
};
|
|
164
|
+
if (env.orgUrl) sfdcEnv.orgUrl = env.orgUrl;
|
|
165
|
+
if (env.namespace) sfdcEnv.namespace = env.namespace;
|
|
166
|
+
if (env.appName) sfdcEnv.appName = env.appName;
|
|
167
|
+
if (language) sfdcEnv.language = language;
|
|
168
|
+
const sfdcEnvLiteral = JSON.stringify(sfdcEnv).replace(/</g, "\\u003c");
|
|
169
|
+
tags.push({
|
|
170
|
+
tag: "script",
|
|
171
|
+
children: `(function() { globalThis.SFDC_ENV = ${sfdcEnvLiteral}; })();`,
|
|
172
|
+
injectTo: "body"
|
|
173
|
+
});
|
|
174
|
+
return { html, tags };
|
|
175
|
+
}
|
|
176
|
+
function createCorePlugins(options = {}, hooks = {}) {
|
|
177
|
+
const resolveBasePath = hooks.resolveBasePath ?? identityResolver;
|
|
178
|
+
const proxyOptions = {
|
|
179
|
+
debug: options.debug ?? false
|
|
180
|
+
};
|
|
181
|
+
let orgInfo;
|
|
182
|
+
let manifest;
|
|
183
|
+
let environment;
|
|
184
|
+
let proxyHandler;
|
|
185
|
+
let codeBuilderProxyUrl;
|
|
186
|
+
const corePlugin = {
|
|
187
|
+
name: "@salesforce/vite-plugin-ui-bundle:core",
|
|
188
|
+
enforce: "pre",
|
|
189
|
+
async config(_config, env) {
|
|
190
|
+
let version;
|
|
191
|
+
try {
|
|
192
|
+
orgInfo = await getOrgInfo(options.orgAlias);
|
|
193
|
+
version = orgInfo?.apiVersion || DEFAULT_API_VERSION;
|
|
194
|
+
if (options.debug) {
|
|
195
|
+
console.log(`[ui-bundle-plugin] Using Salesforce API version: ${version}`);
|
|
196
|
+
}
|
|
197
|
+
} catch {
|
|
198
|
+
version = DEFAULT_API_VERSION;
|
|
199
|
+
}
|
|
200
|
+
codeBuilderProxyUrl = process.env.CODE_BUILDER_FRAMEWORK_PROXY_URI;
|
|
201
|
+
const isCodeBuilder = !!codeBuilderProxyUrl;
|
|
202
|
+
const define = {
|
|
203
|
+
__SF_API_VERSION__: JSON.stringify(version)
|
|
204
|
+
};
|
|
205
|
+
let base = "./";
|
|
206
|
+
if (env.mode !== "production") {
|
|
207
|
+
const basePath = isCodeBuilder ? getCodeBuilderBasePath(codeBuilderProxyUrl, getPort()) : "/";
|
|
208
|
+
environment = { basePath, apiPath: basePath, orgUrl: orgInfo?.instanceUrl };
|
|
209
|
+
if (isCodeBuilder) {
|
|
210
|
+
base = basePath;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
return {
|
|
214
|
+
define,
|
|
215
|
+
base,
|
|
216
|
+
server: {
|
|
217
|
+
port: getPort(),
|
|
218
|
+
// Code Builder specific configuration
|
|
219
|
+
...isCodeBuilder && {
|
|
220
|
+
allowedHosts: true,
|
|
221
|
+
strictPort: true
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
};
|
|
225
|
+
},
|
|
226
|
+
async configResolved(config) {
|
|
227
|
+
try {
|
|
228
|
+
const rootPath = config.root ?? process.cwd();
|
|
229
|
+
if (environment) {
|
|
230
|
+
environment.namespace = getNamespace(rootPath);
|
|
231
|
+
environment.appName = getAppName(rootPath);
|
|
232
|
+
}
|
|
233
|
+
manifest = await loadManifest(`${rootPath}/ui-bundle.json`);
|
|
234
|
+
const target = getDevServerTarget(codeBuilderProxyUrl, config.server.port ?? DEFAULT_PORT);
|
|
235
|
+
proxyHandler = createProxyHandler(
|
|
236
|
+
manifest,
|
|
237
|
+
orgInfo,
|
|
238
|
+
target,
|
|
239
|
+
environment?.basePath,
|
|
240
|
+
proxyOptions
|
|
241
|
+
);
|
|
242
|
+
} catch (error) {
|
|
243
|
+
console.error(`[ui-bundle-plugin] Initialization failed:`, error);
|
|
244
|
+
}
|
|
245
|
+
},
|
|
246
|
+
configureServer(server) {
|
|
247
|
+
server.middlewares.use(async (req, res, next) => {
|
|
248
|
+
if (proxyHandler) {
|
|
249
|
+
try {
|
|
250
|
+
await proxyHandler(req, res, next);
|
|
251
|
+
} catch (error) {
|
|
252
|
+
console.error("[ui-bundle-plugin] Proxy handler error:", error);
|
|
253
|
+
next();
|
|
254
|
+
}
|
|
255
|
+
} else {
|
|
256
|
+
if (req.url?.startsWith("/services")) {
|
|
257
|
+
res.writeHead(503, { "Content-Type": "application/json" });
|
|
258
|
+
res.end(
|
|
259
|
+
JSON.stringify({
|
|
260
|
+
error: "SERVICE_UNAVAILABLE",
|
|
261
|
+
message: "Proxy not initialized."
|
|
262
|
+
})
|
|
263
|
+
);
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
next();
|
|
267
|
+
}
|
|
268
|
+
});
|
|
269
|
+
},
|
|
270
|
+
async handleHotUpdate({ file, server }) {
|
|
271
|
+
if (file.endsWith("ui-bundle.json")) {
|
|
272
|
+
const updatedManifest = await loadManifest(file);
|
|
273
|
+
if (updatedManifest) {
|
|
274
|
+
manifest = updatedManifest;
|
|
275
|
+
const target = getDevServerTarget(
|
|
276
|
+
codeBuilderProxyUrl,
|
|
277
|
+
server.config.server.port ?? DEFAULT_PORT
|
|
278
|
+
);
|
|
279
|
+
proxyHandler = createProxyHandler(
|
|
280
|
+
manifest,
|
|
281
|
+
orgInfo,
|
|
282
|
+
target,
|
|
283
|
+
environment?.basePath,
|
|
284
|
+
proxyOptions
|
|
285
|
+
);
|
|
286
|
+
server.ws.send({
|
|
287
|
+
type: "full-reload",
|
|
288
|
+
path: "*"
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
},
|
|
293
|
+
transformIndexHtml: {
|
|
294
|
+
order: "pre",
|
|
295
|
+
handler(html, ctx) {
|
|
296
|
+
if (!environment) {
|
|
297
|
+
return { html, tags: [] };
|
|
298
|
+
}
|
|
299
|
+
return buildEnvTags(html, environment, ctx?.originalUrl, resolveBasePath);
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
};
|
|
303
|
+
const designPlugin = createDesignPlugin(options);
|
|
304
|
+
return [designPlugin, corePlugin];
|
|
305
|
+
}
|
|
306
|
+
export {
|
|
307
|
+
createCorePlugins as c
|
|
308
|
+
};
|
package/dist/index.d.ts
CHANGED
|
@@ -1,23 +1,18 @@
|
|
|
1
1
|
import { Plugin } from 'vite';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
*
|
|
18
|
-
* @default ["/components/ui/"]
|
|
19
|
-
*/
|
|
20
|
-
designModeExcludePaths?: string[];
|
|
21
|
-
}
|
|
2
|
+
import { CorePluginOptions } from './core/createCorePlugins';
|
|
3
|
+
export type { BasePathResolver, Environment } from './core/env';
|
|
4
|
+
export type { CorePluginOptions, CoreHooks } from './core/createCorePlugins';
|
|
5
|
+
/**
|
|
6
|
+
* Options for the generic UI-bundle plugin: `orgAlias`, `debug`, `designMode`,
|
|
7
|
+
* and `designModeExcludePaths`.
|
|
8
|
+
*/
|
|
9
|
+
export type PluginOptions = CorePluginOptions;
|
|
10
|
+
/**
|
|
11
|
+
* Generic UI-bundle Vite plugin.
|
|
12
|
+
*
|
|
13
|
+
* `basePath` is always `/` (or the CodeBuilder proxy path) and no language is
|
|
14
|
+
* folded in — the default for every bundle. Site bundles that need per-request
|
|
15
|
+
* language folding import `@salesforce/vite-plugin-ui-bundle/site` instead.
|
|
16
|
+
*/
|
|
22
17
|
export default function uiBundlePlugin(options?: PluginOptions): Plugin[];
|
|
23
18
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AACnC,OAAO,EAAqB,KAAK,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAErF,YAAY,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAChE,YAAY,EAAE,iBAAiB,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAE7E;;;GAGG;AACH,MAAM,MAAM,aAAa,GAAG,iBAAiB,CAAC;AAE9C;;;;;;GAMG;AACH,MAAM,CAAC,OAAO,UAAU,cAAc,CAAC,OAAO,GAAE,aAAkB,GAAG,MAAM,EAAE,CAG5E"}
|
package/dist/index.js
CHANGED
|
@@ -1,298 +1,6 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { loadManifest, getOrgInfo } from "@salesforce/ui-bundle/app";
|
|
3
|
-
import { createProxyHandler, injectLivePreviewScript } from "@salesforce/ui-bundle/proxy";
|
|
4
|
-
import { getRuntimeScriptContent } from "@salesforce/ui-design-mode/runtime";
|
|
5
|
-
import reactDesignTimeLocatorBabelPlugin from "@salesforce/ui-design-mode/source-locator/react";
|
|
6
|
-
import { dirname, join, basename } from "node:path";
|
|
7
|
-
const DEFAULT_PORT = 5173;
|
|
8
|
-
const DEFAULT_API_VERSION = "65.0";
|
|
9
|
-
const DEFAULT_NAMESPACE = "c";
|
|
10
|
-
function getAppName(rootPath) {
|
|
11
|
-
try {
|
|
12
|
-
const files = readdirSync(rootPath);
|
|
13
|
-
const metaFile = files.find((f) => f.endsWith(".uibundle-meta.xml"));
|
|
14
|
-
if (metaFile) {
|
|
15
|
-
return metaFile.replace(".uibundle-meta.xml", "");
|
|
16
|
-
}
|
|
17
|
-
} catch {
|
|
18
|
-
}
|
|
19
|
-
return basename(rootPath);
|
|
20
|
-
}
|
|
21
|
-
function getNamespace(startDir) {
|
|
22
|
-
let dir = startDir;
|
|
23
|
-
for (let parent = dirname(dir); ; dir = parent, parent = dirname(dir)) {
|
|
24
|
-
const sfdxProjectPath = join(dir, "sfdx-project.json");
|
|
25
|
-
if (existsSync(sfdxProjectPath)) {
|
|
26
|
-
try {
|
|
27
|
-
const namespace = JSON.parse(readFileSync(sfdxProjectPath, "utf-8")).namespace;
|
|
28
|
-
if (typeof namespace === "string" && namespace.trim()) {
|
|
29
|
-
return namespace.trim();
|
|
30
|
-
}
|
|
31
|
-
} catch {
|
|
32
|
-
}
|
|
33
|
-
return DEFAULT_NAMESPACE;
|
|
34
|
-
}
|
|
35
|
-
if (parent === dir) {
|
|
36
|
-
break;
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
return DEFAULT_NAMESPACE;
|
|
40
|
-
}
|
|
41
|
-
function getCodeBuilderBasePath(proxyUri, port) {
|
|
42
|
-
try {
|
|
43
|
-
const url = new URL(proxyUri.replace("{{port}}", port.toString()));
|
|
44
|
-
return url.pathname;
|
|
45
|
-
} catch (error) {
|
|
46
|
-
console.error("Failed to parse CODE_BUILDER_FRAMEWORK_PROXY_URI:", error);
|
|
47
|
-
return `/absproxy/${port}`;
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
function getDevServerTarget(codeBuilderProxyUrl, port) {
|
|
51
|
-
if (codeBuilderProxyUrl) {
|
|
52
|
-
return getCodeBuilderBasePath(codeBuilderProxyUrl, port);
|
|
53
|
-
}
|
|
54
|
-
return `http://localhost:${port}`;
|
|
55
|
-
}
|
|
56
|
-
function getPort() {
|
|
57
|
-
return parseInt(process.env.SF_UIBUNDLE_PORT || DEFAULT_PORT.toString(), 10);
|
|
58
|
-
}
|
|
1
|
+
import { c as createCorePlugins } from "./createCorePlugins-C2ODv7o-.js";
|
|
59
2
|
function uiBundlePlugin(options = {}) {
|
|
60
|
-
|
|
61
|
-
debug: options.debug ?? false
|
|
62
|
-
};
|
|
63
|
-
let orgInfo;
|
|
64
|
-
let manifest;
|
|
65
|
-
let environment;
|
|
66
|
-
let proxyHandler;
|
|
67
|
-
let designModeEnabled = options.designMode ?? false;
|
|
68
|
-
let codeBuilderProxyUrl;
|
|
69
|
-
const corePlugin = {
|
|
70
|
-
name: "@salesforce/vite-plugin-ui-bundle:core",
|
|
71
|
-
enforce: "pre",
|
|
72
|
-
async config(_config, env) {
|
|
73
|
-
let version;
|
|
74
|
-
try {
|
|
75
|
-
orgInfo = await getOrgInfo(options.orgAlias);
|
|
76
|
-
version = orgInfo?.apiVersion || DEFAULT_API_VERSION;
|
|
77
|
-
if (options.debug) {
|
|
78
|
-
console.log(`[ui-bundle-plugin] Using Salesforce API version: ${version}`);
|
|
79
|
-
}
|
|
80
|
-
} catch {
|
|
81
|
-
version = DEFAULT_API_VERSION;
|
|
82
|
-
}
|
|
83
|
-
codeBuilderProxyUrl = process.env.CODE_BUILDER_FRAMEWORK_PROXY_URI;
|
|
84
|
-
const isCodeBuilder = !!codeBuilderProxyUrl;
|
|
85
|
-
const define = {
|
|
86
|
-
__SF_API_VERSION__: JSON.stringify(version)
|
|
87
|
-
};
|
|
88
|
-
let base = "./";
|
|
89
|
-
if (env.mode !== "production") {
|
|
90
|
-
const basePath = isCodeBuilder ? getCodeBuilderBasePath(codeBuilderProxyUrl, getPort()) : "/";
|
|
91
|
-
environment = { basePath, apiPath: basePath, orgUrl: orgInfo?.instanceUrl };
|
|
92
|
-
if (isCodeBuilder) {
|
|
93
|
-
base = basePath;
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
return {
|
|
97
|
-
define,
|
|
98
|
-
base,
|
|
99
|
-
server: {
|
|
100
|
-
port: getPort(),
|
|
101
|
-
// Code Builder specific configuration
|
|
102
|
-
...isCodeBuilder && {
|
|
103
|
-
allowedHosts: true,
|
|
104
|
-
strictPort: true
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
};
|
|
108
|
-
},
|
|
109
|
-
async configResolved(config) {
|
|
110
|
-
try {
|
|
111
|
-
const rootPath = config.root ?? process.cwd();
|
|
112
|
-
if (environment) {
|
|
113
|
-
environment.namespace = getNamespace(rootPath);
|
|
114
|
-
environment.appName = getAppName(rootPath);
|
|
115
|
-
}
|
|
116
|
-
manifest = await loadManifest(`${rootPath}/ui-bundle.json`);
|
|
117
|
-
const target = getDevServerTarget(codeBuilderProxyUrl, config.server.port ?? DEFAULT_PORT);
|
|
118
|
-
proxyHandler = createProxyHandler(
|
|
119
|
-
manifest,
|
|
120
|
-
orgInfo,
|
|
121
|
-
target,
|
|
122
|
-
environment?.basePath,
|
|
123
|
-
proxyOptions
|
|
124
|
-
);
|
|
125
|
-
} catch (error) {
|
|
126
|
-
console.error(`[ui-bundle-plugin] Initialization failed:`, error);
|
|
127
|
-
}
|
|
128
|
-
},
|
|
129
|
-
configureServer(server) {
|
|
130
|
-
server.middlewares.use(async (req, res, next) => {
|
|
131
|
-
if (proxyHandler) {
|
|
132
|
-
try {
|
|
133
|
-
await proxyHandler(req, res, next);
|
|
134
|
-
} catch (error) {
|
|
135
|
-
console.error("[ui-bundle-plugin] Proxy handler error:", error);
|
|
136
|
-
next();
|
|
137
|
-
}
|
|
138
|
-
} else {
|
|
139
|
-
if (req.url?.startsWith("/services")) {
|
|
140
|
-
res.writeHead(503, { "Content-Type": "application/json" });
|
|
141
|
-
res.end(
|
|
142
|
-
JSON.stringify({
|
|
143
|
-
error: "SERVICE_UNAVAILABLE",
|
|
144
|
-
message: "Proxy not initialized."
|
|
145
|
-
})
|
|
146
|
-
);
|
|
147
|
-
return;
|
|
148
|
-
}
|
|
149
|
-
next();
|
|
150
|
-
}
|
|
151
|
-
});
|
|
152
|
-
},
|
|
153
|
-
async handleHotUpdate({ file, server }) {
|
|
154
|
-
if (file.endsWith("ui-bundle.json")) {
|
|
155
|
-
const updatedManifest = await loadManifest(file);
|
|
156
|
-
if (updatedManifest) {
|
|
157
|
-
manifest = updatedManifest;
|
|
158
|
-
const target = getDevServerTarget(
|
|
159
|
-
codeBuilderProxyUrl,
|
|
160
|
-
server.config.server.port ?? DEFAULT_PORT
|
|
161
|
-
);
|
|
162
|
-
proxyHandler = createProxyHandler(
|
|
163
|
-
manifest,
|
|
164
|
-
orgInfo,
|
|
165
|
-
target,
|
|
166
|
-
environment?.basePath,
|
|
167
|
-
proxyOptions
|
|
168
|
-
);
|
|
169
|
-
server.ws.send({
|
|
170
|
-
type: "full-reload",
|
|
171
|
-
path: "*"
|
|
172
|
-
});
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
},
|
|
176
|
-
transformIndexHtml: {
|
|
177
|
-
order: "pre",
|
|
178
|
-
handler(html) {
|
|
179
|
-
if (environment) {
|
|
180
|
-
html = injectLivePreviewScript(html);
|
|
181
|
-
}
|
|
182
|
-
const tags = [];
|
|
183
|
-
if (environment) {
|
|
184
|
-
const baseHref = environment.basePath.endsWith("/") ? environment.basePath : `${environment.basePath}/`;
|
|
185
|
-
tags.push({
|
|
186
|
-
tag: "base",
|
|
187
|
-
attrs: { href: baseHref },
|
|
188
|
-
injectTo: "head-prepend"
|
|
189
|
-
});
|
|
190
|
-
const sfdcEnv = {
|
|
191
|
-
basePath: environment.basePath,
|
|
192
|
-
apiPath: environment.apiPath
|
|
193
|
-
};
|
|
194
|
-
if (environment.orgUrl) sfdcEnv.orgUrl = environment.orgUrl;
|
|
195
|
-
if (environment.namespace) sfdcEnv.namespace = environment.namespace;
|
|
196
|
-
if (environment.appName) sfdcEnv.appName = environment.appName;
|
|
197
|
-
const sfdcEnvLiteral = JSON.stringify(sfdcEnv).replace(/</g, "\\u003c");
|
|
198
|
-
tags.push({
|
|
199
|
-
tag: "script",
|
|
200
|
-
children: `(function() { globalThis.SFDC_ENV = ${sfdcEnvLiteral}; })();`,
|
|
201
|
-
injectTo: "body"
|
|
202
|
-
});
|
|
203
|
-
}
|
|
204
|
-
return { html, tags };
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
};
|
|
208
|
-
const designPlugin = {
|
|
209
|
-
name: "@salesforce/vite-plugin-ui-bundle:design",
|
|
210
|
-
enforce: "pre",
|
|
211
|
-
config(_config, env) {
|
|
212
|
-
designModeEnabled = options.designMode ?? env.mode === "design";
|
|
213
|
-
},
|
|
214
|
-
configureServer(server) {
|
|
215
|
-
server.middlewares.use(async (req, res, next) => {
|
|
216
|
-
if (!designModeEnabled) {
|
|
217
|
-
next();
|
|
218
|
-
return;
|
|
219
|
-
}
|
|
220
|
-
const urlPath = stripUrlQuery(req.url);
|
|
221
|
-
if (urlPath.endsWith("/_sfdc/design-mode-interactions.js")) {
|
|
222
|
-
try {
|
|
223
|
-
const script = getRuntimeScriptContent();
|
|
224
|
-
if (script !== null) {
|
|
225
|
-
res.setHeader("Content-Type", "application/javascript");
|
|
226
|
-
res.setHeader("Cache-Control", "no-cache");
|
|
227
|
-
res.end(script);
|
|
228
|
-
return;
|
|
229
|
-
}
|
|
230
|
-
console.error(
|
|
231
|
-
`[ui-bundle-plugin] Design mode runtime script not found. Run 'npm run build' in @salesforce/ui-design-mode.`
|
|
232
|
-
);
|
|
233
|
-
res.writeHead(404);
|
|
234
|
-
res.end("Design mode script not found");
|
|
235
|
-
return;
|
|
236
|
-
} catch (error) {
|
|
237
|
-
console.error("[ui-bundle-plugin] Error serving design mode script:", error);
|
|
238
|
-
res.writeHead(500);
|
|
239
|
-
res.end("Error loading design mode script");
|
|
240
|
-
return;
|
|
241
|
-
}
|
|
242
|
-
}
|
|
243
|
-
next();
|
|
244
|
-
});
|
|
245
|
-
},
|
|
246
|
-
async transform(code, id) {
|
|
247
|
-
if (!designModeEnabled) return null;
|
|
248
|
-
const filepath = id.split("?", 1)[0] ?? id;
|
|
249
|
-
const isTsx = filepath.endsWith(".tsx");
|
|
250
|
-
const isJsx = filepath.endsWith(".jsx");
|
|
251
|
-
if (!isTsx && !isJsx) return null;
|
|
252
|
-
if (filepath.includes("node_modules")) return null;
|
|
253
|
-
const excludePaths = options.designModeExcludePaths ?? ["/components/ui/"];
|
|
254
|
-
if (excludePaths.some((p) => filepath.includes(p))) return null;
|
|
255
|
-
let originalSource;
|
|
256
|
-
try {
|
|
257
|
-
originalSource = fs.readFileSync(filepath, "utf-8");
|
|
258
|
-
} catch {
|
|
259
|
-
}
|
|
260
|
-
const { transformAsync } = await import("@babel/core");
|
|
261
|
-
const result = await transformAsync(code, {
|
|
262
|
-
filename: filepath,
|
|
263
|
-
babelrc: false,
|
|
264
|
-
configFile: false,
|
|
265
|
-
sourceMaps: true,
|
|
266
|
-
parserOpts: {
|
|
267
|
-
sourceType: "module",
|
|
268
|
-
plugins: isTsx ? ["jsx", "typescript"] : ["jsx"]
|
|
269
|
-
},
|
|
270
|
-
plugins: [[reactDesignTimeLocatorBabelPlugin, { excludePaths, originalSource }]]
|
|
271
|
-
});
|
|
272
|
-
if (!result?.code) return null;
|
|
273
|
-
return { code: result.code, map: result.map };
|
|
274
|
-
},
|
|
275
|
-
transformIndexHtml: {
|
|
276
|
-
order: "pre",
|
|
277
|
-
handler(html) {
|
|
278
|
-
const tags = [];
|
|
279
|
-
if (designModeEnabled) {
|
|
280
|
-
tags.push({
|
|
281
|
-
tag: "script",
|
|
282
|
-
attrs: { src: "/_sfdc/design-mode-interactions.js" },
|
|
283
|
-
injectTo: "body"
|
|
284
|
-
});
|
|
285
|
-
}
|
|
286
|
-
return { html, tags };
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
|
-
};
|
|
290
|
-
return [designPlugin, corePlugin];
|
|
291
|
-
}
|
|
292
|
-
function stripUrlQuery(url) {
|
|
293
|
-
if (!url) return "";
|
|
294
|
-
const queryIndex = url.indexOf("?");
|
|
295
|
-
return queryIndex === -1 ? url : url.slice(0, queryIndex);
|
|
3
|
+
return createCorePlugins(options);
|
|
296
4
|
}
|
|
297
5
|
export {
|
|
298
6
|
uiBundlePlugin as default
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Plugin } from 'vite';
|
|
2
|
+
import { SitePluginOptions } from './site-plugin';
|
|
3
|
+
import { CorePluginOptions } from '../core/createCorePlugins';
|
|
4
|
+
export type { SitePluginOptions } from './site-plugin';
|
|
5
|
+
export { resolveLanguageFromUrl, normalizeLanguages } from './languages';
|
|
6
|
+
/** Options for {@link siteUiBundlePlugin}: the core options plus `languages`. */
|
|
7
|
+
export type SiteUiBundlePluginOptions = CorePluginOptions & SitePluginOptions;
|
|
8
|
+
/**
|
|
9
|
+
* Site UI-bundle Vite plugin.
|
|
10
|
+
*
|
|
11
|
+
* Everything the generic plugin does (proxy, org info, API-version bake-in,
|
|
12
|
+
* design mode, HMR), plus — for local dev only — per-request `basePath` +
|
|
13
|
+
* `SFDC_ENV.language` folding driven by `languages`, and serving
|
|
14
|
+
* language-prefixed paths (SPA fallback). Selected by importing
|
|
15
|
+
* `@salesforce/vite-plugin-ui-bundle/site` in a site bundle's `vite.config.ts`.
|
|
16
|
+
*
|
|
17
|
+
* With no `languages` (or an empty array) it behaves identically to the generic
|
|
18
|
+
* plugin.
|
|
19
|
+
*/
|
|
20
|
+
export default function siteUiBundlePlugin(options?: SiteUiBundlePluginOptions): Plugin[];
|
|
21
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/site/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AACnC,OAAO,EAAoB,KAAK,iBAAiB,EAAE,MAAM,eAAe,CAAC;AACzE,OAAO,EAAqB,KAAK,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAEtF,YAAY,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AACvD,OAAO,EAAE,sBAAsB,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAEzE,iFAAiF;AACjF,MAAM,MAAM,yBAAyB,GAAG,iBAAiB,GAAG,iBAAiB,CAAC;AAE9E;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,OAAO,UAAU,kBAAkB,CAAC,OAAO,GAAE,yBAA8B,GAAG,MAAM,EAAE,CAO5F"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { c as createCorePlugins } from "../createCorePlugins-C2ODv7o-.js";
|
|
2
|
+
function resolveLanguageFromUrl(url, supported) {
|
|
3
|
+
const [defaultLang, ...nonDefault] = supported;
|
|
4
|
+
if (defaultLang === void 0) return void 0;
|
|
5
|
+
const path = (url ?? "").split("?")[0] ?? "";
|
|
6
|
+
const [first] = path.replace(/^\/+/, "").split("/");
|
|
7
|
+
if (first && nonDefault.includes(first)) {
|
|
8
|
+
return { language: first, segment: first };
|
|
9
|
+
}
|
|
10
|
+
return { language: defaultLang };
|
|
11
|
+
}
|
|
12
|
+
function normalizeLanguages(languages) {
|
|
13
|
+
return languages.map((s) => s.trim().replace(/_/g, "-")).filter(Boolean);
|
|
14
|
+
}
|
|
15
|
+
function createSitePlugin(options = {}) {
|
|
16
|
+
const supported = normalizeLanguages(options.languages ?? []);
|
|
17
|
+
let enabled = false;
|
|
18
|
+
const resolveBasePath = (originalUrl, env) => {
|
|
19
|
+
if (!enabled) return { basePath: env.basePath };
|
|
20
|
+
const resolved = resolveLanguageFromUrl(originalUrl, supported);
|
|
21
|
+
if (!resolved) return { basePath: env.basePath };
|
|
22
|
+
const basePath = resolved.segment && env.basePath === "/" ? `/${resolved.segment}` : env.basePath;
|
|
23
|
+
return { basePath, language: resolved.language };
|
|
24
|
+
};
|
|
25
|
+
const plugin = {
|
|
26
|
+
name: "@salesforce/vite-plugin-ui-bundle:site",
|
|
27
|
+
enforce: "pre",
|
|
28
|
+
config(_config, envConfig) {
|
|
29
|
+
const isCodeBuilder = !!process.env.CODE_BUILDER_FRAMEWORK_PROXY_URI;
|
|
30
|
+
enabled = envConfig.mode !== "production" && !isCodeBuilder && supported.length > 0;
|
|
31
|
+
},
|
|
32
|
+
configureServer(server) {
|
|
33
|
+
server.middlewares.use((req, _res, next) => {
|
|
34
|
+
if (enabled && req.url) {
|
|
35
|
+
const seg = resolveLanguageFromUrl(req.url, supported)?.segment;
|
|
36
|
+
if (seg) {
|
|
37
|
+
const rest = req.url.slice(`/${seg}`.length);
|
|
38
|
+
req.url = rest.startsWith("/") ? rest : `/${rest}`;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
next();
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
return { plugin, resolveBasePath };
|
|
46
|
+
}
|
|
47
|
+
function siteUiBundlePlugin(options = {}) {
|
|
48
|
+
const { plugin: sitePlugin, resolveBasePath } = createSitePlugin({
|
|
49
|
+
languages: options.languages
|
|
50
|
+
});
|
|
51
|
+
const core = createCorePlugins(options, { resolveBasePath });
|
|
52
|
+
return [sitePlugin, ...core];
|
|
53
|
+
}
|
|
54
|
+
export {
|
|
55
|
+
siteUiBundlePlugin as default,
|
|
56
|
+
normalizeLanguages,
|
|
57
|
+
resolveLanguageFromUrl
|
|
58
|
+
};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) 2026, Salesforce, Inc.,
|
|
3
|
+
* All rights reserved.
|
|
4
|
+
* For full license text, see the LICENSE.txt file
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Resolve the active language for a request, in hyphenated URL form.
|
|
8
|
+
*
|
|
9
|
+
* The default language (the FIRST supported entry) is served un-prefixed, so:
|
|
10
|
+
* - a leading URL segment matching a NON-DEFAULT supported language -> that
|
|
11
|
+
* language (it carries a "/<lang>" segment);
|
|
12
|
+
* - no segment, or a segment equal to the default -> the default language.
|
|
13
|
+
*
|
|
14
|
+
* Returns `undefined` only when there are no supported languages (feature
|
|
15
|
+
* absent), so `SFDC_ENV.language` is otherwise ALWAYS set — matching production,
|
|
16
|
+
* which sets it even for the default at the root.
|
|
17
|
+
*
|
|
18
|
+
* Detection is anchored to the exact supported set, so a real route segment
|
|
19
|
+
* (e.g. a page named like a locale) is never mistaken for a language.
|
|
20
|
+
*
|
|
21
|
+
* @param url The request URL (may include a query string) or `undefined`.
|
|
22
|
+
* @param supported Supported languages in hyphenated form; first entry is default.
|
|
23
|
+
* @returns The resolved `language` and, when present, the leading `segment`.
|
|
24
|
+
*/
|
|
25
|
+
export declare function resolveLanguageFromUrl(url: string | undefined, supported: string[]): {
|
|
26
|
+
language: string;
|
|
27
|
+
segment?: string;
|
|
28
|
+
} | undefined;
|
|
29
|
+
/**
|
|
30
|
+
* Normalize the feature's `LANGUAGES` codes to hyphenated URL form
|
|
31
|
+
* (`en_US` -> `en-US`), dropping blanks. This mirrors how the switcher's client
|
|
32
|
+
* code (`buildLanguageUrl`) and the platform both use hyphens in URL segments.
|
|
33
|
+
*/
|
|
34
|
+
export declare function normalizeLanguages(languages: string[]): string[];
|
|
35
|
+
//# sourceMappingURL=languages.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"languages.d.ts","sourceRoot":"","sources":["../../src/site/languages.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,sBAAsB,CACrC,GAAG,EAAE,MAAM,GAAG,SAAS,EACvB,SAAS,EAAE,MAAM,EAAE,GACjB;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CASpD;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAEhE"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { Plugin } from 'vite';
|
|
2
|
+
import { BasePathResolver } from '../core/env';
|
|
3
|
+
export interface SitePluginOptions {
|
|
4
|
+
/**
|
|
5
|
+
* Supported languages, from the language-switcher feature's `LANGUAGES`. The
|
|
6
|
+
* FIRST entry is the default (served un-prefixed at `/`). Codes may be in
|
|
7
|
+
* underscore (`en_US`) or hyphen (`en-US`) form; they are normalized to the
|
|
8
|
+
* hyphenated URL form the switcher and platform use. Empty/omitted -> the
|
|
9
|
+
* plugin is a no-op and behaves identically to the generic plugin.
|
|
10
|
+
*/
|
|
11
|
+
languages?: string[];
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Build the site plugin plus the {@link BasePathResolver} the core threads into
|
|
15
|
+
* its `transformIndexHtml`. Returning both from one factory keeps the resolver
|
|
16
|
+
* and the request-URL strip middleware sharing the same `enabled`/`supported`
|
|
17
|
+
* state without leaking an internal property onto the plugin object.
|
|
18
|
+
*/
|
|
19
|
+
export declare function createSitePlugin(options?: SitePluginOptions): {
|
|
20
|
+
plugin: Plugin;
|
|
21
|
+
resolveBasePath: BasePathResolver;
|
|
22
|
+
};
|
|
23
|
+
//# sourceMappingURL=site-plugin.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"site-plugin.d.ts","sourceRoot":"","sources":["../../src/site/site-plugin.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAiB,MAAM,MAAM,CAAC;AAElD,OAAO,KAAK,EAAE,gBAAgB,EAAe,MAAM,aAAa,CAAC;AAEjE,MAAM,WAAW,iBAAiB;IACjC;;;;;;OAMG;IACH,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;CACrB;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,GAAE,iBAAsB,GAAG;IAClE,MAAM,EAAE,MAAM,CAAC;IACf,eAAe,EAAE,gBAAgB,CAAC;CAClC,CAiDA"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@salesforce/vite-plugin-ui-bundle",
|
|
3
3
|
"description": "Vite plugin for Salesforce UI Bundles",
|
|
4
|
-
"version": "11.
|
|
4
|
+
"version": "11.56.0",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE.txt",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "./dist/index.js",
|
|
@@ -12,6 +12,10 @@
|
|
|
12
12
|
"types": "./dist/index.d.ts",
|
|
13
13
|
"import": "./dist/index.js"
|
|
14
14
|
},
|
|
15
|
+
"./site": {
|
|
16
|
+
"types": "./dist/site/index.d.ts",
|
|
17
|
+
"import": "./dist/site/index.js"
|
|
18
|
+
},
|
|
15
19
|
"./package.json": "./package.json"
|
|
16
20
|
},
|
|
17
21
|
"files": [
|
|
@@ -27,8 +31,8 @@
|
|
|
27
31
|
},
|
|
28
32
|
"dependencies": {
|
|
29
33
|
"@babel/core": "^7.29.6",
|
|
30
|
-
"@salesforce/ui-bundle": "^11.
|
|
31
|
-
"@salesforce/ui-design-mode": "11.
|
|
34
|
+
"@salesforce/ui-bundle": "^11.56.0",
|
|
35
|
+
"@salesforce/ui-design-mode": "11.56.0"
|
|
32
36
|
},
|
|
33
37
|
"devDependencies": {
|
|
34
38
|
"@types/babel__core": "^7.20.5",
|