RFC: API-driven web front-end
Open, NormalPublic

"Love" token, awarded by Milimetric."Mountain of Wealth" token, awarded by RandomDSdevel."Love" token, awarded by Renoirb."Like" token, awarded by Addshore."Like" token, awarded by Smalyshev."Love" token, awarded by Jhernandez."Like" token, awarded by fbstj.
Assigned To
Authored By
GWicke, Sep 5 2015


Problem statement

Our front-end and CDN architecture is facing formidable challenges. Close to 50% of our users are now using mobile devices in a wide range of specifications and form factors. Bandwidth conditions range from barely-connected 2G to gigabit fiber to the home. Use cases range from a quick definition look-up to immersive browsing with rich media and data-driven visualizations.

In response to the wide range of requirements, we have created a mobile site using MediaWiki's skin system, some content post-processing, and user agent based redirects. This site is now serving a sizeable chunk of our overall traffic, but it is ultimately still a fairly static server-side HTML skin. Its scaling relies on Varnish caching layers serving the vast majority of anonymous requests. These caching layers are fairly complex and inflexible. Significant customization of responses by user, device, or bandwidth conditions are typically not feasible without disabling edge caching altogether. This means that such customizations are currently limited to authenticated users, at the price of disabled caching and thus significantly higher request latencies.

Our native apps side-step a lot of these issues. They are pure API consumers, and perform most customizations in the client. This makes it a lot simpler to experiment with new ideas in the client, while still benefiting from caching of fairly static API responses. However, the vast majority of our users are using the web, and don't yet benefit from the same levels of performance and customization.

Proposed solution

This task proposes to leverage recent developments in the web platform to bring app-like levels of performance, customization and functionality to the general web experience.

New browser features like ServiceWorkers have recently made it feasible to apply the API-driven front-end strategy to the web, without incurring the complexities and performance penalties of traditional single-page applications. While some of these web platform features are fairly cutting edge (ex: ~61% support for ServiceWorkers), they are generally designed to work as progressive enhancements, with server-side fall-backs facilitated by the convergence of client-side and server-side technologies around JavaScript. By gradually moving the bulk of per-request customization to clients, we should be able to use freed-up server-side resources to provide the same level of customization for the long tail of older clients, at latencies comparable to or better than those seen by authenticated users right now.

Summary of potential benefits

  • Performance
    • Authenticated views aren't currently cacheable, which means that editors are getting worse performance than anonymous users. An API-driven front-end lets us cache general content separately from per-user data, which means that authenticated views can be fully cached, bringing performance on par with anonymous users.
    • Potentially reduce first-view-in-session latency for returning visitors by keeping offline copies of static assets.
    • Potential for full offline support.
    • Through improved caching, reduce load on the app server cluster from cache misses, reducing hardware needs and environmental impact.
    • Composition can be implemented efficiently as string concatenation, without a need for expensive DOM parsing and -manipulation.
    • Potential to initialize VE without re-loading content.
  • Architecture
    • Introduce a clean API separation between data and UI/UX layer. This will drive API and content / data representation improvements, reduce complexity in the data layer, and accelerate front-end innovation from WMF & others.
    • Reduce code and test duplication by using the same JavaScript code for client-side & server-side content composition.
    • Clean no-JavaScript fall-back to server-side rendering without code duplication.
    • Reduce complexity in caching layers by separating per-user from per-page data.
    • Avoid complexity and performance issues of single-page apps.
    • Allows gradual testing of Parsoid HTML for page views, possibly as a beta feature.
  • Design / product
    • Potential to support more user customization and dynamically updated content elements without incurring cache fragmentation and increased latency.
    • Quicker iteration on the client, using technology front-end engineers are familiar with.

Prototype in Q2

Services and Readers-Web-Backlog are currently prototyping a basic API-driven client-side skin using existing APIs and Parsoid HTML. The goal is to evaluate the feasibility and performance of this approach, to inform a discussion on the topic at the Developer Summit in early January.

Concrete steps:

See also

Related Objects

There are a very large number of changes, so older changes are hidden. Show Older Changes
GWicke updated the task description. (Show Details)Oct 21 2015, 3:38 AM

November 6, and this proposal doesn't seem to have much traction, it is not on track. Unless there is a sudden change, I will leave the ultimate decision of pre-scheduling it for the Wikimedia-Developer-Summit-2016 to @RobLa-WMF and the Architecture Committee.

bd808 updated the task description. (Show Details)Nov 18 2015, 10:14 PM
Smalyshev added a subscriber: Smalyshev.
jmadler added a subscriber: jmadler.Jan 9 2016, 1:28 AM
Majr added a subscriber: Majr.Jan 12 2016, 5:45 AM

Wikimedia Developer Summit 2016 ended two weeks ago. This task is still open. If the session in this task took place, please make sure 1) that the session Etherpad notes are linked from this task, 2) that followup tasks for any actions identified have been created and linked from this task, 3) to change the status of this task to "resolved". If this session did not take place, change the task status to "declined". If this task itself has become a well-defined action which is not finished yet, drag and drop this task into the "Work continues after Summit" column on the project workboard. Thank you for your help!

Agabi10 added a subscriber: Agabi10.Feb 7 2016, 8:46 PM
Qgil removed a subscriber: Qgil.Feb 11 2016, 12:37 PM

Discussed with @GWicke at Wikimania.

