Edit in GitHubLog an issue

Targets and Targetables

Targets and Targetables are features provided by PWA Studio's extensibility framework. They give you the ability to change feature behaviors, component logic, and even component source code without editing a local copy of PWA Studio code.

Intercept file#

The intercept file is where you directly interact with Targets and Targetables to apply customizations. It exports a default function that accepts a TargetProvider parameter.

Intercept file name and location#

The file name and location of your intercept file is a custom value you specify in your project's package.json file.

To register the location of your intercept file, set the value for pwa-studio.targets.intercept. For example, the following entry registers src/targets/intercept.js as this project's intercept file.

Copied to your clipboard
1"pwa-studio": {
2 "targets": {
3 "intercept": "src/targets/intercept"
4 }
5}

How interception works#

Interception logic executes during the build process. The @magento/pwa-buildpack module creates a BuildBus process to run intercept files in the storefront project or its dependencies.

The BuildBus process executes intercept files in named direct dependencies in a project. This means that modules listed under dependencies and devDependencies in a project's package.json file have the ability to intercept Targets and Targetables in the project. The process does not execute intercept files in dependencies beyond those modules in the dependency tree.

Interception order#

The interception process executes files in dependency order. This means that if your module declares another module that has an intercept file as a peer dependency, the other module's intercept file executes first.

Target#

A Target is a formal extension point exposed by a package. Buildpack, Peregrine, and Venia UI expose their own set of Targets that let developers change the behavior of the underlying code. Targets are a package's public API and can be intercepted in storefront or extension projects.

Intercepting Targets#

Use the TargetProvider given to the intercept file's default function to access Targets from your project's dependencies.

Copied to your clipboard
1module.exports = (targets) => {
2 // Set buildpack features
3 const builtins = targets.of("@magento/pwa-buildpack");
4 builtins.specialFeatures.tap((featuresByModule) => {
5 featuresByModule["my-extension"] = {
6 // Tells buildpack that this extension uses ES Modules
7 esModules: true,
8 };
9 });
10};

PWA Studio target reference#

The following PWA Studio packages contain Targets that developers can intercept:

Targetables#

Targetables are objects that give you access to the source code for the files in your project or library. They let you change the final application bundles by applying transformations to the source code during the build process.

Targetables are useful in two scenarios:

  • As a storefront developer, you can use Targetables to transform the source file in any of your project's dependencies.
  • As an extension developer, you can use Targetables to add Targets to your own extension.

Access the TargetableSet class#

The most common pattern for working with Targetable objects is to connect an instance of the TargetableSet to the TargetProvider sent to the intercept file. Then, you can use that instance to create Targetable objects.

Copied to your clipboard
1// Access the TargetableSet class
2const { Targetables } = require("@magento/pwa-buildpack");
3
4module.exports = (targets) => {
5 // Create a TargetableSet instance connected to this project's TargetProvider
6 const targetables = Targetables.using(targets);
7
8 // Use the TargetableSet to create Targetable objects
9};

Create Targetable objects#

Use the TargetableSet instance to create a TargetableModule class object or one of its subclasses. The TargetableModule class itself represents a plain module. It contains functions that let it manipulate the source code directly.

Copied to your clipboard
1const { Targetables } = require("@magento/pwa-buildpack");
2
3module.exports = (targets) => {
4 const targetables = Targetables.using(targets);
5
6 // Create a TargetableModule instance that points to the main.js source
7 const MainComponent = targetables.module(
8 "@magento/venia-ui/lib/components/Main/main.js"
9 );
10
11 // Insert a console log message in the source
12 MainComponent.insertAfterSource(
13 "const Main = props => {\n",
14 '\tconsole.log("Hello World");\n'
15 );
16};

Other Targetable classes, such as TargetableESModule, are subclasses of TargetableModule. They contain specialized functions that let it work with different modules or file types.

Chain transformations#

Some Targetable classes, such as TargetableModule and TargetableReactComponent, support method chaining. Certain methods in these classes are chainable, which let you call these methods one after another in your code.

Copied to your clipboard
1const { Targetables } = require("@magento/pwa-buildpack");
2
3module.exports = (targets) => {
4 const targetables = Targetables.using(targets);
5
6 const MainComponent = targetables.reactComponent(
7 "@magento/venia-ui/lib/components/Main/main.js"
8 );
9
10 MainComponent.appendJSX(
11 "div className={pageClass}",
12 "<span>appendJSX succeeded!</span>"
13 )
14 .addJSXClassName("Header", '"myClass"')
15 .insertBeforeJSX("<Header />", "<span>insertBeforeJSX succeeded!</span>");
16};

Unbound Targetable objects#

A less common pattern for using Targetables is to access the Targetables classes directly and creating an object that is not connected to a project's TargetProvider.

Copied to your clipboard
1const { Targetables } = require("@magento/pwa-buildpack");
2
3module.exports = (targets) => {
4 // Create an unbound Targetable ESModule object from a file
5 const handlers = new Targetables.ESModule("src/lib/handlers.js");
6
7 // Wrap an export in a decorator from another file
8 handlers.wrapWithFile("handleLoad", "src/overrides/doSomethingOnLoad.js");
9
10 // Send it all to the build
11 targets.of("@magento/pwa-buildpack").transformModules.tap((addTransform) => {
12 handlers.flush().forEach((request) => addTransform(request));
13 });
14};

Next steps

  • Privacy
  • Terms of Use
  • Do not sell my personal information
  • AdChoices
Copyright © 2022 Adobe. All rights reserved.