From 573cf24730f9ef0869cfd4fb939e0bcbee15a326 Mon Sep 17 00:00:00 2001 From: Matt Kane Date: Tue, 11 Oct 2022 14:47:27 +0100 Subject: [PATCH 01/18] feat: add wasm support --- demos/default/next.config.js | 9 +- demos/default/package.json | 1 + demos/default/pages/api/og.tsx | 29 ++ package-lock.json | 286 +++++++++++++++--- packages/runtime/src/helpers/edge.ts | 75 ++++- packages/runtime/src/templates/edge/bundle.js | 2 + .../runtime/src/templates/edge/runtime.ts | 11 +- 7 files changed, 353 insertions(+), 60 deletions(-) create mode 100644 demos/default/pages/api/og.tsx diff --git a/demos/default/next.config.js b/demos/default/next.config.js index 5321fa20b9..43ea089e48 100644 --- a/demos/default/next.config.js +++ b/demos/default/next.config.js @@ -8,6 +8,9 @@ module.exports = { defaultLocale: 'en', locales: ['en', 'es', 'fr'], }, + eslint: { + ignoreDuringBuilds: true, + }, async headers() { return [ { @@ -75,8 +78,8 @@ module.exports = { remotePatterns: [ { hostname: '*.imgur.com', - } - ] + }, + ], }, // https://nextjs.org/docs/basic-features/built-in-css-support#customizing-sass-options sassOptions: { @@ -84,5 +87,5 @@ module.exports = { }, experimental: { optimizeCss: false, - } + }, } diff --git a/demos/default/package.json b/demos/default/package.json index 3c93b24290..d6a18f82fe 100644 --- a/demos/default/package.json +++ b/demos/default/package.json @@ -20,6 +20,7 @@ "dependencies": { "@reach/dialog": "^0.16.2", "@reach/visually-hidden": "^0.16.0", + "@vercel/og": "^0.0.15", "next": "^12.3.0", "react": "^18.0.0", "react-dom": "^18.0.0" diff --git a/demos/default/pages/api/og.tsx b/demos/default/pages/api/og.tsx new file mode 100644 index 0000000000..8bd19ec51d --- /dev/null +++ b/demos/default/pages/api/og.tsx @@ -0,0 +1,29 @@ +import { ImageResponse } from '@vercel/og' + +export const config = { + runtime: 'experimental-edge', +} +export default function () { + return new ImageResponse( + ( +
+ Hello world! +
+ ), + { + width: 1200, + height: 600, + }, + ) +} diff --git a/package-lock.json b/package-lock.json index 8b82e4af09..ad9b2a60f8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -115,6 +115,7 @@ "dependencies": { "@reach/dialog": "^0.16.2", "@reach/visually-hidden": "^0.16.0", + "@vercel/og": "^0.0.15", "next": "^12.3.0", "react": "^18.0.0", "react-dom": "^18.0.0" @@ -5182,12 +5183,35 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@resvg/resvg-wasm": { + "version": "2.0.0-alpha.4", + "resolved": "https://registry.npmjs.org/@resvg/resvg-wasm/-/resvg-wasm-2.0.0-alpha.4.tgz", + "integrity": "sha512-pWIG9a/x1ky8gXKRhPH1OPKpHFoMN1ISLbJ+O+gPXQHIAKhNd5I28RlWf7q576hAOQA9JZTlo3p/M2uyLzJmmw==", + "engines": { + "node": ">= 10" + } + }, "node_modules/@rushstack/eslint-patch": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.1.3.tgz", "integrity": "sha512-WiBSI6JBIhC6LRIsB2Kwh8DsGTlbBU+mLRxJmAe3LjHTdkDpwIbEOZgoXBbZilk/vlfjK8i6nKRAvIRn1XaIMw==", "dev": true }, + "node_modules/@shuding/opentype.js": { + "version": "1.4.0-beta.0", + "resolved": "https://registry.npmjs.org/@shuding/opentype.js/-/opentype.js-1.4.0-beta.0.tgz", + "integrity": "sha512-3NgmNyH3l/Hv6EvsWJbsvpcpUba6R8IREQ83nH83cyakCw7uM1arZKNfHwv1Wz6jgqrF/j4x5ELvR6PnK9nTcA==", + "dependencies": { + "fflate": "^0.7.3", + "string.prototype.codepointat": "^0.2.1" + }, + "bin": { + "ot": "bin/ot" + }, + "engines": { + "node": ">= 8.0.0" + } + }, "node_modules/@sindresorhus/is": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-2.1.1.tgz", @@ -5557,13 +5581,13 @@ "version": "15.7.5", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==", - "devOptional": true + "dev": true }, "node_modules/@types/react": { "version": "17.0.50", "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.50.tgz", "integrity": "sha512-ZCBHzpDb5skMnc1zFXAXnL3l1FAdi+xZvwxK+PkglMmBrwjpp9nKaWuEvrGnSifCJmBFGxZOOFuwC6KH/s0NuA==", - "devOptional": true, + "dev": true, "dependencies": { "@types/prop-types": "*", "@types/scheduler": "*", @@ -5589,7 +5613,7 @@ "version": "0.16.2", "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==", - "devOptional": true + "dev": true }, "node_modules/@types/sinonjs__fake-timers": { "version": "8.1.1", @@ -5640,6 +5664,11 @@ "@types/node": "*" } }, + "node_modules/@types/yoga-layout": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/@types/yoga-layout/-/yoga-layout-1.9.2.tgz", + "integrity": "sha512-S9q47ByT2pPvD65IvrWp7qppVMpk9WGMbVq9wbWZOHg6tnXSD4vyhao6nOSBwwfDdV2p3Kx9evA9vI+XWTfDvw==" + }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "5.20.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.20.0.tgz", @@ -5988,6 +6017,19 @@ "resolved": "https://registry.npmjs.org/@vercel/node-bridge/-/node-bridge-2.2.2.tgz", "integrity": "sha512-haGBC8noyA5BfjCRXRH+VIkHCDVW5iD5UX24P2nOdilwUxI4qWsattS/co8QBGq64XsNLRAMdM5pQUE3zxkF9Q==" }, + "node_modules/@vercel/og": { + "version": "0.0.15", + "resolved": "https://registry.npmjs.org/@vercel/og/-/og-0.0.15.tgz", + "integrity": "sha512-AHa25M8Hxt+83aSAY+GPFYuE1oTNGzbw1sJZBa9AsYNUW6vmXPTGW9jJmOUnkjp2dp+wyY3gtAZRa26HjSeNSw==", + "dependencies": { + "@resvg/resvg-wasm": "2.0.0-alpha.4", + "satori": "0.0.38", + "yoga-wasm-web": "0.1.2" + }, + "engines": { + "node": ">=16" + } + }, "node_modules/abab": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", @@ -7317,6 +7359,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/camelize": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/camelize/-/camelize-1.0.0.tgz", + "integrity": "sha512-W2lPwkBkMZwFlPCXhIlYgxu+7gC/NUlCtdK652DAJ1JdgV0sTrvuPFshNPrFa1TY2JOkLhgdeEBplB4ezEa+xg==" + }, "node_modules/caniuse-lite": { "version": "1.0.30001402", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001402.tgz", @@ -9057,6 +9104,24 @@ "node": ">=8" } }, + "node_modules/css-background-parser": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/css-background-parser/-/css-background-parser-0.1.0.tgz", + "integrity": "sha512-2EZLisiZQ+7m4wwur/qiYJRniHX4K5Tc9w93MT3AS0WS1u5kaZ4FKXlOTBhOjc+CgEgPiGY+fX1yWD8UwpEqUA==" + }, + "node_modules/css-box-shadow": { + "version": "1.0.0-3", + "resolved": "https://registry.npmjs.org/css-box-shadow/-/css-box-shadow-1.0.0-3.tgz", + "integrity": "sha512-9jaqR6e7Ohds+aWwmhe6wILJ99xYQbfmK9QQB9CcMjDbTxPZjwEmUQpU91OG05Xgm8BahT5fW+svbsQGjS/zPg==" + }, + "node_modules/css-color-keywords": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/css-color-keywords/-/css-color-keywords-1.0.0.tgz", + "integrity": "sha512-FyyrDHZKEjXDpNJYvVsV960FiqQyXc/LlYmsxl2BcdMb2WPx0OGRVgTg55rPSyLSNMqP52R9r8geSp7apN3Ofg==", + "engines": { + "node": ">=4" + } + }, "node_modules/css-select": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", @@ -9073,6 +9138,16 @@ "url": "https://github.com/sponsors/fb55" } }, + "node_modules/css-to-react-native": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/css-to-react-native/-/css-to-react-native-3.0.0.tgz", + "integrity": "sha512-Ro1yETZA813eoyUp2GDBhG2j+YggidUmzO1/v9eYBKR2EHVEniE2MI/NqpTQ954BMpTPZFsGNPm46qFB9dpaPQ==", + "dependencies": { + "camelize": "^1.0.0", + "css-color-keywords": "^1.0.0", + "postcss-value-parser": "^4.0.2" + } + }, "node_modules/css-what": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", @@ -9118,7 +9193,7 @@ "version": "3.0.11", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.11.tgz", "integrity": "sha512-sa6P2wJ+CAbgyy4KFssIb/JNMLxFvKF1pCYCSXS8ZMuqZnMsrxqI2E5sPyoTpxoPU/gVZMzr2zjOfg8GIZOMsw==", - "devOptional": true + "dev": true }, "node_modules/custom-routes": { "resolved": "demos/custom-routes", @@ -11985,6 +12060,11 @@ "node": "^12.20 || >= 14.13" } }, + "node_modules/fflate": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.7.4.tgz", + "integrity": "sha512-5u2V/CDW15QM1XbbgS+0DfPxVB+jUKhWEKuuFuHncbk3tEEqzmoXL+2KyOFuKGqOnmdIy0/davWF1CkuwtibCw==" + }, "node_modules/figures": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/figures/-/figures-4.0.1.tgz", @@ -13144,7 +13224,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.0.0.tgz", "integrity": "sha512-zIE9hX70qew5qTUjSS7wi1iwj/l7+m54KWU247nhM3v806UdGj1yDndXj+IOYxxtW9zyLI+xqFNZjTuDaLUqFw==", - "devOptional": true + "dev": true }, "node_modules/import-fresh": { "version": "3.3.0", @@ -18901,6 +18981,11 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" + }, "node_modules/postcss-values-parser": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/postcss-values-parser/-/postcss-values-parser-6.0.2.tgz", @@ -20320,7 +20405,7 @@ "version": "1.50.1", "resolved": "https://registry.npmjs.org/sass/-/sass-1.50.1.tgz", "integrity": "sha512-noTnY41KnlW2A9P8sdwESpDmo+KBNkukI1i8+hOK3footBUcohNHtdOJbckp46XO95nuvcHDDZ+4tmOnpK3hjw==", - "devOptional": true, + "dev": true, "dependencies": { "chokidar": ">=3.0.0 <4.0.0", "immutable": "^4.0.0", @@ -20333,6 +20418,22 @@ "node": ">=12.0.0" } }, + "node_modules/satori": { + "version": "0.0.38", + "resolved": "https://registry.npmjs.org/satori/-/satori-0.0.38.tgz", + "integrity": "sha512-o8nMTp5IiLKi3oOw80Y3LdDAReGS+UfC1StQBAwlnFNzHmY1A3JGFT+9gam6x8I6uMDFrs82FnG9R/kI9iONdg==", + "dependencies": { + "@shuding/opentype.js": "1.4.0-beta.0", + "css-background-parser": "^0.1.0", + "css-box-shadow": "1.0.0-3", + "css-to-react-native": "^3.0.0", + "postcss-value-parser": "^4.2.0", + "yoga-layout-prebuilt": "^1.10.0" + }, + "engines": { + "node": ">=16" + } + }, "node_modules/saxes": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", @@ -21350,6 +21451,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/string.prototype.codepointat": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/string.prototype.codepointat/-/string.prototype.codepointat-0.2.1.tgz", + "integrity": "sha512-2cBVCj6I4IOvEnjgO/hWqXjqBGsY+zwPmHl12Srk9IXSZ56Jwwmy+66XO5Iut/oQVR7t5ihYdLB0GMa4alEUcg==" + }, "node_modules/string.prototype.matchall": { "version": "4.0.7", "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.7.tgz", @@ -23315,6 +23421,22 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/yoga-layout-prebuilt": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/yoga-layout-prebuilt/-/yoga-layout-prebuilt-1.10.0.tgz", + "integrity": "sha512-YnOmtSbv4MTf7RGJMK0FvZ+KD8OEe/J5BNnR0GHhD8J/XcG/Qvxgszm0Un6FTHWW4uHlTgP0IztiXQnGyIR45g==", + "dependencies": { + "@types/yoga-layout": "1.9.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yoga-wasm-web": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/yoga-wasm-web/-/yoga-wasm-web-0.1.2.tgz", + "integrity": "sha512-8SkgawHcA0RUbMrnhxbaQkZDBi8rMed8pQHixkFF9w32zGhAwZ9/cOHWlpYfr6RCx42Yp3siV45/jPEkJxsk6w==" + }, "node_modules/zip-stream": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-4.1.0.tgz", @@ -25857,8 +25979,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-3.0.0.tgz", "integrity": "sha512-V3wD15YHfHz6y0KdhYFjyy9vWtEVALT9UrxfN3zqlI6dMioHnJrqOYfyPKol3oqrnCM9uwkcdCwkJ0WUcbLMTQ==", - "dev": true, - "requires": {} + "dev": true }, "chalk": { "version": "5.1.0", @@ -26209,8 +26330,7 @@ "version": "17.0.0", "resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-17.0.0.tgz", "integrity": "sha512-/2ks1GKyqSOkH7JFvXJicu0iMpoojkwB+f5Du/1SC0PtBL+s8v30k9njRZ21pm2drKYm2342jFnGWzttxPmZVg==", - "dev": true, - "requires": {} + "dev": true }, "eslint-import-resolver-typescript": { "version": "3.3.0", @@ -26783,12 +26903,26 @@ } } }, + "@resvg/resvg-wasm": { + "version": "2.0.0-alpha.4", + "resolved": "https://registry.npmjs.org/@resvg/resvg-wasm/-/resvg-wasm-2.0.0-alpha.4.tgz", + "integrity": "sha512-pWIG9a/x1ky8gXKRhPH1OPKpHFoMN1ISLbJ+O+gPXQHIAKhNd5I28RlWf7q576hAOQA9JZTlo3p/M2uyLzJmmw==" + }, "@rushstack/eslint-patch": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.1.3.tgz", "integrity": "sha512-WiBSI6JBIhC6LRIsB2Kwh8DsGTlbBU+mLRxJmAe3LjHTdkDpwIbEOZgoXBbZilk/vlfjK8i6nKRAvIRn1XaIMw==", "dev": true }, + "@shuding/opentype.js": { + "version": "1.4.0-beta.0", + "resolved": "https://registry.npmjs.org/@shuding/opentype.js/-/opentype.js-1.4.0-beta.0.tgz", + "integrity": "sha512-3NgmNyH3l/Hv6EvsWJbsvpcpUba6R8IREQ83nH83cyakCw7uM1arZKNfHwv1Wz6jgqrF/j4x5ELvR6PnK9nTcA==", + "requires": { + "fflate": "^0.7.3", + "string.prototype.codepointat": "^0.2.1" + } + }, "@sindresorhus/is": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-2.1.1.tgz", @@ -27124,13 +27258,13 @@ "version": "15.7.5", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==", - "devOptional": true + "dev": true }, "@types/react": { "version": "17.0.50", "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.50.tgz", "integrity": "sha512-ZCBHzpDb5skMnc1zFXAXnL3l1FAdi+xZvwxK+PkglMmBrwjpp9nKaWuEvrGnSifCJmBFGxZOOFuwC6KH/s0NuA==", - "devOptional": true, + "dev": true, "requires": { "@types/prop-types": "*", "@types/scheduler": "*", @@ -27156,7 +27290,7 @@ "version": "0.16.2", "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==", - "devOptional": true + "dev": true }, "@types/sinonjs__fake-timers": { "version": "8.1.1", @@ -27207,6 +27341,11 @@ "@types/node": "*" } }, + "@types/yoga-layout": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/@types/yoga-layout/-/yoga-layout-1.9.2.tgz", + "integrity": "sha512-S9q47ByT2pPvD65IvrWp7qppVMpk9WGMbVq9wbWZOHg6tnXSD4vyhao6nOSBwwfDdV2p3Kx9evA9vI+XWTfDvw==" + }, "@typescript-eslint/eslint-plugin": { "version": "5.20.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.20.0.tgz", @@ -27414,6 +27553,16 @@ "resolved": "https://registry.npmjs.org/@vercel/node-bridge/-/node-bridge-2.2.2.tgz", "integrity": "sha512-haGBC8noyA5BfjCRXRH+VIkHCDVW5iD5UX24P2nOdilwUxI4qWsattS/co8QBGq64XsNLRAMdM5pQUE3zxkF9Q==" }, + "@vercel/og": { + "version": "0.0.15", + "resolved": "https://registry.npmjs.org/@vercel/og/-/og-0.0.15.tgz", + "integrity": "sha512-AHa25M8Hxt+83aSAY+GPFYuE1oTNGzbw1sJZBa9AsYNUW6vmXPTGW9jJmOUnkjp2dp+wyY3gtAZRa26HjSeNSw==", + "requires": { + "@resvg/resvg-wasm": "2.0.0-alpha.4", + "satori": "0.0.38", + "yoga-wasm-web": "0.1.2" + } + }, "abab": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", @@ -27464,8 +27613,7 @@ "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "requires": {} + "dev": true }, "acorn-walk": { "version": "7.2.0", @@ -28435,6 +28583,11 @@ } } }, + "camelize": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/camelize/-/camelize-1.0.0.tgz", + "integrity": "sha512-W2lPwkBkMZwFlPCXhIlYgxu+7gC/NUlCtdK652DAJ1JdgV0sTrvuPFshNPrFa1TY2JOkLhgdeEBplB4ezEa+xg==" + }, "caniuse-lite": { "version": "1.0.30001402", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001402.tgz", @@ -29765,6 +29918,21 @@ "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", "dev": true }, + "css-background-parser": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/css-background-parser/-/css-background-parser-0.1.0.tgz", + "integrity": "sha512-2EZLisiZQ+7m4wwur/qiYJRniHX4K5Tc9w93MT3AS0WS1u5kaZ4FKXlOTBhOjc+CgEgPiGY+fX1yWD8UwpEqUA==" + }, + "css-box-shadow": { + "version": "1.0.0-3", + "resolved": "https://registry.npmjs.org/css-box-shadow/-/css-box-shadow-1.0.0-3.tgz", + "integrity": "sha512-9jaqR6e7Ohds+aWwmhe6wILJ99xYQbfmK9QQB9CcMjDbTxPZjwEmUQpU91OG05Xgm8BahT5fW+svbsQGjS/zPg==" + }, + "css-color-keywords": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/css-color-keywords/-/css-color-keywords-1.0.0.tgz", + "integrity": "sha512-FyyrDHZKEjXDpNJYvVsV960FiqQyXc/LlYmsxl2BcdMb2WPx0OGRVgTg55rPSyLSNMqP52R9r8geSp7apN3Ofg==" + }, "css-select": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.3.0.tgz", @@ -29778,6 +29946,16 @@ "nth-check": "^2.0.1" } }, + "css-to-react-native": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/css-to-react-native/-/css-to-react-native-3.0.0.tgz", + "integrity": "sha512-Ro1yETZA813eoyUp2GDBhG2j+YggidUmzO1/v9eYBKR2EHVEniE2MI/NqpTQ954BMpTPZFsGNPm46qFB9dpaPQ==", + "requires": { + "camelize": "^1.0.0", + "css-color-keywords": "^1.0.0", + "postcss-value-parser": "^4.0.2" + } + }, "css-what": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", @@ -29816,7 +29994,7 @@ "version": "3.0.11", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.11.tgz", "integrity": "sha512-sa6P2wJ+CAbgyy4KFssIb/JNMLxFvKF1pCYCSXS8ZMuqZnMsrxqI2E5sPyoTpxoPU/gVZMzr2zjOfg8GIZOMsw==", - "devOptional": true + "dev": true }, "custom-routes": { "version": "file:demos/custom-routes", @@ -30158,6 +30336,7 @@ "@types/fs-extra": "^9.0.13", "@types/jest": "^27.4.1", "@types/node": "^17.0.25", + "@vercel/og": "^0.0.15", "critters": "^0.0.16", "husky": "^7.0.4", "if-env": "^1.0.4", @@ -30946,8 +31125,7 @@ "version": "8.5.0", "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.5.0.tgz", "integrity": "sha512-obmWKLUNCnhtQRKc+tmnYuQl0pFU1ibYJQ5BGhTVB08bHe9wC8qUeG7c08dj9XX+AuPj1YSGSQIHl1pnDHZR0Q==", - "dev": true, - "requires": {} + "dev": true }, "eslint-formatter-codeframe": { "version": "7.32.1", @@ -31392,8 +31570,7 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-6.0.1.tgz", "integrity": "sha512-uM4Tgo5u3UWQiroOyDEsYcVMOo7re3zmno0IZmB5auxoaQNIceAbXEkSt8RNrKtaYehARHG06pYK6K1JhtP0Zw==", - "dev": true, - "requires": {} + "dev": true }, "eslint-plugin-react": { "version": "7.29.4", @@ -31441,8 +31618,7 @@ "version": "4.5.0", "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.5.0.tgz", "integrity": "sha512-8k1gRt7D7h03kd+SAAlzXkQwWK22BnK6GKZG+FJA6BAGy22CFvl8kCIXKpVux0cCxMWDQUPqSok0LKaZ0aOcCw==", - "dev": true, - "requires": {} + "dev": true }, "eslint-plugin-unicorn": { "version": "43.0.2", @@ -32061,6 +32237,11 @@ "web-streams-polyfill": "^3.0.3" } }, + "fflate": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.7.4.tgz", + "integrity": "sha512-5u2V/CDW15QM1XbbgS+0DfPxVB+jUKhWEKuuFuHncbk3tEEqzmoXL+2KyOFuKGqOnmdIy0/davWF1CkuwtibCw==" + }, "figures": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/figures/-/figures-4.0.1.tgz", @@ -32915,7 +33096,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.0.0.tgz", "integrity": "sha512-zIE9hX70qew5qTUjSS7wi1iwj/l7+m54KWU247nhM3v806UdGj1yDndXj+IOYxxtW9zyLI+xqFNZjTuDaLUqFw==", - "devOptional": true + "dev": true }, "import-fresh": { "version": "3.3.0", @@ -33977,8 +34158,7 @@ "version": "1.2.2", "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz", "integrity": "sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==", - "dev": true, - "requires": {} + "dev": true }, "jest-regex-util": { "version": "27.5.1", @@ -37338,6 +37518,11 @@ "source-map-js": "^1.0.2" } }, + "postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" + }, "postcss-values-parser": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/postcss-values-parser/-/postcss-values-parser-6.0.2.tgz", @@ -38406,13 +38591,26 @@ "version": "1.50.1", "resolved": "https://registry.npmjs.org/sass/-/sass-1.50.1.tgz", "integrity": "sha512-noTnY41KnlW2A9P8sdwESpDmo+KBNkukI1i8+hOK3footBUcohNHtdOJbckp46XO95nuvcHDDZ+4tmOnpK3hjw==", - "devOptional": true, + "dev": true, "requires": { "chokidar": ">=3.0.0 <4.0.0", "immutable": "^4.0.0", "source-map-js": ">=0.6.2 <2.0.0" } }, + "satori": { + "version": "0.0.38", + "resolved": "https://registry.npmjs.org/satori/-/satori-0.0.38.tgz", + "integrity": "sha512-o8nMTp5IiLKi3oOw80Y3LdDAReGS+UfC1StQBAwlnFNzHmY1A3JGFT+9gam6x8I6uMDFrs82FnG9R/kI9iONdg==", + "requires": { + "@shuding/opentype.js": "1.4.0-beta.0", + "css-background-parser": "^0.1.0", + "css-box-shadow": "1.0.0-3", + "css-to-react-native": "^3.0.0", + "postcss-value-parser": "^4.2.0", + "yoga-layout-prebuilt": "^1.10.0" + } + }, "saxes": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", @@ -38667,14 +38865,12 @@ "styled-jsx": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.0.2.tgz", - "integrity": "sha512-LqPQrbBh3egD57NBcHET4qcgshPks+yblyhPlH2GY8oaDgKs8SK4C3dBh3oSJjgzJ3G5t1SYEZGHkP+QEpX9EQ==", - "requires": {} + "integrity": "sha512-LqPQrbBh3egD57NBcHET4qcgshPks+yblyhPlH2GY8oaDgKs8SK4C3dBh3oSJjgzJ3G5t1SYEZGHkP+QEpX9EQ==" }, "use-sync-external-store": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.1.0.tgz", - "integrity": "sha512-SEnieB2FPKEVne66NpXPd1Np4R1lTNKfjuy3XdIoPQKYBAFdzbzSZlSn1KJZUiihQLQC5Znot4SBz1EOTBwQAQ==", - "requires": {} + "integrity": "sha512-SEnieB2FPKEVne66NpXPd1Np4R1lTNKfjuy3XdIoPQKYBAFdzbzSZlSn1KJZUiihQLQC5Znot4SBz1EOTBwQAQ==" } } }, @@ -39392,6 +39588,11 @@ "strip-ansi": "^7.0.1" } }, + "string.prototype.codepointat": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/string.prototype.codepointat/-/string.prototype.codepointat-0.2.1.tgz", + "integrity": "sha512-2cBVCj6I4IOvEnjgO/hWqXjqBGsY+zwPmHl12Srk9IXSZ56Jwwmy+66XO5Iut/oQVR7t5ihYdLB0GMa4alEUcg==" + }, "string.prototype.matchall": { "version": "4.0.7", "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.7.tgz", @@ -39486,8 +39687,7 @@ "styled-jsx": { "version": "5.0.6", "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.0.6.tgz", - "integrity": "sha512-xOeROtkK5MGMDimBQ3J6iPId8q0t/BDoG5XN6oKkZClVz9ISF/hihN8OCn2LggMU6N32aXnrXBdn3auSqNS9fA==", - "requires": {} + "integrity": "sha512-xOeROtkK5MGMDimBQ3J6iPId8q0t/BDoG5XN6oKkZClVz9ISF/hihN8OCn2LggMU6N32aXnrXBdn3auSqNS9fA==" }, "supports-color": { "version": "9.2.2", @@ -40209,8 +40409,7 @@ "ws": { "version": "8.5.0", "resolved": "https://registry.npmjs.org/ws/-/ws-8.5.0.tgz", - "integrity": "sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg==", - "requires": {} + "integrity": "sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg==" } } }, @@ -40328,8 +40527,7 @@ "use-sync-external-store": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", - "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==", - "requires": {} + "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==" }, "util-deprecate": { "version": "1.0.2", @@ -40734,8 +40932,7 @@ "version": "7.5.7", "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.7.tgz", "integrity": "sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A==", - "dev": true, - "requires": {} + "dev": true }, "xdg-basedir": { "version": "4.0.0", @@ -40870,6 +41067,19 @@ "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==" }, + "yoga-layout-prebuilt": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/yoga-layout-prebuilt/-/yoga-layout-prebuilt-1.10.0.tgz", + "integrity": "sha512-YnOmtSbv4MTf7RGJMK0FvZ+KD8OEe/J5BNnR0GHhD8J/XcG/Qvxgszm0Un6FTHWW4uHlTgP0IztiXQnGyIR45g==", + "requires": { + "@types/yoga-layout": "1.9.2" + } + }, + "yoga-wasm-web": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/yoga-wasm-web/-/yoga-wasm-web-0.1.2.tgz", + "integrity": "sha512-8SkgawHcA0RUbMrnhxbaQkZDBi8rMed8pQHixkFF9w32zGhAwZ9/cOHWlpYfr6RCx42Yp3siV45/jPEkJxsk6w==" + }, "zip-stream": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/zip-stream/-/zip-stream-4.1.0.tgz", diff --git a/packages/runtime/src/helpers/edge.ts b/packages/runtime/src/helpers/edge.ts index f17a776f16..af41dd13c5 100644 --- a/packages/runtime/src/helpers/edge.ts +++ b/packages/runtime/src/helpers/edge.ts @@ -21,6 +21,10 @@ interface EdgeFunctionDefinitionV1 { regexp: string } +interface AssetRef { + name: string + filePath: string +} export interface MiddlewareMatcher { regexp: string locale?: false @@ -34,6 +38,8 @@ interface EdgeFunctionDefinitionV2 { name: string page: string matchers: MiddlewareMatcher[] + wasm?: AssetRef[] + assets?: AssetRef[] } type EdgeFunctionDefinition = EdgeFunctionDefinitionV1 | EdgeFunctionDefinitionV2 @@ -71,17 +77,49 @@ const sanitizeName = (name: string) => `next_${name.replace(/\W/g, '_')}` /** * Initialization added to the top of the edge function bundle */ -const bootstrap = /* js */ ` -globalThis.process = { env: {...Deno.env.toObject(), NEXT_RUNTIME: 'edge', 'NEXT_PRIVATE_MINIMAL_MODE': '1' } } -globalThis._ENTRIES ||= {} -// Deno defines "window", but naughty libraries think this means it's a browser -delete globalThis.window +const preamble = /* js */ ` + import { + decode as base64Decode, +} from "https://deno.land/std@0.159.0/encoding/base64.ts"; + // Deno defines "window", but naughty libraries think this means it's a browser + delete globalThis.window + globalThis.process = { env: {...Deno.env.toObject(), NEXT_RUNTIME: 'edge', 'NEXT_PRIVATE_MINIMAL_MODE': '1' } } + // Next uses "self" as a function-scoped global-like object + const self = {} + let _ENTRIES = {} + let resolveSiteUrl + +// The site URL isn't available until we've had a request, so we make a promise which we resolve once we have the URL + let SITE_URL = new Promise(resolve => { + resolveSiteUrl = resolve + }) + export function setSiteUrl(url) { + resolveSiteUrl(url) + } + +// Next uses blob: urls to refer to local assets, so we need to intercept these + const _fetch = globalThis.fetch + const fetch = async (url, init) => { + if (typeof url === 'object' && url.href?.startsWith('blob:')) { + // There's a race condition on first run, but if we await it then we're ok + const siteUrl = await SITE_URL + const requestUrl = new URL(url.href.replace('blob:', siteUrl + "/server/edge-chunks/asset_")) + return _fetch(requestUrl, init) + } + return _fetch(url, init) + } + + ` -/** - * Concatenates the Next edge function code with the required chunks and adds an export - */ +const IMPORT_UNSUPPORTED = [ + `Object.defineProperty(globalThis,"__import_unsupported"`, + ` Object.defineProperty(globalThis, "__import_unsupported"`, +] +// +// Concatenates the Next edge function code with the required chunks and adds an export +// const getMiddlewareBundle = async ({ edgeFunctionDefinition, netlifyConfig, @@ -90,17 +128,26 @@ const getMiddlewareBundle = async ({ netlifyConfig: NetlifyConfig }): Promise => { const { publish } = netlifyConfig.build - const chunks: Array = [bootstrap] + const chunks: Array = [preamble] + + if ('wasm' in edgeFunctionDefinition) { + for (const { name, filePath } of edgeFunctionDefinition.wasm) { + const wasm = await fs.readFile(join(publish, filePath)) + chunks.push(`const ${name} = base64Decode(${JSON.stringify(wasm.toString('base64'))}).buffer`) + } + } + for (const file of edgeFunctionDefinition.files) { const filePath = join(publish, file) - const data = await fs.readFile(filePath, 'utf8') + + let data = await fs.readFile(filePath, 'utf8') + data = IMPORT_UNSUPPORTED.reduce( + (acc, val) => acc.replace(val, `('__import_unsupported' in globalThis)||${val}`), + data, + ) chunks.push('{', data, '}') } - const middleware = await fs.readFile(join(publish, `server`, `${edgeFunctionDefinition.name}.js`), 'utf8') - - chunks.push(middleware) - const exports = /* js */ `export default _ENTRIES["middleware_${edgeFunctionDefinition.name}"].default;` chunks.push(exports) return chunks.join('\n') diff --git a/packages/runtime/src/templates/edge/bundle.js b/packages/runtime/src/templates/edge/bundle.js index 0765289028..b96fd1e931 100644 --- a/packages/runtime/src/templates/edge/bundle.js +++ b/packages/runtime/src/templates/edge/bundle.js @@ -5,3 +5,5 @@ * @returns {Promise} */ export default async ({ request }) => {} + +export const setSiteUrl = (url) => {} diff --git a/packages/runtime/src/templates/edge/runtime.ts b/packages/runtime/src/templates/edge/runtime.ts index e5b1870184..d34562e5d6 100644 --- a/packages/runtime/src/templates/edge/runtime.ts +++ b/packages/runtime/src/templates/edge/runtime.ts @@ -2,7 +2,7 @@ import type { Context } from 'https://edge.netlify.com' // Available at build time import matchers from './matchers.json' assert { type: 'json' } import nextConfig from '../edge-shared/nextConfig.json' assert { type: 'json' } -import edgeFunction from './bundle.js' +import edgeFunction, { setSiteUrl } from './bundle.js' import { buildResponse } from '../edge-shared/utils.ts' import { getMiddlewareRouteMatcher, MiddlewareRouteMatch, searchParamsToUrlQuery } from '../edge-shared/next-utils.ts' @@ -50,12 +50,13 @@ declare global { globalThis.NFRequestContextMap ||= new Map() const handler = async (req: Request, context: Context) => { - if (Deno.env.get('NETLIFY_DEV')) { - // Don't run in dev - return - } + // if (Deno.env.get('NETLIFY_DEV')) { + // // Don't run in dev + // return + // } const url = new URL(req.url) + setSiteUrl(url.origin) // While we have already checked the path when mapping to the edge function, // Next.js supports extra rules that we need to check here too. From 95a4c3db012b5b494c7bd60e673dff701c3af05a Mon Sep 17 00:00:00 2001 From: Matt Kane Date: Tue, 11 Oct 2022 14:55:59 +0100 Subject: [PATCH 02/18] chore: snapidoo --- test/__snapshots__/index.js.snap | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test/__snapshots__/index.js.snap b/test/__snapshots__/index.js.snap index 5256ac3769..359a3c4bcf 100644 --- a/test/__snapshots__/index.js.snap +++ b/test/__snapshots__/index.js.snap @@ -11,6 +11,7 @@ exports.resolvePages = () => { require.resolve('../../../.next/server/pages/api/exitPreview.js') require.resolve('../../../.next/server/pages/api/hello-background.js') require.resolve('../../../.next/server/pages/api/hello.js') + require.resolve('../../../.next/server/pages/api/og.js') require.resolve('../../../.next/server/pages/api/shows/[...params].js') require.resolve('../../../.next/server/pages/api/shows/[id].js') require.resolve('../../../.next/server/pages/deep/import.js') @@ -47,6 +48,7 @@ exports.resolvePages = () => { require.resolve('../../../.next/server/pages/api/exitPreview.js') require.resolve('../../../.next/server/pages/api/hello-background.js') require.resolve('../../../.next/server/pages/api/hello.js') + require.resolve('../../../.next/server/pages/api/og.js') require.resolve('../../../.next/server/pages/api/shows/[...params].js') require.resolve('../../../.next/server/pages/api/shows/[id].js') require.resolve('../../../.next/server/pages/deep/import.js') @@ -83,6 +85,7 @@ exports.resolvePages = () => { require.resolve('../../../web/.next/server/pages/api/exitPreview.js') require.resolve('../../../web/.next/server/pages/api/hello-background.js') require.resolve('../../../web/.next/server/pages/api/hello.js') + require.resolve('../../../web/.next/server/pages/api/og.js') require.resolve('../../../web/.next/server/pages/api/shows/[...params].js') require.resolve('../../../web/.next/server/pages/api/shows/[id].js') require.resolve('../../../web/.next/server/pages/deep/import.js') @@ -119,6 +122,7 @@ exports.resolvePages = () => { require.resolve('../../../web/.next/server/pages/api/exitPreview.js') require.resolve('../../../web/.next/server/pages/api/hello-background.js') require.resolve('../../../web/.next/server/pages/api/hello.js') + require.resolve('../../../web/.next/server/pages/api/og.js') require.resolve('../../../web/.next/server/pages/api/shows/[...params].js') require.resolve('../../../web/.next/server/pages/api/shows/[id].js') require.resolve('../../../web/.next/server/pages/deep/import.js') From bff9b41f584c51d27f67f7549a3ff5701cb163f2 Mon Sep 17 00:00:00 2001 From: Matt Kane Date: Tue, 11 Oct 2022 15:08:36 +0100 Subject: [PATCH 03/18] chore: log --- packages/runtime/src/templates/edge/runtime.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/runtime/src/templates/edge/runtime.ts b/packages/runtime/src/templates/edge/runtime.ts index d34562e5d6..bd6855d5ca 100644 --- a/packages/runtime/src/templates/edge/runtime.ts +++ b/packages/runtime/src/templates/edge/runtime.ts @@ -92,6 +92,7 @@ const handler = async (req: Request, context: Context) => { try { const result = await edgeFunction({ request }) + console.log({ result }) return buildResponse({ result, request: req, context }) } catch (error) { console.error(error) From 4f441a775f5c428339d70d3b7178183c94ed14a8 Mon Sep 17 00:00:00 2001 From: Matt Kane Date: Tue, 11 Oct 2022 16:15:14 +0100 Subject: [PATCH 04/18] chore: log fetch wrapper --- packages/runtime/src/helpers/edge.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/runtime/src/helpers/edge.ts b/packages/runtime/src/helpers/edge.ts index af41dd13c5..60c19b6068 100644 --- a/packages/runtime/src/helpers/edge.ts +++ b/packages/runtime/src/helpers/edge.ts @@ -104,6 +104,7 @@ const preamble = /* js */ ` // There's a race condition on first run, but if we await it then we're ok const siteUrl = await SITE_URL const requestUrl = new URL(url.href.replace('blob:', siteUrl + "/server/edge-chunks/asset_")) + console.log({requestUrl}) return _fetch(requestUrl, init) } return _fetch(url, init) From 25d107805ff2a76abca991c8ae0a8a7ac6126c56 Mon Sep 17 00:00:00 2001 From: Matt Kane Date: Tue, 11 Oct 2022 16:28:03 +0100 Subject: [PATCH 05/18] fix: allow acess to edge-chunks --- packages/runtime/src/helpers/redirects.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/packages/runtime/src/helpers/redirects.ts b/packages/runtime/src/helpers/redirects.ts index 2e950e807e..ec45614072 100644 --- a/packages/runtime/src/helpers/redirects.ts +++ b/packages/runtime/src/helpers/redirects.ts @@ -240,6 +240,13 @@ export const generateRedirects = async ({ join(netlifyConfig.build.publish, 'routes-manifest.json'), ) + // no-op to override the exclusion of the server folder + netlifyConfig.redirects.push({ + from: `${basePath}/server/edge-chunks/*`, + to: `${basePath}/server/edge-chunks/:splat`, + status: 200, + }) + netlifyConfig.redirects.push(...generateHiddenPathRedirects({ basePath })) if (i18n && i18n.localeDetection !== false) { From 60665669fe118a59cc7fd4f69c1d00608a70a4be Mon Sep 17 00:00:00 2001 From: Matt Kane Date: Tue, 11 Oct 2022 16:51:43 +0100 Subject: [PATCH 06/18] chore: make example more dynamic --- demos/default/pages/api/og.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/demos/default/pages/api/og.tsx b/demos/default/pages/api/og.tsx index 8bd19ec51d..1050354e4f 100644 --- a/demos/default/pages/api/og.tsx +++ b/demos/default/pages/api/og.tsx @@ -18,7 +18,7 @@ export default function () { justifyContent: 'center', }} > - Hello world! + Hi, it's {new Date().toLocaleTimeString()}! ), { From ca4597713c5ff94249faace12d6ebee94e7b5d5b Mon Sep 17 00:00:00 2001 From: Matt Kane Date: Tue, 11 Oct 2022 17:11:36 +0100 Subject: [PATCH 07/18] chore: add image debug, remove logs --- demos/default/pages/api/og.tsx | 1 + packages/runtime/src/helpers/edge.ts | 1 - packages/runtime/src/templates/edge/runtime.ts | 1 - 3 files changed, 1 insertion(+), 2 deletions(-) diff --git a/demos/default/pages/api/og.tsx b/demos/default/pages/api/og.tsx index 1050354e4f..b6dd86d390 100644 --- a/demos/default/pages/api/og.tsx +++ b/demos/default/pages/api/og.tsx @@ -24,6 +24,7 @@ export default function () { { width: 1200, height: 600, + debug: true, }, ) } diff --git a/packages/runtime/src/helpers/edge.ts b/packages/runtime/src/helpers/edge.ts index 60c19b6068..af41dd13c5 100644 --- a/packages/runtime/src/helpers/edge.ts +++ b/packages/runtime/src/helpers/edge.ts @@ -104,7 +104,6 @@ const preamble = /* js */ ` // There's a race condition on first run, but if we await it then we're ok const siteUrl = await SITE_URL const requestUrl = new URL(url.href.replace('blob:', siteUrl + "/server/edge-chunks/asset_")) - console.log({requestUrl}) return _fetch(requestUrl, init) } return _fetch(url, init) diff --git a/packages/runtime/src/templates/edge/runtime.ts b/packages/runtime/src/templates/edge/runtime.ts index bd6855d5ca..d34562e5d6 100644 --- a/packages/runtime/src/templates/edge/runtime.ts +++ b/packages/runtime/src/templates/edge/runtime.ts @@ -92,7 +92,6 @@ const handler = async (req: Request, context: Context) => { try { const result = await edgeFunction({ request }) - console.log({ result }) return buildResponse({ result, request: req, context }) } catch (error) { console.error(error) From 04b61fac3e4516f74089901a85f71f3d331d9c25 Mon Sep 17 00:00:00 2001 From: Matt Kane Date: Tue, 11 Oct 2022 17:36:14 +0100 Subject: [PATCH 08/18] chore: remove debug --- demos/default/pages/api/og.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/demos/default/pages/api/og.tsx b/demos/default/pages/api/og.tsx index b6dd86d390..1050354e4f 100644 --- a/demos/default/pages/api/og.tsx +++ b/demos/default/pages/api/og.tsx @@ -24,7 +24,6 @@ export default function () { { width: 1200, height: 600, - debug: true, }, ) } From 322c752317cb98b1cf56247b47d03f077a464921 Mon Sep 17 00:00:00 2001 From: Matt Kane Date: Tue, 11 Oct 2022 21:55:49 +0100 Subject: [PATCH 09/18] fix: inlline assets --- packages/runtime/src/helpers/edge.ts | 31 +++++++++---------- packages/runtime/src/helpers/redirects.ts | 7 ----- packages/runtime/src/templates/edge/bundle.js | 4 +-- .../runtime/src/templates/edge/runtime.ts | 3 +- 4 files changed, 17 insertions(+), 28 deletions(-) diff --git a/packages/runtime/src/helpers/edge.ts b/packages/runtime/src/helpers/edge.ts index af41dd13c5..06ec6e5b24 100644 --- a/packages/runtime/src/helpers/edge.ts +++ b/packages/runtime/src/helpers/edge.ts @@ -78,8 +78,8 @@ const sanitizeName = (name: string) => `next_${name.replace(/\W/g, '_')}` * Initialization added to the top of the edge function bundle */ const preamble = /* js */ ` - import { - decode as base64Decode, +import { + decode as _base64Decode, } from "https://deno.land/std@0.159.0/encoding/base64.ts"; // Deno defines "window", but naughty libraries think this means it's a browser delete globalThis.window @@ -87,24 +87,15 @@ const preamble = /* js */ ` // Next uses "self" as a function-scoped global-like object const self = {} let _ENTRIES = {} - let resolveSiteUrl - -// The site URL isn't available until we've had a request, so we make a promise which we resolve once we have the URL - let SITE_URL = new Promise(resolve => { - resolveSiteUrl = resolve - }) - export function setSiteUrl(url) { - resolveSiteUrl(url) - } // Next uses blob: urls to refer to local assets, so we need to intercept these const _fetch = globalThis.fetch const fetch = async (url, init) => { if (typeof url === 'object' && url.href?.startsWith('blob:')) { - // There's a race condition on first run, but if we await it then we're ok - const siteUrl = await SITE_URL - const requestUrl = new URL(url.href.replace('blob:', siteUrl + "/server/edge-chunks/asset_")) - return _fetch(requestUrl, init) + const key = url.href.slice(5) + if (key in _ASSETS) { + return new Response(_base64Decode(_ASSETS[key])) + } } return _fetch(url, init) } @@ -133,7 +124,15 @@ const getMiddlewareBundle = async ({ if ('wasm' in edgeFunctionDefinition) { for (const { name, filePath } of edgeFunctionDefinition.wasm) { const wasm = await fs.readFile(join(publish, filePath)) - chunks.push(`const ${name} = base64Decode(${JSON.stringify(wasm.toString('base64'))}).buffer`) + chunks.push(`const ${name} = _base64Decode(${JSON.stringify(wasm.toString('base64'))}).buffer`) + } + } + + if ('assets' in edgeFunctionDefinition) { + chunks.push(`const _ASSETS = {}`) + for (const { name, filePath } of edgeFunctionDefinition.assets) { + const wasm = await fs.readFile(join(publish, filePath)) + chunks.push(`_ASSETS[${JSON.stringify(name)}] = ${JSON.stringify(wasm.toString('base64'))}`) } } diff --git a/packages/runtime/src/helpers/redirects.ts b/packages/runtime/src/helpers/redirects.ts index ec45614072..2e950e807e 100644 --- a/packages/runtime/src/helpers/redirects.ts +++ b/packages/runtime/src/helpers/redirects.ts @@ -240,13 +240,6 @@ export const generateRedirects = async ({ join(netlifyConfig.build.publish, 'routes-manifest.json'), ) - // no-op to override the exclusion of the server folder - netlifyConfig.redirects.push({ - from: `${basePath}/server/edge-chunks/*`, - to: `${basePath}/server/edge-chunks/:splat`, - status: 200, - }) - netlifyConfig.redirects.push(...generateHiddenPathRedirects({ basePath })) if (i18n && i18n.localeDetection !== false) { diff --git a/packages/runtime/src/templates/edge/bundle.js b/packages/runtime/src/templates/edge/bundle.js index b96fd1e931..757d42d69f 100644 --- a/packages/runtime/src/templates/edge/bundle.js +++ b/packages/runtime/src/templates/edge/bundle.js @@ -2,8 +2,6 @@ * This placeholder is replaced with the compiled Next.js bundle at build time * @param {Object} props * @param {import("./runtime.ts").RequestData} props.request - * @returns {Promise} + * @returns {Promise} */ export default async ({ request }) => {} - -export const setSiteUrl = (url) => {} diff --git a/packages/runtime/src/templates/edge/runtime.ts b/packages/runtime/src/templates/edge/runtime.ts index d34562e5d6..89c7744784 100644 --- a/packages/runtime/src/templates/edge/runtime.ts +++ b/packages/runtime/src/templates/edge/runtime.ts @@ -2,7 +2,7 @@ import type { Context } from 'https://edge.netlify.com' // Available at build time import matchers from './matchers.json' assert { type: 'json' } import nextConfig from '../edge-shared/nextConfig.json' assert { type: 'json' } -import edgeFunction, { setSiteUrl } from './bundle.js' +import edgeFunction from './bundle.js' import { buildResponse } from '../edge-shared/utils.ts' import { getMiddlewareRouteMatcher, MiddlewareRouteMatch, searchParamsToUrlQuery } from '../edge-shared/next-utils.ts' @@ -56,7 +56,6 @@ const handler = async (req: Request, context: Context) => { // } const url = new URL(req.url) - setSiteUrl(url.origin) // While we have already checked the path when mapping to the edge function, // Next.js supports extra rules that we need to check here too. From 91b05a51bd60f1b904620e984e37743404e6ec06 Mon Sep 17 00:00:00 2001 From: Matt Kane Date: Wed, 12 Oct 2022 11:58:36 +0100 Subject: [PATCH 10/18] chore: nicer example --- demos/default/pages/api/og.tsx | 37 ++++++++++++++++++++++++++-------- 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/demos/default/pages/api/og.tsx b/demos/default/pages/api/og.tsx index 1050354e4f..4fd08722fd 100644 --- a/demos/default/pages/api/og.tsx +++ b/demos/default/pages/api/og.tsx @@ -1,29 +1,50 @@ import { ImageResponse } from '@vercel/og' +import { NextRequest } from 'next/server' export const config = { runtime: 'experimental-edge', } -export default function () { + +export default async function handler(req: NextRequest) { + const { searchParams } = req.nextUrl + const username = searchParams.get('username') + if (!username) { + return new ImageResponse(<>Visit with "?username=netlify", { + width: 1200, + height: 630, + }) + } + return new ImageResponse( (
- Hi, it's {new Date().toLocaleTimeString()}! + +

github.com/{username}

), { width: 1200, - height: 600, + height: 630, }, ) } From 8a3156afbf811b171a3a1cb676834f389f19b1a1 Mon Sep 17 00:00:00 2001 From: Matt Kane Date: Wed, 12 Oct 2022 12:28:41 +0100 Subject: [PATCH 11/18] chore: error handling --- packages/runtime/src/helpers/edge.ts | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/packages/runtime/src/helpers/edge.ts b/packages/runtime/src/helpers/edge.ts index 06ec6e5b24..61cd017e97 100644 --- a/packages/runtime/src/helpers/edge.ts +++ b/packages/runtime/src/helpers/edge.ts @@ -90,17 +90,21 @@ import { // Next uses blob: urls to refer to local assets, so we need to intercept these const _fetch = globalThis.fetch - const fetch = async (url, init) => { - if (typeof url === 'object' && url.href?.startsWith('blob:')) { - const key = url.href.slice(5) - if (key in _ASSETS) { - return new Response(_base64Decode(_ASSETS[key])) + const fetch = async (url, init) => { + try { + if (typeof url === 'object' && url.href?.startsWith('blob:')) { + const key = url.href.slice(5) + if (key in _ASSETS) { + return new Response(_base64Decode(_ASSETS[key])) + } } + console.log('fetch', url) + return await _fetch(url, init) + } catch (error) { + console.error(error) + throw error } - return _fetch(url, init) - } - - + } ` From 3275dbb0bcbab266fd4457fa874e711140d8c392 Mon Sep 17 00:00:00 2001 From: Matt Kane Date: Wed, 12 Oct 2022 12:41:03 +0100 Subject: [PATCH 12/18] chore: remove log and format --- packages/runtime/src/helpers/edge.ts | 37 ++++++++++++++-------------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/packages/runtime/src/helpers/edge.ts b/packages/runtime/src/helpers/edge.ts index 61cd017e97..23d95e256b 100644 --- a/packages/runtime/src/helpers/edge.ts +++ b/packages/runtime/src/helpers/edge.ts @@ -81,30 +81,29 @@ const preamble = /* js */ ` import { decode as _base64Decode, } from "https://deno.land/std@0.159.0/encoding/base64.ts"; - // Deno defines "window", but naughty libraries think this means it's a browser - delete globalThis.window - globalThis.process = { env: {...Deno.env.toObject(), NEXT_RUNTIME: 'edge', 'NEXT_PRIVATE_MINIMAL_MODE': '1' } } - // Next uses "self" as a function-scoped global-like object - const self = {} - let _ENTRIES = {} +// Deno defines "window", but naughty libraries think this means it's a browser +delete globalThis.window +globalThis.process = { env: {...Deno.env.toObject(), NEXT_RUNTIME: 'edge', 'NEXT_PRIVATE_MINIMAL_MODE': '1' } } +// Next uses "self" as a function-scoped global-like object +const self = {} +let _ENTRIES = {} // Next uses blob: urls to refer to local assets, so we need to intercept these - const _fetch = globalThis.fetch - const fetch = async (url, init) => { - try { - if (typeof url === 'object' && url.href?.startsWith('blob:')) { - const key = url.href.slice(5) - if (key in _ASSETS) { - return new Response(_base64Decode(_ASSETS[key])) - } +const _fetch = globalThis.fetch +const fetch = async (url, init) => { + try { + if (typeof url === 'object' && url.href?.startsWith('blob:')) { + const key = url.href.slice(5) + if (key in _ASSETS) { + return new Response(_base64Decode(_ASSETS[key])) } - console.log('fetch', url) - return await _fetch(url, init) - } catch (error) { - console.error(error) - throw error } + return await _fetch(url, init) + } catch (error) { + console.error(error) + throw error } +} ` From 3258cc0246482d9cf93fc2114d99169d70614c12 Mon Sep 17 00:00:00 2001 From: Matt Kane Date: Fri, 14 Oct 2022 10:54:28 +0100 Subject: [PATCH 13/18] chore: add e2e test --- cypress/integration/default/wasm.spec.ts | 8 ++++++++ demos/default/pages/api/og.tsx | 14 ++++++-------- 2 files changed, 14 insertions(+), 8 deletions(-) create mode 100644 cypress/integration/default/wasm.spec.ts diff --git a/cypress/integration/default/wasm.spec.ts b/cypress/integration/default/wasm.spec.ts new file mode 100644 index 0000000000..e651431e03 --- /dev/null +++ b/cypress/integration/default/wasm.spec.ts @@ -0,0 +1,8 @@ +describe('WebAssembly support', () => { + it('generates an API route with wasm chunks', () => { + cy.request('/api/og?username=netlify').then((response) => { + // Failure state is zero-length body + expect(response.body).to.have.length.above(10000) + }) + }) +}) diff --git a/demos/default/pages/api/og.tsx b/demos/default/pages/api/og.tsx index 4fd08722fd..75f1069bac 100644 --- a/demos/default/pages/api/og.tsx +++ b/demos/default/pages/api/og.tsx @@ -8,12 +8,6 @@ export const config = { export default async function handler(req: NextRequest) { const { searchParams } = req.nextUrl const username = searchParams.get('username') - if (!username) { - return new ImageResponse(<>Visit with "?username=netlify", { - width: 1200, - height: 630, - }) - } return new ImageResponse( ( @@ -34,17 +28,21 @@ export default async function handler(req: NextRequest) { -

github.com/{username}

+ {username ?

github.com/{username}

:

Visit with "?username=netlify"

} ), { width: 1200, height: 630, + headers: { + // By default this has an immutable cache, but this is for testing + 'Cache-Control': 'public, max-age=0, must-revalidate', + }, }, ) } From 983444def452622fdd13018326e234bab1ad9615 Mon Sep 17 00:00:00 2001 From: Matt Kane Date: Mon, 17 Oct 2022 18:51:09 +0100 Subject: [PATCH 14/18] chore: fix test --- package-lock.json | 65 +++++++++++++++++++---------------------------- test/index.js | 18 +++++++++---- 2 files changed, 39 insertions(+), 44 deletions(-) diff --git a/package-lock.json b/package-lock.json index c0f8058843..78eaaa238d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5581,13 +5581,13 @@ "version": "15.7.5", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==", - "devOptional": true + "dev": true }, "node_modules/@types/react": { "version": "17.0.50", "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.50.tgz", "integrity": "sha512-ZCBHzpDb5skMnc1zFXAXnL3l1FAdi+xZvwxK+PkglMmBrwjpp9nKaWuEvrGnSifCJmBFGxZOOFuwC6KH/s0NuA==", - "devOptional": true, + "dev": true, "dependencies": { "@types/prop-types": "*", "@types/scheduler": "*", @@ -5613,7 +5613,7 @@ "version": "0.16.2", "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==", - "devOptional": true + "dev": true }, "node_modules/@types/sinonjs__fake-timers": { "version": "8.1.1", @@ -9198,7 +9198,7 @@ "version": "3.0.11", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.11.tgz", "integrity": "sha512-sa6P2wJ+CAbgyy4KFssIb/JNMLxFvKF1pCYCSXS8ZMuqZnMsrxqI2E5sPyoTpxoPU/gVZMzr2zjOfg8GIZOMsw==", - "devOptional": true + "dev": true }, "node_modules/custom-routes": { "resolved": "demos/custom-routes", @@ -13235,7 +13235,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.0.0.tgz", "integrity": "sha512-zIE9hX70qew5qTUjSS7wi1iwj/l7+m54KWU247nhM3v806UdGj1yDndXj+IOYxxtW9zyLI+xqFNZjTuDaLUqFw==", - "devOptional": true + "dev": true }, "node_modules/import-fresh": { "version": "3.3.0", @@ -20411,7 +20411,7 @@ "version": "1.50.1", "resolved": "https://registry.npmjs.org/sass/-/sass-1.50.1.tgz", "integrity": "sha512-noTnY41KnlW2A9P8sdwESpDmo+KBNkukI1i8+hOK3footBUcohNHtdOJbckp46XO95nuvcHDDZ+4tmOnpK3hjw==", - "devOptional": true, + "dev": true, "dependencies": { "chokidar": ">=3.0.0 <4.0.0", "immutable": "^4.0.0", @@ -23482,7 +23482,7 @@ }, "packages/runtime": { "name": "@netlify/plugin-nextjs", - "version": "4.25.0", + "version": "4.26.0", "license": "MIT", "dependencies": { "@netlify/esbuild": "0.14.39", @@ -25996,8 +25996,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-3.0.0.tgz", "integrity": "sha512-V3wD15YHfHz6y0KdhYFjyy9vWtEVALT9UrxfN3zqlI6dMioHnJrqOYfyPKol3oqrnCM9uwkcdCwkJ0WUcbLMTQ==", - "dev": true, - "requires": {} + "dev": true }, "chalk": { "version": "5.1.0", @@ -26348,8 +26347,7 @@ "version": "17.0.0", "resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-17.0.0.tgz", "integrity": "sha512-/2ks1GKyqSOkH7JFvXJicu0iMpoojkwB+f5Du/1SC0PtBL+s8v30k9njRZ21pm2drKYm2342jFnGWzttxPmZVg==", - "dev": true, - "requires": {} + "dev": true }, "eslint-import-resolver-typescript": { "version": "3.3.0", @@ -27270,13 +27268,13 @@ "version": "15.7.5", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==", - "devOptional": true + "dev": true }, "@types/react": { "version": "17.0.50", "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.50.tgz", "integrity": "sha512-ZCBHzpDb5skMnc1zFXAXnL3l1FAdi+xZvwxK+PkglMmBrwjpp9nKaWuEvrGnSifCJmBFGxZOOFuwC6KH/s0NuA==", - "devOptional": true, + "dev": true, "requires": { "@types/prop-types": "*", "@types/scheduler": "*", @@ -27302,7 +27300,7 @@ "version": "0.16.2", "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==", - "devOptional": true + "dev": true }, "@types/sinonjs__fake-timers": { "version": "8.1.1", @@ -27625,8 +27623,7 @@ "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "requires": {} + "dev": true }, "acorn-walk": { "version": "7.2.0", @@ -30012,7 +30009,7 @@ "version": "3.0.11", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.11.tgz", "integrity": "sha512-sa6P2wJ+CAbgyy4KFssIb/JNMLxFvKF1pCYCSXS8ZMuqZnMsrxqI2E5sPyoTpxoPU/gVZMzr2zjOfg8GIZOMsw==", - "devOptional": true + "dev": true }, "custom-routes": { "version": "file:demos/custom-routes", @@ -31143,8 +31140,7 @@ "version": "8.5.0", "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.5.0.tgz", "integrity": "sha512-obmWKLUNCnhtQRKc+tmnYuQl0pFU1ibYJQ5BGhTVB08bHe9wC8qUeG7c08dj9XX+AuPj1YSGSQIHl1pnDHZR0Q==", - "dev": true, - "requires": {} + "dev": true }, "eslint-formatter-codeframe": { "version": "7.32.1", @@ -31589,8 +31585,7 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-6.0.1.tgz", "integrity": "sha512-uM4Tgo5u3UWQiroOyDEsYcVMOo7re3zmno0IZmB5auxoaQNIceAbXEkSt8RNrKtaYehARHG06pYK6K1JhtP0Zw==", - "dev": true, - "requires": {} + "dev": true }, "eslint-plugin-react": { "version": "7.29.4", @@ -31638,8 +31633,7 @@ "version": "4.5.0", "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.5.0.tgz", "integrity": "sha512-8k1gRt7D7h03kd+SAAlzXkQwWK22BnK6GKZG+FJA6BAGy22CFvl8kCIXKpVux0cCxMWDQUPqSok0LKaZ0aOcCw==", - "dev": true, - "requires": {} + "dev": true }, "eslint-plugin-unicorn": { "version": "43.0.2", @@ -33123,7 +33117,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.0.0.tgz", "integrity": "sha512-zIE9hX70qew5qTUjSS7wi1iwj/l7+m54KWU247nhM3v806UdGj1yDndXj+IOYxxtW9zyLI+xqFNZjTuDaLUqFw==", - "devOptional": true + "dev": true }, "import-fresh": { "version": "3.3.0", @@ -34176,8 +34170,7 @@ "version": "1.2.2", "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz", "integrity": "sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==", - "dev": true, - "requires": {} + "dev": true }, "jest-regex-util": { "version": "27.5.1", @@ -38602,7 +38595,7 @@ "version": "1.50.1", "resolved": "https://registry.npmjs.org/sass/-/sass-1.50.1.tgz", "integrity": "sha512-noTnY41KnlW2A9P8sdwESpDmo+KBNkukI1i8+hOK3footBUcohNHtdOJbckp46XO95nuvcHDDZ+4tmOnpK3hjw==", - "devOptional": true, + "dev": true, "requires": { "chokidar": ">=3.0.0 <4.0.0", "immutable": "^4.0.0", @@ -38876,14 +38869,12 @@ "styled-jsx": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.0.2.tgz", - "integrity": "sha512-LqPQrbBh3egD57NBcHET4qcgshPks+yblyhPlH2GY8oaDgKs8SK4C3dBh3oSJjgzJ3G5t1SYEZGHkP+QEpX9EQ==", - "requires": {} + "integrity": "sha512-LqPQrbBh3egD57NBcHET4qcgshPks+yblyhPlH2GY8oaDgKs8SK4C3dBh3oSJjgzJ3G5t1SYEZGHkP+QEpX9EQ==" }, "use-sync-external-store": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.1.0.tgz", - "integrity": "sha512-SEnieB2FPKEVne66NpXPd1Np4R1lTNKfjuy3XdIoPQKYBAFdzbzSZlSn1KJZUiihQLQC5Znot4SBz1EOTBwQAQ==", - "requires": {} + "integrity": "sha512-SEnieB2FPKEVne66NpXPd1Np4R1lTNKfjuy3XdIoPQKYBAFdzbzSZlSn1KJZUiihQLQC5Znot4SBz1EOTBwQAQ==" } } }, @@ -39700,8 +39691,7 @@ "styled-jsx": { "version": "5.0.6", "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.0.6.tgz", - "integrity": "sha512-xOeROtkK5MGMDimBQ3J6iPId8q0t/BDoG5XN6oKkZClVz9ISF/hihN8OCn2LggMU6N32aXnrXBdn3auSqNS9fA==", - "requires": {} + "integrity": "sha512-xOeROtkK5MGMDimBQ3J6iPId8q0t/BDoG5XN6oKkZClVz9ISF/hihN8OCn2LggMU6N32aXnrXBdn3auSqNS9fA==" }, "supports-color": { "version": "9.2.2", @@ -40429,8 +40419,7 @@ "ws": { "version": "8.9.0", "resolved": "https://registry.npmjs.org/ws/-/ws-8.9.0.tgz", - "integrity": "sha512-Ja7nszREasGaYUYCI2k4lCKIRTt+y7XuqVoHR44YpI49TtryyqbqvDMn5eqfW7e6HzTukDRIsXqzVHScqRcafg==", - "requires": {} + "integrity": "sha512-Ja7nszREasGaYUYCI2k4lCKIRTt+y7XuqVoHR44YpI49TtryyqbqvDMn5eqfW7e6HzTukDRIsXqzVHScqRcafg==" } } }, @@ -40548,8 +40537,7 @@ "use-sync-external-store": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz", - "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==", - "requires": {} + "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==" }, "util-deprecate": { "version": "1.0.2", @@ -40954,8 +40942,7 @@ "version": "7.5.7", "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.7.tgz", "integrity": "sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A==", - "dev": true, - "requires": {} + "dev": true }, "xdg-basedir": { "version": "4.0.0", diff --git a/test/index.js b/test/index.js index c3046db7bd..9639e9a892 100644 --- a/test/index.js +++ b/test/index.js @@ -590,16 +590,16 @@ describe('onBuild()', () => { process.env.DISABLE_IPX = '1' await moveNextDist() await nextRuntime.onBuild(defaultArgs) - const nextImageRedirect = netlifyConfig.redirects.find(redirect => redirect.from.includes('/_next/image')) - + const nextImageRedirect = netlifyConfig.redirects.find((redirect) => redirect.from.includes('/_next/image')) + expect(nextImageRedirect).toBeDefined() - expect(nextImageRedirect.to).toEqual("/404.html") + expect(nextImageRedirect.to).toEqual('/404.html') expect(nextImageRedirect.status).toEqual(404) expect(nextImageRedirect.force).toEqual(true) - + delete process.env.DISABLE_IPX }) - + test('generates an ipx edge function by default', async () => { await moveNextDist() await nextRuntime.onBuild(defaultArgs) @@ -617,6 +617,14 @@ describe('onBuild()', () => { test('does not generate an ipx edge function if Netlify Edge is disabled', async () => { process.env.NEXT_DISABLE_NETLIFY_EDGE = '1' await moveNextDist() + + // We need to pretend there's no edge API routes, because otherwise it'll fail + // when we try to disable edge runtime. + const manifest = path.join('.next', 'server', 'middleware-manifest.json') + const manifestContent = await readJson(manifest) + manifestContent.functions = {} + await writeJSON(manifest, manifestContent) + await nextRuntime.onBuild(defaultArgs) expect(existsSync(path.join('.netlify', 'edge-functions', 'ipx', 'index.ts'))).toBeFalsy() From 348abe07a1c1e89d133e948a928374a607b5b142 Mon Sep 17 00:00:00 2001 From: Matt Kane Date: Mon, 17 Oct 2022 19:00:46 +0100 Subject: [PATCH 15/18] chore: re-enable dev check in edge function --- packages/runtime/src/templates/edge/runtime.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/runtime/src/templates/edge/runtime.ts b/packages/runtime/src/templates/edge/runtime.ts index 89c7744784..e5b1870184 100644 --- a/packages/runtime/src/templates/edge/runtime.ts +++ b/packages/runtime/src/templates/edge/runtime.ts @@ -50,10 +50,10 @@ declare global { globalThis.NFRequestContextMap ||= new Map() const handler = async (req: Request, context: Context) => { - // if (Deno.env.get('NETLIFY_DEV')) { - // // Don't run in dev - // return - // } + if (Deno.env.get('NETLIFY_DEV')) { + // Don't run in dev + return + } const url = new URL(req.url) From c73b56404b257381ee1c6b087e4c0286ab7014b9 Mon Sep 17 00:00:00 2001 From: Matt Kane Date: Mon, 17 Oct 2022 22:48:50 +0100 Subject: [PATCH 16/18] chore: change from review --- demos/default/next.config.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/demos/default/next.config.js b/demos/default/next.config.js index 43ea089e48..f91db4024b 100644 --- a/demos/default/next.config.js +++ b/demos/default/next.config.js @@ -8,9 +8,6 @@ module.exports = { defaultLocale: 'en', locales: ['en', 'es', 'fr'], }, - eslint: { - ignoreDuringBuilds: true, - }, async headers() { return [ { From 6cb97a897d69cd0218a1b135dc4a43a54972e251 Mon Sep 17 00:00:00 2001 From: Matt Kane Date: Tue, 18 Oct 2022 09:55:20 +0100 Subject: [PATCH 17/18] chore: update snapshots --- package-lock.json | 2 +- test/__snapshots__/index.js.snap | 5 +++++ test/index.js | 7 +++++++ 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/package-lock.json b/package-lock.json index 78eaaa238d..a3ab065c9d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23482,7 +23482,7 @@ }, "packages/runtime": { "name": "@netlify/plugin-nextjs", - "version": "4.26.0", + "version": "4.27.0", "license": "MIT", "dependencies": { "@netlify/esbuild": "0.14.39", diff --git a/test/__snapshots__/index.js.snap b/test/__snapshots__/index.js.snap index 512b8b85bf..88c6391bfc 100644 --- a/test/__snapshots__/index.js.snap +++ b/test/__snapshots__/index.js.snap @@ -1120,6 +1120,11 @@ Array [ "status": 404, "to": "/404.html", }, + Object { + "from": "/api/og", + "status": 200, + "to": "/.netlify/functions/_api_og-handler", + }, Object { "from": "/api/shows/:id", "status": 200, diff --git a/test/index.js b/test/index.js index e2b3d8ad92..842ae14f5e 100644 --- a/test/index.js +++ b/test/index.js @@ -1594,6 +1594,13 @@ describe('api route file analysis', () => { config: { schedule: '@hourly', type: 'experimental-scheduled' }, route: '/api/hello-scheduled', }, + { + compiled: 'pages/api/og.js', + config: { + runtime: 'experimental-edge', + }, + route: '/api/og', + }, ]), ) }) From 414413509a980ffa5740b1f4f1a978786130cbed Mon Sep 17 00:00:00 2001 From: Matt Kane Date: Mon, 24 Oct 2022 20:55:10 +0100 Subject: [PATCH 18/18] fix: correct content-length in middleware --- packages/runtime/src/templates/edge-shared/utils.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/runtime/src/templates/edge-shared/utils.ts b/packages/runtime/src/templates/edge-shared/utils.ts index b741bab623..4d9b95cde6 100644 --- a/packages/runtime/src/templates/edge-shared/utils.ts +++ b/packages/runtime/src/templates/edge-shared/utils.ts @@ -83,7 +83,10 @@ export const buildResponse = async ({ const transformed = response.dataTransforms.reduce((prev, transform) => { return transform(prev) }, props) - return new Response(JSON.stringify(transformed), response) + const body = JSON.stringify(transformed) + const headers = new Headers(response.headers) + headers.set('content-length', String(body.length)) + return new Response(body, { ...response, headers }) } // This var will hold the contents of the script tag let buffer = ''