-
Notifications
You must be signed in to change notification settings - Fork 50
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #294 from player-ui/afimbres/docs-plugin-cli
[Docs] plugin and cli updates, links fix
- Loading branch information
Showing
7 changed files
with
139 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
--- | ||
title: Plugin Implementation | ||
--- | ||
|
||
# Plugin Implementation | ||
|
||
The main purpose of a Plugin is to extend or add new functionality by tapping into Player's pipeline of components via hooks. In this section we'll go over the steps to implement a plugin. | ||
|
||
We'll use the [stage-revert-data](./plugins/stage-revert-data) plugin as example. After creating our plugin class, we'll use the `apply` method which provides access to the Player instance, which then gives access to the necessary hooks. | ||
|
||
```typescript | ||
export default class StageRevertDataPlugin implements PlayerPlugin { | ||
name = 'stage-revert-data-plugin'; | ||
|
||
apply(player: Player) { | ||
let dataController: DataController; | ||
let stageData: String; | ||
let commitTransitions: String[]; | ||
let commitShadowModel: Boolean = false; | ||
|
||
const GatedDataMiddleware = new ValidationMiddleware( | ||
() => | ||
commitShadowModel | ||
? undefined | ||
: { | ||
message: 'staging data', | ||
severity: 'error', | ||
}, | ||
{ shouldIncludeInvalid: () => true } | ||
); | ||
``` | ||
For this case we needed to define variables that will store references for the scope the hooks will share: | ||
- `dataController`: Reference to the data controller hook in the Player instance, can be used to read, update or commit new changes to the data model | ||
- `stageData`: View attribute that comes from the view state, used for enabling the staging of data | ||
- `commitTransitions`: The list of view names which the shadow model should be committed if transitioned to. Comes from the view state attribute as well. | ||
- `commitShadowModel`: Flag that enables committing shadow model into data model after the transition, only if `stageData` is set to true and the next target view name is included in `commitTransitions`. | ||
- `GatedDataMiddleware` Instance from `ValidationMiddleware` to be used as a middleware to intercept the data-model pipeline before any data is committed and cache the data instead, only if `stageData` is set to true. | ||
The next step is to tap into the necessary Player hooks. First we tap into the `viewController` which we can then intercept the `resolveView` hook. Player hooks are implemented with the [Tapable](https://github.com/webpack/tapable) package, so we can use the interception API's `call` method, this triggers everytime the hook is triggered, then we get access to the current view state and read the `stageData` and `commitTransitions` attributes. | ||
```typescript | ||
player.hooks.viewController.tap(this.name, (vc) => { | ||
vc.hooks.resolveView.intercept({ | ||
call: (view, id, state) => { | ||
stageData = state?.attributes?.stageData; | ||
commitTransitions = state?.attributes?.commitTransitions; | ||
}, | ||
}); | ||
}); | ||
``` | ||
`Note`: notice how each time we tap into a hook, we use the `this.name` property as the name of the plugin. This is important to avoid conflicts with other plugins. | ||
Next we tap into the `dataController`, so we can scope the data controller instance for future use. Then we tap into the `resolveDataStages` plugin in this data controller instance. If the `stage` property is set to true, we add our `GatedDataMiddleware` to the data pipeline. If not, we return the data pipeline as is. | ||
```typescript | ||
player.hooks.dataController.tap(this.name, (dc: DataController) => { | ||
dataController = dc; | ||
|
||
dc.hooks.resolveDataStages.tap(this.name, (dataPipeline) => { | ||
return stageData | ||
? [...dataPipeline, GatedDataMiddleware] | ||
: [...dataPipeline]; | ||
}); | ||
}); | ||
``` | ||
Finally, we tap into the `flowController` so we can intercept the `flow` hook. We then tap into the `transition` hook, which is called every time the player transitions from one view to another. If the `commitTransitions` includes the next view name, we set the `commitShadowModel` flag to true, and commit the data stored in the shadow model through `GatedDataMiddleware` into the data model. Whether the data was committed from the shadow model or not, we clear the shadow model paths in the `GatedDataMiddleware` instance and set the `commitShadowModel` flag to false as final steps. | ||
```typescript | ||
player.hooks.flowController.tap(this.name, (flowController) => { | ||
flowController.hooks.flow.tap(this.name, (flow) => { | ||
flow.hooks.transition.tap(this.name, (from, to) => { | ||
if (from) { | ||
if (commitTransitions.includes(to.name)) { | ||
commitShadowModel = true; | ||
player.logger.debug( | ||
'Shadow Model Data to be committed %s', | ||
GatedDataMiddleware.shadowModelPaths | ||
); | ||
dataController.set(GatedDataMiddleware.shadowModelPaths); | ||
} | ||
|
||
commitShadowModel = false; | ||
GatedDataMiddleware.shadowModelPaths.clear(); | ||
} | ||
}); | ||
}); | ||
}); | ||
``` | ||
And this is how we implement a plugin that manages the staging of data based on the view state attributes. | ||
Code Snippets Reference: [StageRevertDataPlugin](https://github.com/player-ui/player/blob/main/plugins/stage-revert-data/core/src/index.ts) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters