Generating a web component is almost the same as generating a regular journey. To turn a regular journey into a web component you need to pass the option --target=webcomponent
during the generation of the journey. The generated journey will then include all the necessary changes to be bundled and used as a web component.
As with a regular journey, there are two scenarios:
In case you want to generate the web component inside an existing Nx workspace like the itmp-frontend-workspace
you can use the journey-src
generator provided by the package @allianz/taly-nx
. If that's not installed in your workspace, you can add it with:
yarn add @allianz/taly-nx
# or
npm install @allianz/taly-nx
npx nx generate journey-src \
--project=<the-name-of-your-project> \
--target=webcomponent
The generated app will include the necessary changes to turn it into a web component.
By default, TALY will infer the deploy URL at runtime, allowing the web component's assets like images to load properly. For this to work, images need to use the talyNormalizeUrl
pipe.
Note that this feature of automatically detecting the deploy url does not work for the url()
function in CSS. If a used Building Block relies on url()
in its styles, you need to explicitly pass the --deploy-url
of the web component (make sure it ends with a slash) to the nx generate
command.
To now turn this generated app into a web component you need to first build it:
npx nx build-generated-app <the-name-of-your-project> --configuration=webcomponent
The generator call added the webcomponent
configuration. This is needed to support a web component build in addition to the default standalone build. Here are some details about its content:
zone.js
must be provided as a separate bundle so that the web component can lazy-load it if necessary. If the hosting application or another web component on the same page already provides a Zone then the web component will use that one.deploy-url
needs to match the value passed through the generator parameter --deploy-url
, in case this option is passed to the generator at all. This configuration is required by the Angular build to properly hardcode the paths to the lazily loaded bundles.vendorChunk
needs to be turned off. This is automatically disabled and recommended being turned off for production build by Angular.outputHashing
needs to be none
. It is an Angular default configuration to produce simple file names for the bundler to deal with (like vendor.js instead of vendor-cb243bcb53.js).deploy-url
is given then inlineCritical
optimization needs to be turned off to make sure that the application contains all the necessary styles. Angular 12 activated the inlineCritical
optimization by default. The effect of this optimization is, that critical CSS gets directly inlined into the index.html
file. As the content of this file is not used, the CSS from there would be lost.localize
to true
or to an array of a subset of the previously defined locale identifiers to build a separate distributable copy of the application for each locale.assets
:AllianzNeo
and Allianz-Icons
fonts are added to the build assets. This is necessary for the web component to automatically load the fonts and icons it needs in case the parent application does not provide them, or when the web component is consumed as a standalone app.normalize.css
of ng-aquila is added to the assets.The generator call will also create a webcomponent-bundle
target in your project configuration. This target can now be used to bundle the built application into a single web component file:
npx nx webcomponent-bundle <the-name-of-your-project>
This will produce a webcomponent-bundle.js
file for every locale that got built by the build-generated-app
command. This file contains the code that is required to render the web component. To serve the web component(s), you need to "serve" the locale-specific folder in the dist
folder of your journey (e.g. ./dist/my-journey/en-US
) with a server of your choice. Note that the above command did not remove the generated {main,polyfills,runtime,scripts,styles}.js and index.html
files. This allows you to serve the dist/[locale]
folder and be able to load the journey as a standalone application through the index.html
file, while also being able to load it as a web component from /webcomponent-bundle.js
.
To generate a journey that exists outside of an Nx workspace as a web component, you can use functions and CLI commands provided by the package @allianz/taly-sdk
. Install it like so:
yarn add @allianz/taly-sdk
# or
npm install @allianz/taly-sdk
Afterwards you can use the SDK and the CLI like described in Generate a Journey Outside of an Nx workspace Using the TALY SDK.
To generate a journey as a web component with the TALY CLI, pass the --target=webcomponent
flag, like so:
npx taly generate-journey --name="My customer journey" --target=webcomponent
To generate a web component with the generateJourney
SDK function, you can pass the option target: 'webcomponent'
, like so:
import { generateJourney } from '@allianz/taly-sdk/node';
for await (const progress of generateJourney({
name: 'My customer journey',
target: 'webcomponent'
})) {
// do something with the progress
}
The app will be generated with the dependencies and the changes required for the web component.
By default, TALY will infer the deploy URL at runtime, allowing the web component's assets like images to load properly. You can override this behavior by passing the future deployUrl
/--deploy-url
of the web component (make sure it ends with a slash). In both cases, for local development or tests this will most likely be some localhost
URL.
webcomponent
ConfigurationThe generated workspace will include an Nx project with your new journey. You can build that project in the generated workspace with this command (note the --configuration webcomponent
):
cd <path/to/your/generated/workspace>
npx nx build-generated-app <name-of-your-journey> --configuration webcomponent
You now need to bundle all of the produced files in the dist
folder into a single file to serve it as a web component.
To bundle all relevant files in the dist
folder of your journey in the generated workspace, you can run this command:
cd <path/to/your/generated/workspace>
npx nx webcomponent-bundle <name-of-your-journey>
This will produce a webcomponent-bundle.js
file for every locale that got built by the build-generated-app
command. This file contains the code that is required to render the web component. To serve the web component(s), you need to "serve" the locale-specific folder in the dist
folder of your generated workspace (e.g. ./generated/apps/my-journey/dist/en-US
) with a server of your choice. Note that the above command did not remove the generated {main,polyfills,runtime,scripts,styles}.js and index.html
files. This allows you to serve the dist/[locale]
folder and be able to load the journey as a standalone application through the index.html
file, while also being able to load it as a web component from /webcomponent-bundle.js
.
The idea of web components is to have elements that you can easily use anywhere on any page and they are expected to "just work". While this is mostly true, web components and the underlying technologies are still a fairly young trend and browsers still lack some functionality to make web components as pleasant as they sound.
💡 If your application is hosted in oneMarketing you don't need to worry about these requirements. oneMarketing provides the necessary environment to run TALY-generated web components.
If you want to integrate a TALY web component into a parent application, the host should import @allianz/ngx-ndbx/css/ndbx-base.css
so that the TALY web component and other web components can access the font definitions. If the parent application does not provide the required fonts, TALY will load them automatically. For this purpose, make sure that the build options contain the required assets.
💡 A TALY web component only loads fonts that the host doesn't provide and will never load a font that is already provided by the host.
A lot of the available NDBX components rely on 1rem
to equal 10px
. This can be achieved by setting the font-size
for the html
element to 10px
or 62.5%
. Hosting applications that don't explicitly set this property might lead to web components that contain NDBX components that look broken. Setting this property can either be done manually or by importing the ndbx-base.css
styles, like in the requirement for the "Allianz Neo" font family. This of course affects the entire application so it's advised to apply this style as soon as possible in the development process of the hosting application.
Example of a manual approach:
html {
font-size: 62.5%;
}
TALY does not provide any utility to integrate the generated web component into the parent app. You can use already existing third party libraries like Angular Extensions Elements or your own script to load the web component in the host.
🧩 A full example setup can be found in the webcomponent-integration recipe
Integrating the generated web component in a Non-Angular web application is very straightforward.
webcomponent-bundle.js
file in your scriptsselector
in the HTML💡 The actual selector is the name of the project. If you generated a project called
my-custom-journey
, then use<my-custom-journey></my-custom-journey>
. Note, that if the name of the project is not a valid name for a web component, TALY tries to make it valid. To verify the selector, check your generated app'sAppModule
for the value of theWEB_COMPONENT_ID
injection token:{ provide: WEB_COMPONENT_ID, useValue: 'my-custom-journey' }
<script src="https://your-server.com/webcomponent-bundle.js"></script>
...
<my-custom-journey></my-custom-journey>
💡 Note that it's important to not import the web component bundle as
type="module"
since this will break the dynamic detection of the web component's deploy URL.
A "Location Strategy" in Angular determines the way that the routing in an application affects the URL.
We provide a location strategy for Angular called WebComponentLocationStrategy
that uses a special syntax to allow web component routing that is reflected in the URL without interfering with the hosting app's routing - assuming that it is not using hash based routing. This location strategy is the default for TALY-generated web components.
Given a WEB_COMPONENT_ID
of "my-web-component"
and a the route /internalPath
in that web component, the WebComponentLocationStrategy
will produce paths like this:
.../some/host/path/#(my-web-component:/internalPath)
Given there are multiple web components on the same page that use this location strategy they will neatly live alongside each other and produce paths like so:
.../path/#(my-web-component:/internalPath,other-web-component:/other/path)
⚠️ This location strategy changes the hash of the URL.
This location strategy works fine if there are multiple web components on the same page that use this location strategy.
Scenarios exist where it might not be a good idea to take control over or change the URL's hash. This is a (probably incomplete) list of scenarios where you would want to avoid using this location strategy:
Fragment scrolling
The WebComponentLocationStrategy
is not meant to be used on pages that use fragments as part of their URLs. If a page some/path#overview
contains a web component that uses this location strategy it will lead to paths like some/path#overview(some-web-component:/some-path)
. This new URL will break the browser-built-in fragment-scrolling.
Hash based routing in host application
If the host application of your web component is using a hash based location strategy (like Angular's built-in HashLocationStrategy
) then the WebComponentLocationStrategy
cannot be used since it would interfere with the host application's routing. In this case it is advised to use the NoopLocationStrategy
(see below) for your web component that doesn't change the URL at all. Another solution would be to ask the host application to change to a path based location strategy.
Someone else owns the hash
If the web component that uses the WebComponentLocationStrategy
lives on the same page with another element that wants to take control over the hash (e.g. another web component that uses a different strategy or some other element/script) then they might get in each other's way. In this case it's better to use the NoopLocationStrategy
in your web component (see below).
Apart from the WebComponentLocationStrategy
, we also provide another location strategy called NoopLocationStrategy
that does not change the URL at all. This is useful if you find that the WebComponentLocationStrategy
leads to conflicts with the host application of your web component.
If you want to use the NoopLocationStrategy
you can pass the flag --use-noop-location-strategy
to your generator call. Alternatively, you can also set the useNoopLocationStrategy
flag in the executor options of your project.json
:
{
"...": "...",
"options": {
"useNoopLocationStrategy": true
}
}
Building Blocks that include assets (e.g. images) need to use the talyNormalizeUrl
pipe (documentation) in order to work properly inside a web component. Otherwise, the browser will try to load the assets from the hosting application instead of the web component server.
If you notice missing assets in your web component, make sure that the used Building Blocks are using the talyNormalizeUrl
pipe to normalize their asset URLs.
💡 This feature is only supported for Retail journeys.
TALY provides the ability to link back to another page from two different places throughout the journey. It is possible to display a back link in the upper part of the TALY Frame stage and/or to navigate to the same URL when clicking on the "Next" button on the last page of the journey. This feature is mostly intended to navigate back to an external link from which the journey was started, but it could be used for any other purpose.
To enable this feature, the host application needs to provide the value(s) to use for the back links. See the below subsection for an AEM integration example. If you are using a TALY generated web component without AEM and need to configure back links, please reach out to us.
For the back link in the TALY Frame stage, the link can be disabled on the page level using the hideBackLink
flag inside the page configuration for the journey:
// Page configuration
{
"id": "my-page-c",
"blocks": [{ "...": "..." }],
"title": {
"headline": "Page C is good",
"showAsStage": true,
"subline": "Really good",
"hideBackLink": true
}
}
Additionally, and likewise only applicably to the stage back link, a PFE Service Activator can be executed when clicking on the back link, before redirecting. TALY will prevent the redirect if the Service Activator call fails. Here is an example of how to configure this in your journey configuration:
{
"...": "...",
"frame": {
"stage": {
"backLink": {
"onClickServiceActivator": "users"
}
},
"...": "..."
},
"...": "..."
}
For this feature to work with AEM pages, the back link configuration needs to be added to the customconfiguration
object via the AEM user interface. More precisely, a key called backLinkConfig
needs to be set to a value that implements the BackLinkConfiguration interface defined in TALY. This is an example of this value (note the use of double quotes preceded by a backslash, this is required for the data to be extracted from customconfiguration
at runtime).
{\"backLinks\": [ {\"path\": \"dashboard\", \"stageLinklabel\": \"Go Back to Dashboard\", \"nextButtonLabel\": \"Go to Dashboard\"}, {\"path\": \"localhost:4000\", \"stageLinkLabel\": \"Back to example app\"} ], \"default\": {\"path\": \"https://allianz.com\", \"stageLinkLabel\": \"Default\" }}
TALY reads the data from the root element and processes it. The functionality is based on the value of document.referrer
. In a nutshell, it does the following:
backLinks
via customconfiguration
, that item is used for the back link.backLinks
, if provided it takes the default
entry from customconfiguration
.stageLinkLabel
field, the back link will not be displayed in the TALY Frame stage. The same applies to the "Next" button on the last page of the journey. If the field nextButtonLabel
is not provided, the back link feature is disabled for that button, and the button will be hidden unless it is explicitly configured to be shown in the PFE configuration.The host application needs to pass the configuration data to the web component in a way that allows the corresponding adapter to read it. An example is the AEM integration, explained in the previous section.
TALY-based customer journey web components provide the possibility to get and restore their state from outside.
The current PFE state can be retrieved via the getState()
method provided in the web component element.
For example:
const webComponent = // get the element reference from the DOM, for example by the tag name
const currentState = webComponent.getState();
The host application can provide an initial state for the customer journey. This state is then restored when the customer journey starts up and the journey continues where it left off.
The journey can be initialized with a state like this:
<my-taly-app initial-state='{"state": "value"}'> </my-taly-app>
For Angular hosts, the initial state can alternatively be passed to the journey via dynamic binding:
// Component class
// Imports and component decorator...
export class AppComponent {
webComponentInitialState = '{ "state": "value" }';
}
<!-- Component template -->
<my-taly-app [initialState]="webComponentInitialState"> </my-taly-app>
In this case, the bound property can be a JSON string or a promise that eventually resolves to a JSON string.
💡 Keep in mind that this feature is incompatible with other PFE state initialization strategies, like web component inputs added to the journey configuration or PFE state updates performed by TALY plugin modules during their initialization. This is the intended behavior, since the initial state feature is meant to fully restore the PFE state from a previous session, and no other PFE state initializations should happen in parallel to that.
Instead of providing the entire state as shown above, TALY-generated web components can be configured to receive individual values from their host application. This has to be configured ahead of generating the web component in the pages.json
file, like so:
// pages.jsonc
{
// other configuration
"webcomponent": {
"inputs": [
{
// name of the input that will be available on the web component
"name": "customer-name",
// the path where the received value will be stored in the web component's PFE store
"storeExpression": "$.fromHost.customerName"
}
]
}
}
The hosting application can then provide values for these inputs via regular HTML attributes, like so:
<my-web-component customer-name="John Doe"></my-web-component>