-
Notifications
You must be signed in to change notification settings - Fork 263
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
Support installing WP as needed in Playground remote #1841
base: trunk
Are you sure you want to change the base?
Conversation
Getting this error when running
|
If anyone wants to take this while I'm AFK today, please feel free. Otherwise, I hope to finish this next week. |
I'm guessing the vite dev server error is related to this wordpress-playground/packages/playground/client/vite.config.ts Lines 25 to 30 in 0a4cd5f
and the fact that this PR introduces a direct dependency between the website package on a real export from |
This didn't help. But moving the |
680cd19
to
2e376d2
Compare
I just dug up this old PR I made and I felt there's some connection with this work. I don't have anything specific, I mostly mean this as a potential source of inspiration. Maybe it's completely unrelated. |
0a4cd5f
to
9ebeb51
Compare
@@ -188,6 +189,24 @@ export class PlaygroundWorkerEndpoint extends PHPWorker { | |||
} | |||
|
|||
try { | |||
if (shouldInstallWordPress === 'auto') { |
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.
How could we make this reusable for Playground CLI?
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.
How could we make this reusable for Playground CLI?
Both Playground remote and CLI leverage bootWordPress()
, but AFAICT, everything before that is custom setup for their individual context. I'll consider whether there is more we can share, but at the very least, we could implement the same logic for CLI.
The CLI's skipWordPressSetup
argument is a potential conflict and maybe could be deprecated in favor of a shouldInstallWordPress
argument. Or they could be complementary.
Thanks for drawing my attention to this.
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.
How could we make this reusable for Playground CLI?
Both Playground remote and CLI leverage
bootWordPress()
, but AFAICT, everything before that is custom setup for their individual context. I'll consider whether there is more we can share, but at the very least, we could implement the same logic for CLI.
I was thinking of saying the following:
To be able to implement this check in a way that works for both PHP and CLI, maybe such a feature should be moved into
bootWordPress()
. That way, we can write the check in PHP and...
But if we want to allow parallel downloads of PHP and WP resources in a web context, we need to check before PHP has been downloaded and loaded.
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 made a reusable looksLikePlaygroundDirectory()
function under @wp-playground/wordpress
. The relative nature of the fileExists()
predicate feels a little clunky, but I think this is workable for sharing the looks-like-playground-dir heuristic.
/**
* Check if the given directory handle directory is a Playground directory.
*
* @param fileExists Function A function that checks if a file exists relative to an assumed directory.
* @returns Promise<boolean> Whether the directory looks like a Playground directory.
*/
export async function looksLikePlaygroundDirectory(
fileExists: (relativePath: string) => Promise<boolean>
) {
const results = await Promise.all(
['wp-config.php', 'wp-content/database/.ht.sqlite'].map(fileExists)
);
return results.every(Boolean);
}
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.
There's something similar in wp-now, you may want to review their "WordPress mode". One assumption this implementation makes is that we're running on SQLite whereas Playground CLI supports MySQL, too
Note: The vite dev server error went away when pivoting away from |
I think this is ready for review. Question: |
"if-missing"? |
It would be nice to know whether WP was just installed or we are just "resuming", so that diff blueprint steps can be run accordingly. |
@ashfame oh, interesting. You're asking about the same problems we've solved for in the website app. See wordpress-playground/packages/playground/website/src/lib/state/redux/boot-site-client.ts Lines 97 to 113 in 6295aa2
For a moment I thought about exporting this entire function as a public API, but it's very website-specific after all. The conditional Blueprint execution, though, would be another useful addition to startPlaygroundWeb({
blueprint,
shouldRunBlueprint: 'when-installing-wordpress' | 'always' // naming tbd
}); ...with the default being |
* Whether to install WordPress. Value may be boolean or 'auto'. | ||
* If 'auto', WordPress will be installed if it is not already installed. | ||
*/ | ||
shouldInstallWordPress?: boolean | 'auto'; |
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.
How about this?
shouldInstallWordPress?: boolean | 'auto'; | |
shouldInstallWordPress?: boolean | 'if-not-installed'; |
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 like if-not-installed
better than auto
but is it really necessary to define a string default here? Can't we do a check against undefined
to infer "auto" behavior & prevent mixing of type?
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.
@ashfame which of these reads clearer to you?
const config = { shouldInstallWordPress: auto ? undefined : false; };
// or
const config = { shouldInstallWordPress: auto ? 'if-not-installed' : false; };
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.
Not sure I follow. What I meant was keeping shouldInstallWordPress?: boolean
as it is. When that property is explicitly specified, do what's being asked (Current behavior) and when not defined at all, just assume the "auto" behavior i.e. install if no WP files are found, otherwise let it be.
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.
Sure, that makes sense and sounds convenient for omitting the shouldInstallWordPress
option:
startPlaygroundWeb({
// shouldInstallWordPress is not here, which means we use the "auto" mode
});
I was just pointing out that it reads awkward when you want to explicitly declare the shouldInstallWordPress
key and need to explicitly type in undefined
as a value:
startPlaygroundWeb({
// This is not very informative:
shouldInstallWordPress: undefined
});
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.
Yep, a user should never have to explicitly pass undefined
. But I don't see why someone would have to do that with my suggestion? IF they need to specify it, they should know whether it's a true or false. And if they don't they should omit and let the default behavior take place, no?
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 not uncommon to define object literals like this:
startPlaygroundWeb({
shouldInstallWordPress: getUserPreference()
});
or like this:
startPlaygroundWeb({
shouldInstallWordPress
});
or like this:
startPlaygroundWeb({
shouldInstallWordPress: condition ? true : undefined
});
In which case the undefined
literal would show up somewhere.
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.
Sure! Implementation details aside, I think we are on the same page as to how it should behave, which is: Do as explicitly asked and figure out if we need to, as the default behavior. Thought I will reiterate it, in case this PR was waiting on me to close the loop of our conversation. cc: @brandonpayton
@adamziel This allows conveying, whether "always" or just on "first boot". Doesn't let a user specify blueprint for only post-installation boots. In simple terms, the user would want to specify two different blueprints - one for first boot and another for second boot onwards, right? Former never runs after running once and latter has no context to run prior or along with former. Also, I would like to avoid property coupling here. And since current behavior is to run the blueprint always with each boot. I think the safest (and also easiest/quickest) way would be to add another blueprint which is meant to be executed always, just not on first boot. Naming is hard, but something like This way, the intent its clear. Backwards compatibility is maintained and properties are not coupled. cc: @brandonpayton |
This seems to touch a deeper problem of distinguishing between the Blueprint steps (install these plugins) and the runtime configuration (use this PHP version). I'd love to separate these as we harmonize the boot across the webapp and the CLI. Then we could have a This still wouldn't solve for first-time Blueprints and subsequent Blueprints, though. Perhaps Blueprint could also be a callback, e.g. startPlaygroundWeb({
// This works:
blueprint: { "plugins": ["hello-dolly"] }
});
startPlaygroundWeb({
// This could also work:
blueprint: ({ isWordPressInstalled }) => {
return isWordPressInstalled ? initialBlueprint : subsequentBlueprint;
}
}); But actually I wanted to ask – what problem are we solving here with the initial/subsequent Blueprint execution? Is it about |
@adamziel While liberating a site, we would only realize the current site is an e-commerce store, post initial setup of playground as user express interest in liberating "products". At this point, we desire to run a bunch of steps (imagine installing woo commerce + some add-ons + config), which is why we would need that ability to specify yet another blueprint, preferably without even reloading the playground. So, I guess this requires both: decoupling running of blueprints from boot (ability to arbitrary invoke a blueprint) and running subsequent blueprints and not being limited to just the initial. I am not sure the overlap with what you call But then, should we call it something else other than blueprint? I don't think so. Here is how I think about it:
|
@adamziel @bgrgicak I just looked at this again and am wondering: Is there a reason we shouldn't just have Playground web client always auto-install WordPress if needed? Is there a case where we don't want WP to be installed even if it isn't present? If we're worried about making the wrong choice on behalf of users, we could look at strengthening our is-WP-installed checks. |
@ashfame what if Playground client exposed a @adamziel @bgrgicak what do you think of that possibility for a separate PR? |
I like this. Technically allowing JS API users to run Blueprint steps is similar to running Blueprints on existing sites, so this would be a good way for us to start that exploration. |
@brandonpayton Yep, being able to invoke a |
Sounds good to me. I'd just be careful with the client bundle size, bundling |
Good point! Thanks for word of the caution. |
Note: The awkward part to me is the typing. The I'm thinking about renaming the type export of |
Motivation for the change, related issues
Applications that integrate Playground do not have a good way of detecting whether a given Playground exists or has WordPress installed yet. Yet the
@wp-playground/client
'sstartPlaygroundWeb()
function will attempt to install WP into a Playground by default and will cause a Playground boot failure if WP is already installed.This PR expands
startPlaygroundWeb()
's booleanshouldInstallWordPress
argument to also support an "auto" value. WhenshouldInstallWordPress: "auto"
is specified, the Playground boot process will now attempt to detect whether there is an existing WP install and only install WP if needed.Related to:
WordPress/try-wordpress#44
WordPress/try-wordpress#62
cc @psrpinto @ashfame
Implementation details
This PR updates the worker thread to check each specified mount for the presence of expected WordPress+Playground files. If it finds the appearance of a Playground WP install, it skips downloading and installing WP, but if it finds nothing, it defaults to installing WP.
Testing Instructions (or ideally a Blueprint)
I ended up just testing this manually by:
npm run dev
shouldInstallWordPress
hardcoded here:false
, loading temporary sites will fail because WordPress wasn't installedtrue
, loading temp sites works, but loading saved sites doesn't because Playground errors while trying to overwrite existing WP source filesauto
, loading both temp sites and saved sites works.