From e8067bf13ec94fac80ca6ce495a32249dcd5130c Mon Sep 17 00:00:00 2001 From: Matt Kane Date: Thu, 3 Feb 2022 13:34:21 +0000 Subject: [PATCH 1/2] fix: correctly disable ISR disk flushing (#1190) * chore: add blocking ISR demo * fix: ensure all files are patched correctly --- .../withFallbackBlocking/[id].js | 45 +++++++++++++ src/helpers/files.ts | 50 +++++++++------ src/helpers/utils.ts | 17 +++++ test/__snapshots__/index.js.snap | 64 +++++++++++++++++++ test/index.js | 29 ++++++++- 5 files changed, 182 insertions(+), 23 deletions(-) create mode 100644 demos/default/pages/getStaticProps/withRevalidate/withFallbackBlocking/[id].js diff --git a/demos/default/pages/getStaticProps/withRevalidate/withFallbackBlocking/[id].js b/demos/default/pages/getStaticProps/withRevalidate/withFallbackBlocking/[id].js new file mode 100644 index 0000000000..38058f5d42 --- /dev/null +++ b/demos/default/pages/getStaticProps/withRevalidate/withFallbackBlocking/[id].js @@ -0,0 +1,45 @@ +import Link from 'next/link' + +const Show = ({ show, time }) => ( +
+

This page uses getStaticProps() to pre-fetch a TV show.

+

Ids 1 and 2 are prerendered

+
+ +

Show #{show.id}

+

{show.name}

+

Rendered at {time}

+
+ + + Go back home + +
+) + +export async function getStaticPaths() { + // Set the paths we want to pre-render + const paths = [{ params: { id: '1' } }, { params: { id: '2' } }] + + // We'll pre-render only these paths at build time. + + return { paths, fallback: 'blocking' } +} + +export async function getStaticProps({ params }) { + // The ID to render + const { id } = params + + const res = await fetch(`https://api.tvmaze.com/shows/${id}`) + const data = await res.json() + const time = new Date().toLocaleTimeString() + return { + props: { + show: data, + time, + }, + revalidate: 60, + } +} + +export default Show diff --git a/src/helpers/files.ts b/src/helpers/files.ts index 90d0eaa79e..757f5abca1 100644 --- a/src/helpers/files.ts +++ b/src/helpers/files.ts @@ -15,6 +15,7 @@ import { MINIMUM_REVALIDATE_SECONDS, DIVIDER } from '../constants' import { NextConfig } from './config' import { Rewrites, RoutesManifest } from './types' +import { findModuleFromBase } from './utils' const TEST_ROUTE = /(|\/)\[[^/]+?](\/|\.html|$)/ @@ -272,47 +273,56 @@ export const moveStaticPages = async ({ } } -const patchFile = async ({ file, from, to }: { file: string; from: string; to: string }): Promise => { +/** + * Attempt to patch a source file, preserving a backup + */ +const patchFile = async ({ file, from, to }: { file: string; from: string; to: string }): Promise => { if (!existsSync(file)) { - return + console.warn('File was not found') + + return false } const content = await readFile(file, 'utf8') if (content.includes(to)) { - return + console.log('File already patched') + return false } const newContent = content.replace(from, to) + if (newContent === content) { + console.warn('File was not changed') + return false + } await writeFile(`${file}.orig`, content) await writeFile(file, newContent) + console.log('Done') + return true } +/** + * The file we need has moved around a bit over the past few versions, + * so we iterate through the options until we find it + */ const getServerFile = (root) => { - let serverFile - try { - serverFile = require.resolve('next/dist/server/next-server', { paths: [root] }) - } catch { - // Ignore - } - if (!serverFile) { - try { - // eslint-disable-next-line node/no-missing-require - serverFile = require.resolve('next/dist/next-server/server/next-server', { paths: [root] }) - } catch { - // Ignore - } - } - return serverFile + const candidates = [ + 'next/dist/server/base-server', + 'next/dist/server/next-server', + 'next/dist/next-server/server/next-server', + ] + + return findModuleFromBase({ candidates, paths: [root] }) } -export const patchNextFiles = async (root: string): Promise => { +export const patchNextFiles = (root: string): Promise | boolean => { const serverFile = getServerFile(root) console.log(`Patching ${serverFile}`) if (serverFile) { - await patchFile({ + return patchFile({ file: serverFile, from: `let ssgCacheKey = `, to: `let ssgCacheKey = process.env._BYPASS_SSG || `, }) } + return false } export const unpatchNextFiles = async (root: string): Promise => { diff --git a/src/helpers/utils.ts b/src/helpers/utils.ts index cb46b75ebe..f4a94ab5df 100644 --- a/src/helpers/utils.ts +++ b/src/helpers/utils.ts @@ -157,3 +157,20 @@ export const shouldSkip = (): boolean => process.env.NEXT_PLUGIN_FORCE_RUN === '0' || process.env.NETLIFY_NEXT_PLUGIN_SKIP === 'true' || process.env.NETLIFY_NEXT_PLUGIN_SKIP === '1' + +/** + * Given an array of base paths and candidate modules, return the first one that exists + */ +export const findModuleFromBase = ({ paths, candidates }): string | null => { + for (const candidate of candidates) { + try { + const modulePath = require.resolve(candidate, { paths }) + if (modulePath) { + return modulePath + } + } catch (error) { + console.error(error) + } + } + return null +} diff --git a/test/__snapshots__/index.js.snap b/test/__snapshots__/index.js.snap index 91e49adb40..8f2e0888af 100644 --- a/test/__snapshots__/index.js.snap +++ b/test/__snapshots__/index.js.snap @@ -29,6 +29,7 @@ exports.resolvePages = () => { require.resolve('../../../.next/server/pages/getStaticProps/withFallbackBlocking/[id].js') require.resolve('../../../.next/server/pages/getStaticProps/withRevalidate/[id].js') require.resolve('../../../.next/server/pages/getStaticProps/withRevalidate/withFallback/[id].js') + require.resolve('../../../.next/server/pages/getStaticProps/withRevalidate/withFallbackBlocking/[id].js') require.resolve('../../../.next/server/pages/index.js') require.resolve('../../../.next/server/pages/middle/_middleware.js') require.resolve('../../../.next/server/pages/previewTest.js') @@ -67,6 +68,7 @@ exports.resolvePages = () => { require.resolve('../../../.next/server/pages/getStaticProps/withFallbackBlocking/[id].js') require.resolve('../../../.next/server/pages/getStaticProps/withRevalidate/[id].js') require.resolve('../../../.next/server/pages/getStaticProps/withRevalidate/withFallback/[id].js') + require.resolve('../../../.next/server/pages/getStaticProps/withRevalidate/withFallbackBlocking/[id].js') require.resolve('../../../.next/server/pages/index.js') require.resolve('../../../.next/server/pages/middle/_middleware.js') require.resolve('../../../.next/server/pages/previewTest.js') @@ -105,6 +107,7 @@ exports.resolvePages = () => { require.resolve('../../../web/.next/server/pages/getStaticProps/withFallbackBlocking/[id].js') require.resolve('../../../web/.next/server/pages/getStaticProps/withRevalidate/[id].js') require.resolve('../../../web/.next/server/pages/getStaticProps/withRevalidate/withFallback/[id].js') + require.resolve('../../../web/.next/server/pages/getStaticProps/withRevalidate/withFallbackBlocking/[id].js') require.resolve('../../../web/.next/server/pages/index.js') require.resolve('../../../web/.next/server/pages/middle/_middleware.js') require.resolve('../../../web/.next/server/pages/previewTest.js') @@ -143,6 +146,7 @@ exports.resolvePages = () => { require.resolve('../../../web/.next/server/pages/getStaticProps/withFallbackBlocking/[id].js') require.resolve('../../../web/.next/server/pages/getStaticProps/withRevalidate/[id].js') require.resolve('../../../web/.next/server/pages/getStaticProps/withRevalidate/withFallback/[id].js') + require.resolve('../../../web/.next/server/pages/getStaticProps/withRevalidate/withFallbackBlocking/[id].js') require.resolve('../../../web/.next/server/pages/index.js') require.resolve('../../../web/.next/server/pages/middle/_middleware.js') require.resolve('../../../web/.next/server/pages/previewTest.js') @@ -647,6 +651,30 @@ Array [ "status": 200, "to": "/.netlify/builders/___netlify-odb-handler", }, + Object { + "force": true, + "from": "/_next/data/build-id/en/getStaticProps/withRevalidate/withFallbackBlocking/1.json", + "status": 200, + "to": "/.netlify/builders/___netlify-odb-handler", + }, + Object { + "force": true, + "from": "/getStaticProps/withRevalidate/withFallbackBlocking/1", + "status": 200, + "to": "/.netlify/builders/___netlify-odb-handler", + }, + Object { + "force": true, + "from": "/_next/data/build-id/en/getStaticProps/withRevalidate/withFallbackBlocking/2.json", + "status": 200, + "to": "/.netlify/builders/___netlify-odb-handler", + }, + Object { + "force": true, + "from": "/getStaticProps/withRevalidate/withFallbackBlocking/2", + "status": 200, + "to": "/.netlify/builders/___netlify-odb-handler", + }, Object { "force": false, "from": "/_next/data/build-id/en/index.json", @@ -1367,6 +1395,42 @@ Array [ "status": 200, "to": "/.netlify/builders/___netlify-odb-handler", }, + Object { + "force": false, + "from": "/_next/data/build-id/en/getStaticProps/withRevalidate/withFallbackBlocking/:id.json", + "status": 200, + "to": "/.netlify/builders/___netlify-odb-handler", + }, + Object { + "force": false, + "from": "/getStaticProps/withRevalidate/withFallbackBlocking/:id", + "status": 200, + "to": "/.netlify/builders/___netlify-odb-handler", + }, + Object { + "force": false, + "from": "/_next/data/build-id/es/getStaticProps/withRevalidate/withFallbackBlocking/:id.json", + "status": 200, + "to": "/.netlify/builders/___netlify-odb-handler", + }, + Object { + "force": false, + "from": "/es/getStaticProps/withRevalidate/withFallbackBlocking/:id", + "status": 200, + "to": "/.netlify/builders/___netlify-odb-handler", + }, + Object { + "force": false, + "from": "/_next/data/build-id/fr/getStaticProps/withRevalidate/withFallbackBlocking/:id.json", + "status": 200, + "to": "/.netlify/builders/___netlify-odb-handler", + }, + Object { + "force": false, + "from": "/fr/getStaticProps/withRevalidate/withFallbackBlocking/:id", + "status": 200, + "to": "/.netlify/builders/___netlify-odb-handler", + }, Object { "force": false, "from": "/_next/data/build-id/en/getStaticProps/withRevalidate/:id.json", diff --git a/test/index.js b/test/index.js index 7539a494c3..04f27bf565 100644 --- a/test/index.js +++ b/test/index.js @@ -1,4 +1,4 @@ -const { writeJSON, unlink, existsSync, readFileSync, copy, ensureDir, readJson, writeFile } = require('fs-extra') +const { writeJSON, unlink, existsSync, readFileSync, copy, ensureDir, readJson } = require('fs-extra') const path = require('path') const process = require('process') const os = require('os') @@ -10,10 +10,16 @@ const plugin = require('../src') const { HANDLER_FUNCTION_NAME, ODB_FUNCTION_NAME } = require('../src/constants') const { join } = require('pathe') -const { matchMiddleware, stripLocale, matchesRedirect, matchesRewrite } = require('../src/helpers/files') +const { + matchMiddleware, + stripLocale, + matchesRedirect, + matchesRewrite, + patchNextFiles, + unpatchNextFiles, +} = require('../src/helpers/files') const { dirname } = require('path') const { getProblematicUserRewrites } = require('../src/helpers/verification') -const { outdent } = require('outdent') const FIXTURES_DIR = `${__dirname}/fixtures` const SAMPLE_PROJECT_DIR = `${__dirname}/../demos/default` @@ -659,6 +665,23 @@ describe('utility functions', () => { expect(matchesRewrite(path, REWRITES)).toBeTruthy() }) }) + + test('patches Next server files', async () => { + const root = path.resolve(dirname(__dirname)) + await copy(join(root, 'package.json'), path.join(process.cwd(), 'package.json')) + await ensureDir(path.join(process.cwd(), 'node_modules')) + await copy(path.join(root, 'node_modules', 'next'), path.join(process.cwd(), 'node_modules', 'next')) + + expect(await patchNextFiles(process.cwd())).toBeTruthy() + const serverFile = path.resolve(process.cwd(), 'node_modules', 'next', 'dist', 'server', 'base-server.js') + const patchedData = await readFileSync(serverFile, 'utf8') + expect(patchedData.includes('_BYPASS_SSG')).toBeTruthy() + + await unpatchNextFiles(process.cwd()) + + const unPatchedData = await readFileSync(serverFile, 'utf8') + expect(unPatchedData.includes('_BYPASS_SSG')).toBeFalsy() + }) }) describe('function helpers', () => { From b27c2f299c47ff387e726f76ad03847271e9d8e5 Mon Sep 17 00:00:00 2001 From: "token-generator-app[bot]" <82042599+token-generator-app[bot]@users.noreply.github.com> Date: Thu, 3 Feb 2022 13:39:41 +0000 Subject: [PATCH 2/2] chore(main): release 4.2.4 (#1191) Co-authored-by: token-generator-app[bot] <82042599+token-generator-app[bot]@users.noreply.github.com> --- CHANGELOG.md | 7 +++++++ package-lock.json | 2 +- package.json | 2 +- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 345771f59d..b457ddec4f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +### [4.2.4](https://github.com/netlify/netlify-plugin-nextjs/compare/v4.2.3...v4.2.4) (2022-02-03) + + +### Bug Fixes + +* correctly disable ISR disk flushing ([#1190](https://github.com/netlify/netlify-plugin-nextjs/issues/1190)) ([e8067bf](https://github.com/netlify/netlify-plugin-nextjs/commit/e8067bf13ec94fac80ca6ce495a32249dcd5130c)) + ### [4.2.3](https://github.com/netlify/netlify-plugin-nextjs/compare/v4.2.2...v4.2.3) (2022-02-02) diff --git a/package-lock.json b/package-lock.json index 3a1f37c244..d8d8422b32 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "@netlify/plugin-nextjs", - "version": "4.2.3", + "version": "4.2.4", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index cc9e51461c..5b075c55b0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@netlify/plugin-nextjs", - "version": "4.2.3", + "version": "4.2.4", "description": "Run Next.js seamlessly on Netlify", "main": "lib/index.js", "files": [