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

Partytown support #176

Open
luisherranz opened this issue Feb 16, 2022 · 24 comments · Fixed by #556 · May be fixed by #1247
Open

Partytown support #176

luisherranz opened this issue Feb 16, 2022 · 24 comments · Fixed by #556 · May be fixed by #1247
Assignees
Labels
Needs Review Anything that requires code review [Type] Feature A new feature within an existing module

Comments

@luisherranz
Copy link
Member

Description

I'm opening this issue to discuss how WordPress could take advantage of Partytown to improve its performance.

What is Partytown?

Partytown is a library to execute scripts inside a Web Worker and off the main thread. Its main goal is to increase the site's performance freeing the main thread by offloading non-critical scripts to a Web Worker. It acts as a bridge between the Web Worker and the DOM in a way that is 100% transparent to the executed script.

How does Partytown work?

Scripts use the type "text/partytown" to avoid running in the main thread. Partytown loads those scripts inside a Web Worker that has a proxied version of all the DOM APIs. When the script access a DOM API, the proxy intercepts it and uses one of these two implementations:

  1. If Atomics are available, Partytown uses them to communicate synchronously between the main and worker thread.
  2. If they are not, Partytown uses synchronous XHR requests intercepted by a Service Worker.

If neither Atomics nor Service Workers are available, Partytown just runs the scripts in the main thread.

It's probably worth noting that when a script executed inside a Partytown Web Worker adds a new script (using APIs like document.createElement('script')), that script is also added inside of the Web Worker and not leaked to the main thread.

More information about how it works in their official docs.

Partytown tradeoffs

  1. DOM operations are slower (and even throttled to reduce work in the main thread), so it should not be used for intensive UI scripts.
  2. Partytown fetches all the scripts using fetch(), so they need to have CORS headers (or they need to use a proxy).
  3. Events handled by scripts that call event.preventDefault() will have no effect.

More info about the tradeoffs in their official docs.

Restricted access to DOM APIs

Because scripts executed with Partytown are sandboxed and it controls the bridge, site owners can increase the security/control over those scripts by allowing or denying access to the DOM APIs on a per-API basis.

I don't think Partytown has an API to control this yet, but they have mentioned it several times.

Partytown Status

Partytown is still a young project. It moved from Alpha to Beta on 5th Jan 2022.

Goals

  1. Allow plugin developers to execute scripts inside a Partytown Web Worker.
  2. Allow site admins to select which scripts they want to execute inside a Partytown Web Worker.

Proposals

1. Add a worker-partytown strategy on wp_enqueue_script

