Reading/Web/Projects/NewMobileWebsite/Technical overview

Introduction
This document intends to explain the technical approach to accomplish the requirements for the project outlined in the documentation. See the following sections for links to background information, goals and an overview of the proposal. At the end of the document you can find Frequently asked questions and a Glossary to answer and address common doubts that are not addressed anywhere else.

Background documentation
Project page on mediawiki.org/wiki/Reading/Web/Projects/NewMobileWebsite
 * Proposal
 * High-Level Functional Requirements
 * Roadmap Outline
 * Software projects
 * Phabricator board #marvin
 * Gerrit repository (marvin)

Goals
Goal of the project is to build a mobile website for Wikimedia projects with a focus on better handling poor connectivity scenarios and enabling possible offline reading experiences in the future.

More in detail, derived from the proposal:
 * 1) Optimizing for a modern browsing experience
 * 2) Client side connection management and offline resiliency. Remain functional with good UX and smooth transitions during short bursts of low connectivity or loss of network connection
 * 3) Data efficiency, for low end network connections
 * 4) Providing the ability to implement a fully offline reading experience in the future
 * 5) Inform decisions for other Wikimedia platforms/products in the future. For example:
 * 6) Encourage creation and design of more and better content APIs and services
 * 7) API driven frontends
 * 8) New performance patterns and front-end tooling
 * 9) Possibilities of evolution for the desktop website

Rendering and UI
In order to fulfill the Client side connection management and offline resiliency goal, the client side of the application in the browser needs to be able to render content and UI without relying on a server, since the user may interact with the UI without a network connection. On the other hand, only rendering on the client would mean a big loss of performance when loading the page for the first time, one of our most important use cases at the moment. To stay performant, a server side render is needed. On our current platform, we rely on JavaScript for rendering UIs and content in the client, and PHP for rendering UIs and content on the server.

Given we need to have rendering and UI code in both the client and the server, there are several options to consider in order to fulfill our objectives: We think that given the client rendering is going to need to be implemented for any features, we should focus on the second option. By coding the client rendering being aware that it needs to run in client and server environments from the start, we can avoid duplicating the render code twice in different languages. We can structure the client side render and UI code in a way that is environment agnostic, so that most of it is common (also called isomorphic or universal).
 * Duplicate the rendering code on the client
 * This entails keeping in sync two different full rendering paths, which seems to double the maintenance and new developments for rendering features, and a significant risk of becoming desynchronized, or diverging in terms of features, or UI differences
 * Write the client rendering code so that in can be used in the server rendering
 * The client side rendering path needs to exist for the offline goals. Given it needs to be implemented, if we could use that same render pipeline for the UIs and content in the server context, we could keep a single source of truth for the UI rendering, thus keeping the maintenance and new development cost from duplicating and being able to deliver our goals

As proposed, we will be setting a clean separation of responsibilities (routing, rendering, API fetching and state management) in the same language (JS) so that the pieces can be reused in the server and client rendering. Effectively meaning:
 * The website will be a server side rendered website, to serve very fast and minimal HTML with inlined critical CSS to provide content to the clients as fast as possible
 * The website will be enhanced as a web application in the client after the initial content has loaded, to provide the basic connection management features, and...
 * Install Service Workers where available in capable clients to provide advanced connection management features and (maybe in the future) full offline support and an installable website (also called, Progressive Web Apps)
 * As much of the client code as possible needs to be reused for the server rendering (UI renderers, data models and fetching, etc).

Related RFCs

 * T88301: RFC: Clean front-end - backend separation; make all front-ends API consumers

Content sources
Both the server and browser clients will rely on the same services (REST & action api) for content consumption and will be in charge of rendering the data. As much as possible, these services should be shared between platforms, like the MediaWiki desktop and mobile experiences, and the mobile apps. By sharing content sources we all benefit from the same improvements and avoid having to repeat the same efforts for each different platform.

This would allow us to more easily build modern browsing experiences and better UX. Some examples of UX experiences powered by services are Page previews (Desktop), Related articles (Mobile web), the Feed and modern article reading experience (Android and iOS native apps).

Some examples of UX experiences powered by services are Page previews (Desktop), Related articles (Mobile web), the Feed and modern article reading experience (Android and iOS native apps).

Architecture

 * Server
 * Node.js server
 * Reuses common code for:
 * UI layer (Router + Views)
 * Content rendering
 * API client layer (REST + MW API)
 * Client
 * Reuses common code for:
 * UI layer (Router + Views)
 * Content rendering
 * API client layer (REST + MW API)
 * Client caching (IndexedDB or browser caches)
 * Service worker layer
 * Common
 * Code capable of running on server and client environments

Page rendering, document composition and JSON / HTML APIs in the client
Because of the need to support the most used devices (given a big percentage doesn’t implement Service Workers and those devices probably won’t stop being used for years), right now we need to focus on implementing a solution that gives the best possible experience to both non-service-workers devices (iOS) and service-workers devices (Android). We don’t want to settle on only server-side composition on non-Service Worker devices. Modern iOS devices (for example) are capable and should be able to compose documents on the client too.

