Skip to content
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

Revisit SPA API #159

Closed
jakearchibald opened this issue Jun 10, 2022 · 10 comments
Closed

Revisit SPA API #159

jakearchibald opened this issue Jun 10, 2022 · 10 comments

Comments

@jakearchibald
Copy link
Collaborator

jakearchibald commented Jun 10, 2022

Now seems like a good time to revisit the design of the API.

We need 'touch points' that cover the following:

  • Before the DOM change, so the browser can capture the current state
  • After the current state is captured, so the developer can modify the DOM
  • After the DOM is modified, and any important assets have loaded, so the browser can capture the new state
  • After the new state is captured, so the developer can target the full set of pseudo elements (eg with WAAPI)
  • After the transition is complete, so the developer can delay particular DOM updates

I think .start() was originally intended to fulfill as soon as the new state is captured, but in the current implementation it fulfills once the transition is complete. Either way, it leaves one of the points uncovered.

Alternate proposal:

This proposal doesn't allow for JS-added transitions elements. See below for a revised proposal.
// Before the DOM change
await document.performDocumentTransition(async (transition) => {
  // After the current state is captured
  coolFramework.updateDOM();
  // After the DOM is modified
  await transition.start();
  // After the new state is captured
});
// After the transition is complete

API details:

  • By "callback promise" I mean the promise returned by the callback passed to performDocumentTransition.
  • If the callback promise rejects, the transition is abandoned.
  • If transition.start is not called before the callback promise fulfills, it's called automatically (simplifying cases where the developer doesn't need to run code after the start of the transition).
  • transition.start rejects if the transition cannot be started, or is called after the callback promise settles.
  • The promise returned by performDocumentTransition rejects if the transition is aborted.
  • I haven't thought too hard about the naming
@absurdprofit
Copy link

document.performDocumentTransition is a bit redundant. document.performTransition seems a bit better.

@jakearchibald
Copy link
Collaborator Author

Agreed. Although we need something to distinguish this kind of transition from CSS transitions. We've thrown layoutTransition around a bit, but I think that change might happen as part of a larger bikeshedding session.

@khushalsagar
Copy link
Collaborator

We can use the next rAF after the callback passed to start() returns for the missing touch point : "After the new state is captured, so the developer can target the full set of pseudo elements (eg with WAAPI)". That's actually how the example in the explainer is setup. Also our WPT uses that pattern.

@jakearchibald
Copy link
Collaborator Author

We can use the next rAF after the callback passed to start()

Is that reliable? Particularly as rAF can mean different things at different points in the event loop. Sometimes it means before next render, sometimes it's before the render after that. Either way, it's a bit of a rough edge in the API.

@jakearchibald
Copy link
Collaborator Author

jakearchibald commented Jun 13, 2022

My proposal in the OP doesn't provide a moment to configure the transition with JS before the current state is captured (eg (setElement).

Revised proposal:

const transition = document.createDocumentTransition();
// Before the DOM change
await transition.prepare(async () => {
  // After the current state is captured
  await coolFramework.updateDOM();
  // After the DOM is modified
});
// After the new state is captured
await transition.finished;
// After the transition is complete

This is a relatively minor change from the current API, and maybe closer to @flackr's original proposal. The differences:

  • start renamed prepare.
  • Promise returned by prepare fulfills when transition DOM is ready and can be animated with WAAPI.
  • Introduces transition.finished, which fulfills once the transition is complete. Maybe .done is a better name here, but animations use .finished.

@khushalsagar
Copy link
Collaborator

Is that reliable? Particularly as rAF can mean different things at different points in the event loop. Sometimes it means before next render, sometimes it's before the render after that.

That's a good question. I suppose if the promise returned by the callback passed to start resolves in the middle of a frame, so we've already dispatched rAF for it, then it means before the render after that.

The new proposal looks good. But a slight preference to change the API once we're wrapping up the OT.

@tabatkins
Copy link

This looks reasonable to me as well. (My initial read of the explainer had the promise resolving at your recommended point as well; Khushal brought up that it was wrong!)

Having a .finished promise sounds good, and finally leans us one way on the "singleton or constructor" question - we should have a constructor.

@jakearchibald
Copy link
Collaborator Author

jakearchibald commented Jun 20, 2022

@khushalsagar

But a slight preference to change the API once we're wrapping up the OT.

Fair enough! If we want to do it sooner, we could add .prepare & .finished but leave .start there until after the OT.

In fact, .start could be replaced with:

DocumentTransition.prototype.start = async function(...args) {
  await this.prepare(...args);
  await this.finished;
}

@vmpstr
Copy link
Collaborator

vmpstr commented Jun 20, 2022

I think that's a decent plan, we can add finished and prepare without removing start and make it clear in any documentation that start is deprecated / will be removed

@jakearchibald
Copy link
Collaborator Author

Latest spec fixes this

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants