-
Notifications
You must be signed in to change notification settings - Fork 19
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: add toolbar events #89
Conversation
This looks great and really opens up a lot of possibilities! Hot reloading preview updates and exits is a killer feature. I have some thoughts below on the API and how we might alter the implementation. Simpler APISupporting both Example 1: Using middleware to redirect on a preview update. <script
async
defer
src="https://static.cdn.prismic.io/prismic.min.js?repo=200629-sms-hoy&new=true"
></script>
<script>
window.prismic.middleware.previewUpdate = () => {
window.location = '/api/prismic-preview-update'
}
</script> Compared to the Example 2: Using <script
async
defer
src="https://static.cdn.prismic.io/prismic.min.js?repo=200629-sms-hoy&new=true"
data-redirect-url-on-update="/api/prismic-preview-update"
></script> Example 1 is longer, but it is clearer what it is doing. It is also extensible if necessary, where Example 2 is not immediately extensible. Example 2 could still implement a middleware function, but now functionality is split between two APIs. In other words, Example 1 is clearer, more obviously extensible, and should be simpler to maintain for both consumers of and developers working on the toolbar. (I recognize that I posted a long message on proposing the Naming
window.prismic.toolbar = {
onPreviewUpdate: (next) => {
// Called on update events
},
onPreviewExit: (next) => {
// Called on exit events
},
} In addition to renaming Requires discussion: Use native events?Event handlers are typically handled using element.addEventListener('click', () => {
// Called on click events
}) Should we use this existing concept rather than build our own event dispatcher and handler? Note: @lihbr originally proposed something very similar here: #68 Why should we use it? Using the native event system allows us to hook into the existing event framework. It means we get support for multiple listeners, default behavior management, and listener cancellation for free. Why shouldn't we use it? It could introduce education complexity as there are more concepts to address. This can be mitigated by simply ignoring the advanced use cases and relying on users to understand native browser event management to make use of it. We can teach the simple, common use cases. How would we use it? Custom events can be registered using // In the toolbar, create a new event. CustomEvent is an Event with custom associated data.
const event = new CustomEvent('prismicPreviewUpdate', {
detail: 'arbitrary data can be provided if needed',
})
// Dispatch the event when an update happens:
window.dispatchEvent(event) In users' code, event listeners can be managed like any other event listener: const onPrismicPreviewUpdate = (event) => {
// Called on preview update events
}
const alsoOnPrismicPreviewUpdate = (event) => {
// Called on preview update events
}
// Add listeners:
window.addEventListener('prismicPreviewUpdate', onPrismicPreviewUpdate)
window.addEventListener('prismicPreviewUpdate', alsoOnPrismicPreviewUpdate)
// Use native event functions to remove a listener:
window.removeEventListener('prismicPreviewUpdate', onPrismicPreviewUpdate) This gives the user flexibility in adding their own event listeners, but also enables framework integrations to add their own. In the case that we want to support default behavior, such as the existing full page refresh, we can rely on window.addEventListener('prismicPreviewUpdate', (event) => {
event.preventDefault()
// Do things without the full page refresh
}) In the toolbar's code, we can detect if // In the toolbar, register a new event.
const event = new CustomEvent('prismicPreviewUpdate')
// Dispatch the event when an update happens:
const shouldPerformDefaultBehavior = window.dispatchEvent(event)
if (shouldPerformDefaultBehavior) {
window.location.reload()
} |
Thanks @angeloashmore! Simpler APII agree, will remove the NamingWorks for me if we don't decide to go the native events way. Native eventsThat's the implementation I prefer too. If we find consensus with @arnaudlewis on it, I'll refactor the code to use the native event API! |
I refactored the code to implement the simpler API and naming proposed by @angeloashmore. The initial PR post has been updated accordingly. The last topic remaining to be answered is whether or not we should migrate to native events, apart from that one the PR is ready. |
Update: code needs to be refactored to use native events we agreed on using during our last open-source meeting. |
Refactored the code to use native custom events. Updated the initial post to reflect those API changes. ✅ The PR is ready, awaiting review & QA. |
Looks nice and clean. Should the existing "init" event use the same framework you have setup with prismic-toolbar/src/toolbar/index.js Line 43 in 94ef3d8
|
Was kinda afraid to break something haha, but yes, I'll add it! |
Updated. |
@@ -65,12 +72,30 @@ const Share = { | |||
const State = { | |||
liveStateNeeded: Boolean(getCookie('is-logged-in')) || Boolean(getCookie('io.prismic.previewSession')), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Check if this is still necessary (if the toolbar is not loaded when no cookie is found, we can get rid of this @arnaudlewis)
Status
✅ Following first, second, and third implementations (described below), this PR is ready, awaiting review & QA.
Types of changes
Overview
This Pull Request adds events to the toolbar in the form of native JavaScript
CustomEvent
.The toolbar registers and triggers two custom events on the
window
object:prismicPreviewUpdate
andprismicPreviewEnd
. Users can listen to them using the native JavaScript API:window.addEventListener()
These events are meant to solve preview issues some frameworks have while also allowing some others to fully enable their preview capabilities.
Background Information
The toolbar is the companion integration of Prismic within Prismic-powered websites, it is mainly responsible for orchestrating Prismic preview sessions within those. In order to work for all Prismic users, the toolbar is designed to be and remain framework-agnostic.
This design choice appeared to cause issues for some frameworks that require specific actions to be performed for their preview capabilities to work correctly. These issues have been discussed lengthily within the following threads:
An initial proposal and integration were made last year to address these issues but did not lead to a merge for various reasons:
Description
Toolbar events allow users to listen to them on the
window
object. Registered event handlers are executed sequentially before the default toolbar behavior (hard reloading the page).Due to their relative complexity, custom events are not meant to be used by users directly. They are meant to be used by framework kits we provide to enable on users' behalf the best preview experience.
Usage
Each toolbar events follow the native JavaScript event API:
Toolbar events are cancelable: if any of the registered handlers calls
event.preventDefault()
, then the default behavior of the toolbar won't be executed.Some toolbar events come with additional data, users can access them inside the
event.detail
object.prismicPreviewUpdate
The preview update event will be fired every time there's an update on the preview session. The
event.detail
object will contain the new preview API ref (event.detail.ref
).Logging something each time the preview session gets updated:
Using Nuxt.js built-in refresh to allow hot reload instead of the default toolbar hard reload each time the preview session gets updated:
prismicPreviewEnd
The preview end event will be fired when the preview session ends (gets closed). The
event.detail
object will benull
.Logging something each time the preview session ends:
Exiting Next.js preview correctly each time the preview session ends:
Concerns
While I was able to test the toolbar locally with success, I wasn't able to test its iframe changes because I'm not able to run wroom locally.
I had to make the following changes to the iframe because the toolbar can now perform hot reload and cannot solely rely on a hard refresh to reset its state anymore: https://github.com/prismicio/prismic-toolbar/pull/89/files#diff-c58e75bd72479a6f9867399b1bb8bd6c1dbceba4eee441a890fb0d39eae9d33d
These changes allow the current preview state and its ref to be updated when the preview ping call returns a new ref, theoretically allowing the toolbar to perform multiple updates without hard reloading the page.
Without these changes, the toolbar wants to constantly update the preview as soon as a first change is detected.
This will need to be tested on wroom or with someone able to run wroom locally.
History
First implementation (window & redirect middleware)
Overview
This Pull Request adds two types of middleware to the toolbar:
window
object that the toolbar can call upon certain events;data-*
attribute values registered on the toolbar script tag itself that the toolbar uses to redirect users upon certain events if present.Those two types of middleware are both available and fired for the toolbar
previewUpdate
andpreviewEnd
events. They are meant to solve preview issues some frameworks have while also allowing some others to fully enable their preview capabilities.Background Information
The toolbar is the companion integration of Prismic within Prismic-powered websites, it is mainly responsible for orchestrating Prismic preview sessions within those. In order to work for all Prismic users, the toolbar is designed to be and remain framework-agnostic.
This design choice appeared to cause issues for some frameworks that require specific actions to be performed for their preview capabilities to work correctly. These issues have been discussed lengthily within the following threads:
An initial proposal and integration were made last year to address these issues but did not lead to a merge for various reasons:
Description
Window Middleware
Window middleware allow registering functions in the
window
object inside the already existingwindow.prismic
namespace. If any of those functions are registered the toolbar will then run them and may still execute its default behavior depending on those middleware functions implementations.Due to their relative complexity, window middleware are not meant to be used by users directly. They are meant to be used by framework kits we provide to enable on users' behalf the best preview experience.
Usage
Each middleware function has the following interface:
Not calling and returning
next()
inside the middleware will result in the default toolbar behavior not being performed.window.prismic.middleware.previewUpdate
The preview update middleware will be fired every time there's an update on the preview session.
Logging something each time the preview session gets updated:
Performing an async task each time the preview session gets updated:
Using Nuxt.js built-in refresh to allow hot reload instead of the default toolbar hard reload each time the preview session gets updated:
window.prismic.middleware.previewEnd
The preview end middleware will be fired when the preview session ends (gets closed).
Logging something each time the preview session ends:
Performing an async task each time the preview session ends:
Redirect Middleware
Redirect middleware allow registering routes using
data-*
attributes on the toolbar script itself. If any of those attributes are registered the toolbar will then redirect users to those routes instead of executing its default behavior (refreshing the current location).Due to their relative user-friendly interface, redirect middleware might be used by users directly. While remaining optional for most users, this additional configuration step might be necessary for some users to get previews to work correctly with their framework.
Usage
Each redirect middleware gets registered on the toolbar script itself:
data-redirect-url-on-update
The preview update redirect specifies a route to redirect the user to every time there's an update on the preview session.
Redirecting to
/api/prismic-preview-update
each time the preview session gets updated:data-redirect-url-on-end
The preview end redirect specifies a route to redirect the user to when the preview session ends (gets closed).
Redirecting to
/api/prismic-preview-end
each time the preview session ends:Additional Information
Window and redirect middleware can be used together. Window middleware are executed before redirect middleware as executing them after wouldn't be possible. Not calling
next()
inside a window middleware will result in the following redirect middleware not being applied.Concerns
While I was able to test the toolbar locally with success, I wasn't able to test its iframe changes because I'm not able to run wroom locally.
I had to make the following changes to the iframe because the toolbar can now perform hot reload and cannot solely rely on a hard refresh to reset its state anymore: https://github.com/prismicio/prismic-toolbar/pull/89/files#diff-c58e75bd72479a6f9867399b1bb8bd6c1dbceba4eee441a890fb0d39eae9d33d
These changes allow the current preview state and its ref to be updated when the preview ping call returns a new ref, theoretically allowing the toolbar to perform multiple updates without hard reloading the page.
Without these changes, the toolbar wants to constantly update the preview as soon as a first change is detected.
This will need to be tested on wroom or with someone able to run wroom locally.
Second implementation (window middleware)
Overview
This Pull Request adds window middleware to the toolbar in the form of events that can be registered.
Window middleware are functions registered on the
window
object that the toolbar can call upon certain events. They are available and fired for the toolbarpreviewUpdate
andpreviewEnd
events.Window middleware are meant to solve preview issues some frameworks have while also allowing some others to fully enable their preview capabilities.
Background Information
The toolbar is the companion integration of Prismic within Prismic-powered websites, it is mainly responsible for orchestrating Prismic preview sessions within those. In order to work for all Prismic users, the toolbar is designed to be and remain framework-agnostic.
This design choice appeared to cause issues for some frameworks that require specific actions to be performed for their preview capabilities to work correctly. These issues have been discussed lengthily within the following threads:
An initial proposal and integration were made last year to address these issues but did not lead to a merge for various reasons:
Description
Window middleware allow registering functions on the
window
object inside the already existingwindow.prismic
namespace. If any of those functions are registered the toolbar will then run them and may still execute its default behavior depending on those middleware functions implementations.Due to their relative complexity, window middleware are not meant to be used by users directly. They are meant to be used by framework kits we provide to enable on users' behalf the best preview experience.
Usage
Each middleware function has the following interface:
Not calling and returning
next()
inside the middleware will result in the default toolbar behavior not being performed.window.prismic.toolbar.onPreviewUpdate
The preview update middleware will be fired every time there's an update on the preview session.
Logging something each time the preview session gets updated:
Performing an async task each time the preview session gets updated:
Using Nuxt.js built-in refresh to allow hot reload instead of the default toolbar hard reload each time the preview session gets updated:
window.prismic.toolbar.onPreviewEnd
The preview end middleware will be fired when the preview session ends (gets closed).
Logging something each time the preview session ends:
Performing an async task each time the preview session ends:
Exiting Next.js preview correctly each time the preview session ends:
Concerns
While I was able to test the toolbar locally with success, I wasn't able to test its iframe changes because I'm not able to run wroom locally.
I had to make the following changes to the iframe because the toolbar can now perform hot reload and cannot solely rely on a hard refresh to reset its state anymore: https://github.com/prismicio/prismic-toolbar/pull/89/files#diff-c58e75bd72479a6f9867399b1bb8bd6c1dbceba4eee441a890fb0d39eae9d33d
These changes allow the current preview state and its ref to be updated when the preview ping call returns a new ref, theoretically allowing the toolbar to perform multiple updates without hard reloading the page.
Without these changes, the toolbar wants to constantly update the preview as soon as a first change is detected.
This will need to be tested on wroom or with someone able to run wroom locally.