From 8aed1207a6bb6a2c4ff8166eaf2ee80fcee1c8bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adam=20Zieli=C5=84ski?= Date: Mon, 8 Jul 2024 15:52:14 +0200 Subject: [PATCH] php-wasm/node: Ship as ESM and CJS (#1585) The `@php-wasm/node` package used to be CommonJS only. This created tricky dependency identity problems in ESM applications, e.g. in #1577 the main script imports the ESM version of `@php-wasm/universal`, but `@php-wasm/node` imports the CJS version of it. This PR ensures `@php-wasm/node` has an ESM version available. This is first step towards solving https://github.com/WordPress/wordpress-playground/issues/1583 Closes https://github.com/WordPress/wordpress-playground/issues/1579 Closes https://github.com/WordPress/wordpress-playground/issues/1577 ## Testing instructions Run `npm run build`, copy the built packages from `dist/packages/php-wasm` to node_modules in another directory, create a test.js script with the following contents: ``` import { PHP } from '@php-wasm/universal'; import { loadNodeRuntime, useHostFilesystem } from '@php-wasm/node'; const php = new PHP(await loadNodeRuntime('8.0')); console.log("Hey"); console.log(await php.run({ code: 'echo "Hello, World!";' })); ``` Then create a package.json file with `{"type":"module"}` and confirm that running test.js works. Then create test.cjs file as follows: ```js const { PHP } = require('@php-wasm/universal'); const { loadNodeRuntime } = require('@php-wasm/node'); async function main() { const runtimeId = await loadNodeRuntime('8.0'); console.log({runtimeId}) const php = new PHP(runtimeId); console.log(php); } main(); ``` And confirm this one works, too. --- packages/php-wasm/node/build.js | 97 +++++++++++++++++++++++++++++ packages/php-wasm/node/esbuild.js | 28 --------- packages/php-wasm/node/package.json | 11 +++- packages/php-wasm/node/project.json | 30 ++------- 4 files changed, 111 insertions(+), 55 deletions(-) create mode 100644 packages/php-wasm/node/build.js delete mode 100644 packages/php-wasm/node/esbuild.js diff --git a/packages/php-wasm/node/build.js b/packages/php-wasm/node/build.js new file mode 100644 index 0000000000..4a6a52bac3 --- /dev/null +++ b/packages/php-wasm/node/build.js @@ -0,0 +1,97 @@ +import esbuild from 'esbuild'; +import fs from 'fs'; +import path from 'path'; + +try { + fs.mkdirSync('dist/packages/php-wasm/node', { recursive: true }); +} catch (e) { + // Ignore +} + +async function build() { + await esbuild.build({ + entryPoints: [ + 'packages/php-wasm/node/src/index.ts', + 'packages/php-wasm/node/src/noop.ts', + ], + supported: { + 'dynamic-import': false, + }, + outExtension: { '.js': '.cjs' }, + outdir: 'dist/packages/php-wasm/node', + platform: 'node', + assetNames: '[name]', + chunkNames: '[name]', + logOverride: { + 'commonjs-variable-in-esm': 'silent', + }, + format: 'cjs', + bundle: true, + tsconfig: 'packages/php-wasm/node/tsconfig.json', + external: ['@php-wasm/*', '@wp-playground/*', 'ws'], + loader: { + '.php': 'text', + '.ini': 'file', + '.wasm': 'file', + }, + }); + + const nodeModules = new RegExp(/^(?:.*[\\/])?node_modules(?:[\\/].*)?$/); + await esbuild.build({ + entryPoints: [ + 'packages/php-wasm/node/src/index.ts', + 'packages/php-wasm/node/src/noop.ts', + ], + banner: { + js: "import { createRequire as topLevelCreateRequire } from 'module';\n const require = topLevelCreateRequire(import.meta.url);", + }, + plugins: [ + { + name: 'Support __dirname in ESM', + setup(build) { + build.onLoad({ filter: /.*/ }, ({ path: filePath }) => { + if (!filePath.match(nodeModules)) { + let contents = fs.readFileSync(filePath, 'utf8'); + const loader = path.extname(filePath).substring(1); + const dirname = path.dirname(filePath); + contents = contents + .replaceAll('__dirname', `"${dirname}"`) + .replaceAll('__filename', `"${filePath}"`); + return { + contents, + loader, + }; + } + }); + }, + }, + ], + outdir: 'dist/packages/php-wasm/node', + platform: 'node', + assetNames: '[name]', + chunkNames: '[name]', + logOverride: { + 'commonjs-variable-in-esm': 'silent', + }, + packages: 'external', + bundle: true, + tsconfig: 'packages/php-wasm/node/tsconfig.json', + external: ['@php-wasm/*', '@wp-playground/*', 'ws', 'fs', 'path'], + supported: { + 'dynamic-import': true, + 'top-level-await': true, + }, + format: 'esm', + loader: { + '.php': 'text', + '.ini': 'file', + '.wasm': 'file', + }, + }); + + fs.copyFileSync( + 'packages/php-wasm/node/README.md', + 'dist/packages/php-wasm/node/README.md' + ); +} +build(); diff --git a/packages/php-wasm/node/esbuild.js b/packages/php-wasm/node/esbuild.js deleted file mode 100644 index e9f434368e..0000000000 --- a/packages/php-wasm/node/esbuild.js +++ /dev/null @@ -1,28 +0,0 @@ -const esbuild = require('esbuild'); - -module.exports = { - entryPoints: [ - 'packages/php-wasm/node/src/index.ts', - 'packages/php-wasm/node/src/noop.ts', - ], - supported: { - 'dynamic-import': false, - }, - format: 'cjs', - outExtension: { '.js': '.cjs' }, - outdir: 'dist/packages/php-wasm/node', - platform: 'node', - assetNames: '[name]', - chunkNames: '[name]', - logOverride: { - 'commonjs-variable-in-esm': 'silent', - }, - bundle: true, - tsconfig: 'packages/php-wasm/node/tsconfig.json', - external: ['@php-wasm/*', '@wp-playground/*', 'ws'], - loader: { - '.php': 'text', - '.ini': 'file', - '.wasm': 'file', - }, -}; diff --git a/packages/php-wasm/node/package.json b/packages/php-wasm/node/package.json index 1465a784cf..63ec8d8025 100644 --- a/packages/php-wasm/node/package.json +++ b/packages/php-wasm/node/package.json @@ -15,6 +15,16 @@ "url": "https://github.com/adamziel" } ], + "exports": { + ".": { + "import": "./index.js", + "require": "./index.cjs" + }, + "./package.json": "./package.json" + }, + "type": "module", + "main": "./index.cjs", + "module": "./index.js", "typedoc": { "entryPoint": "./src/index.ts", "readmeFile": "./README.md", @@ -26,7 +36,6 @@ "directory": "../../../dist/packages/php-wasm/node" }, "license": "GPL-2.0-or-later", - "main": "index.cjs", "types": "index.d.ts", "gitHead": "2f8d8f3cea548fbd75111e8659a92f601cddc593", "engines": { diff --git a/packages/php-wasm/node/project.json b/packages/php-wasm/node/project.json index 7f8cad4f8b..66b7c712c3 100644 --- a/packages/php-wasm/node/project.json +++ b/packages/php-wasm/node/project.json @@ -51,33 +51,11 @@ }, "build:bundle": { "executor": "@nx/esbuild:esbuild", - "outputs": ["{options.outputPath}"], - "defaultConfiguration": "production", + "outputs": ["dist/packages/php-wasm/node"], + "executor": "nx:run-commands", "options": { - "main": "packages/php-wasm/node/src/index.ts", - "outputPath": "dist/packages/php-wasm/node", - "additionalEntryPoints": ["packages/php-wasm/node/src/noop.ts"], - "tsConfig": "packages/php-wasm/node/tsconfig.lib.json", - "project": "packages/php-wasm/node/package.json", - "assets": [ - { - "glob": "packages/php-wasm/node/README.md", - "input": ".", - "output": "." - } - ], - "bundle": true, - "format": ["cjs"], - "esbuildConfig": "packages/php-wasm/node/esbuild.js", - "thirdParty": true - }, - "configurations": { - "development": { - "minify": false - }, - "production": { - "minify": false - } + "command": "node packages/php-wasm/node/build.js", + "parallel": false } }, "recompile-php": {