Cracking the Code: Two Components, One App Scope

Every great spy film has some code that needs cracking. Today’s mission, should you choose to accept it, is to crack the code (pun intended) of the Now Experience UI Framework so that two custom web components can exist in a single app scope.

Part 1: The Backstory

Part of what makes a great spy film is a captivating backstory. The backstory is the reason behind the mission – the driving force. Our motivation stems from the fact that an app can only have one custom component project tied to its scope. Configurable workspaces allow users to put components anywhere on any page. With this in mind, it is very possible that a user would want multiple components for their app. However, if one component project has already been built and deployed to an app scope and then a second component project is built and deployed to that same scope, an error will be thrown:

Failed to deploy!
Scope, x_123456_mission already contains 4 component records.
Existing component tags: x-123456-mission-impossible
Attempted to deploy component tags: x-123456-second-component-example
If you deploy, the existing component records will be overwritten and may be deleted.

Our mission is to find a way around this roadblock. We want to have the ability to create as many components in our app scope as we would like.

Part 2: The Mission

Now it is time for action. How do we get from HQ to the target? The answer is in both how we create our new components, as well as the setup of the now-ui.json file (which is automatically created when the component project is created). Here is an example now-ui.json file:

{
	"components": {
		"x-123456-mission-impossible": {
			"innerComponents": [],
			"uiBuilder": {
				"associatedTypes": ["global.core", "global.landing-page"],
				"label": "Mission Impossible",
				"icon": "magnifying-glass-fill",
				"description": "Demo Component Wrapper",
				"category": "primitives"
			}
		}
	},
	"scopeName": "x_123456_mission"
}

Note that the JSON above has both a "components" property and a "scopeName" property. Everything listed in the "components" property will be applied to the scope specified in "scopeName". Since this is just a regular JSON object, we can add additional components to the "components" property. Let’s imagine that we want two components: one for displaying our inventory of spy gear, and one that has a map with our target’s location. The trick is to add all of our new components to the same project as the original component, instead of creating a new project for each component. As we build out these components, our file structure should look something like this:

Now that we have our additional components built out, we need to import them in the src/index.js file that was created by the CLI. We do this so that the deploy command will load the source code for all of our components, not just the default component.

import './x-123456-mission-impossible';
import './x-123456-gear-inventory';
import './x-123456-map-to-target';

All that we need to do now in order to acquire our target is to add the new components to our now-ui.json and then deploy! This is what the file will look like once we add our two components to it:

{
	"components": {
		"x-123456-mission-impossible": {
			"innerComponents": [],
			"uiBuilder": {
				"associatedTypes": ["global.core", "global.landing-page"],
				"label": "Mission Impossible",
				"icon": "magnifying-glass-fill",
				"description": "Demo Component Wrapper",
				"category": "primitives"
			}
		},
		"x-123456-gear-inventory": {
			"innerComponents": [],
			"uiBuilder": {
				"associatedTypes": ["global.core", "global.landing-page"],
				"label": "Gear Inventory",
				"icon": "address-book-outline",
				"description": "A component for our inventory of spy gear",
				"category": "primitives"
			}
		},
		"x-123456-map-to-target": {
			"innerComponents": [],
			"uiBuilder": {
				"associatedTypes": ["global.core", "global.landing-page"],
				"label": "Map to Target",
				"icon": "chart-geomap-outline",
				"description": "A component for the map to our target",
				"category": "primitives"
			}
		}
	},
	"scopeName": "x_123456_mission"
}

Part 3: The Resolution

We all know that a story is not any good without a proper resolution. The final step in our journey is delivering the target to HQ. Now that we have built our new components and deployed them to our app scope, we are ready to use them! We should now be able to see both additional components as options in our component picker in UI Builder:


Mission Accomplished!