afv-library/skills/generating-salesforce-ui-bundle-metadata/SKILL.md
k-j-kim 445ac2f126
Rename webapp/webapplication to UI bundle across the codebase
Directory renames: webapplications/ → uiBundles/, samples dirs drop -experimental suffix
File renames: *.webapplication-meta.xml → *.uibundle-meta.xml, webapplication.json → ui-bundle.json
XML metadata: <WebApplication> → <UIBundle>
NPM packages: @salesforce/webapp-* → @salesforce/ui-bundle-*
Skill names: *-webapplication-* → *-salesforce-ui-bundle-*
CLI references: sf webapp → sf ui-bundle
Source code: function/variable/type names, import paths, string literals updated
ESLint config: Added .worktrees/** to ignores
CHANGELOG repo URLs preserved
2026-03-27 17:54:18 -07:00

4.5 KiB

name description
generating-salesforce-ui-bundle-metadata Scaffold new Salesforce UI bundles and configure their metadata — sf ui-bundle generate, UI Bundles (meta XML, ui-bundle.json with routing/headers/outputDir), and CSP Trusted Sites for external domains. Use whenever creating a new UI bundle, setting up UI bundle metadata structure, configuring routing or headers, setting outputDir, adding external domains that need CSP registration, or editing bundle configuration. Triggers on: create UI bundle, create ui bundle, new app, sf ui-bundle generate, metadata, ui-bundle.json, CSP, trusted site, bundle configuration, meta XML, routing config, external domain, headers config, outputDir.

UI Bundle Metadata

Scaffolding a New UI Bundle

Use sf ui-bundle generate to create new apps — not create-react-app, Vite, or other generic scaffolds.

UI bundle name (-n): Alphanumerical only — no spaces, hyphens, underscores, or special characters. Example: CoffeeBoutique (not Coffee Boutique).

After generation:

  1. Replace all default boilerplate — "React App", "Vite + React", default <title>, placeholder text
  2. Populate the home page with real content (landing section, banners, hero, navigation)
  3. Update navigation and placeholders (see the generating-salesforce-ui-bundle-ui skill)

Always install dependencies before running any scripts in the UI bundle directory.


UI Bundle

A UI Bundle lives under uiBundles/<AppName>/ and must contain:

  • <AppName>.uibundle-meta.xml — filename must exactly match the folder name
  • A build output directory (default: dist/) with at least one file

Meta XML

Required fields: masterLabel, version (max 20 chars), isActive (boolean). Optional: description (max 255 chars).

ui-bundle.json

Optional file. Allowed top-level keys: outputDir, routing, headers.

Constraints:

  • Valid UTF-8 JSON, max 100 KB
  • Root must be a non-empty object (never {}, arrays, or primitives)

Path safety (applies to outputDir and routing.fallback): Reject backslashes, leading / or \, .. segments, null/control characters, globs (*, ?, **), and %. All resolved paths must stay within the bundle.

outputDir

Non-empty string referencing a subdirectory (not . or ./). Directory must exist and contain at least one file.

routing

If present, must be a non-empty object. Allowed keys: rewrites, redirects, fallback, trailingSlash, fileBasedRouting.

  • trailingSlash: "always", "never", or "auto"
  • fileBasedRouting: boolean
  • fallback: non-empty string satisfying path safety; target file must exist
  • rewrites: non-empty array of { route?, rewrite } objects — e.g., { "route": "/app/:path*", "rewrite": "/index.html" }
  • redirects: non-empty array of { route?, redirect, statusCode? } objects — statusCode must be 301, 302, 307, or 308

headers

Non-empty array of { source, headers: [{ key, value }] } objects.

Example:

{
  "routing": {
    "rewrites": [{ "route": "/app/:path*", "rewrite": "/index.html" }],
    "trailingSlash": "never"
  },
  "headers": [
    {
      "source": "/assets/**",
      "headers": [{ "key": "Cache-Control", "value": "public, max-age=31536000, immutable" }]
    }
  ]
}

Never suggest: {} as root, empty "routing": {}, empty arrays, [{}], "outputDir": ".", "outputDir": "./".


CSP Trusted Sites

Salesforce enforces Content Security Policy headers. Any external domain not registered as a CSP Trusted Site will be blocked (images won't load, API calls fail, fonts missing).

When to Create

Whenever the app references a new external domain: CDN images, external fonts, third-party APIs, map tiles, iframes, external stylesheets.

Steps

  1. Identify external domains — extract the origin (scheme + host) from each external URL in the code
  2. Check existing registrations — look in force-app/main/default/cspTrustedSites/
  3. Map resource type to CSP directive:
Resource Type Directive Field
Images isApplicableToImgSrc
API calls (fetch, XHR) isApplicableToConnectSrc
Fonts isApplicableToFontSrc
Stylesheets isApplicableToStyleSrc
Video / audio isApplicableToMediaSrc
Iframes isApplicableToFrameSrc

Always also set isApplicableToConnectSrc to true for preflight/redirect handling.

  1. Create the metadata file — follow implementation/csp-metadata-format.md for the .cspTrustedSite-meta.xml format. Place in force-app/main/default/cspTrustedSites/.