Following @adamsilverstein proposal of a strategy parameter on wp_enqueue_script (#168), plugin developers could simply opt-in to execute any script in a Partytown Web Worker by using the worker-partytown strategy.

wp_enqueue_script(
  'non-critical-script',
  plugins_url( 'non-critical-script.js', __FILE__ ),
  array(),
  '1.0.0',
  'worker-partytown'
);

There could be other worker strategies as well, so I'd suggest using worker-partytown for this one. For example worker-dom for WorkerDOM or simply worker for a regular Web Worker.

With this API, plugins could start offering the Web Worker option to their users:

Web Worker option in plugins

We could expose a filter to allow plugins to configure Partytown:

function my_plugin_partytown_config( $config ) {
  $config["debug"] = true;
  return $config;
}
add_filter( 'partytown_configuration', 'my_plugin_partytown_config' );
<script>
  partytown = {
    debug: true,
  };
</script>

2. Partytown module/plugin

Create a module that exposes a user interface to let the site admins configure which services they want to execute inside a Partytown Web Worker.

We could add integrations one by one, making sure Partytown supports those services. If necessary, it should also take care of configuring the forwarded events.

Integrations could use regular expressions to find the scripts in the HTML and add the type="text/partytown" attribute to the script tag. For example, identify scripts with https://www.google-analytics.com/analytics.js and/or ga(...) for Google Analytics.

<!-- Loaded in Partytown Web Worker -->
<script type="text/partytown">
  (function (i, s, o, g, r, a, m) {
    /* ... */
  })(
    window,
    document,
    "script",
    "https://www.google-analytics.com/analytics.js",
    "ga"
  );
  ga("create", "", "auto");
  ga("send", "pageview");
</script>

If this module is successful, we could export its functionality to a Partytown plugin.

Service Worker integration

We would probably want to integrate it with the PWA plugin and only add the Service Worker directly if the PWA plugin is not present.

@eclarke1
Copy link

@aristath @sgomes I have added this new issue to the [JavaScript] focus area, but please do let me know if this is not accurate. Added to Backlog for prioritisation.

@eclarke1 eclarke1 added [Focus] JavaScript [Type] Feature A new feature within an existing module and removed [Focus] JavaScript labels Feb 18, 2022
@eclarke1 eclarke1 added this to Backlog in [Focus] JS & CSS via automation Feb 18, 2022
@adamsilverstein
Copy link
Member

Thanks for this proposal @luisherranz... cc: @westonruter who maintains the PWA plugin

@thelovekesh
Copy link
Member

@luisherranz I would like to take this one. Can you please assign it to me?
cc: @westonruter

@luisherranz
Copy link
Member Author

luisherranz commented Mar 17, 2022

Hey @thelovekesh, great to hear that 🙂

I don't have permission to add assignees, but Weston or someone else will do it.

What approach are you going to follow?

@thelovekesh
Copy link
Member

Sorry for the late reply @luisherranz.

I was working around an approach to show users an option, to enable Execute third-party scripts in Worker thread .

Once it enables, enqueue the party town script in the head. Now idea is to append type="text/partytown" in such scripts which have partytown in deps array.

wp_enqueue_script(
  'non-critical-script',
  plugins_url( 'non-critical-script.js', __FILE__ ),
  array('partytown'),
  '1.0.0'
);

Expected output:

// Loaded in Partytown Web Worker
<script type="text/partytown" src="/wp-content/plugins/labs/non-critical-script.js?ver=1.0.0"></script>

But appending the type attribute based on script dependency will be the best approach?


We could expose a filter to allow plugins to configure Partytown:

Related to exposing a filter to configure partytown, I agree with the approach suggested above 👍🏼

@thelovekesh
Copy link
Member

thelovekesh commented Mar 22, 2022

I have created a POC for testing this functionality.
Partytown Plugin - https://github.com/rtCamp/wp-partytown

Steps to use these plugins:

  • Install the first plugin and enable partytown support from Settings->Partytown page.
  • Plugin also has some examples to test it out. Simply un-comment example files paths in the main plugin file.
require_once plugin_dir_path( __FILE__ ) . 'examples/counter.php';
require_once plugin_dir_path( __FILE__ ) . 'examples/get-request.php';
require_once plugin_dir_path( __FILE__ ) . 'examples/post-request.php';
1.mp4

I have used the approach discussed in #176 (comment)

@eclarke1 eclarke1 moved this from Backlog to In progress in [Focus] JS & CSS Mar 22, 2022
@luisherranz
Copy link
Member Author

Wow! That's awesome Lovekesh. I've just tested and it works great 😄 👏


But appending the type attribute based on script dependency will be the best approach?

I don't know, to be honest. @adamsilverstein, what do you think? What alternatives do we have? (until we have something like #168).


@thelovekesh: Will you be willing to submit a PR to add it as a module so it can be tested by all the users of this plugin? That way it's also easier for other members of the Performance Team to contribute to the code 🙂

@thelovekesh
Copy link
Member

Wow! That's awesome Lovekesh. I've just tested and it works great smile clap

Thank you @luisherranz ! Glad you liked it.

Will you be willing to submit a PR to add it as a module so it can be tested by all the users of this plugin?

Of course, I will raise the PR ASAP probably by Monday so that team can release it in upcoming version very soon.

@thelovekesh
Copy link
Member

@luisherranz I have raised the PR to add this as a module. Please have a look and let me know your thoughts.

@eclarke1 eclarke1 moved this from In progress to Review in [Focus] JS & CSS Mar 29, 2022
@eclarke1 eclarke1 added the Needs Review Anything that requires code review label Mar 29, 2022
@alessandrocarrera
Copy link

Hi @thelovekesh , awesome work! I tried locally and it works for the second and third test, but not for the first test (the only thats enqueue a script). When I click the button it not increment the counter. Furthermore, basing on the official doc (for the second and third tests), I see that the script changes in type="text/partytown-x" after the script runs but not in this case. With the second and third tests I see that the script type is always the same (before and after of the execution). Do you see a change of the script type after execute the script? Thank you again for your support 😊

@alessandrocarrera
Copy link

@thelovekesh I add that I tried it on a Wordpress clean installation (same theme of you and with only your plugin active). Thank you!

@erip2
Copy link

erip2 commented Sep 12, 2022

I tried it too and I have the same result as @alessandrocarrera.
Furthermore none of the scripts changed to type="text/partytown-x".

Is anything new about this and PR #271 ? :)

@bethanylang
Copy link
Contributor

Thanks for testing, @alessandrocarrera and @erip2!

@thelovekesh Are you able to take a look?

@thelovekesh
Copy link
Member

Hello @alessandrocarrera @erip2

If I am not mistaken, you have tried to work with the POC plugin . To enable partytown with that plugin you first have to allow partytown in the plugin's settings(Settings > Partytown > Enable PartyTown).

To avoid such confusions in future I will enable partytown setting in the POC plugin by default 👍🏼

image

@bethanylang I have tested and confirmed that functionally is fully working on both the POC plugin and raised PR.

@erip2
Copy link

erip2 commented Sep 15, 2022

I did enable this option.

@alessandrocarrera
Copy link

I did enable this option.

@thelovekesh me, too.

@thelovekesh
Copy link
Member

thelovekesh commented Sep 15, 2022

@erip2 @alessandrocarrera Can you try this on a fresh installation without the performance plugin? Also please check if it's enqueueing the partytown.js script with partytown handler.

Edit:
Just for convenience, I have added @wordpress/env for a quick local environment. All you need is to run npm install && npm run wp-env start

@erip2
Copy link

erip2 commented Sep 15, 2022

Trying in my theme, but now none of the examples work. Can confirm that the partytown.js is loaded.

The window.partytown returns:

{ "lib": "https://mytheme.test/app/plugins/wp-partytown-develop/includes/js/partytown/" }

I should note that I haven't installed the "Performance Lab" plugin.

Trying it in the plugin with @wordpress/env and the examples work. The counter example doesn't work on Firefox but works on Safari & Chrome.

@thelovekesh
Copy link
Member

@erip2 I think in your case either the service worker is not registered correctly or is unable to intercept dom events. You can find a similar issue here - BuilderIO/partytown#107

@luisherranz
Copy link
Member Author

Are you testing this with https?

@westonruter
Copy link
Member

westonruter commented Dec 1, 2022

I've just finished some research on the sandboxing capabilities of Partytown, which hadn't before been documented. I just blogged a writeup: Sandboxing with Partytown

@luisherranz
Copy link
Member Author

Very interesting, Weston. Thanks for sharing.

@Chiflaos
Copy link

Hello, I'm new to this and I'm trying to optimize WordPress with the Partytown plugin. I have installed and activated it in the settings, I can see it in the source code, but it has not been applied to third-party scripts and my performance numbers in PageSpeed are still the same.

@Mte90
Copy link

Mte90 commented Apr 2, 2023

I saw now this ticket but an year ago I did an experimental plugin that just enable all the js registered for partytown in wordpress https://github.com/CodeAtCode/wp-partytown

Probably the only thing to do is update the assets that aren't updated since a while. So maybe can be interesting to have a dedicated plugin as it is too much effort for the performance plugin (in a previous PR there was some doubt about that is a beta project etc)?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Needs Review Anything that requires code review [Type] Feature A new feature within an existing module