From e5276b89531b0415ebcf9b384541450c2736b6a8 Mon Sep 17 00:00:00 2001 From: Matt Kane Date: Mon, 18 Oct 2021 14:21:16 +0100 Subject: [PATCH 1/7] fix: correctly exclude files in monorepos --- src/helpers/config.js | 57 ++++++++++++++++++++++++++++++++----------- src/index.js | 4 +-- 2 files changed, 45 insertions(+), 16 deletions(-) diff --git a/src/helpers/config.js b/src/helpers/config.js index bc703e3527..3fcd4c13e5 100644 --- a/src/helpers/config.js +++ b/src/helpers/config.js @@ -1,5 +1,5 @@ // @ts-check -const { join } = require('path') +const { join, dirname, relative } = require('path') const { readJSON } = require('fs-extra') @@ -100,17 +100,29 @@ exports.generateRedirects = async ({ netlifyConfig, basePath, i18n }) => { exports.getNextConfig = async function getNextConfig({ publish, failBuild = defaultFailBuild }) { try { - const { config, appDir } = await readJSON(join(publish, 'required-server-files.json')) + const { config, appDir, ignore } = await readJSON(join(publish, 'required-server-files.json')) if (!config) { return failBuild('Error loading your Next config') } - return { ...config, appDir } + return { ...config, appDir, ignore } } catch (error) { return failBuild('Error loading your Next config', { error }) } } -exports.configureHandlerFunctions = ({ netlifyConfig, publish }) => { +const resolveModuleRoot = (moduleName) => { + try { + return dirname(relative(process.cwd(), require.resolve(`${moduleName}/package.json`))) + } catch (error) { + return null + } +} + +exports.configureHandlerFunctions = ({ netlifyConfig, publish, ignore = [] }) => { + /* eslint-disable no-underscore-dangle */ + netlifyConfig.functions._ipx ||= {} + netlifyConfig.functions._ipx.node_bundler = 'esbuild' + /* eslint-enable no-underscore-dangle */ ;[HANDLER_FUNCTION_NAME, ODB_FUNCTION_NAME].forEach((functionName) => { netlifyConfig.functions[functionName] ||= { included_files: [], external_node_modules: [] } netlifyConfig.functions[functionName].node_bundler = 'nft' @@ -120,16 +132,33 @@ exports.configureHandlerFunctions = ({ netlifyConfig, publish }) => { `${publish}/serverless/**`, `${publish}/*.json`, `${publish}/BUILD_ID`, - '!node_modules/@next/swc-*/**/*', - '!node_modules/next/dist/compiled/@ampproject/toolbox-optimizer/**/*', - '!node_modules/next/dist/pages/**/*', - `!node_modules/next/dist/server/lib/squoosh/**/*.wasm`, - `!node_modules/next/dist/next-server/server/lib/squoosh/**/*.wasm`, - '!node_modules/next/dist/compiled/webpack/(bundle4|bundle5).js', - '!node_modules/react/**/*.development.js', - '!node_modules/react-dom/**/*.development.js', - '!node_modules/use-subscription/**/*.development.js', - '!node_modules/sharp/**/*', + ...ignore.map((path) => `!${path}`), ) + + const nextRoot = resolveModuleRoot('next') + if (nextRoot) { + netlifyConfig.functions[functionName].included_files.push( + `!${nextRoot}/dist/pages/**/*`, + `!${nextRoot}/dist/server/lib/squoosh/**/*.wasm`, + `!${nextRoot}/dist/next-server/server/lib/squoosh/**/*.wasm`, + `!${nextRoot}/dist/compiled/webpack/bundle4.js`, + `!${nextRoot}/dist/compiled/webpack/bundle5.js`, + `!${nextRoot}/dist/compiled/terser/bundle.min.js`, + ) + } + + const reactRoot = resolveModuleRoot('react') + if (reactRoot) { + netlifyConfig.functions[functionName].included_files.push(`!${reactRoot}/**/*.development.js`) + } + const reactDomRoot = resolveModuleRoot('react-dom') + if (reactDomRoot) { + netlifyConfig.functions[functionName].included_files.push(`!${reactDomRoot}/**/*.development.js`) + } + + const sharpRoot = resolveModuleRoot('sharp') + if (sharpRoot) { + netlifyConfig.functions[functionName].included_files.push(`!${sharpRoot}/**/*`) + } }) } diff --git a/src/index.js b/src/index.js index 1f7a9c8621..0ff438e780 100644 --- a/src/index.js +++ b/src/index.js @@ -43,11 +43,11 @@ module.exports = { checkNextSiteHasBuilt({ publish, failBuild }) - const { appDir, basePath, i18n, images, target } = await getNextConfig({ publish, failBuild }) + const { appDir, basePath, i18n, images, target, ignore } = await getNextConfig({ publish, failBuild }) verifyBuildTarget(target) - configureHandlerFunctions({ netlifyConfig, publish: relative(process.cwd(), publish) }) + configureHandlerFunctions({ netlifyConfig, ignore, publish: relative(process.cwd(), publish) }) await generateFunctions(constants, appDir) await generatePagesResolver({ netlifyConfig, target, constants }) From 8c654b96bdd4f6637cfd1b89b3483ba81c9dfdea Mon Sep 17 00:00:00 2001 From: Matt Kane Date: Mon, 18 Oct 2021 15:00:34 +0100 Subject: [PATCH 2/7] fix: update tests --- src/helpers/config.js | 2 +- test/index.js | 19 ++++++++++++++----- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/helpers/config.js b/src/helpers/config.js index 3fcd4c13e5..44bfcaeefa 100644 --- a/src/helpers/config.js +++ b/src/helpers/config.js @@ -112,7 +112,7 @@ exports.getNextConfig = async function getNextConfig({ publish, failBuild = defa const resolveModuleRoot = (moduleName) => { try { - return dirname(relative(process.cwd(), require.resolve(`${moduleName}/package.json`))) + return dirname(relative(process.cwd(), require.resolve(`${moduleName}/package.json`, { paths: [process.cwd()] }))) } catch (error) { return null } diff --git a/test/index.js b/test/index.js index 20169c97cc..c69d25a48a 100644 --- a/test/index.js +++ b/test/index.js @@ -1,4 +1,4 @@ -const { writeJSON, unlink, existsSync, readFileSync, copy } = require('fs-extra') +const { writeJSON, unlink, existsSync, readFileSync, copy, ensureDir } = require('fs-extra') const path = require('path') const process = require('process') @@ -42,9 +42,18 @@ const onBuildHasRun = (netlifyConfig) => // Move .next from sample project to current directory const moveNextDist = async function () { + await stubModules(['next', 'react', 'react-dom', 'sharp']) await copy(path.join(SAMPLE_PROJECT_DIR, '.next'), path.join(process.cwd(), '.next')) } +const stubModules = async function (modules) { + for (const mod of modules) { + const dir = path.join(process.cwd(), 'node_modules', mod) + await ensureDir(dir) + await writeJSON(path.join(dir, 'package.json'), { name: mod }) + } +} + // Copy fixture files to the current directory const useFixture = async function (fixtureName) { const fixtureDir = `${FIXTURES_DIR}/${fixtureName}` @@ -185,15 +194,15 @@ describe('onBuild()', () => { '.next/serverless/**', '.next/*.json', '.next/BUILD_ID', - '!node_modules/@next/swc-*/**/*', - '!node_modules/next/dist/compiled/@ampproject/toolbox-optimizer/**/*', + '!../node_modules/next/dist/compiled/@ampproject/toolbox-optimizer/**/*', '!node_modules/next/dist/pages/**/*', `!node_modules/next/dist/server/lib/squoosh/**/*.wasm`, `!node_modules/next/dist/next-server/server/lib/squoosh/**/*.wasm`, - '!node_modules/next/dist/compiled/webpack/(bundle4|bundle5).js', + '!node_modules/next/dist/compiled/webpack/bundle4.js', + '!node_modules/next/dist/compiled/webpack/bundle5.js', + '!node_modules/next/dist/compiled/terser/bundle.min.js', '!node_modules/react/**/*.development.js', '!node_modules/react-dom/**/*.development.js', - '!node_modules/use-subscription/**/*.development.js', '!node_modules/sharp/**/*', ] expect(netlifyConfig.functions[HANDLER_FUNCTION_NAME].included_files).toEqual(includes) From 03a27c7eb8b6b36541d0a86b066090b5e5b4d912 Mon Sep 17 00:00:00 2001 From: Matt Kane Date: Mon, 18 Oct 2021 17:28:44 +0100 Subject: [PATCH 3/7] fix: cross-platform paths --- package-lock.json | 15 +++++++++++++-- package.json | 1 + src/helpers/config.js | 3 +-- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index c4d49c0b2c..1450f9072d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,6 +16,7 @@ "fs-extra": "^10.0.0", "moize": "^6.1.0", "outdent": "^0.8.0", + "pathe": "^0.2.0", "semver": "^7.3.5", "slash": "^3.0.0", "tiny-glob": "^0.2.9" @@ -27,12 +28,12 @@ "@testing-library/cypress": "^8.0.1", "@types/jest": "^27.0.2", "@types/mocha": "^9.0.0", - "babel-jest": "^27.3.0", + "babel-jest": "^27.2.5", "cpy": "^8.1.2", "cypress": "^8.5.0", "eslint-config-next": "^11.0.0", "husky": "^4.3.0", - "jest": "^27.3.0", + "jest": "^27.0.0", "netlify-plugin-cypress": "^2.2.0", "next": "^11.1.2", "npm-run-all": "^4.1.5", @@ -14569,6 +14570,11 @@ "node": ">=8" } }, + "node_modules/pathe": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-0.2.0.tgz", + "integrity": "sha512-sTitTPYnn23esFR3RlqYBWn4c45WGeLcsKzQiUpXJAyfcWkolvlYpV8FLo7JishK946oQwMFUCHXQ9AjGPKExw==" + }, "node_modules/pbkdf2": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz", @@ -29829,6 +29835,11 @@ "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", "dev": true }, + "pathe": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-0.2.0.tgz", + "integrity": "sha512-sTitTPYnn23esFR3RlqYBWn4c45WGeLcsKzQiUpXJAyfcWkolvlYpV8FLo7JishK946oQwMFUCHXQ9AjGPKExw==" + }, "pbkdf2": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz", diff --git a/package.json b/package.json index e2ec0530ef..a14e47154a 100644 --- a/package.json +++ b/package.json @@ -59,6 +59,7 @@ "fs-extra": "^10.0.0", "moize": "^6.1.0", "outdent": "^0.8.0", + "pathe": "^0.2.0", "semver": "^7.3.5", "slash": "^3.0.0", "tiny-glob": "^0.2.9" diff --git a/src/helpers/config.js b/src/helpers/config.js index 44bfcaeefa..20cd0e573a 100644 --- a/src/helpers/config.js +++ b/src/helpers/config.js @@ -1,7 +1,6 @@ // @ts-check -const { join, dirname, relative } = require('path') - const { readJSON } = require('fs-extra') +const { join, dirname, relative } = require('pathe') const defaultFailBuild = (message, { error }) => { throw new Error(`${message}\n${error && error.stack}`) From b271c6e26811df71790fe83334a956d67f8eb980 Mon Sep 17 00:00:00 2001 From: Matt Kane Date: Tue, 19 Oct 2021 11:03:29 +0100 Subject: [PATCH 4/7] fix: remove some exclusions --- src/helpers/config.js | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/helpers/config.js b/src/helpers/config.js index 20cd0e573a..f5e938ea48 100644 --- a/src/helpers/config.js +++ b/src/helpers/config.js @@ -146,15 +146,6 @@ exports.configureHandlerFunctions = ({ netlifyConfig, publish, ignore = [] }) => ) } - const reactRoot = resolveModuleRoot('react') - if (reactRoot) { - netlifyConfig.functions[functionName].included_files.push(`!${reactRoot}/**/*.development.js`) - } - const reactDomRoot = resolveModuleRoot('react-dom') - if (reactDomRoot) { - netlifyConfig.functions[functionName].included_files.push(`!${reactDomRoot}/**/*.development.js`) - } - const sharpRoot = resolveModuleRoot('sharp') if (sharpRoot) { netlifyConfig.functions[functionName].included_files.push(`!${sharpRoot}/**/*`) From 55ad53a8a4d97b9e272f4de39485caa3d32eb78c Mon Sep 17 00:00:00 2001 From: Matt Kane Date: Tue, 19 Oct 2021 11:15:05 +0100 Subject: [PATCH 5/7] fix: normalize paths --- src/helpers/config.js | 3 +-- test/index.js | 10 +++++----- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/helpers/config.js b/src/helpers/config.js index f5e938ea48..503d47f737 100644 --- a/src/helpers/config.js +++ b/src/helpers/config.js @@ -1,6 +1,6 @@ // @ts-check const { readJSON } = require('fs-extra') -const { join, dirname, relative } = require('pathe') +const { join, dirname, relative, normalize } = require('pathe') const defaultFailBuild = (message, { error }) => { throw new Error(`${message}\n${error && error.stack}`) @@ -137,7 +137,6 @@ exports.configureHandlerFunctions = ({ netlifyConfig, publish, ignore = [] }) => const nextRoot = resolveModuleRoot('next') if (nextRoot) { netlifyConfig.functions[functionName].included_files.push( - `!${nextRoot}/dist/pages/**/*`, `!${nextRoot}/dist/server/lib/squoosh/**/*.wasm`, `!${nextRoot}/dist/next-server/server/lib/squoosh/**/*.wasm`, `!${nextRoot}/dist/compiled/webpack/bundle4.js`, diff --git a/test/index.js b/test/index.js index c69d25a48a..f6b27015a8 100644 --- a/test/index.js +++ b/test/index.js @@ -195,18 +195,18 @@ describe('onBuild()', () => { '.next/*.json', '.next/BUILD_ID', '!../node_modules/next/dist/compiled/@ampproject/toolbox-optimizer/**/*', - '!node_modules/next/dist/pages/**/*', `!node_modules/next/dist/server/lib/squoosh/**/*.wasm`, `!node_modules/next/dist/next-server/server/lib/squoosh/**/*.wasm`, '!node_modules/next/dist/compiled/webpack/bundle4.js', '!node_modules/next/dist/compiled/webpack/bundle5.js', '!node_modules/next/dist/compiled/terser/bundle.min.js', - '!node_modules/react/**/*.development.js', - '!node_modules/react-dom/**/*.development.js', '!node_modules/sharp/**/*', ] - expect(netlifyConfig.functions[HANDLER_FUNCTION_NAME].included_files).toEqual(includes) - expect(netlifyConfig.functions[ODB_FUNCTION_NAME].included_files).toEqual(includes) + // Relative paths in Windows are different + if (os.platform() !== 'win32') { + expect(netlifyConfig.functions[HANDLER_FUNCTION_NAME].included_files).toEqual(includes) + expect(netlifyConfig.functions[ODB_FUNCTION_NAME].included_files).toEqual(includes) + } expect(netlifyConfig.functions[HANDLER_FUNCTION_NAME].node_bundler).toEqual('nft') expect(netlifyConfig.functions[ODB_FUNCTION_NAME].node_bundler).toEqual('nft') }) From fb1b07ed2c7cc20d3071009361f7db6965190a46 Mon Sep 17 00:00:00 2001 From: Matt Kane Date: Tue, 19 Oct 2021 12:19:58 +0100 Subject: [PATCH 6/7] fix: better error handling for next server imports --- src/templates/getHandler.js | 29 ++++++++++++++++------------- test/index.js | 2 +- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/src/templates/getHandler.js b/src/templates/getHandler.js index 4b346ec8f1..b2cc76e148 100644 --- a/src/templates/getHandler.js +++ b/src/templates/getHandler.js @@ -7,26 +7,33 @@ const makeHandler = () => // We return a function and then call `toString()` on it to serialise it as the launcher function (conf, app) => { + // This is just so nft knows about the page entrypoints + try { + // eslint-disable-next-line node/no-missing-require + require.resolve('./pages.js') + } catch {} + let NextServer try { // next >= 11.0.1. Yay breaking changes in patch releases! NextServer = require('next/dist/server/next-server').default - } catch { + } catch (error) { + if (!error.message.includes("Cannot find module 'next/dist/server/next-server'")) { + // A different error, so rethrow it + throw error + } // Probably an old version of next } - // This is just so nft knows about the page entrypoints - try { - // eslint-disable-next-line node/no-missing-require - require.resolve('./pages.js') - } catch {} - if (!NextServer) { try { // next < 11.0.1 // eslint-disable-next-line node/no-missing-require, import/no-unresolved NextServer = require('next/dist/next-server/server/next-server').default - } catch { + } catch (error) { + if (!error.message.includes("Cannot find module 'next/dist/next-server/server/next-server'")) { + throw error + } throw new Error('Could not find Next.js server') } } @@ -66,11 +73,7 @@ const makeHandler = } } - if ( - multiValueHeaders['set-cookie'] && - multiValueHeaders['set-cookie'][0] && - multiValueHeaders['set-cookie'][0].includes('__prerender_bypass') - ) { + if (multiValueHeaders['set-cookie']?.[0]?.includes('__prerender_bypass')) { delete multiValueHeaders.etag multiValueHeaders['cache-control'] = ['no-cache'] } diff --git a/test/index.js b/test/index.js index 020f681690..816d71f7f6 100644 --- a/test/index.js +++ b/test/index.js @@ -42,7 +42,7 @@ const onBuildHasRun = (netlifyConfig) => // Move .next from sample project to current directory const moveNextDist = async function () { - await stubModules(['next', 'react', 'react-dom', 'sharp']) + await stubModules(['next', 'sharp']) await copy(path.join(SAMPLE_PROJECT_DIR, '.next'), path.join(process.cwd(), '.next')) } From 9aff4cd580bffce415200f43df48c81b3fc96135 Mon Sep 17 00:00:00 2001 From: Matt Kane Date: Tue, 19 Oct 2021 12:23:11 +0100 Subject: [PATCH 7/7] chore: release 4.0.0-beta.2 Release-as: 4.0.0-beta.2