This seems so simple on the face of it, but ends up quite difficult to achieve. I did manage, and on the way learned quite a bit. The main learning points:
- You have to have just the right metadata and scratch org definition.
- Just because you find suggestions as to how to achieve certain things, such as including profiles and sharing sets in the unlocked package, these don't seem to function at you might hope.
- It's worth including prefixes on API names for clarity as to what metadata comes from the package and what does not (since it may be no-namespaced).
- Whatever you do, there will be some post-installation manual activities to perform.
Let's take a look at the metadata. For the digital experience itself, you likely need:
- contentassets - for the images included in the experience "pages". To function correctly when installed from the unlocked package, these appear to need to be marked as visible to unauthenticated users (despite not being on guest accessible pages). Without this broken image links are shown in the rendered page.
- email - without ensuring to create duplicates of the "standard" email templates you cannot successfully package the site (the references don't get resolved).
- experiences - the experience bundle itself, lock, stock and barrel. Note that if you generated this before Summer '21 you'll need to deploy to a Summer '21 scratch org and pull down the updated theme template to add the new "Service Not Available" metadata required to allow installation on a Summer '21 org and create a new package version.
- flows - any flows you use in the experience.
- layouts - any layouts for object types you have lists, headers or details for in your experience "pages".
- lwc - any bespoke LWCs used in the experience "pages".
- navigationMenus - all navigation options you use in your experience.
- networks - the network equivalent to your experience bundle.
- permissionsets - the permission set(s) relevant to community users who will use the experience.
- profiles - that you want for use with your experience bundle (however, see later).
- quickActions - any lightning quick actions you use in the layouts included.
- sites - the site equivalent to your experience bundle. Even though this contains org-specific property values, it appears that Salesforce is smart enough to ignore these values and to replace them with values appropriate to the target org.
- staticresources - a way to "package" the login branding icon (see later).
NB: You can include other metadata in the package as well, such as custom fields, but that's not important here.
To do this development, make sure to include the following in your project-scratch-def.json
's settings:
"experienceBundleSettings": {
"enableExperienceBundleMetadata": true
},
"communitiesSettings": {
"enableNetworksEnabled": true
}
You additionally need the following added to "features" in project-scratch-def.json
:
PublishAuraExpBuilderBasedSna
for Aura-based experiences
PublishExpBuilderBasedSna
for LWR-based experiences
Things that you CANNOT package are:
- networkBranding - this metadata type isn't supported for any form of packaging. This means there is a post-installation activity for the admin to go set the branding up for login.
- sharingSets - despite there being documented means to include this in an no-namespaced, unlocked 2GP, when I included these in the package I got "field integrity exception" errors during installation (see later).
Strangely when installing the no-namespace, unlocked package on a scratch org using the CLI, all packaged Profiles do not get installed. According to @David Reed, there is different behaviour around Profiles based on the way the package is installed (through CLI/API or through the Setup UI). Because of this you will get "field integrity exception" errors during install if you included such profiles in the network's "networkMemberGroups", or if you try to include sharing sets. You therefore need to package use of permission set membership for the Experience Builder Site instead, and include a post-install manual step to add sharing sets (see below).
Also worth noting; I left the "admin" as a member of the Experience Builder Site. If you have no users that are members, the All Sites entry for the Site becomes inaccessible. See this Q&A for more.
Because not everything can be packaged, the admin has a number of post-installation activities to perform:
- Create all required Profiles (for page layout assignments required for the object types used in the experience "pages" - don't use them for CRUD/FLS permissions, use permission sets for this).
- In the
Setup > Digital Experience > Settings
, create any necessary Sharing Sets
for the above profiles. For example, if you expose Contact and its master detail children you'll need to create a sharing set against "Account" to grant access "User:Contact.Account = Account:Id" as "Read/Write" since Contact OWD external sharing is typically Controlled by Parent or even Private on many orgs.
- In
Setup > Digital Experience > All Sites
, select the Workspaces
for the packaged experience then select the Administration card:
- Select "Login & Registration" and set the logo, colours and footer text. This is where we ensure the logo image has been included as a static resource; the admin must first download the static resource and then can re-upload it through this UI. (I didn't try to use a URL-based logo.)
- Select "Members" and add any required Profiles, if you use Profile-based (instead of Permission Set-based) membership. (We switched to using perm set based membership, which reduces friction in setting up the package and removes this post-installation step.)
At the end of all this, you'll have a functional Digital Experience on your org, mostly coming from the no-namespace unlocked package.
There is an alternative approach that seems favoured by the Salesforce TEs, which is to package a Community Template created from the Digital Experience, but for me this:
- Means the admin has more work to do after installation of the package.
- Doesn't support fixes for, and updates to, the Digital Experience from being installed at a later date.
- Makes the packaging more complex since you must separately manage the source Digital Experience from which the template is subsequently generated and pulled back down that template for inclusion in git, or at least the package version creation against an appropriate package directory.
Obviously having an "upgradeable" Digital Experience has its downsides; local changes to the same metadata can be lost when the package is upgraded on the org - this suggests a cloning exercise where post-installation modification is desired, if there is a plan to later upgrade. This does, at least, allow selective (if rather manual) inclusion of updates into the cloned metadata.