-
Notifications
You must be signed in to change notification settings - Fork 98
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
Bring back "Turbo" mode to Admin #42
Conversation
} | ||
|
||
// @todo This will cache both min.js and .js, however, not all the files have .min.js. Is it OK to cache all the files? | ||
$routes[] = strstr( $filename, '/wp-includes' ); |
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.
Should we try to precache only the files which are visibly minified (ending with .min.js
) or don't have a minified version separated?
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.
If there are two versions of a given URL, cache the min version. Otherwise, if there is no min version then cache the regular.
For example, jQuery is bundled with core and it is pre-minified so there is no minified version. The jquery-migrate
script, however, does have a minified version:
Basically look for the presence of the $suffix
variable in the registered URLs.
); | ||
|
||
if ( SCRIPT_DEBUG || is_preview() ) { | ||
$this->register_cached_route( '/(wp-admin|wp-includes)/.*\.(?:js|css)/', self::STRATEGY_NETWORK_ONLY ); |
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.
This is missing a regex
flag?
array() | ||
); | ||
|
||
if ( SCRIPT_DEBUG || is_preview() ) { |
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.
Why is_preview()
? How will this ever return true
given that it is the service worker response?
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.
Right💡 Will remove.
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.
Hmm, actually, at this moment init
is called on any page if any route caching is registered, not only when serving the request of the registered service worker.
} | ||
|
||
// @todo This will cache both min.js and .js, however, not all the files have .min.js. Is it OK to cache all the files? | ||
$routes[] = strstr( $filename, '/wp-includes' ); |
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.
If there are two versions of a given URL, cache the min version. Otherwise, if there is no min version then cache the regular.
For example, jQuery is bundled with core and it is pre-minified so there is no minified version. The jquery-migrate
script, however, does have a minified version:
Basically look for the presence of the $suffix
variable in the registered URLs.
); | ||
|
||
if ( SCRIPT_DEBUG || is_preview() ) { | ||
$this->register_cached_route( '/(wp-admin|wp-includes)/.*\.(?:js|css)/', self::STRATEGY_NETWORK_ONLY ); |
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.
Is this pattern missing image extensions?
/** | ||
* Initialize the class. | ||
*/ | ||
public function init() { | ||
|
||
if ( ! function_exists( 'list_files' ) ) { |
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.
The list_files()
function is slow. What about instead just iterating over of the registered scripts and styles in wp_scripts()
and wp_styles()
? Use the ver
with each registered asset as the revision.
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.
What about the images? Do you think we should list them out one by one instead of getting dynamically? If I'm not mistaken that's how it was in the Turbo mode. Thoughts?
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.
Changed the logic to use wp_scripts()
and wp_styles()
, left in the list_files()
for images for now within 024eab3.
return; | ||
} | ||
|
||
$this->register_cached_route( $routes, self::STRATEGY_PRECACHE ); |
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.
It's going to be slow to as it is right now because it is going to fetch the file contents for all of the URLs to compute the hashes of each. Instead, we should use the current WordPress version as the revision, and get the list of files by looking at what is registered among default scripts and styles.
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.
Removed using md5
hash and added using WP version by default in case the revision is not set within 84258c0. This way the API users can set the revision but it'll default to WP version if missing. Do you think the WP version is okay to use as the general default?
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.
Yes. It's what WordPress uses as the default ver
as well:
); | ||
|
||
if ( SCRIPT_DEBUG ) { | ||
$this->register_cached_route( '/(wp-admin|wp-includes)/.*\.(?:js|css|gif|png|svg)/', self::STRATEGY_NETWORK_ONLY, array(), true ); |
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.
Come to think of it, should not this condition be removed entirely? If using networkOnly
then this is just passing through to the network and it would be better to just skip caching the route entirely. In other words, this if
could become:
if ( ! SCRIPT_DEBUG ) {
$this->precache_admin_assets();
}
$routes = array_merge( | ||
$this->get_routes_from_file_list( $admin_images, 'wp-admin' ), | ||
$this->get_routes_from_file_list( $inc_images, 'wp-includes' ), | ||
$this->get_admin_routes_from_dependency_list( wp_scripts()->registered ), |
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.
We should only include assets that are in the wp-admin
and wp-includes
directories. We should not include plugin-registered assets by default, I don't think. Or maybe we should. My concern is a plugin updated which doesn't define the ver
, and so when the plugin updates and a new version of the script is included, then the service worker will not update the cache.
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.
Sorry, I see you're doing this already in get_admin_routes_from_dependency_list
!!
if ( false === strpos( $params->src, 'wp-admin' ) && false === strpos( $params->src, 'wp-includes' ) ) { | ||
continue; | ||
} | ||
$revision = false === $params->ver ? get_bloginfo( 'version' ) : $params->ver; |
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.
We could potentially opt-in to using the service worker for theme/plugin assets if we detect that the script is located within wp-content/themes
or wp-content/plugins
and then grab the version for the theme or plugin to use if the ver
is empty. Or even, the ver
could be combined with the version of the plugin to use as the revision.
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.
Maybe precaching theme/plugin assets could be something that could be opted in from admin UI as a setting instead of doing this by default? Thinking that precaching theme and plugin files could cause issues (as you mentioned above) if the version is not changed when updating the code (either in WP repo or directly in the environment). Feels like it's better to leave the asset precaching by default for the admin interface only, at least for now. Thoughts?
$routes = array(); | ||
foreach ( $list as $filename ) { | ||
$ext = pathinfo( $filename, PATHINFO_EXTENSION ); | ||
if ( ! in_array( $ext, array( 'png', 'gif', 'svg' ), true ) ) { |
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.
I was going to ask about JPEG but then I saw that there are no JPEGS in core. For reference, the static assets are (via git ls-files wp-includes/ wp-admin/ | sed 's/.*\.//' | sort | uniq -c | sort -nr
):
99 png
62 gif
51 css
10 scss
7 txt
6 svg
3 woff
3 ttf
3 eot
1 xml
1 crt
It doesn't make sense to include crt
, eot
, xml
, or scss
. But woff
would be very useful. Also, if this is used for themes then it would be good to include the JPEG extension(s).
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.
Thinking that maybe instead of using list_files
for getting the 3 woff
files we could list these out manually?
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.
Added the three .woff
files as a static list within 7132b74.
@@ -105,6 +105,15 @@ class WP_Service_Workers extends WP_Scripts { | |||
*/ | |||
public function init() { | |||
|
|||
// Only init if it's for the service worker. | |||
if ( ! isset( $_REQUEST['wp_service_worker'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.NoNonceVerification |
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.
Added this since if any of the API methods are used that init the WP_Service_Worker
such as wp_register_service_worker()
then the init logic will run on every page load instead of just when the service worker script is generated.
@westonruter Let me know if anything else seems to be missing from the PR, otherwise this should be ready for review (again). |
return; | ||
} | ||
|
||
do_action( 'admin_init' ); |
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.
This is an issue that I had when wanting to do_action('admin_enqueue_scripts')
for the admin as it is doing wp_enqueue_scripts()
for the frontend. This fails, however, when the user is not logged-in and thus the service worker would not be able to be installed at wp-login.php
, for example.
* @since 0.2 | ||
* @var int | ||
*/ | ||
protected $scope = WP_Service_Workers::SCOPE_ALL; |
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.
@felixarntz Note how this had to be added to the subclass to override the variable in the base class. Something doesn't seem quite right.
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.
@westonruter I think it makes sense to have integrations define their scope. However, the implementation I made may not be obvious enough. Currently, the default scope is SCOPE_FRONT
, via the property. So in order to change it to SCOPE_ADMIN
or SCOPE_ALL
you need to reset the property in the child class. Two ideas:
- It might make more sense to set the default scope to
SCOPE_ALL
. - Or alternatively, maybe it's better to not have any default scope, but instead make the
WP_Service_Worker_Base_Integration::get_scope()
method abstract, thus require each integration to explicitly define it. That would also make it obvious that you as the interface developer have to handle it.
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.
This can be removed, as it is no longer necessary after #72.
wp-includes/service-workers.php
Outdated
@@ -236,4 +236,14 @@ function wp_default_service_workers( $service_workers ) { | |||
); | |||
} | |||
} | |||
|
|||
add_action( 'wp_admin_service_worker', array( $service_workers, 'precache_admin_assets' ), 9 ); |
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.
@felixarntz With the change to WP_Service_Worker_Scripts_Integration
and WP_Service_Worker_Styles_Integration
to add them to both the front and admin scopes, then the integration will run at wp_admin_service_worker
priority 10:
This means that in order to set the precache
flags on admin-specific scripts and styles that the flag has to be set at priority 9 of thewp_admin_service_worker
action. Something is missing here.
wp-includes/default-filters.php
Outdated
@@ -18,3 +18,8 @@ | |||
add_action( 'wp_head', 'wp_add_error_template_no_robots' ); | |||
add_action( 'error_head', 'wp_add_error_template_no_robots' ); | |||
add_action( 'wp_default_service_workers', 'wp_default_service_workers' ); | |||
|
|||
// Disable contactenation of scripts and styles on admin pages. | |||
foreach ( array( 'wp_default_styles', 'wp_print_scripts' ) as $filter ) { |
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.
I think this would be better done once at admin_init
instead.
/** | ||
* Disables concatenating scripts to leverage caching the assets via Service Worker instead. | ||
*/ | ||
function wp_disable_script_concatenation() { |
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.
Something we need to look into is what to do for users who don't have service workers available. In their case, we actually need to retain the concatenation functionality.
The only option that comes to mind is that when the promise returned by navigator.serviceWorker.register()
resolves:
diff --git a/wp-includes/service-workers.php b/wp-includes/service-workers.php
index 69a39fb..4d2029c 100644
--- a/wp-includes/service-workers.php
+++ b/wp-includes/service-workers.php
@@ -112,7 +112,9 @@ function wp_print_service_workers() {
navigator.serviceWorker.register(
<?php echo wp_json_encode( wp_get_service_worker_url( $name ) ); ?>,
<?php echo wp_json_encode( compact( 'scope' ) ); ?>
- );
+ ).then( function() {
+ document.cookie = 'wordpress_sw_installed=1; path=/; expires=Fri, 31 Dec 9999 23:59:59 GMT; secure; samesite=strict';
+ } );
<?php } ?>
} );
}
That we can set a cookie like wordpress_sw_installed
which can then be used to check for whether to proceed with concatenation.
So then in this wp_disable_script_concatenation
it can first check if isset( $_COOKIE['wordpress_sw_installed'] )
before proceeding.
Note that concatenation only applies in the admin, which entails that the user is authenticated, and no full-page caching is used. Thus there won't be concerns about reading the cookie since these pages won't be cached.
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.
@westonruter Thanks for bringing that issue out and also for the solution suggestion, good idea!
Added within ec569c4.
…talled successfully.
* @since 0.2 | ||
* @var int | ||
*/ | ||
protected $scope = WP_Service_Workers::SCOPE_ALL; |
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.
This can be removed, as it is no longer necessary after #72. The scripts and styles integrations are now already available in both scopes.
* @since 0.2 | ||
* @var int | ||
*/ | ||
protected $scope = WP_Service_Workers::SCOPE_ALL; |
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.
This can be removed, as it is no longer necessary after #72.
Only add precaching route if url exists.
* @global WP $wp | ||
* | ||
* @return int Scope. Either SCOPE_FRONT, SCOPE_ADMIN, or if neither then 0. | ||
* @todo We don't really need this. A simple call to is_admin() is all that is required. |
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.
@westonruter Not related to this specifically but a little bit related in terms of checking for self::QUERY_VAR
:
Should we only init
WP_Service_Worker_Scripts
if the self::QUERY_VAR
does exist? Otherwise wouldn't the scripts always be registered but only served if self::QUERY_VAR
is set? Wouldn't the scripts need to be registered only in case of serving the service worker? Thoughts?
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.
In order to test this, it is important to have the plugin installed on a WordPress build install where SCRIPT_DEBUG
is false.
We'll need to further refine this, especially in regards to being more selective about which assets we precache based on whether they will ever be used, or likely to be used.
Fixes #34.
Using Workbox API Prototype for caching the admin assets separately and replacing the usage of
load-scripts.php
andload-styles.php
.Screenshots of the PR in use:
Workbox log:
Network tab:
Output in the SW script: