@salesforce/vite-plugin-lwc-ui-bundle 11.13.2 → 11.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.
- package/dist/index.d.ts +32 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +30 -5
- package/dist/index.js.map +1 -1
- package/dist/providers/access-check.d.ts.map +1 -1
- package/dist/providers/gate.d.ts.map +1 -1
- package/dist/providers/i18n.d.ts +16 -0
- package/dist/providers/i18n.d.ts.map +1 -1
- package/dist/providers/index.d.ts +2 -0
- package/dist/providers/index.d.ts.map +1 -1
- package/dist/providers/index.js +3 -178
- package/dist/providers/index.js.map +1 -1
- package/dist/providers/labels-graphql/index.d.ts.map +1 -1
- package/dist/providers/labels-graphql/index.js +12 -3
- package/dist/providers/labels-graphql/index.js.map +1 -1
- package/dist/providers/labels-graphql/runtime.d.ts +21 -14
- package/dist/providers/labels-graphql/runtime.d.ts.map +1 -1
- package/dist/providers/labels-graphql/runtime.js +39 -26
- package/dist/providers/labels-graphql/runtime.js.map +1 -1
- package/dist/providers/platform-graphql/constants.d.ts +15 -0
- package/dist/providers/platform-graphql/constants.d.ts.map +1 -0
- package/dist/providers/platform-graphql/i18n-static.d.ts +19 -0
- package/dist/providers/platform-graphql/i18n-static.d.ts.map +1 -0
- package/dist/providers/platform-graphql/index.d.ts +58 -0
- package/dist/providers/platform-graphql/index.d.ts.map +1 -0
- package/dist/providers/platform-graphql/index.js +312 -0
- package/dist/providers/platform-graphql/index.js.map +1 -0
- package/dist/providers/platform-graphql/runtime.d.ts +30 -0
- package/dist/providers/platform-graphql/runtime.d.ts.map +1 -0
- package/dist/providers/platform-graphql/runtime.js +189 -0
- package/dist/providers/platform-graphql/runtime.js.map +1 -0
- package/docs/consumer-guide.md +120 -4
- package/package.json +5 -5
- package/skills/setup-lwc-vite-plugin/SKILL.md +44 -1
- package/skills/setup-lwc-vite-plugin/references/known-pitfalls.md +57 -0
package/docs/consumer-guide.md
CHANGED
|
@@ -259,6 +259,21 @@ export default defineConfig({
|
|
|
259
259
|
});
|
|
260
260
|
```
|
|
261
261
|
|
|
262
|
+
**What is the `providers` array?** It is the list of resolvers for `@salesforce/*`
|
|
263
|
+
scoped-module imports (`@salesforce/label/*`, `@salesforce/i18n/*`,
|
|
264
|
+
`@salesforce/userPermission/*`, `@salesforce/gate/*`, …) that don't exist as
|
|
265
|
+
real npm packages. Each `builtins.*()` returns a Vite plugin that intercepts one
|
|
266
|
+
family of specifiers and generates the module the platform LWC compiler would
|
|
267
|
+
otherwise provide.
|
|
268
|
+
|
|
269
|
+
**You usually don't need it.** When you **omit** `providers` entirely, the plugin
|
|
270
|
+
installs a default set that resolves labels, i18n, permissions, and access checks
|
|
271
|
+
at runtime via GraphQL (see [GraphQL-backed scoped modules](#graphql-backed-scoped-modules-default)
|
|
272
|
+
below). Pass `providers` only to opt a family **out** of the runtime fetch (e.g.
|
|
273
|
+
`builtins.i18n()` for browser/`Intl`-derived locale identity, `builtins.label()`
|
|
274
|
+
for static build-time labels) or to add extra config — the explicit list above
|
|
275
|
+
shows the opt-out shape, not a required one.
|
|
276
|
+
|
|
262
277
|
#### Component Directory Configuration
|
|
263
278
|
|
|
264
279
|
The plugin supports two directory structures:
|
|
@@ -298,8 +313,22 @@ Components are importable as `myNamespace/myComponent`.
|
|
|
298
313
|
|
|
299
314
|
#### Configuring Labels
|
|
300
315
|
|
|
301
|
-
|
|
302
|
-
|
|
316
|
+
There are two providers for `@salesforce/label/*`:
|
|
317
|
+
|
|
318
|
+
- **`builtins.labelsGraphql()` — the default.** Resolves labels at runtime via UI
|
|
319
|
+
API GraphQL through the Platform Data SDK (`createDataSDK()`), so labels reflect
|
|
320
|
+
the current user's translation. The SDK picks the transport per surface: a
|
|
321
|
+
direct session-authenticated GraphQL request in a full-page web app, or the
|
|
322
|
+
`window.openai` bridge in an MCP/ChatGPT host. Build-time values (or the
|
|
323
|
+
key-derived fallback) render until the runtime fetch resolves. Included
|
|
324
|
+
automatically when you omit the `providers` array.
|
|
325
|
+
- **`builtins.label()` — static.** Resolves to a fixed build-time string. Use it
|
|
326
|
+
to opt out of runtime fetching (e.g. a pure off-core demo with no org).
|
|
327
|
+
|
|
328
|
+
Both accept the same overrides object; `labelsGraphql` uses the overrides as the
|
|
329
|
+
static fallback shown before/instead of a successful GraphQL fetch.
|
|
330
|
+
|
|
331
|
+
How you configure labels depends on your project:
|
|
303
332
|
|
|
304
333
|
**SFDX project with `CustomLabels.labels-meta.xml`:**
|
|
305
334
|
|
|
@@ -340,8 +369,95 @@ you'll get runtime errors like:
|
|
|
340
369
|
Uncaught TypeError: Cannot read properties of undefined (reading 'isOpen')
|
|
341
370
|
```
|
|
342
371
|
|
|
343
|
-
|
|
344
|
-
`
|
|
372
|
+
Include `builtins.gate()` when using `lightning-base-components`. (When you omit
|
|
373
|
+
the `providers` array entirely, the default set already covers these.)
|
|
374
|
+
|
|
375
|
+
#### GraphQL-backed scoped modules (default)
|
|
376
|
+
|
|
377
|
+
When you **omit** the `providers` array, these scoped modules resolve at runtime
|
|
378
|
+
via UI API GraphQL through the Platform Data SDK (with build-time first-paint
|
|
379
|
+
values):
|
|
380
|
+
|
|
381
|
+
| Scoped module | GraphQL source (`uiapi.platform.*`) | Provider | First-paint value |
|
|
382
|
+
| -------------------------------------- | ----------------------------------- | ------------------- | ------------------------------------ |
|
|
383
|
+
| `@salesforce/label/*` | `labels` | `labelsGraphql()` | override or key-derived text |
|
|
384
|
+
| `@salesforce/i18n/*` (locale identity) | `i18n` | `platformGraphql()` | CLDR placeholder |
|
|
385
|
+
| `@salesforce/userPermission/*` | `userPermissions` | `platformGraphql()` | **required — you must configure it** |
|
|
386
|
+
| `@salesforce/accessCheck/*` | `userPermissions` | `platformGraphql()` | `false` (deny-by-default) |
|
|
387
|
+
| `@salesforce/customPermission/*` | `customPermissions` | `platformGraphql()` | **required — you must configure it** |
|
|
388
|
+
|
|
389
|
+
The generated modules export the first-paint value as `default` and an opt-in
|
|
390
|
+
`subscribe(callback)` that fires with the resolved org value.
|
|
391
|
+
|
|
392
|
+
##### Named permissions must be configured (no silent guess)
|
|
393
|
+
|
|
394
|
+
A `@salesforce/userPermission/<Name>` or `@salesforce/customPermission/<Name>`
|
|
395
|
+
import is an assertion about **per-user runtime state**. A plain default import
|
|
396
|
+
binds the module's value **once** at module-eval time and never updates on its
|
|
397
|
+
own — so if the plugin silently defaulted an unconfigured permission to `false`,
|
|
398
|
+
your UI would render a permanent, wrong answer about what the current user can do
|
|
399
|
+
(and it would be wrong even on the GraphQL **success** path, because a default
|
|
400
|
+
import never re-reads the resolved value).
|
|
401
|
+
|
|
402
|
+
Rather than guess, **the build fails** if you import a named permission without
|
|
403
|
+
declaring the value it should show before the org responds:
|
|
404
|
+
|
|
405
|
+
```
|
|
406
|
+
[platform-graphql] @salesforce/userPermission/ApiEnabled was imported but has no
|
|
407
|
+
first-paint value configured. …
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
Declare it with the `defaultProviders()` helper — which lets you configure this
|
|
411
|
+
one provider while keeping every other default in place:
|
|
412
|
+
|
|
413
|
+
```js
|
|
414
|
+
import lwcVitePlugin, { defaultProviders } from "@salesforce/vite-plugin-lwc-ui-bundle";
|
|
415
|
+
|
|
416
|
+
lwcVitePlugin({
|
|
417
|
+
modules: { dirs: [{ path: "force-app/main/default/lwc", namespace: "c" }] },
|
|
418
|
+
providers: defaultProviders({
|
|
419
|
+
platformGraphql: {
|
|
420
|
+
userPermissionDefaults: { ApiEnabled: false, CustomizeApplication: false },
|
|
421
|
+
customPermissionDefaults: { My_Custom_Perm: false },
|
|
422
|
+
},
|
|
423
|
+
}),
|
|
424
|
+
});
|
|
425
|
+
```
|
|
426
|
+
|
|
427
|
+
Use `false` unless you have a specific reason to render `true` before the fetch
|
|
428
|
+
resolves. `@salesforce/accessCheck/*` is exempt: it's a feature **gate**, so an
|
|
429
|
+
unconfigured check safely deny-defaults to `false` (base components rely on this),
|
|
430
|
+
though you can still override it.
|
|
431
|
+
|
|
432
|
+
##### Reflecting the resolved value reactively (`subscribe`)
|
|
433
|
+
|
|
434
|
+
The configured value is only the **first paint**. To show the real org value once
|
|
435
|
+
the GraphQL fetch lands, import the module's `subscribe(callback)` export and
|
|
436
|
+
assign to a reactive field — the callback fires immediately with the current value
|
|
437
|
+
and again when the resolved value differs:
|
|
438
|
+
|
|
439
|
+
```js
|
|
440
|
+
import apiEnabled, { subscribe } from "@salesforce/userPermission/ApiEnabled";
|
|
441
|
+
|
|
442
|
+
export default class extends LightningElement {
|
|
443
|
+
apiEnabled = apiEnabled; // first paint (your configured value)
|
|
444
|
+
connectedCallback() {
|
|
445
|
+
subscribe((v) => (this.apiEnabled = v)); // corrects in the DOM when the org responds
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
```
|
|
449
|
+
|
|
450
|
+
> **Dual-deploy note:** the `subscribe` export exists only when the module is
|
|
451
|
+
> served by this plugin. If the **same** component source must also deploy as
|
|
452
|
+
> on-platform LWC metadata (where `@salesforce/userPermission/*` has no `subscribe`
|
|
453
|
+
> export), keep a plain default import — it will render the configured first-paint
|
|
454
|
+
> value off-core and the platform-resolved value on-core.
|
|
455
|
+
|
|
456
|
+
i18n number/date **format** patterns and calendar data stay static (CLDR reference
|
|
457
|
+
data, no org source). `@salesforce/gate/*` also stays static — its GraphQL field is
|
|
458
|
+
UiTier-context-only and not reachable off-core. The static `builtins.i18n()` /
|
|
459
|
+
`builtins.accessCheck()` / `builtins.label()` providers remain available for
|
|
460
|
+
explicit opt-out.
|
|
345
461
|
|
|
346
462
|
### Step 3: Create `index.html`
|
|
347
463
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@salesforce/vite-plugin-lwc-ui-bundle",
|
|
3
|
-
"version": "11.
|
|
3
|
+
"version": "11.14.0",
|
|
4
4
|
"description": "Vite plugin for compiling LWC components into static bundles for off-platform and MCP use",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE.txt",
|
|
6
6
|
"author": "Salesforce",
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
"skills"
|
|
50
50
|
],
|
|
51
51
|
"scripts": {
|
|
52
|
-
"build": "vite build && vite build --mode runtime-lds && vite build --mode runtime-labels-graphql",
|
|
52
|
+
"build": "vite build && vite build --mode runtime-lds && vite build --mode runtime-labels-graphql && vite build --mode runtime-platform-graphql",
|
|
53
53
|
"clean": "rm -rf dist",
|
|
54
54
|
"dev": "vite build --watch",
|
|
55
55
|
"test": "vitest run",
|
|
@@ -74,9 +74,9 @@
|
|
|
74
74
|
},
|
|
75
75
|
"peerDependencies": {
|
|
76
76
|
"@lwc/rollup-plugin": "^9.0.0",
|
|
77
|
-
"@salesforce/platform-sdk": "^11.
|
|
77
|
+
"@salesforce/platform-sdk": "^11.14.0",
|
|
78
78
|
"@salesforce/state-managers-uiapi": "^0.31.0",
|
|
79
|
-
"@salesforce/ui-bundle": "^11.
|
|
79
|
+
"@salesforce/ui-bundle": "^11.14.0",
|
|
80
80
|
"lwc": "^9.0.0",
|
|
81
81
|
"vite": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0",
|
|
82
82
|
"zod": "^3.23.8"
|
|
@@ -100,7 +100,7 @@
|
|
|
100
100
|
"devDependencies": {
|
|
101
101
|
"@conduit-client/bindings-utils": "3.19.6",
|
|
102
102
|
"@conduit-client/command-base": "3.19.6",
|
|
103
|
-
"@salesforce/platform-sdk": "^11.
|
|
103
|
+
"@salesforce/platform-sdk": "^11.14.0",
|
|
104
104
|
"@types/ws": "^8.5.12",
|
|
105
105
|
"typescript": "^5.9.3",
|
|
106
106
|
"vite": "^7.0.0",
|
|
@@ -157,7 +157,15 @@ Starting from the root component, trace the dependency tree:
|
|
|
157
157
|
providers because base components use these modules internally even
|
|
158
158
|
if user code doesn't
|
|
159
159
|
- `@salesforce/gate/*`, `@salesforce/accessCheck/*` → handled by
|
|
160
|
-
those providers
|
|
160
|
+
those providers (accessCheck deny-defaults to `false`, no per-name
|
|
161
|
+
config required)
|
|
162
|
+
- `@salesforce/userPermission/<Name>`, `@salesforce/customPermission/<Name>`
|
|
163
|
+
→ **collect every `<Name>`.** These are named per-user permissions:
|
|
164
|
+
the default `platformGraphql()` provider **fails the build** unless
|
|
165
|
+
each imported name has a first-paint value declared in
|
|
166
|
+
`userPermissionDefaults` / `customPermissionDefaults`. Record the
|
|
167
|
+
exact names so Step 7 can generate them (default them to `false`
|
|
168
|
+
unless the user says otherwise). See `known-pitfalls.md#17`.
|
|
161
169
|
- `@salesforce/i18n/*` → `i18n` provider
|
|
162
170
|
- `@salesforce/client/*` → `client` provider (provides `formFactor`
|
|
163
171
|
based on viewport width)
|
|
@@ -227,6 +235,13 @@ Check in this order:
|
|
|
227
235
|
present (the default registry covers all three specifiers)
|
|
228
236
|
- Step 4 found any `@salesforce/i18n/*` → `builtins.i18n()` must be
|
|
229
237
|
present
|
|
238
|
+
- Step 4 found any `@salesforce/userPermission/<Name>` or
|
|
239
|
+
`@salesforce/customPermission/<Name>` → the default
|
|
240
|
+
`platformGraphql()` provider must declare a first-paint value for
|
|
241
|
+
**each** name in `userPermissionDefaults` / `customPermissionDefaults`,
|
|
242
|
+
or the build throws. Use the `defaultProviders({ platformGraphql: {…} })`
|
|
243
|
+
helper so the rest of the registry stays default. See
|
|
244
|
+
`references/known-pitfalls.md#17`.
|
|
230
245
|
- Step 4 found any `@salesforce/client/*` → `builtins.client()` must
|
|
231
246
|
be present
|
|
232
247
|
- `modules.npm` includes `lightning-base-components` (or
|
|
@@ -465,6 +480,34 @@ Adapt based on earlier findings:
|
|
|
465
480
|
|
|
466
481
|
- Set `dirs` for the detected project structure (SFDX vs namespaced).
|
|
467
482
|
- Populate `builtins.label({...})` with values from Step 6.
|
|
483
|
+
- **Declare a first-paint value for every named permission Step 4 found.**
|
|
484
|
+
Each `@salesforce/userPermission/<Name>` / `@salesforce/customPermission/<Name>`
|
|
485
|
+
import needs an entry, or the build throws (`known-pitfalls.md#17`).
|
|
486
|
+
Prefer the `defaultProviders()` helper so you configure only this while
|
|
487
|
+
keeping the rest of the default registry:
|
|
488
|
+
|
|
489
|
+
```js
|
|
490
|
+
import lwcVitePlugin, { defaultProviders } from "@salesforce/vite-plugin-lwc-ui-bundle";
|
|
491
|
+
|
|
492
|
+
lwcVitePlugin({
|
|
493
|
+
modules: {
|
|
494
|
+
/* ... */
|
|
495
|
+
},
|
|
496
|
+
providers: defaultProviders({
|
|
497
|
+
platformGraphql: {
|
|
498
|
+
userPermissionDefaults: { ApiEnabled: false, CustomizeApplication: false },
|
|
499
|
+
customPermissionDefaults: { My_Custom_Perm: false },
|
|
500
|
+
},
|
|
501
|
+
}),
|
|
502
|
+
});
|
|
503
|
+
```
|
|
504
|
+
|
|
505
|
+
Default each to `false` unless the user wants a `true` first paint; note
|
|
506
|
+
the resolved org value only reaches the DOM if the component imports the
|
|
507
|
+
module's `subscribe()` export (keep a plain default import if the same
|
|
508
|
+
source also deploys on-platform). `@salesforce/accessCheck/*` needs no
|
|
509
|
+
such config — it deny-defaults to `false`.
|
|
510
|
+
|
|
468
511
|
- Include `builtins.primitiveUtils()` if using `lightning-base-components`.
|
|
469
512
|
- Include `builtins.lds()` if any component uses `lightning/uiRecordApi`,
|
|
470
513
|
`lightning/uiObjectInfoApi`, `lightning/graphql`, or any of the
|
|
@@ -440,3 +440,60 @@ the plugin with `livePreview({ debug: true })` (or run with plugin debug
|
|
|
440
440
|
logging) — it logs the underlying import error. Note the bridge is a
|
|
441
441
|
local-dev convenience only; its absence never affects the compiled
|
|
442
442
|
bundle.
|
|
443
|
+
|
|
444
|
+
## 17. Build fails: named permission imported with no first-paint value
|
|
445
|
+
|
|
446
|
+
**Symptom:** `vite build` (or `npm run dev`) fails with:
|
|
447
|
+
|
|
448
|
+
```
|
|
449
|
+
[platform-graphql] @salesforce/userPermission/ApiEnabled was imported but
|
|
450
|
+
has no first-paint value configured. A permission is per-user runtime
|
|
451
|
+
state, so the plugin refuses to silently render a fabricated `false`. …
|
|
452
|
+
```
|
|
453
|
+
|
|
454
|
+
**Cause:** A component imports `@salesforce/userPermission/<Name>` or
|
|
455
|
+
`@salesforce/customPermission/<Name>`, but no value was declared for that
|
|
456
|
+
name. A named permission is an assertion about **per-user runtime state**;
|
|
457
|
+
a plain default import binds the value **once** at module-eval time and
|
|
458
|
+
never updates on its own (only the module's `subscribe()` export does).
|
|
459
|
+
So a silently-defaulted `false` would render a permanent, wrong answer —
|
|
460
|
+
even when the GraphQL fetch **succeeds**. Rather than guess, the plugin
|
|
461
|
+
requires you to state the value shown before the org responds. (This is
|
|
462
|
+
**not** the same as `@salesforce/accessCheck/*`, which is a feature gate
|
|
463
|
+
and safely deny-defaults to `false` — see pitfall #8.)
|
|
464
|
+
|
|
465
|
+
**Fix:** Declare each imported permission's first-paint value via the
|
|
466
|
+
`defaultProviders()` helper (keeps every other default in place):
|
|
467
|
+
|
|
468
|
+
```js
|
|
469
|
+
import lwcVitePlugin, { defaultProviders } from "@salesforce/vite-plugin-lwc-ui-bundle";
|
|
470
|
+
|
|
471
|
+
lwcVitePlugin({
|
|
472
|
+
modules: {
|
|
473
|
+
/* ... */
|
|
474
|
+
},
|
|
475
|
+
providers: defaultProviders({
|
|
476
|
+
platformGraphql: {
|
|
477
|
+
userPermissionDefaults: { ApiEnabled: false, CustomizeApplication: false },
|
|
478
|
+
customPermissionDefaults: { My_Custom_Perm: false },
|
|
479
|
+
},
|
|
480
|
+
}),
|
|
481
|
+
});
|
|
482
|
+
```
|
|
483
|
+
|
|
484
|
+
Use `false` unless you have a specific reason to render `true` before the
|
|
485
|
+
fetch resolves. To reflect the **resolved** org value in the DOM, import
|
|
486
|
+
the module's `subscribe(callback)` export and assign to a reactive field:
|
|
487
|
+
|
|
488
|
+
```js
|
|
489
|
+
import apiEnabled, { subscribe } from "@salesforce/userPermission/ApiEnabled";
|
|
490
|
+
// this.apiEnabled = apiEnabled; // first paint (configured)
|
|
491
|
+
// connectedCallback() { subscribe(v => this.apiEnabled = v); } // corrects in DOM
|
|
492
|
+
```
|
|
493
|
+
|
|
494
|
+
If the same component must also deploy on-platform (where the scoped
|
|
495
|
+
module has no `subscribe` export), keep the plain default import.
|
|
496
|
+
|
|
497
|
+
**Prevention:** SKILL.md Step 4 flags every `@salesforce/userPermission/*`
|
|
498
|
+
and `@salesforce/customPermission/*` import so the generated config
|
|
499
|
+
declares its first-paint value up front.
|