As such, initially, we lean towards consuming JSON APIs because JSON parsing is extremely optimized on all browsers, which is very important on mobile devices.

Special attention will be put into rendering the long form content streaming and as fast as possible into the document to be as performant as possible. In non-service-worker capable clients, there are approaches(iframe hack [1 ], streaming ND-JSON [2 ]) for getting content streamed into the window.

Using Service Workers for document composition on server and client
In the future, when most of the devices support Service Worker, we will explore performance optimizations for using HTML APIs instead and extracting metadata and content in an efficient way, streaming and composing documents on the fly using Service Workers both in client and server.

Learnings and use for future improvements to the desktop site
The project focuses on the mobile website given that it’s reduced scope and requirements make it feasible to improve it over a short-medium timespan (1-2 years). The choices and technology will inform future improvements for the desktop site, regarding API driven frontends, use of Service Workers technology, inlining critical CSS, using Parsoid content for reads, and other various topics. Hopefully, we can end up bringing the same sort of improvements adapted for the desktop web to also improve the experience.

What happens with MobileFrontend?
There is no specific plan at the moment, until this project advances and we know what it is good for and if it is successful. Once we know how this project is going, there are many things we can do. I’ll list a few in no particular order (and of course there are many other options):
 * Put it in maintenance mode, no new development will happen
 * Work on aggressively trimming Wikimedia specific parts, and give it to the community as the mobile experience for third party wikis
 * Refactor it to be the grade C experience for old browsers and Opera mini / UC browser removing all the JSÚ
 * Split out a Minerva skin and deprecate support for the MobileFormatter in favor of REST services/upstream changes to core (e.g. section wrapping in the parser)

Root domain and abstraction of language switching
Could we consider making the new website more “app-like” by abstracting away the project domains much like the iOS and Android apps? In this model, the new website would be hosted somewhere generic like: “ https://mobile.wikipedia.org/ ” or “ https://lite.wikipedia.org/ ”. And language switching would happen with a control (much like it does now in the website).

Related: Is a goal to provide a unified experience of all wikimedia projects? Only wikipedias?
Would we provide a single project app e.g. use the app to render content from all Wikimedia projects such as other languages/other projects e.g. wiktionary? This is a topic that needs discussion and exploration as the project evolves. Refer to the parent proposal for discussion.

Which APIs will be used from REST services and which from API.php
General guidelines of “when necessary and when it makes sense” apply. In consultation with the Reading teams (apps and services) and the Services team. Some general principles:
 * High volume read APIs will usually be consumed from the REST layer. Things like page content, page summary, etc.
 * Endpoints that may be needed that don’t exist right now (like page history for example) will have to be created.
 * PHP APIs ready for high volume consumption (like search) we may consume from the existing endpoint and only wrap around a REST service if it is needed and makes sense, and always as a shared effort across the Reading teams so that the API can be used for the different platforms.
 * Non-cacheable APIs like random we’ll consume from API.php.
 * In the specific case of random there is an ongoing effort to create smart random that the apps team were working on, in which case a caching strategy may be worked out and then we’d use the REST service.

How is this going to work with the editing experience?
We have met with the Editing department and discussed different options. Initially in the prototyping phases, we would use the existing mobile web editing experience, which gives the Editing team a stable target to aim at.

If the project advances successfully, when it starts getting out of prototype versions we’ll start collaborating in order to bring the mobile visual editing experience to this project. Given VisualEditor core is a standalone and portable piece of software, and that it has been integrated into different targets (desktop, flow, mobile incoming), ending up integrating it into the specifics of the project as a first class part of it would be the best final outcome and experience for users.

Glossary

 * PWA (Progressive Web App): a term used to denote web apps that uses the latest web technologies. Progressive web apps are technically regular web pages (or websites) but can appear to the user like traditional applications or (native) mobile applications.
 * Varnish: an HTTP accelerator.
 * Node.js: an open-source, cross-platform JavaScript run-time environment for executing JavaScript code server-side.
 * Action: Data representing an intent or an event that happened in the system and that may be of interest to the state and business logic of the application. Example action in mediawiki/extensions/Popups
 * Action creator: Function that given some arguments will perform side effects or trigger actions. Example action creator on mediawiki/extensions/Popups
 * State container: Part of the application that holds all the state of your application. It doesn't let you change that state directly, but instead forces you to describe changes as plain objects called "actions". Actions can be recorded and replayed later, so this makes state management predictable. With the same actions in the same order, you're going to end up in the same state.
 * Change listener: Event listener that is called when the application state changes with the previous and current state. It may then decide to perform side effects or call action creators.

Links

 * Notes from previous discussion with ArchCom 2017/03/15