Building the service immediate for handling MediaWiki traffic is gonna be quite tricky since MediaWiki's skin system isn't ready for that right now.

  • Skin should be executable independent of global state. Ideally in a way that is able to share code with the Node service and/or in a way that can be exported through the API.
  • All hooks must be reduced to static conditions. (But sidebar links can still vary by page or user name, tabs may vary on page meta data and user permissions, etc.).
  • Need to be able to compile the skin layer down to a cacheable function (e.g. mustache template) that can be invoked with page and user data and produce the output - streamable.
  • Goal: With $wgUseFileCache enabled, the Skin layer should be cacheable independently of the page and applied at run-time. For deployments that use a CDN (e.g. Wikimedia with Varnish) one would use a separate service for the skin (the composition server from this RFC).
  • Benefits: 1) Response time for logged-in users comparable to that of logged-out users. 2) Skin updates apply in a unified way - at once. (Instead of gradually as different pages expire from the cache.)

I'd like to consider to first build a MVP for a non-MediaWiki use case (e.g. Wikipedia portal). We'll continue work on MediaWiki. Meanwhile, we can start making progress on the performance characteristics and implementation details of the composition server.

Krinkle renamed this task from [RFC] API-driven web front-end to RFC: API-driven web front-end.Jul 18 2016, 9:04 PM
Renoirb added a comment.EditedJul 19 2016, 5:01 AM

I had spent some thoughts about this problem space.

Things I had in mind (e.g. WebWorker, a null theme only basic HTML patterns, and an API view) had been outlined.

In an ideal system, we want to optimize cache opportunity, lower same resource representation variants, keep editing capability and allow customization.

Let's assume we have:

  1. The article body HTML is the same regardless of which type of Web Browser you're using.
  2. We create cookies only to a context root Set-Cookie: Foo=...; Path=/ui/partials; ...

Then we can

  1. Create HTML "partial" renderer (e.g. what parsoid does)
  2. Patch up view to a given context.
  3. Use the exact same HTML to everyone regardless if user is signed-in or not
  4. If user is signed in (i.e. has a cookie matching Path /ui/partials) we patch up user actions snippets into the DOM asynchronously.

To illustrate my thoughts, I've made this screen capture.

PS: Imagine it's Wikipedia instead of MDN, please.

Thought it would be useful here.

@Renoirb, what you describe is indeed pretty close to what we have in mind. We have a bit more per-user variance in the UI, mostly related to editing functionality. For example, tabs for page deletions or protection are only shown to admin users with the appropriate rights. We also want to support varying the UI by device and network conditions. We are especially interested in improving support for poor network connectivity or even offline use. Some of these changes would be difficult to pull off cleanly & with good performance by using DOM patch-ups only.

Thankfully, once a user is logged in using a modern browser, we can leverage a ServiceWorker to compose content client-side. We are currently prototyping a basic composition / templating layer with streaming support. Current work is building on elematch, but @Krinkle is also looking into supporting mustache syntax. This should give us performance data for server-side use, where we would like to run the same serviceworker code using a faux environment like https://github.com/gwicke/node-serviceworker.

Jdlrobson added a comment.EditedJul 26 2016, 7:11 PM

I should point out that given the mobile site currently supports a much smaller subset of functionality compared to desktop it might be a good place to iterate on some of the ideas here. Currently there is very little reason we need to vary cache for logged in users of the mobile site.

On the server side the UI only changes for logged in users in the following way:

  • talk link added
  • notification (echo) link added to top right
  • menu links / labels are different for logged in user (but all are rendered via JS - so this could easily be done at the JS level)

Viewing source of the mobile site, the main issues would be the following config variables shipped as inline js:

  • wgMinervaMenuData
  • wgUserName
Krinkle added a comment.EditedAug 3 2016, 8:12 PM

As of last week, @GWicke and I have started to meet on a weekly basis to track progress on one of the first sub items of this task: T106099: RFC: Page composition using service workers and server-side JS fall-back.

Quick summary:

  • We're working on a more detailed draft and spec for the composition server (no code yet).
  • We've begun coding some of the low-level libraries required for the server. Relating to transform streams, Mustache support, and the ability to run the same code in both a ServiceWorker client and in a Node.js service.

See T106099 for more details.

RandomDSdevel awarded a token.
GWicke updated the task description. (Show Details)Sep 9 2016, 4:53 PM
GWicke updated the task description. (Show Details)Sep 14 2016, 2:59 PM

A prototype service is now available at https://swproxy.wmflabs.org/wiki/Wikipedia. This is running unmodified ServiceWorker code in a server-side proxy environment equivalent to a Browser, and also installs the same ServiceWorker in modern clients. Resources are cached for offline use. See T106099 for the details.

  • clean Barack - 5.5s
  • w/ ServiceWorker, first load - 3s
  • w/ ServiceWorker subsequent load - 2s

Very nice!

Restricted Application added a project: Operations. · View Herald TranscriptSep 22 2016, 3:56 PM
BBlack moved this task from Triage to Watching on the Traffic board.Oct 4 2016, 12:43 PM
Krinkle removed Krinkle as the assignee of this task.Mar 8 2017, 12:22 AM
Nirmos added a subscriber: Nirmos.Jun 28 2017, 6:20 AM
GWicke moved this task from Backlog to designing on the Services board.Jul 12 2017, 7:27 PM
GWicke edited projects, added Services (designing); removed Services.
Krinkle moved this task from Limbo to External on the Performance-Team (Radar) board.