From 4955767c30c33baabf34aec1f53c03afa8ccb490 Mon Sep 17 00:00:00 2001 From: Matt Kane Date: Thu, 16 Dec 2021 12:38:39 +0000 Subject: [PATCH 1/2] feat: add support for env var to skip running plugin --- README.md | 8 +++++++ src/helpers/utils.ts | 6 +++++ src/helpers/verification.ts | 5 ++-- src/index.ts | 29 ++++++++++++++++++++++- test/index.js | 47 +++++++++++++++++++++++++++++++++++++ 5 files changed, 91 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 7be0dda210..d4f28979ee 100644 --- a/README.md +++ b/README.md @@ -76,6 +76,14 @@ If you are using Nx, then you will need to point `publish` to the folder inside The Essential Next.js plugin now fully supports ISR on Netlify. For more details see [the ISR docs](https://github.com/netlify/netlify-plugin-nextjs/blob/main/docs/isr.md). +## Use with `next export` + +If you are using `next export` to generate a static site, you do not need most of the functionality of this plugin and +you can remove it. Alternatively you can +[set the environment variable](https://docs.netlify.com/configure-builds/environment-variables/) +`NETLIFY_NEXT_PLUGIN_SKIP` to `true` and the plugin will handle caching but won't generate any functions for SSR +support. + ## Feedback If you think you have found a bug in the plugin, diff --git a/src/helpers/utils.ts b/src/helpers/utils.ts index e50ff9073e..37431c4f8d 100644 --- a/src/helpers/utils.ts +++ b/src/helpers/utils.ts @@ -33,3 +33,9 @@ export const netlifyRoutesForNextRoute = (nextRoute: string): Array => { .replace(DYNAMIC_PARAMETER_REGEX, '/:$1'), ) } + +export const shouldSkip = (): boolean => + process.env.NEXT_PLUGIN_FORCE_RUN === 'false' || + process.env.NEXT_PLUGIN_FORCE_RUN === '0' || + process.env.NETLIFY_NEXT_PLUGIN_SKIP === 'true' || + process.env.NETLIFY_NEXT_PLUGIN_SKIP === '1' diff --git a/src/helpers/verification.ts b/src/helpers/verification.ts index f7b87a170e..a62e66a1ad 100644 --- a/src/helpers/verification.ts +++ b/src/helpers/verification.ts @@ -72,14 +72,13 @@ export const checkNextSiteHasBuilt = ({ publish, )}" does not contain a Next.js production build. Perhaps the build command was not run, or you specified the wrong publish directory. ${outWarning} - If you are using "next export" then the Essential Next.js plugin should be removed. See https://ntl.fyi/remove-plugin for details. + If you are using "next export" then you should set the environment variable NETLIFY_NEXT_PLUGIN_SKIP to "true". `) } if (existsSync(path.join(publish, 'export-detail.json'))) { failBuild(outdent` Detected that "next export" was run, but site is incorrectly publishing the ".next" directory. - This plugin is not needed for "next export" so should be removed, and publish directory set to "out". - See https://ntl.fyi/remove-plugin for more details on how to remove this plugin. + The publish directory should be set to "out", and you should set the environment variable NETLIFY_NEXT_PLUGIN_SKIP to "true". `) } } diff --git a/src/index.ts b/src/index.ts index 616a0b24c3..287c9b1f19 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,13 +1,15 @@ import { join, relative } from 'path' import { NetlifyPlugin } from '@netlify/build' +import { existsSync } from 'fs-extra' -import { ODB_FUNCTION_NAME } from './constants' +import { HANDLER_FUNCTION_NAME, ODB_FUNCTION_NAME } from './constants' import { restoreCache, saveCache } from './helpers/cache' import { getNextConfig, configureHandlerFunctions } from './helpers/config' import { moveStaticPages, movePublicFiles, patchNextFiles, unpatchNextFiles } from './helpers/files' import { generateFunctions, setupImageFunction, generatePagesResolver } from './helpers/functions' import { generateRedirects } from './helpers/redirects' +import { shouldSkip } from './helpers/utils' import { verifyNetlifyBuildVersion, checkNextSiteHasBuilt, @@ -26,6 +28,14 @@ const plugin: NetlifyPlugin = { }, }) { const { publish } = netlifyConfig.build + if (shouldSkip()) { + await restoreCache({ cache, publish }) + console.log('Not running Essential Next.js plugin') + if (existsSync(join(constants.INTERNAL_FUNCTIONS_SRC, HANDLER_FUNCTION_NAME))) { + console.log(`Please ensure you remove any generated functions from ${constants.INTERNAL_FUNCTIONS_SRC}`) + } + return + } checkForRootPublish({ publish, failBuild }) verifyNetlifyBuildVersion({ failBuild, ...constants }) @@ -43,6 +53,9 @@ const plugin: NetlifyPlugin = { build: { failBuild }, }, }) { + if (shouldSkip()) { + return + } const { publish } = netlifyConfig.build checkNextSiteHasBuilt({ publish, failBuild }) @@ -84,6 +97,7 @@ const plugin: NetlifyPlugin = { async onPostBuild({ netlifyConfig, utils: { + status, cache, functions, build: { failBuild }, @@ -91,6 +105,19 @@ const plugin: NetlifyPlugin = { constants: { FUNCTIONS_DIST }, }) { await saveCache({ cache, publish: netlifyConfig.build.publish }) + + if (shouldSkip()) { + status.show({ + title: 'Essential Next.js plugin did not run', + summary: `Next cache was stored, but all other functions were skipped because ${ + process.env.NETLIFY_NEXT_PLUGIN_SKIP + ? `NETLIFY_NEXT_PLUGIN_SKIP is set` + : `NEXT_PLUGIN_FORCE_RUN is set to ${process.env.NEXT_PLUGIN_FORCE_RUN}` + }`, + }) + return + } + await checkForOldFunctions({ functions }) await checkZipSize(join(FUNCTIONS_DIST, `${ODB_FUNCTION_NAME}.zip`)) const { basePath } = await getNextConfig({ publish: netlifyConfig.build.publish, failBuild }) diff --git a/test/index.js b/test/index.js index 350690f356..4a29a32626 100644 --- a/test/index.js +++ b/test/index.js @@ -205,6 +205,24 @@ describe('onBuild()', () => { expect(onBuildHasRun(netlifyConfig)).toBe(true) }) + test('skips if NETLIFY_NEXT_PLUGIN_SKIP is set', async () => { + process.env.NETLIFY_NEXT_PLUGIN_SKIP = 'true' + await moveNextDist() + await plugin.onBuild(defaultArgs) + + expect(onBuildHasRun(netlifyConfig)).toBe(false) + delete process.env.NETLIFY_NEXT_PLUGIN_SKIP + }) + + test('skips if NEXT_PLUGIN_FORCE_RUN is "false"', async () => { + process.env.NEXT_PLUGIN_FORCE_RUN = 'false' + await moveNextDist() + await plugin.onBuild(defaultArgs) + + expect(onBuildHasRun(netlifyConfig)).toBe(false) + delete process.env.NEXT_PLUGIN_FORCE_RUN + }) + test("fails if BUILD_ID doesn't exist", async () => { await moveNextDist() await unlink(path.join(process.cwd(), '.next/BUILD_ID')) @@ -442,6 +460,35 @@ describe('onPostBuild', () => { console.log = oldLog }) + + test('warns if NETLIFY_NEXT_PLUGIN_SKIP is set', async () => { + await moveNextDist() + + process.env.NETLIFY_NEXT_PLUGIN_SKIP = 'true' + await moveNextDist() + const show = jest.fn() + await plugin.onPostBuild({ ...defaultArgs, utils: { ...defaultArgs.utils, status: { show } } }) + expect(show).toHaveBeenCalledWith({ + summary: 'Next cache was stored, but all other functions were skipped because NETLIFY_NEXT_PLUGIN_SKIP is set', + title: 'Essential Next.js plugin did not run', + }) + delete process.env.NETLIFY_NEXT_PLUGIN_SKIP + }) + + test('warns if NEXT_PLUGIN_FORCE_RUN is "false"', async () => { + await moveNextDist() + + process.env.NEXT_PLUGIN_FORCE_RUN = 'false' + await moveNextDist() + const show = jest.fn() + await plugin.onPostBuild({ ...defaultArgs, utils: { ...defaultArgs.utils, status: { show } } }) + expect(show).toHaveBeenCalledWith({ + summary: + 'Next cache was stored, but all other functions were skipped because NEXT_PLUGIN_FORCE_RUN is set to false', + title: 'Essential Next.js plugin did not run', + }) + delete process.env.NEXT_PLUGIN_FORCE_RUN + }) }) describe('utility functions', () => { From d114d26993fde2df2c694037f0a7ed80c2b58ba7 Mon Sep 17 00:00:00 2001 From: Matt Kane Date: Thu, 16 Dec 2021 13:24:00 +0000 Subject: [PATCH 2/2] chore: add demo --- README.md | 3 +- demos/next-export/.eslintrc | 4 + demos/next-export/.gitignore | 34 +++++ demos/next-export/README.md | 2 + demos/next-export/local-plugin/index.js | 1 + demos/next-export/local-plugin/manifest.yml | 1 + .../local-plugin/package-lock.json | 5 + demos/next-export/local-plugin/package.json | 11 ++ demos/next-export/netlify.toml | 16 +++ demos/next-export/next.config.js | 5 + demos/next-export/pages/_app.js | 7 + demos/next-export/pages/another.js | 22 ++++ demos/next-export/pages/index.js | 45 +++++++ demos/next-export/public/favicon.ico | Bin 0 -> 15086 bytes demos/next-export/styles/Home.module.css | 121 ++++++++++++++++++ demos/next-export/styles/globals.css | 16 +++ 16 files changed, 292 insertions(+), 1 deletion(-) create mode 100644 demos/next-export/.eslintrc create mode 100644 demos/next-export/.gitignore create mode 100644 demos/next-export/README.md create mode 100644 demos/next-export/local-plugin/index.js create mode 100644 demos/next-export/local-plugin/manifest.yml create mode 100644 demos/next-export/local-plugin/package-lock.json create mode 100644 demos/next-export/local-plugin/package.json create mode 100644 demos/next-export/netlify.toml create mode 100644 demos/next-export/next.config.js create mode 100644 demos/next-export/pages/_app.js create mode 100644 demos/next-export/pages/another.js create mode 100644 demos/next-export/pages/index.js create mode 100644 demos/next-export/public/favicon.ico create mode 100644 demos/next-export/styles/Home.module.css create mode 100644 demos/next-export/styles/globals.css diff --git a/README.md b/README.md index d4f28979ee..97db72e69a 100644 --- a/README.md +++ b/README.md @@ -82,7 +82,8 @@ If you are using `next export` to generate a static site, you do not need most o you can remove it. Alternatively you can [set the environment variable](https://docs.netlify.com/configure-builds/environment-variables/) `NETLIFY_NEXT_PLUGIN_SKIP` to `true` and the plugin will handle caching but won't generate any functions for SSR -support. +support. See [`demos/next-export`](https://github.com/netlify/netlify-plugin-nextjs/tree/main/demos/next-export) for an +example. ## Feedback diff --git a/demos/next-export/.eslintrc b/demos/next-export/.eslintrc new file mode 100644 index 0000000000..abd5579b49 --- /dev/null +++ b/demos/next-export/.eslintrc @@ -0,0 +1,4 @@ +{ + "extends": "next", + "root": true +} diff --git a/demos/next-export/.gitignore b/demos/next-export/.gitignore new file mode 100644 index 0000000000..1437c53f70 --- /dev/null +++ b/demos/next-export/.gitignore @@ -0,0 +1,34 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# local env files +.env.local +.env.development.local +.env.test.local +.env.production.local + +# vercel +.vercel diff --git a/demos/next-export/README.md b/demos/next-export/README.md new file mode 100644 index 0000000000..5bf45f2878 --- /dev/null +++ b/demos/next-export/README.md @@ -0,0 +1,2 @@ +This is an example of a site that uses `next export`. It only uses the plugin for cache handling and sets +`NETLIFY_NEXT_PLUGIN_SKIP` to disable everything else. diff --git a/demos/next-export/local-plugin/index.js b/demos/next-export/local-plugin/index.js new file mode 100644 index 0000000000..9e852e382e --- /dev/null +++ b/demos/next-export/local-plugin/index.js @@ -0,0 +1 @@ +module.exports = require('../../../lib') diff --git a/demos/next-export/local-plugin/manifest.yml b/demos/next-export/local-plugin/manifest.yml new file mode 100644 index 0000000000..7091f91411 --- /dev/null +++ b/demos/next-export/local-plugin/manifest.yml @@ -0,0 +1 @@ +name: '@netlify/plugin-nextjs-local' diff --git a/demos/next-export/local-plugin/package-lock.json b/demos/next-export/local-plugin/package-lock.json new file mode 100644 index 0000000000..11a2e6611e --- /dev/null +++ b/demos/next-export/local-plugin/package-lock.json @@ -0,0 +1,5 @@ +{ + "name": "local-plugin", + "version": "1.0.0", + "lockfileVersion": 1 +} diff --git a/demos/next-export/local-plugin/package.json b/demos/next-export/local-plugin/package.json new file mode 100644 index 0000000000..d692119a5b --- /dev/null +++ b/demos/next-export/local-plugin/package.json @@ -0,0 +1,11 @@ +{ + "name": "local-plugin", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "preinstall": "cd ../../.. && npm i" + }, + "author": "", + "license": "ISC" +} diff --git a/demos/next-export/netlify.toml b/demos/next-export/netlify.toml new file mode 100644 index 0000000000..4983d3f911 --- /dev/null +++ b/demos/next-export/netlify.toml @@ -0,0 +1,16 @@ +[build] +command = "next build && next export" +publish = "out" +ignore = "git diff --quiet $CACHED_COMMIT_REF $COMMIT_REF ../../" + +[build.environment] +NETLIFY_NEXT_PLUGIN_SKIP = "true" + +[dev] +framework = "#static" + +[[plugins]] +package = "./local-plugin" + +[[plugins]] +package = "@netlify/plugin-local-install-core" diff --git a/demos/next-export/next.config.js b/demos/next-export/next.config.js new file mode 100644 index 0000000000..b6c5f701fc --- /dev/null +++ b/demos/next-export/next.config.js @@ -0,0 +1,5 @@ +module.exports = { + // Configurable site features we support: + // distDir: 'build', + generateBuildId: () => 'build-id', +} diff --git a/demos/next-export/pages/_app.js b/demos/next-export/pages/_app.js new file mode 100644 index 0000000000..1e1cec9242 --- /dev/null +++ b/demos/next-export/pages/_app.js @@ -0,0 +1,7 @@ +import '../styles/globals.css' + +function MyApp({ Component, pageProps }) { + return +} + +export default MyApp diff --git a/demos/next-export/pages/another.js b/demos/next-export/pages/another.js new file mode 100644 index 0000000000..e9cebb8bfd --- /dev/null +++ b/demos/next-export/pages/another.js @@ -0,0 +1,22 @@ +import Head from 'next/head' +import { useRouter } from 'next/router' +import styles from '../styles/Home.module.css' + +export default function Home() { + const { locale } = useRouter() + return ( +
+ + Create Next App + + + + +
+

Another page

+
+ + +
+ ) +} diff --git a/demos/next-export/pages/index.js b/demos/next-export/pages/index.js new file mode 100644 index 0000000000..e860ce871b --- /dev/null +++ b/demos/next-export/pages/index.js @@ -0,0 +1,45 @@ +import Head from 'next/head' +import { useRouter } from 'next/router' +import styles from '../styles/Home.module.css' + +export default function Home() { + const { locale } = useRouter() + return ( +
+ + Create Next App + + + + +
+

+ Welcome to Next.js! +

+ +

The current locale is {locale}

+ +

+ Get started by editing pages/index.js +

+ + +
+
+ ) +} diff --git a/demos/next-export/public/favicon.ico b/demos/next-export/public/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..4965832f2c9b0605eaa189b7c7fb11124d24e48a GIT binary patch literal 15086 zcmeHOOH5Q(7(R0cc?bh2AT>N@1PWL!LLfZKyG5c!MTHoP7_p!sBz0k$?pjS;^lmgJ zU6^i~bWuZYHL)9$wuvEKm~qo~(5=Lvx5&Hv;?X#m}i|`yaGY4gX+&b>tew;gcnRQA1kp zBbm04SRuuE{Hn+&1wk%&g;?wja_Is#1gKoFlI7f`Gt}X*-nsMO30b_J@)EFNhzd1QM zdH&qFb9PVqQOx@clvc#KAu}^GrN`q5oP(8>m4UOcp`k&xwzkTio*p?kI4BPtIwX%B zJN69cGsm=x90<;Wmh-bs>43F}ro$}Of@8)4KHndLiR$nW?*{Rl72JPUqRr3ta6e#A z%DTEbi9N}+xPtd1juj8;(CJt3r9NOgb>KTuK|z7!JB_KsFW3(pBN4oh&M&}Nb$Ee2 z$-arA6a)CdsPj`M#1DS>fqj#KF%0q?w50GN4YbmMZIoF{e1yTR=4ablqXHBB2!`wM z1M1ke9+<);|AI;f=2^F1;G6Wfpql?1d5D4rMr?#f(=hkoH)U`6Gb)#xDLjoKjp)1;Js@2Iy5yk zMXUqj+gyk1i0yLjWS|3sM2-1ECc;MAz<4t0P53%7se$$+5Ex`L5TQO_MMXXi04UDIU+3*7Ez&X|mj9cFYBXqM{M;mw_ zpw>azP*qjMyNSD4hh)XZt$gqf8f?eRSFX8VQ4Y+H3jAtvyTrXr`qHAD6`m;aYmH2zOhJC~_*AuT} zvUxC38|JYN94i(05R)dVKgUQF$}#cxV7xZ4FULqFCNX*Forhgp*yr6;DsIk=ub0Hv zpk2L{9Q&|uI^b<6@i(Y+iSxeO_n**4nRLc`P!3ld5jL=nZRw6;DEJ*1z6Pvg+eW|$lnnjO zjd|8>6l{i~UxI244CGn2kK@cJ|#ecwgSyt&HKA2)z zrOO{op^o*-