From 07b960027ef1f47f6099390c119a7bfb3577896c Mon Sep 17 00:00:00 2001 From: Matt Kilpatrick Date: Tue, 14 Jan 2025 12:52:35 -0500 Subject: [PATCH] feat: support Node 22 (#562) --- .github/workflows/build.yml | 2 +- .github/workflows/playwright.yml | 2 +- .github/workflows/unit_test.yml | 2 +- package.json | 4 ++-- packages/pages/.gitignore | 5 ++++- packages/pages/package.json | 4 ++-- packages/pages/src/bin/spawn.ts | 9 +++++---- packages/pages/src/common/src/loader/vite.ts | 13 ++++++++++++- .../tests/fixtures/src/functions/http/[param].ts | 6 ++---- 9 files changed, 30 insertions(+), 17 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e03cef823..8c9a6f5fe 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -16,7 +16,7 @@ jobs: working-directory: "./packages/${{ inputs.package }}" strategy: matrix: - node-version: [18.x, 20.x] + node-version: [18.x, 20.x, 22.x] steps: - name: "Checkout" uses: actions/checkout@v4.1.6 diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml index 4581348a4..f0637f6e5 100644 --- a/.github/workflows/playwright.yml +++ b/.github/workflows/playwright.yml @@ -12,7 +12,7 @@ jobs: fail-fast: false matrix: os: [windows-latest, ubuntu-latest, macos-latest] - node-version: [18.x, 20.x] + node-version: [18.x, 20.x, 22.x] runs-on: ${{ matrix.os }} steps: - name: "Checkout" diff --git a/.github/workflows/unit_test.yml b/.github/workflows/unit_test.yml index 5e46da625..d5fd605c9 100644 --- a/.github/workflows/unit_test.yml +++ b/.github/workflows/unit_test.yml @@ -16,7 +16,7 @@ jobs: working-directory: ./packages/${{ inputs.package }} strategy: matrix: - node-version: [18.x, 20.x] + node-version: [18.x, 20.x, 22.x] steps: - name: "Checkout" uses: actions/checkout@v4.1.6 diff --git a/package.json b/package.json index 114fe6a40..655ae03bb 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ "*.{ts,js,tsx,jsx}": "eslint --cache --fix" }, "engines": { - "node": "^18 || ^20.2.0" + "node": "^18 || ^20.2.0 || ^22" }, "repository": { "type": "git", @@ -75,4 +75,4 @@ } } } -} +} \ No newline at end of file diff --git a/packages/pages/.gitignore b/packages/pages/.gitignore index a69b80a75..0f39a19e3 100644 --- a/packages/pages/.gitignore +++ b/packages/pages/.gitignore @@ -1,3 +1,6 @@ .env tsdoc-metadata.json -docs/.vitepress/cache \ No newline at end of file +docs/.vitepress/cache + +# Output of 'pnpm pack' +*.tgz \ No newline at end of file diff --git a/packages/pages/package.json b/packages/pages/package.json index eb9631900..f2e819148 100644 --- a/packages/pages/package.json +++ b/packages/pages/package.json @@ -32,7 +32,7 @@ } }, "engines": { - "node": "^18 || ^20.2.0" + "node": "^18 || ^20.2.0 || ^22" }, "scripts": { "watch": "node src/bundler --watch", @@ -117,4 +117,4 @@ "react-dom": "^17.0.2 || ^18.2.0", "vite": "^4.3.0 || ^5.0.2" } -} +} \ No newline at end of file diff --git a/packages/pages/src/bin/spawn.ts b/packages/pages/src/bin/spawn.ts index 49b40c839..81e6ebb21 100644 --- a/packages/pages/src/bin/spawn.ts +++ b/packages/pages/src/bin/spawn.ts @@ -3,12 +3,12 @@ import { spawnSync } from "child_process"; import { fileURLToPath } from "url"; import process from "process"; import path from "path"; +import { pathToFileURL } from "node:url"; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); -const filePrefix = path.sep === path.win32.sep ? "file:\\\\" : ""; const pathToPagesScript = path.resolve(__dirname, "./pages.js"); -const pathToLoader = filePrefix + path.resolve(__dirname, "./loader.js"); +const pathToLoader = pathToFileURL(path.resolve(__dirname, "./loader.js")).href; const nodeVersion = Number( spawnSync("node", ["-v"], { encoding: "utf-8" }) @@ -20,8 +20,9 @@ const experimentalFlags = ["--experimental-vm-modules"]; if (nodeVersion === 18) { experimentalFlags.push("--experimental-specifier-resolution=node"); } else { - experimentalFlags.push("--experimental-loader"); - experimentalFlags.push(pathToLoader); + // Coercion to any is necessary because @types/node is not properly recognizing when dymanically importing + const { register }: any = await import("node:module"); + register(pathToLoader); } const results = spawnSync( diff --git a/packages/pages/src/common/src/loader/vite.ts b/packages/pages/src/common/src/loader/vite.ts index 50b283da3..a8b5dc12c 100644 --- a/packages/pages/src/common/src/loader/vite.ts +++ b/packages/pages/src/common/src/loader/vite.ts @@ -76,10 +76,21 @@ export const loadModules = async ( for (const modulePath of modulePaths) { importedModules.push({ path: modulePath, - module: await import(pathToFileURL(modulePath).toString()), + module: await import(pathToDecodedFileURL(modulePath)), }); } } return importedModules; }; + +/** + * Node 22 changed pathToFileUrl to automatically encode characters that are not valid in URLs, + * while earlier versions did not. This function decodes the file URL to match the behavior of + * earlier versions. + */ +const pathToDecodedFileURL = (path: string): string => { + const fileUrlString = pathToFileURL(path).toString(); + const decodedFileUrlString = decodeURI(fileUrlString); + return decodedFileUrlString.slice(7); // Remove "file://" +}; diff --git a/packages/pages/tests/fixtures/src/functions/http/[param].ts b/packages/pages/tests/fixtures/src/functions/http/[param].ts index aade445ea..58adf7445 100644 --- a/packages/pages/tests/fixtures/src/functions/http/[param].ts +++ b/packages/pages/tests/fixtures/src/functions/http/[param].ts @@ -1,8 +1,6 @@ -import { HttpFunctionArgument, HttpFunctionResponse } from "../../../../../src"; +import { PagesHttpRequest, PagesHttpResponse } from "../../../../../src"; -export default function helloWorld( - _: HttpFunctionArgument -): HttpFunctionResponse { +export default function helloWorld(_: PagesHttpRequest): PagesHttpResponse { return { body: "Hello World", headers: {},