-
Notifications
You must be signed in to change notification settings - Fork 305
[ Intl ] disable Intl functions in bootWordpress by default #2247
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
[ Intl ] disable Intl functions in bootWordpress by default #2247
Conversation
Two files were generated while I was testing my code :
Should I restore them ? This part takes the current
Do you have any suggestions on how and in which file I could test this new feature? |
That's good, they reflect the current Blueprint JSON schema based on TypeScript types. |
@@ -74,6 +74,7 @@ export type BlueprintDeclaration = { | |||
wp: string | 'latest'; | |||
}; | |||
features?: { | |||
icu?: 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.
Maybe intl
instead? The name relates to internationalization and a PHP extension, whereas icu
isn't that well known abbreviation.
packages/playground/blueprints/src/lib/compile.spec.ts may be a good candidate for adding a few more tests. That would test it with the Node.js Playground version. I don't imagine anything would be different in the browser, but if you'd rather test it with Chrome/Safari/Firefox, there's some Playwright tests in |
I managed to get the tests working in Firefox and WebKit:
Even though WebKit initially failed. Chromium failed with |
Rerunning the tests return an
That's odd. Oh no it means, I have to rerun the entire test suite I suppose ? |
No idea! Potentially yes :( |
It seems to pass for Firefox and WebKit, but without an explanation, it's unclear why it doesn't pass for Chromium. |
@mho22 we're storing playwright traces with test run reports, would that help? See the artifacts at: https://github.com/WordPress/wordpress-playground/actions/runs/15556615881?pr=2247 Alternatively, you might be able to run playwright locally and see where it fails. I assume manually following the steps just works since the test passes in the other two browsers? |
339a087
to
c6f41f6
Compare
I ran the isolated tests locally by running this command :
And I got these results :
Let's see if Github actions returns the same results. |
961f470
to
efcc53b
Compare
This is a complete mystery. I have no clue why This could possibly be a problem within |
a8593e2
to
75bda6f
Compare
I wonder if it's something specific to GitHub CI setup. Definitely weird! |
1e93a6d
to
181a93b
Compare
I commented the lines related to the ICU data file fetch in |
These lines are responsible of the empty body : const filePath = (await import('../../public/shared/icudt74l.js')).dataFilename;
const ICUData = await (await fetch(filePath)).arrayBuffer(); @bgrgicak @adamziel @brandonpayton Has this issue occurred in the past during CI tests? Have we observed any unusual behavior related to file imports or fetching? Edit : I am testing this approach const fileName = 'icudt74l.dat';
/* @vite-ignore */
const filePath = (
await import(new URL(`./shared/icudt74l.js`, import.meta.url).pathname)
).dataFilename;
const ICUData = await (await fetch(filePath)).arrayBuffer(); |
c8f92f0
to
fbb8697
Compare
I wonder if we're just running out of memory again and the tab is crashing 😢 I suppose we could disable this test in Chromium if we still have Firefox as a canary |
@mho22 We'll also need to disable Intl classes to address cases like this in WooCommerce – right now it generates a bunch of error logs: |
The use case I'm having issue with is on a private repo, so I need to create an isolated example for you. It might take me a couple of days. I'm currently focused on something else. |
@adamziel Disabling a "built-in" class is a bit more challenging since I couldn't find a direct way to do it. I believe the best approach would be to dynamically load the intl extension. I considered wrapping @bgrgicak No worries at all. |
@mho22 how about the disable_classes php.ini directive? |
@adamziel Unfortunately, I tested some code to verify that : import { PHP, setPhpIniEntries } from '@php-wasm/universal';
import { loadNodeRuntime } from '@php-wasm/node';
const script = `<?php
var_dump( class_exists( 'Collator' ) );
$collator = new Collator('en');
`;
const php = new PHP( await loadNodeRuntime( '8.4' ) );
await setPhpIniEntries( php, { disable_classes : 'Collator' } );
const result = await php.run( { code : script } );
console.log( result.text ); This will result in
And as you can see, |
Ah, snap. Gotcha! Let's wait for the dynamic extensions, then. |
@mho22 I created a isolated test where I load the latest version of the Playground Client and build the project with Vite. |
@bgrgicak Thanks for the update. Let me know if I can help you. |
Thanks, I just update Playground in the private repo and it works without any changes to vite.config.js. |
@mho22 I was finally able to recreate it. This repo will trigger the .dat error. I had to install the Blueprints package, which depends on |
@bgrgicak I'm sorry for the inconvenience. I currently can't reproduce the error locally when I run - "@wp-playground/blueprints": "^1.1.3",
+ "@wp-playground/blueprints": "file://../wordpress-playground/dist/packages/playground/blueprints", It works on my machine. I don't know, I am still investigating. I probably should add |
The published packages are different than the dist directory, eg they may have less files or additional package json entries |
You can use |
@bgrgicak Thank you! Let's try that and correct the issue. |
This is the error encountered by @bgrgicak :
I struggled to find the origin of it. But I finally found it and it seems And I couldn't find a way to customize the loader for So inevitably, I had to avoid the use of "import 'icudt74l.dat' anywhere in the code since esbuild doesn't support This led me to that solution : const fileName = 'icudt74l.dat';
- const filePath = (await import('../../public/shared/icudt74l.js')).dataFilename;
+ const filePath = new URL('../../@php-wasm/web/shared/icudt74l.dat', import.meta.url).toString();
const ICUData = await (await fetch(filePath)).arrayBuffer(); This means we only get the correct url of the file inside I previously used the same technique as for the |
I keep wondering if we could get it to work somehow, either with an esbuild plugin or by migrating to rollup. Vite uses esbuild and rollup behind the scenes after all. AFAIR the only reason we don't use vite for this was some nuance of the |
@mho22 would this plugin help? It seems to be processing dynamic https://github.com/adamziel/esbuild-url-dynamic-import |
I am not sure if you're talking about building it in php-wasm-node [ which uses ESbuild ] or php-wasm-web [ which uses Vite ]. But the current issue comes from
build: {
lib: {
// Could also be a dictionary or array of multiple entry points.
entry: 'src/index.ts',
name: 'php-wasm-web',
fileName: 'index',
formats: ['es', 'cjs'],
},
sourcemap: true,
rollupOptions: {
// Don't bundle the PHP loaders in the final build. See
// the preserve-php-loaders-imports plugin above.
external: [
/php_\d_\d.js$/,
/icudt74l.js$/,
...getExternalModules(),
],
},
}, You probably suggest to replace the Vite building with an Esbuild building to have more control on that import. And you are right, it builds it and resolves it with : icudata_default = new URL("icudata-1c8c6df5.dat", import.meta.url).href; No more 'import', which will solve the issue! I should try to make this work using Vite. |
Actually I got confused with which tool do we use for what. So many tools! I wish we could just use esbuild, but it doesn't do well with commonjs builds which is why Vite also ships rollup. And, after thinking about this more, I guess we do need an import in the built file because that is a library to be imported in other packages and needs a strong, statically analyzable tie between the script and the data file, which the import provides – the downstream build tools can be typically configured to treat the imported .dat file as an asset. |
Okay, I'm completely lost in what the problem is. Is it with build? Is it with running from source? Is it in a downstream build? |
Sorry for the delay. I had to make sure I tested everything before replying. The problem comes from a downstream build. Currently, the
const filePath = (await import('../../public/shared/icudt74l.js')).dataFilename;
const ICUData = await (await fetch(filePath)).arrayBuffer(); it imports the
import dataFilename from './icudt74l.dat';
export { dataFilename }; it exports the path of the file in We also have the vite plugin : {
name: 'preserve-data-loaders-imports',
resolveDynamicImport(specifier): string | void {
if (
command === 'build' &&
typeof specifier === 'string' &&
specifier.match(/icudt74l\.js$/)
) {
/**
* The ../ is weird but necessary to make the final build say
* import("./shared/icudt74l.js")
* and not
* import("shared/icudt74l.js")
*
* The slice(-2) will ensure the 'public/`
* portion is removed.
*/
return '../' + specifier.split('/').slice(-2).join('/');
}
},
}, That will modify the dynamic import path to match the built correct path, while the unbuilt path is already correct. So the source is ok, because intl tests pass. And the build is ok since it doesn't fail to build. But. When I make a simple side project with
{
"type" : "module",
"dependencies" : {
"@php-wasm/universal" : "^1.1.4",
"@php-wasm/web" : "^1.1.4",
"vite" : "^6.2.5"
},
"scripts" : {
"dev" : "vite"
}
}
And run
And this is, to my understanding, because, by default, Vite (via esbuild) tries to statically analyze and bundle all imports, even in
and has no loader for I found solutions by not using the
And since we use Vite to build |
Good investigation @mho22, thank you! Let's move this to a separate issue for posterity, I feel we'll keep bumping into this and we could use a single source of context. This may also be a good opportunity to create a canonical solution for isomorphic loading of static assets across the board. |
Also, I know we're spending a lot of time here and I just want to acknowledge this is actually not an easy problem. Here's the list of scenarios we need to support:
Let's acknowledge all of them in the new issue and consider them in the discussion. |
Thanks! I'll fill in the issue with a summarized block of our comments. |
Motivation for the change, related issues
The presence of the
Intl
extension is detected by checking if functions exist in web mode, even whenwithICU
is set to false or not set at all.Since
withICU
is set to false by default, the related functions should be disabled.This is a first and temporary attempt, as
intl
is currently static. The best approach would be to generate a dynamicintl
extension and load it at runtime, if necessary.Implementation details
Alongside
withNetworking
ornetworking
, addwithICU
andicu
in types and function parameters. SetwithICU
to false by default and load a comprehensive list ofintl
functions to disable ifwithICU
is set to false.To improve readability and maintainability, the list of disabled functions is separated into a dedicated file.
Testing Instructions (or ideally a Blueprint)
Tests are provided in
packages/playground/website/playwright/e2e/blueprints.spec.ts