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

Local Environment: Replace custom setup logic with a Blueprints-based setup #9

Open
adamziel opened this issue May 23, 2023 · 4 comments
Labels
Enhancement New feature or request wp-now

Comments

@adamziel
Copy link
Collaborator

wp-now implements:

  • Downloading and extracting zip files
  • Download parallelization
  • Using the requested PHP / WordPress version via CLI options
  • Aims to have a JSON config at some point

These are Blueprints features. There's no need to re-implement them from scratch. Let's use and contribute to a common standard that other Playground projects will immediately benefit from.

For example, wp-now: download wordpress and sqlite in parallel wouldn't be needed if the assets were downloaded through a Blueprint.

cc @sejas @danielbachhuber @wojtekn @katinthehatsite

@adamziel adamziel added Enhancement New feature or request wp-now labels May 23, 2023
@adamziel adamziel changed the title Local Environment: Use Blueprints for setup Local Environment: Setup with Blueprints (instead of rebuilding features Blueprints already provide) May 23, 2023
@adamziel adamziel changed the title Local Environment: Setup with Blueprints (instead of rebuilding features Blueprints already provide) Local Environment: Replace custom setup with a Blueprints-based setup May 23, 2023
@adamziel adamziel changed the title Local Environment: Replace custom setup with a Blueprints-based setup Local Environment: Replace custom setup logic with a Blueprints-based setup May 23, 2023
@danielbachhuber
Copy link
Member

How do Blueprints work?

@adamziel
Copy link
Collaborator Author

adamziel commented May 23, 2023

I wrote up this documentation last week: https://wordpress.github.io/wordpress-playground/docs/blueprints-api/index

In short, it's a declarative data format where you communicate all the steps needed to set up a WordPress instance, and then the executor finds the optimal way of running these steps. They work in the browser and in Node.js.

For now this means downloading files in parallel with a concurrency limit. In the future it will involve flattening and parallelizing entire steps.

This Blueprint, for example, downloads a plugin and a theme in parallel and then installs both:

{
    "steps": [
        {
            "step": "installPlugin",
            "pluginZipFile": {
                "resource": "wordpress.org/plugins",
                "slug": "coblocks"
            }
        },
        {
            "step": "installTheme",
            "pluginZipFile": {
                "resource": "wordpress.org/themes",
                "slug": "pendant"
            }
        }
    ]
}

This one resolves the PHP and WordPress version to use:

{
    "preferredVersions": {
        "php": "7.4",
        "wp": "5.9"
    }
}

^ Blueprints will be merge-able, which means I'll be able to take a Blog Blueprint and a Woo store Blueprint and create a Woo Blog that uses the right PHP and WordPress versions.

@adamziel
Copy link
Collaborator Author

An update on that last point: WordPress/blueprints#49

@JUVOJustin
Copy link

I love the concept and do think blueprints are an awesome approach. For my specific use case of using the playground as a wp-env replacement, it would be great to have a way to pass a path to a blueprint for my local project as an optional parameter to wp-now. Maybe something like wp-now start -b './blueprint.json'. Some more specific thoughts:

  • Ideally it would automatically use something like playground.blueprint.json by default and as fallback
  • Some data might be provided twice like the php version and the wp version since they can be provided as parameters. Some have to take precedence

This allows to easily prepare various blueprints for various tests inside my ci. To me, it seems like a nice adoption of the committable wp-env.json file.

I love the idea of not only sharing the exact same setup with other developer inside a repo, but also provide example data through php snippets and also use the same instance for ci tests. So many possibilities 🤯

johnhooks pushed a commit to johnhooks/playground-tools that referenced this issue Oct 11, 2024
…s#31)

## What problem does this PR solve?

Adds support for running WASM WordPress in multiple browser tabs and solves WordPress#9.

All WordPress requests are routed through a single service worker shared between all browser tabs. The request lifecycle looks as follows:

1. A request originates in a specific tab
2. A service worker intercepts it and requests the same tab to pass it to its WASM WordPress instance
3. The tab renders it and sends the response to the service worker
4. The service worker responds to the intercepted HTTP request using the WordPress-generated response
5. The original tab receives the WordPress-generated response and displays it to the user

It's a back-and-forth conversation between a specific browser tab and the service worker.

Unfortunately, Service workers communicate with tabs using a `BroadcastChannel` – it's a messaging strategy that routes every message to every listener. As a result, each WordPress request was rendered in every tab, often causing unexpected behaviors.

## How does this PR propose to solve it?

This PR introduces a concept of WordPress `scope` and enables the service worker to post BroadcastChannel messages scoped to specific listeners.

Scoping a WordPress instance means installing it at a unique pathname starting with `/scope:<unique number>`. For example:

* In an unscoped WordPress instance, `/wp-login.php` would be available at `http://localhost:8778/wp-login.php`
* In a scoped WordPress instance, `/wp-login.php` would be available at `http://localhost:8778/scope:96253/wp-login.php`

The scope number is a random and unique number generated by a specific browser tab. The service worker is aware of this concept and will use any `/scope:` found in the request URL to tag all the related `BroadcastChannel` communication. The WASM workers running in specific browser tabs will then ignore all the `BroadcastChannel` communication with an unfamiliar `scope` attached.

## Alternatives considered

* Using the `scope` feature of ServiceWorker – it led to multiple worker registrations and was hard to reason about.
* Loading Workers from a tab-specific unique URL, e.g. `sw.js?tab_id=432` or `sw-1.js` – it led to the same problems as relying on the `scope` feature.
* Match the request with its originating tab in the ServiceWorker – There's not enough information available. The worker can't figure out the top-level client ID from a request originating in an iframe, and the top-level client wouldn't be able to tell whether the request originated in its browsing context.
* Scoping WordPress instance by a domain, e.g. `w87953.localhost` – it  would require setting up a catch-all DNS domain to even use this project. That's a steep barrier of entry.
* Displaying an error in other browser tabs – it would be a large and unnecessary limitation.

## How to test?

Run `npm run dev` and open the WASM WordPress page in a few different browser tabs. Log in, create pages, play with it, and confirm that each tab behaves as expected. Specifically:

* No tab should unexpectedly log you in or out 
* No pages and changes should leak between the browser tabs

## Follow-up work

* If a use-case arises, a tab could use `sessionStorage` to preserve the scope across page reloads.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Enhancement New feature or request wp-now
Projects
None yet
Development

No branches or pull requests

3 participants