From 00066b1fc3751e8cfdb99306fb04b15a42c0d381 Mon Sep 17 00:00:00 2001 From: James Calcaben Date: Wed, 4 Nov 2020 13:17:48 -0600 Subject: [PATCH 01/14] Add TOC entry --- pwa-devdocs/src/_data/getting-started.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pwa-devdocs/src/_data/getting-started.yml b/pwa-devdocs/src/_data/getting-started.yml index a03f618a47..dc0397de2b 100644 --- a/pwa-devdocs/src/_data/getting-started.yml +++ b/pwa-devdocs/src/_data/getting-started.yml @@ -56,6 +56,9 @@ entries: - label: Configuration management url: /pwa-buildpack/configuration-management/ + - label: Extensibility framework + url: /pwa-buildpack/extensibility-framework/ + - label: Scaffolding url: /pwa-buildpack/scaffolding/ From 1e18224a0568831744434a2b85e219df284eda0e Mon Sep 17 00:00:00 2001 From: James Calcaben Date: Wed, 4 Nov 2020 14:36:00 -0600 Subject: [PATCH 02/14] Add new topic file and outline --- .../extensibility-framework/index.md | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 pwa-devdocs/src/pwa-buildpack/extensibility-framework/index.md diff --git a/pwa-devdocs/src/pwa-buildpack/extensibility-framework/index.md b/pwa-devdocs/src/pwa-buildpack/extensibility-framework/index.md new file mode 100644 index 0000000000..77e4e77b74 --- /dev/null +++ b/pwa-devdocs/src/pwa-buildpack/extensibility-framework/index.md @@ -0,0 +1,25 @@ +--- +title: Extensibility framework +--- + +## How it works + +## Targets + +### Targetables + +## Intercept files + +### Interceptors + +## Extendible packages in PWA Studio + +### Buildpack + +### Peregrine + +### Venia UI + +## Testing extensions locally + +## Examples \ No newline at end of file From 89ee0a31177e353f53c969ca566bfa5b0f44d77b Mon Sep 17 00:00:00 2001 From: James Calcaben Date: Thu, 5 Nov 2020 13:58:47 -0600 Subject: [PATCH 03/14] Add how it works section --- .../extensibility-framework/index.md | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/pwa-devdocs/src/pwa-buildpack/extensibility-framework/index.md b/pwa-devdocs/src/pwa-buildpack/extensibility-framework/index.md index 77e4e77b74..7e5edab1bb 100644 --- a/pwa-devdocs/src/pwa-buildpack/extensibility-framework/index.md +++ b/pwa-devdocs/src/pwa-buildpack/extensibility-framework/index.md @@ -2,8 +2,29 @@ title: Extensibility framework --- +PWA Studio's extensibility framework provides the tools you need to customize and extend your storefront without copying over code from the core PWA Studio project. +The extensibility framework gives developers the ability to: + +- Extend the base Venia storefront with minimal core code duplication +- Create and install extensions for PWA Studio storefronts +- Create their own extendible modules and storefronts + ## How it works +The extensibility framework uses a modular approach for modifying application behavior. +It applies configurations and customizations defined inside extensions you install in the project. + +_Extensions_ for PWA Studio storefronts are normal NPM packages you install as a project dependency. +These packages contain instructions that affect the build process and static code output for the generated application bundles. +By modifying the output code during build time, there is no runtime performance cost associated with changing the storefront behavior. + +This is different from a _plugin architecture_ where the application detects and dispatches plugins as the front end loads in the browser. +The more plugins you install with this architecture, the slower the application gets as it becomes bloated with overhead processes. + +### Interceptor pattern + + + ## Targets ### Targetables From ad7f9e2a45d1401e8511d168436556413ade346c Mon Sep 17 00:00:00 2001 From: James Calcaben Date: Fri, 6 Nov 2020 11:24:56 -0600 Subject: [PATCH 04/14] Add interceptor pattern section and image --- .../images/interceptor-pattern.svg | 1 + .../src/pwa-buildpack/extensibility-framework/index.md | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 pwa-devdocs/src/pwa-buildpack/extensibility-framework/images/interceptor-pattern.svg diff --git a/pwa-devdocs/src/pwa-buildpack/extensibility-framework/images/interceptor-pattern.svg b/pwa-devdocs/src/pwa-buildpack/extensibility-framework/images/interceptor-pattern.svg new file mode 100644 index 0000000000..45dd39d93c --- /dev/null +++ b/pwa-devdocs/src/pwa-buildpack/extensibility-framework/images/interceptor-pattern.svg @@ -0,0 +1 @@ +Module AModule CModule B \ No newline at end of file diff --git a/pwa-devdocs/src/pwa-buildpack/extensibility-framework/index.md b/pwa-devdocs/src/pwa-buildpack/extensibility-framework/index.md index 7e5edab1bb..32fba830fb 100644 --- a/pwa-devdocs/src/pwa-buildpack/extensibility-framework/index.md +++ b/pwa-devdocs/src/pwa-buildpack/extensibility-framework/index.md @@ -23,7 +23,10 @@ The more plugins you install with this architecture, the slower the application ### Interceptor pattern +The extensibility framework implements an [interceptor pattern][] to allow changes to the build process. +The interceptor pattern lets a module **C** intercept the flow of logic between module **A** and module **B** and add it's own logic. +![interceptor-pattern-image][] ## Targets @@ -43,4 +46,7 @@ The more plugins you install with this architecture, the slower the application ## Testing extensions locally -## Examples \ No newline at end of file +## Examples + +[interceptor pattern]: https://en.wikipedia.org/wiki/Interceptor_pattern +[interceptor-pattern-image]: ./images/interceptor-pattern.svg \ No newline at end of file From ad090dfd2e35aa834154458b2dece7c4ded147d3 Mon Sep 17 00:00:00 2001 From: James Calcaben Date: Mon, 9 Nov 2020 16:20:31 -0600 Subject: [PATCH 05/14] Add content for Targets section --- .../images/interceptor-pattern.svg | 2 +- .../extensibility-framework/index.md | 53 ++++++++++++++++++- 2 files changed, 52 insertions(+), 3 deletions(-) diff --git a/pwa-devdocs/src/pwa-buildpack/extensibility-framework/images/interceptor-pattern.svg b/pwa-devdocs/src/pwa-buildpack/extensibility-framework/images/interceptor-pattern.svg index 45dd39d93c..4356a6b4ea 100644 --- a/pwa-devdocs/src/pwa-buildpack/extensibility-framework/images/interceptor-pattern.svg +++ b/pwa-devdocs/src/pwa-buildpack/extensibility-framework/images/interceptor-pattern.svg @@ -1 +1 @@ -Module AModule CModule B \ No newline at end of file +Module AModule CModule BModified Logic FlowNormal Logic FlowModule A Targets \ No newline at end of file diff --git a/pwa-devdocs/src/pwa-buildpack/extensibility-framework/index.md b/pwa-devdocs/src/pwa-buildpack/extensibility-framework/index.md index 32fba830fb..491c1175fa 100644 --- a/pwa-devdocs/src/pwa-buildpack/extensibility-framework/index.md +++ b/pwa-devdocs/src/pwa-buildpack/extensibility-framework/index.md @@ -28,14 +28,55 @@ The interceptor pattern lets a module **C** intercept the flow of logic between ![interceptor-pattern-image][] +In PWA Studio, the points where a module may intercept the normal flow of logic and add their own are [Targets][]. +The framework uses the [BuildBus][] to gather instructions from each extension's [Intercept File][]. +These files determine which Targets the extension intercepts and extends during the build process. + ## Targets -### Targetables +_Targets_ are objects that represent areas in code you can access and intercept. +These extension points are variants of a simple, common JavaScript pattern called the [Tapable Hook][] and share some functionality with NodeJS's [`EventEmitter` class][]. + +Targets let you choose a code process's extension point _by name_ and let you run interceptor code when that process executes. +Unlike `EventEmmitter` objects, Targets have defined behavior for how and in what order they run their interceptors. +How those interceptors change the logic is also a defined behavior for Targets. + +Targets are part of a package's public API along with the modules it exports. +They provide another layer of customization on top of using plain code composition techniques with modules. + +### TargetProviders + +A _TargetProvider_ is an object that manages the connections between modules and their Targets. +This object is available to your module's [intercept file][] and is the API you use to access Targets and intercept them. +A common practice is to assign the TargetProvider object to the `targets` variable in your intercept file and access targets in other packages using `targets.of()`. +To access targets declared within the same module, use `targets.own`. + +### Example + +An example of a Target is the [`richContentRenderers` target][] declared by the Venia UI package. +This target lets you change the behavior of the `RichContent` component across your project by adding a rendering strategy. +Tapping into this Target gives access to a `richContentRenders` list object in your intercept function. +Call the `add()` function on this list to add a custom rendering strategy for your storefront. + +The [Page Builder extension][] provides an example by tapping into this Target and adding a custom renderer for any detected Page Builder content. + +```js +targets + .of('@magento/venia-ui') + .richContentRenderers.tap(richContentRenderers => { + richContentRenderers.add({ + componentName: 'PageBuilder', + importPath: '@magento/pagebuilder' + }); + }); +``` ## Intercept files ### Interceptors +## Declare files + ## Extendible packages in PWA Studio ### Buildpack @@ -48,5 +89,13 @@ The interceptor pattern lets a module **C** intercept the flow of logic between ## Examples +[`richcontentrenderers` target]: <{% link venia-ui/reference/targets/index.md %}#richContentRenderers> + [interceptor pattern]: https://en.wikipedia.org/wiki/Interceptor_pattern -[interceptor-pattern-image]: ./images/interceptor-pattern.svg \ No newline at end of file +[interceptor-pattern-image]: ./images/interceptor-pattern.svg +[buildbus]: https://github.com/magento/pwa-studio/blob/develop/packages/pwa-buildpack/lib/BuildBus/BuildBus.js +[targets]: #targets +[intercept file]: #intercept-files +[tapable hook]: https://github.com/webpack/tapable +[`eventemitter` class]: https://nodejs.org/api/events.html#events_class_eventemitter +[page builder extension]: https://github.com/magento/pwa-studio/blob/develop/packages/pagebuilder/lib/intercept.js \ No newline at end of file From 0652593b5e107ec1acd436368cc76a442f699734 Mon Sep 17 00:00:00 2001 From: James Calcaben Date: Tue, 10 Nov 2020 15:56:36 -0600 Subject: [PATCH 06/14] Add content for Intercept files --- .../extensibility-framework/index.md | 23 ++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/pwa-devdocs/src/pwa-buildpack/extensibility-framework/index.md b/pwa-devdocs/src/pwa-buildpack/extensibility-framework/index.md index 491c1175fa..20405158e1 100644 --- a/pwa-devdocs/src/pwa-buildpack/extensibility-framework/index.md +++ b/pwa-devdocs/src/pwa-buildpack/extensibility-framework/index.md @@ -73,7 +73,27 @@ targets ## Intercept files -### Interceptors +The _intercept file_ is the main entry point for the extensibility framework into your project. +It describes which targets you want to intercept and extend. +During build time, the framework looks for this file using the value for `pwa-studio.targets.intercept` in your project's `package.json` file. + +Your intercept files must export a function that accepts a TargetProvider object as a parameter. +This object gives you access to all available Targets in your project that let you make customizations, gather data, change the build itself, or develop and call your own declared targets. + +For more information on how intercept files work, see the tutorial on how to [Intercept a Target][]. + +### Intercept functions + +When you call the `tap()` function on a Target, you supply it with an _intercept function_. +An intercept function is a callback function that provides the interception logic for a specific Target. +Calling the `tap()` function registers your intercept function with that Target. +When the framework builds your project, it generates code that calls your intercept function when the project runs the Target code. + +The function signature for an intercept function depends on the tapped Target. +In the previous Page Builder example, the intercept function signature when you tap the `richContentRenderers` target is a function that receives a list object that let you add custom rendering strategies. +Other Targets may require your intercept function to return a modified value, use an object with a specific API, or provide a configuration. + +Read the reference API on this site or in doc blocks in the source code to learn about the intercept function signatures for each Target. ## Declare files @@ -90,6 +110,7 @@ targets ## Examples [`richcontentrenderers` target]: <{% link venia-ui/reference/targets/index.md %}#richContentRenderers> +[intercept a target]: <{% link tutorials/intercept-a-target/index.md %}> [interceptor pattern]: https://en.wikipedia.org/wiki/Interceptor_pattern [interceptor-pattern-image]: ./images/interceptor-pattern.svg From 6da2b08be11502601e09b8cbb5a9433470754d57 Mon Sep 17 00:00:00 2001 From: James Calcaben Date: Wed, 11 Nov 2020 14:21:41 -0600 Subject: [PATCH 07/14] Finish Declare file content --- .../extensibility-framework/index.md | 81 ++++++++++++++++--- 1 file changed, 69 insertions(+), 12 deletions(-) diff --git a/pwa-devdocs/src/pwa-buildpack/extensibility-framework/index.md b/pwa-devdocs/src/pwa-buildpack/extensibility-framework/index.md index 20405158e1..d20bff053f 100644 --- a/pwa-devdocs/src/pwa-buildpack/extensibility-framework/index.md +++ b/pwa-devdocs/src/pwa-buildpack/extensibility-framework/index.md @@ -29,13 +29,13 @@ The interceptor pattern lets a module **C** intercept the flow of logic between ![interceptor-pattern-image][] In PWA Studio, the points where a module may intercept the normal flow of logic and add their own are [Targets][]. -The framework uses the [BuildBus][] to gather instructions from each extension's [Intercept File][]. +The framework uses the [BuildBus][] to gather instructions from each extension's [Intercept File][intercept files]. These files determine which Targets the extension intercepts and extends during the build process. ## Targets _Targets_ are objects that represent areas in code you can access and intercept. -These extension points are variants of a simple, common JavaScript pattern called the [Tapable Hook][] and share some functionality with NodeJS's [`EventEmitter` class][]. +These extension points are variants of a simple, common JavaScript pattern called the [Tapable hook][tapable] and share some functionality with NodeJS's [`EventEmitter` class][]. Targets let you choose a code process's extension point _by name_ and let you run interceptor code when that process executes. Unlike `EventEmmitter` objects, Targets have defined behavior for how and in what order they run their interceptors. @@ -47,9 +47,10 @@ They provide another layer of customization on top of using plain code compositi ### TargetProviders A _TargetProvider_ is an object that manages the connections between modules and their Targets. -This object is available to your module's [intercept file][] and is the API you use to access Targets and intercept them. -A common practice is to assign the TargetProvider object to the `targets` variable in your intercept file and access targets in other packages using `targets.of()`. -To access targets declared within the same module, use `targets.own`. +This object is available to your module's [intercept file][] and is the API you use to access Targets or declare them. + +Each extension receives its own TargetProvider in its intercept and declare files. +Use this object to declare a module's own targets, intercept its own targets, or intercept the targets of other extensions. ### Example @@ -71,14 +72,60 @@ targets }); ``` +## Declare files + +A _declare file_ lists the Targets available for interception in an extension or package. +During build time, the framework looks for this file using the value set for `pwa-studio.targets.intercept` in your project's `package.json` file. +The framework registers the Targets in all the declare files it finds in the project and dependencies before it runs any [intercept files][]. +This guarantees Target availability to any dependent interceptor. + +Declare files must export a function that accepts a TargetProvider object as a parameter. +It provides a `declare()` function to register your project's Targets by providing it a dictionary object. +The dictionary object provides a mapping of a unique name to its Target. + +When you register your Target, the dictionary key is the named property a developer uses to access that Target. +In the Page Builder example, the dictionary key for the rich content renderers Target that Venia UI declares is `richContentRenderers`. + +The value associated with the key is a variant of a Tapable hook created using one of the class constructors available under the TargetProvider object's `types` property. +Each class constructor accepts an optional array of strings that represent the list of arguments passed to the [intercept function][]. + +The TargetProvider object exposes the same classes as the [Tapable][] package except their names do not end with 'Hook'. +This is intentional to avoid confusion with the concept of React Hooks. +For example, the `SyncWaterfallHook` class from Tapable is `SyncWaterfall` under the TargetProvider object's `types` property. + +See the [Hook types][] section of the Tapable documentation to learn about the available hook types. + +### Example declare file content + +```js +module.exports = targets => { + targets.declare({ + perfReport: new targets.types.AsyncParallel(['report']) + socialIcons: new targets.types.SyncWaterfall(['iconlist']) + }); +} +``` + +The example provided declares two Targets that this project or other modules can intercept, a `perfReport` Target and a `socialIcons` Target. +Intercept files can access these Targets using `targets.of().perReport` and `targets.of().socialIcons` respectively. + +The `perfReport` key maps to a Target type that runs its interceptors asynchronously and in parallel. +This is appropriate for logging and monitoring interceptors that do not affect functionality. + +The `socialIcons` key maps to a Target type that runs its interceptors synchronously and in subscription order, which passes its return values as arguments to the next interceptor. +This is appropriate for customizations that must happen in a predictable order. + +Both targets passes in a single parameter to their intercept functions, a `report` argument and an `iconlist` argument. + ## Intercept files -The _intercept file_ is the main entry point for the extensibility framework into your project. -It describes which targets you want to intercept and extend. +The _intercept file_ describes the targets you want to intercept and define or extend. During build time, the framework looks for this file using the value for `pwa-studio.targets.intercept` in your project's `package.json` file. +These files execute after all the declare files register their Targets. Your intercept files must export a function that accepts a TargetProvider object as a parameter. This object gives you access to all available Targets in your project that let you make customizations, gather data, change the build itself, or develop and call your own declared targets. +The TargetProvider object provides an `of()` function and an `own` property to access Targets in other packages or Targets within its own module respectively. For more information on how intercept files work, see the tutorial on how to [Intercept a Target][]. @@ -90,12 +137,20 @@ Calling the `tap()` function registers your intercept function with that Target. When the framework builds your project, it generates code that calls your intercept function when the project runs the Target code. The function signature for an intercept function depends on the tapped Target. -In the previous Page Builder example, the intercept function signature when you tap the `richContentRenderers` target is a function that receives a list object that let you add custom rendering strategies. -Other Targets may require your intercept function to return a modified value, use an object with a specific API, or provide a configuration. +In the Page Builder example, the intercept function signature when you tap the `richContentRenderers` target is a function that receives a list object, which lets you add custom rendering strategies. +Other Targets may require you to return a modified value, use an object with a specific API, or provide a configuration. Read the reference API on this site or in doc blocks in the source code to learn about the intercept function signatures for each Target. -## Declare files +## Writing intercept and declare files + +When writing intercept and declare files, keep in mind the following requirements: + +- Both files must export a function that accepts a TargetProvider object as a parameter. +- Both files are CommonJS modules that run in Node. +- You can create these files anywhere in your project, but you must specify their paths in your `package.json` file. + +As shown in the previous examples, a common practice when authoring these files involve assigning the TargetProvider object to a `targets` variable. ## Extendible packages in PWA Studio @@ -116,7 +171,9 @@ Read the reference API on this site or in doc blocks in the source code to learn [interceptor-pattern-image]: ./images/interceptor-pattern.svg [buildbus]: https://github.com/magento/pwa-studio/blob/develop/packages/pwa-buildpack/lib/BuildBus/BuildBus.js [targets]: #targets -[intercept file]: #intercept-files -[tapable hook]: https://github.com/webpack/tapable +[intercept files]: #intercept-files +[intercept function]: #intercept-functions +[tapable]: https://github.com/webpack/tapable +[hook types]: https://github.com/webpack/tapable#hook-types [`eventemitter` class]: https://nodejs.org/api/events.html#events_class_eventemitter [page builder extension]: https://github.com/magento/pwa-studio/blob/develop/packages/pagebuilder/lib/intercept.js \ No newline at end of file From dd6e30189a16db4645cc29ee7e0a1a458174b2b4 Mon Sep 17 00:00:00 2001 From: James Calcaben Date: Wed, 11 Nov 2020 15:23:08 -0600 Subject: [PATCH 08/14] Add content for Targets in PWA Studio packages --- .../extensibility-framework/index.md | 22 +++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/pwa-devdocs/src/pwa-buildpack/extensibility-framework/index.md b/pwa-devdocs/src/pwa-buildpack/extensibility-framework/index.md index d20bff053f..9d1ecc7d8b 100644 --- a/pwa-devdocs/src/pwa-buildpack/extensibility-framework/index.md +++ b/pwa-devdocs/src/pwa-buildpack/extensibility-framework/index.md @@ -152,13 +152,23 @@ When writing intercept and declare files, keep in mind the following requirement As shown in the previous examples, a common practice when authoring these files involve assigning the TargetProvider object to a `targets` variable. -## Extendible packages in PWA Studio +## Targets in PWA Studio packages -### Buildpack +When you create a new storefront project using the scaffolding tool, you have access to all the same PWA Studio Targets as the Venia storefront. +The following is a list of PWA Studio packages that contain Targets. -### Peregrine +[Buildpack][] +: Targets in the Buildpack are low level and generic. +They are often used as building blocks for more complicated feature Targets. +You can also find Targets that let you add environment variables or change UPWARD behavior in this package. -### Venia UI +[Peregrine][] +: Targets in the Peregrine package focus mainly on the set of talons it provides. +The `talons` Target lets you [wrap a Talon][] with your own module. + +[Venia UI][] +: Targets in the Venia UI provide access to the list of items used in the UI components. +These Targets let you add new routes, rendering strategies, and payment methods. ## Testing extensions locally @@ -166,6 +176,10 @@ As shown in the previous examples, a common practice when authoring these files [`richcontentrenderers` target]: <{% link venia-ui/reference/targets/index.md %}#richContentRenderers> [intercept a target]: <{% link tutorials/intercept-a-target/index.md %}> +[buildpack]: <{% link /pwa-buildpack/reference/targets/index.md %}> +[peregrine]: <{% link /peregrine/reference/targets/index.md %}> +[wrap a talon]: <{% link /tutorials/intercept-a-target/modify-talon-results/index.md %}> +[venia ui]: <{% link /venia-ui/reference/targets/index.md %}> [interceptor pattern]: https://en.wikipedia.org/wiki/Interceptor_pattern [interceptor-pattern-image]: ./images/interceptor-pattern.svg From 8d1be91bd0233c20930b44c344b96a4df7c9c837 Mon Sep 17 00:00:00 2001 From: James Calcaben Date: Wed, 11 Nov 2020 15:40:29 -0600 Subject: [PATCH 09/14] Add list of extension examples --- .../extensibility-framework/index.md | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/pwa-devdocs/src/pwa-buildpack/extensibility-framework/index.md b/pwa-devdocs/src/pwa-buildpack/extensibility-framework/index.md index 9d1ecc7d8b..2f7471d46e 100644 --- a/pwa-devdocs/src/pwa-buildpack/extensibility-framework/index.md +++ b/pwa-devdocs/src/pwa-buildpack/extensibility-framework/index.md @@ -170,9 +170,17 @@ The `talons` Target lets you [wrap a Talon][] with your own module. : Targets in the Venia UI provide access to the list of items used in the UI components. These Targets let you add new routes, rendering strategies, and payment methods. -## Testing extensions locally +## Extension examples -## Examples +The PWA Studio scaffolding tool also installs extensions on all new storefront projects. +These extensions use the framework to add useful features on top of the base application. +They are also examples of what a PWA Studio storefront extension looks like. + +[@magento/upward-security-headers][] +: This extension adds security headers to UPWARD by tapping into the `transformUpward` Target in Buildpack. + +[@magento/venia-sample-language-packs] +: This extension provides sample translations for PWA Studio's internationalization feature. [`richcontentrenderers` target]: <{% link venia-ui/reference/targets/index.md %}#richContentRenderers> [intercept a target]: <{% link tutorials/intercept-a-target/index.md %}> @@ -190,4 +198,6 @@ These Targets let you add new routes, rendering strategies, and payment methods. [tapable]: https://github.com/webpack/tapable [hook types]: https://github.com/webpack/tapable#hook-types [`eventemitter` class]: https://nodejs.org/api/events.html#events_class_eventemitter -[page builder extension]: https://github.com/magento/pwa-studio/blob/develop/packages/pagebuilder/lib/intercept.js \ No newline at end of file +[page builder extension]: https://github.com/magento/pwa-studio/blob/develop/packages/pagebuilder/lib/intercept.js +[@magento/upward-security-headers]: https://github.com/magento/pwa-studio/tree/develop/packages/extensions/upward-security-headers +[@magento/venia-sample-language-packs]: https://github.com/magento/pwa-studio/tree/develop/packages/extensions/venia-sample-language-packs From aca3416ea677ab5ae04ed34d6c48629bcbcbfe5f Mon Sep 17 00:00:00 2001 From: James Calcaben Date: Thu, 12 Nov 2020 14:02:09 -0600 Subject: [PATCH 10/14] Add extensibility overview diagram --- .../images/extensibility-overview.svg | 1 + .../extensibility-framework/index.md | 18 ++++++++++++------ 2 files changed, 13 insertions(+), 6 deletions(-) create mode 100644 pwa-devdocs/src/pwa-buildpack/extensibility-framework/images/extensibility-overview.svg diff --git a/pwa-devdocs/src/pwa-buildpack/extensibility-framework/images/extensibility-overview.svg b/pwa-devdocs/src/pwa-buildpack/extensibility-framework/images/extensibility-overview.svg new file mode 100644 index 0000000000..a4fc8e39d3 --- /dev/null +++ b/pwa-devdocs/src/pwa-buildpack/extensibility-framework/images/extensibility-overview.svg @@ -0,0 +1 @@ +Extended StorefrontPackage BBase StorefrontBuild PhaseInstall PhaseFinal ResultPackage AProject installs Package Aas a dependencyPWA Studio adds Package Acode to the static code bundlesThe final application includesfeatures provided by Package AProject installs Package A andPackage B as dependenciesPackage APackage A declares itsextension points as TargetsPackage B provides instructionsfor intercepting and extendingPackage A TargetsPWA Studio modifies Target code inPackage A with logic from Package Bbefore adding it to the static code bundlesThe final application includes features provided by Package Amodified by Package Bdeclare.jsintercept.js \ No newline at end of file diff --git a/pwa-devdocs/src/pwa-buildpack/extensibility-framework/index.md b/pwa-devdocs/src/pwa-buildpack/extensibility-framework/index.md index 2f7471d46e..131f887024 100644 --- a/pwa-devdocs/src/pwa-buildpack/extensibility-framework/index.md +++ b/pwa-devdocs/src/pwa-buildpack/extensibility-framework/index.md @@ -18,6 +18,10 @@ _Extensions_ for PWA Studio storefronts are normal NPM packages you install as a These packages contain instructions that affect the build process and static code output for the generated application bundles. By modifying the output code during build time, there is no runtime performance cost associated with changing the storefront behavior. +The following diagram illustrates the general build process for a basic storefront with no extensions and a storefront that installs an extension. + +![extensibility-overview][] + This is different from a _plugin architecture_ where the application detects and dispatches plugins as the front end loads in the browser. The more plugins you install with this architecture, the slower the application gets as it becomes bloated with overhead processes. @@ -47,7 +51,7 @@ They provide another layer of customization on top of using plain code compositi ### TargetProviders A _TargetProvider_ is an object that manages the connections between modules and their Targets. -This object is available to your module's [intercept file][] and is the API you use to access Targets or declare them. +This object is available to your module's [intercept file][intercept files] and is the API you use to access Targets or declare them. Each extension receives its own TargetProvider in its intercept and declare files. Use this object to declare a module's own targets, intercept its own targets, or intercept the targets of other extensions. @@ -55,11 +59,12 @@ Use this object to declare a module's own targets, intercept its own targets, or ### Example An example of a Target is the [`richContentRenderers` target][] declared by the Venia UI package. -This target lets you change the behavior of the `RichContent` component across your project by adding a rendering strategy. +This Target lets you change the behavior of the `RichContent` component across your project by adding a rendering strategy. Tapping into this Target gives access to a `richContentRenders` list object in your intercept function. -Call the `add()` function on this list to add a custom rendering strategy for your storefront. +Calling the `add()` function on this object lets you add a custom rendering strategy for your storefront. -The [Page Builder extension][] provides an example by tapping into this Target and adding a custom renderer for any detected Page Builder content. +The [Page Builder extension][] provides an example of how to intercept this Target. +It taps the Target and provides an intercept function that adds a custom renderer for any detected Page Builder content. ```js targets @@ -80,8 +85,8 @@ The framework registers the Targets in all the declare files it finds in the pro This guarantees Target availability to any dependent interceptor. Declare files must export a function that accepts a TargetProvider object as a parameter. -It provides a `declare()` function to register your project's Targets by providing it a dictionary object. -The dictionary object provides a mapping of a unique name to its Target. +It provides a `declare()` function to register your project's Targets by providing it a dictionary object, +which maps a unique name to its Target. When you register your Target, the dictionary key is the named property a developer uses to access that Target. In the Page Builder example, the dictionary key for the rich content renderers Target that Venia UI declares is `richContentRenderers`. @@ -191,6 +196,7 @@ They are also examples of what a PWA Studio storefront extension looks like. [interceptor pattern]: https://en.wikipedia.org/wiki/Interceptor_pattern [interceptor-pattern-image]: ./images/interceptor-pattern.svg +[extensibility-overview]: ./images/extensibility-overview.svg [buildbus]: https://github.com/magento/pwa-studio/blob/develop/packages/pwa-buildpack/lib/BuildBus/BuildBus.js [targets]: #targets [intercept files]: #intercept-files From 38260fac3b253d4195c15863e1844856755ce333 Mon Sep 17 00:00:00 2001 From: James Calcaben Date: Mon, 16 Nov 2020 12:11:29 -0600 Subject: [PATCH 11/14] Apply suggestions from code review Co-authored-by: Andy Terranova <13182778+supernova-at@users.noreply.github.com> --- .../src/pwa-buildpack/extensibility-framework/index.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pwa-devdocs/src/pwa-buildpack/extensibility-framework/index.md b/pwa-devdocs/src/pwa-buildpack/extensibility-framework/index.md index 131f887024..9cb18c49a7 100644 --- a/pwa-devdocs/src/pwa-buildpack/extensibility-framework/index.md +++ b/pwa-devdocs/src/pwa-buildpack/extensibility-framework/index.md @@ -28,7 +28,7 @@ The more plugins you install with this architecture, the slower the application ### Interceptor pattern The extensibility framework implements an [interceptor pattern][] to allow changes to the build process. -The interceptor pattern lets a module **C** intercept the flow of logic between module **A** and module **B** and add it's own logic. +The interceptor pattern lets a module **C** intercept the flow of logic between module **A** and module **B** and add its own logic. ![interceptor-pattern-image][] @@ -80,7 +80,7 @@ targets ## Declare files A _declare file_ lists the Targets available for interception in an extension or package. -During build time, the framework looks for this file using the value set for `pwa-studio.targets.intercept` in your project's `package.json` file. +During build time, the framework looks for this file using the value set for `pwa-studio.targets.declare` in your project's `package.json` file. The framework registers the Targets in all the declare files it finds in the project and dependencies before it runs any [intercept files][]. This guarantees Target availability to any dependent interceptor. @@ -112,7 +112,7 @@ module.exports = targets => { ``` The example provided declares two Targets that this project or other modules can intercept, a `perfReport` Target and a `socialIcons` Target. -Intercept files can access these Targets using `targets.of().perReport` and `targets.of().socialIcons` respectively. +Intercept files can access these Targets using `targets.of().perfReport` and `targets.of().socialIcons` respectively. The `perfReport` key maps to a Target type that runs its interceptors asynchronously and in parallel. This is appropriate for logging and monitoring interceptors that do not affect functionality. From 7721340a718e0d4a08a4a47d73888be0232eecd8 Mon Sep 17 00:00:00 2001 From: James Calcaben Date: Thu, 12 Nov 2020 14:07:17 -0600 Subject: [PATCH 12/14] Fix links --- .../src/pwa-buildpack/extensibility-framework/index.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pwa-devdocs/src/pwa-buildpack/extensibility-framework/index.md b/pwa-devdocs/src/pwa-buildpack/extensibility-framework/index.md index 9cb18c49a7..ad01322d37 100644 --- a/pwa-devdocs/src/pwa-buildpack/extensibility-framework/index.md +++ b/pwa-devdocs/src/pwa-buildpack/extensibility-framework/index.md @@ -189,10 +189,10 @@ They are also examples of what a PWA Studio storefront extension looks like. [`richcontentrenderers` target]: <{% link venia-ui/reference/targets/index.md %}#richContentRenderers> [intercept a target]: <{% link tutorials/intercept-a-target/index.md %}> -[buildpack]: <{% link /pwa-buildpack/reference/targets/index.md %}> -[peregrine]: <{% link /peregrine/reference/targets/index.md %}> -[wrap a talon]: <{% link /tutorials/intercept-a-target/modify-talon-results/index.md %}> -[venia ui]: <{% link /venia-ui/reference/targets/index.md %}> +[buildpack]: <{% link pwa-buildpack/reference/targets/index.md %}> +[peregrine]: <{% link peregrine/reference/targets/index.md %}> +[wrap a talon]: <{% link tutorials/intercept-a-target/modify-talon-results/index.md %}> +[venia ui]: <{% link venia-ui/reference/targets/index.md %}> [interceptor pattern]: https://en.wikipedia.org/wiki/Interceptor_pattern [interceptor-pattern-image]: ./images/interceptor-pattern.svg From 1ca3d69ea05a8f0cc51b86bd7e82faed62140baf Mon Sep 17 00:00:00 2001 From: James Calcaben Date: Thu, 12 Nov 2020 15:50:38 -0600 Subject: [PATCH 13/14] Fix linting issues --- .../pwa-buildpack/extensibility-framework/index.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/pwa-devdocs/src/pwa-buildpack/extensibility-framework/index.md b/pwa-devdocs/src/pwa-buildpack/extensibility-framework/index.md index ad01322d37..6707b94324 100644 --- a/pwa-devdocs/src/pwa-buildpack/extensibility-framework/index.md +++ b/pwa-devdocs/src/pwa-buildpack/extensibility-framework/index.md @@ -5,9 +5,9 @@ title: Extensibility framework PWA Studio's extensibility framework provides the tools you need to customize and extend your storefront without copying over code from the core PWA Studio project. The extensibility framework gives developers the ability to: -- Extend the base Venia storefront with minimal core code duplication -- Create and install extensions for PWA Studio storefronts -- Create their own extendible modules and storefronts +- Extend the base Venia storefront with minimal core code duplication +- Create and install extensions for PWA Studio storefronts +- Create their own extendible modules and storefronts ## How it works @@ -151,9 +151,9 @@ Read the reference API on this site or in doc blocks in the source code to learn When writing intercept and declare files, keep in mind the following requirements: -- Both files must export a function that accepts a TargetProvider object as a parameter. -- Both files are CommonJS modules that run in Node. -- You can create these files anywhere in your project, but you must specify their paths in your `package.json` file. +- Both files must export a function that accepts a TargetProvider object as a parameter. +- Both files are CommonJS modules that run in Node. +- You can create these files anywhere in your project, but you must specify their paths in your `package.json` file. As shown in the previous examples, a common practice when authoring these files involve assigning the TargetProvider object to a `targets` variable. @@ -184,7 +184,7 @@ They are also examples of what a PWA Studio storefront extension looks like. [@magento/upward-security-headers][] : This extension adds security headers to UPWARD by tapping into the `transformUpward` Target in Buildpack. -[@magento/venia-sample-language-packs] +[@magento/venia-sample-language-packs][] : This extension provides sample translations for PWA Studio's internationalization feature. [`richcontentrenderers` target]: <{% link venia-ui/reference/targets/index.md %}#richContentRenderers> From 84ef8090103658c72a441f7c6f8b3fa64e770aca Mon Sep 17 00:00:00 2001 From: James Calcaben Date: Mon, 16 Nov 2020 15:55:35 -0600 Subject: [PATCH 14/14] Add example intercept file content --- .../extensibility-framework/index.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/pwa-devdocs/src/pwa-buildpack/extensibility-framework/index.md b/pwa-devdocs/src/pwa-buildpack/extensibility-framework/index.md index 6707b94324..35ba489123 100644 --- a/pwa-devdocs/src/pwa-buildpack/extensibility-framework/index.md +++ b/pwa-devdocs/src/pwa-buildpack/extensibility-framework/index.md @@ -134,6 +134,24 @@ The TargetProvider object provides an `of()` function and an `own` property to a For more information on how intercept files work, see the tutorial on how to [Intercept a Target][]. +### Example intercept file content + +```js +module.exports = targets => { + + const builtins = targets.of("@magento/pwa-buildpack"); + builtins.specialFeatures.tap((featuresByModule) => { + featuresByModule["my-extension"] = { + esModules: true, + }; + }); +}; +} +``` + +The example provided defines an intercept file that intercepts the `specialFeatures` target in the `@magento/pwa-buildpack` package. +It adds a webpack configuration for the `my-extension` package that lets the build process know that the package uses ES modules. + ### Intercept functions When you call the `tap()` function on a Target, you supply it with an _intercept function_.