WordPress.org

Make WordPress Core

Opened 2 years ago

Last modified 35 hours ago

#36995 accepted feature request

Support for Service Workers

Reported by: bhubbard Owned by: westonruter
Milestone: Future Release Priority: normal
Severity: normal Version: trunk
Component: General Keywords: needs-patch
Focuses: javascript, administration, performance Cc:

Description

It might make sense into looking to offer a basic service worker for WordPress. It can start with something simple like caching files for wp-admin. Beyond that there are many ways it could be expanded:

  • Cache all scripts and styles for themes/plugins, possibly offering offline mode for sites
  • Possibly Notifications
  • etc

Useful links:

Change History (16)

#1 @bhubbard
2 years ago

  • Type changed from defect (bug) to feature request

#2 @bhubbard
2 years ago

  • Focuses javascript administration performance added

#3 @bhubbard
20 months ago

This project might be a good starting point: https://github.com/mozilla/wp-sw-manager

#4 @westonruter
4 months ago

In the case of the admin, I think a service worker cache could eliminate the need for load-scripts.php

This ticket was mentioned in Slack in #core-js by westonruter. View the logs.


4 months ago

#6 @westonruter
3 months ago

  • Milestone changed from Awaiting Review to Future Release

Incidentally, the WordPress admin used to use Google Gears to cache assets. Google Gears was killed in favor of service workers. So it makes a lot of sense to bring service workers back to fill the gap that Google Gears left.

#7 @westonruter
3 months ago

  • Keywords needs-patch added
  • Version changed from 4.6 to trunk

After a good conversation in #core-js I want to put forward a plan for adding service worker (SW) support in core. Before we can actually start leveraging service workers we need to first start supporting them. By support I mean core needs a framework for core, themes, and plugins to coordinate their respective SW needs (e.g. caching and push notifications). The key that highlights the need for this is the fact that two service workers cannot be installed and running at the same time (so). While eventually multiple service workers may be able to run concurrently in the same scope, the only other alternative I'm aware of is to require layering on a middleware library on top of the service worker. I don't think that core should require using a middleware.

So I'm proposing a lightweight framework for core to facilitate the registration of multiple service workers. Core can create the endpoint and when that endpoint is requested then core can respond with the concatenated service worker scripts. I think we can create an API that follows the same design of WP_Scripts family of scripts, with the key differences being:

  1. Scripts are registered with filesystem paths as opposed to URLs.
  2. Each script needs to indicate the service worker scope, the default being /.

So a function like this:

wp_register_service_worker( $handle, $path, $deps, $ver, $scope )

(The $ver is probably irrelevant here and could be removed since there is no need to cache-bust URLs.)

Here's a couple examples of calls:

wp_register_service_worker( 'foo-front', plugin_dir_path( __FILE__ ) . 'js/front-sw.js', array(), 'v1', '/' );
wp_register_service_worker( 'foo-admin', plugin_dir_path( __FILE__ ) . 'js/admin-sw.js', array(), 'v1', '/wp-admin/' );

At the wp_print_footer_scripts action a new function like wp_print_service_workers() can then run which loops over the registered service workers to get a set of all the scopes. Then given the registered service workers' scopes, the service workers can be installed via:

<script>
if ( navigator.serviceWorker ) {
        navigator.serviceWorker.register(
                <?php echo wp_json_encode( wp_get_service_worker_url( $scope ) ); ?>, 
                { scope: <?php echo wp_json_encode( $scope ); ?> }
        );
}
</script>

Here wp_get_service_worker_url( 'wp-admin' ) could return a URL like /wp-service-worker.js?scope=/wp-admin/, with that path being registered via WP_Rewrite. When the client then fetches this SW URL, this request would be served by WordPress PHP. The response would be handled by taking the requested scope and obtain all registered service workers with that scope and output their concatenated scripts in the order that their declared dependencies require.

The wp_register_service_worker() function would be a wrapper around WP_Service_Workers::add(), where WP_Service_Workers is a subclass of WP_Scripts.

Thoughts?

This ticket was mentioned in Slack in #core-js by westonruter. View the logs.


3 months ago

This ticket was mentioned in Slack in #core-js by aduth. View the logs.


3 months ago

#10 follow-up: @markjaquith
3 months ago

I like the idea of re-using WP_Scripts.

My main question is whether we think this will be rolled out to enough browsers (e.g. Mobile Safari doesn't have it yet) to be worth using before some support for multiple service workers is build into browsers. If we think multiple service worker support is years away (or not even going to happen), then it's smart to get ahead of this.

could return a URL like /wp-service-worker.js?scope=/wp-admin/, with that path being registered via WP_Rewrite

What about non-pretty permalinks?

#11 in reply to: ↑ 10 @westonruter
3 months ago

Replying to markjaquith:

My main question is whether we think this will be rolled out to enough browsers (e.g. Mobile Safari doesn't have it yet) to be worth using before some support for multiple service workers is build into browsers.

There's currently ~75% global browser support for service workers across Chrome and Firefox: https://caniuse.com/#feat=serviceworkers

I can see that support is currently being worked on in Safari and Edge: https://jakearchibald.github.io/isserviceworkerready/

If we think multiple service worker support is years away (or not even going to happen), then it's smart to get ahead of this.

Even if/when browsers support multiple service workers for a given scope it will still make sense to have a wp_register_service_worker() in the same way that it makes sense to have wp_register_script(): it provides a standard way to register a service worker script. This will then allow for the the service worker to be installed appropriately according to the target page, such as using amp-install-serviceworker in AMP HTML.

When/if multiple concurrent-scoped service workers are commonplace, then we can just remove the use of the script-concatenating endpoint and write out the script installation separately. That being said, this could be a good reason to use local filesystem URL as opposed to a filesystem path as that would allow us to eventually install the scripts directly. In other words, we could require assets be registered relative to the document root, just as \WP_Scripts::$default_dirs is used for concatenating for load-scripts.php. If a non-relative path is supplied, the call to wp_register_service_worker() could trigger a _doing_it_wrong().

could return a URL like /wp-service-worker.js?scope=/wp-admin/, with that path being registered via WP_Rewrite

What about non-pretty permalinks?

Yes, if non-pretty permalinks are active then this could instead just be /?wp_service_worker=1&scope=/wp-admin/, similar to what happens when interacting with the REST API with pretty permalinks disabled. Using a pretty permalink wouldn't be necessary actually.

This ticket was mentioned in Slack in #core-js by aduth. View the logs.


3 months ago

This ticket was mentioned in Slack in #core-js by westonruter. View the logs.


3 months ago

#14 @westonruter
3 months ago

  • Owner set to westonruter
  • Status changed from new to accepted

#15 @westonruter
3 weeks ago

Service worker support has landed in Edge: https://blogs.windows.com/msedgedev/2018/04/30/edgehtml-17-april-2018-update/

It is now supported by the latest version of each major browser: https://jakearchibald.github.io/isserviceworkerready/

#16 @westonruter
36 hours ago

I've created a feature plugin repo for collaborating on this: https://github.com/xwp/pwa-wp

Last edited 35 hours ago by westonruter (previous) (diff)
Note: See TracTickets for help on using tickets.