@netlify/plugin-nextjs 3.9.2 → 4.0.0-beta.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (96) hide show
  1. package/README.md +32 -51
  2. package/lib/constants.js +21 -0
  3. package/lib/helpers/cache.js +20 -0
  4. package/lib/helpers/config.js +174 -0
  5. package/lib/helpers/files.js +236 -0
  6. package/lib/helpers/functions.js +65 -0
  7. package/lib/helpers/verification.js +94 -0
  8. package/lib/index.js +55 -0
  9. package/lib/templates/getHandler.js +165 -0
  10. package/lib/templates/getPageResolver.js +24 -0
  11. package/lib/templates/handlerUtils.js +66 -0
  12. package/lib/templates/ipx.js +8 -0
  13. package/manifest.yml +1 -1
  14. package/package.json +56 -58
  15. package/LICENSE.md +0 -7
  16. package/helpers/cacheBuild.js +0 -31
  17. package/helpers/checkNxConfig.js +0 -56
  18. package/helpers/copyUnstableIncludedDirs.js +0 -27
  19. package/helpers/doesNotNeedPlugin.js +0 -49
  20. package/helpers/doesSiteUseNextOnNetlify.js +0 -20
  21. package/helpers/getNextConfig.js +0 -46
  22. package/helpers/getNextRoot.js +0 -20
  23. package/helpers/isStaticExportProject.js +0 -20
  24. package/helpers/resolveNextModule.js +0 -30
  25. package/helpers/usesBuildCommand.js +0 -37
  26. package/helpers/validateNextUsage.js +0 -53
  27. package/helpers/verifyBuildTarget.js +0 -69
  28. package/index.js +0 -175
  29. package/src/index.js +0 -94
  30. package/src/lib/config.js +0 -58
  31. package/src/lib/constants/regex.js +0 -9
  32. package/src/lib/helpers/addDefaultLocaleRedirect.js +0 -25
  33. package/src/lib/helpers/addLocaleRedirects.js +0 -19
  34. package/src/lib/helpers/asyncForEach.js +0 -7
  35. package/src/lib/helpers/convertToBasePathRedirects.js +0 -80
  36. package/src/lib/helpers/copyDynamicImportChunks.js +0 -39
  37. package/src/lib/helpers/formatRedirectTarget.js +0 -9
  38. package/src/lib/helpers/getDataRouteForRoute.js +0 -30
  39. package/src/lib/helpers/getFilePathForRoute.js +0 -10
  40. package/src/lib/helpers/getI18n.js +0 -10
  41. package/src/lib/helpers/getNetlifyFunctionName.js +0 -38
  42. package/src/lib/helpers/getNetlifyRoutes.js +0 -45
  43. package/src/lib/helpers/getNextDistDir.js +0 -12
  44. package/src/lib/helpers/getNextSrcDir.js +0 -5
  45. package/src/lib/helpers/getPagesManifest.js +0 -19
  46. package/src/lib/helpers/getPrerenderManifest.js +0 -40
  47. package/src/lib/helpers/getPreviewModeFunctionName.js +0 -5
  48. package/src/lib/helpers/getRoutesManifest.js +0 -12
  49. package/src/lib/helpers/getSortedRedirects.js +0 -37
  50. package/src/lib/helpers/handleFileTracking.js +0 -61
  51. package/src/lib/helpers/isApiRoute.js +0 -4
  52. package/src/lib/helpers/isDynamicRoute.js +0 -6
  53. package/src/lib/helpers/isFrameworkRoute.js +0 -5
  54. package/src/lib/helpers/isHtmlFile.js +0 -4
  55. package/src/lib/helpers/isRootCatchAllRedirect.js +0 -6
  56. package/src/lib/helpers/isRouteInPrerenderManifest.js +0 -23
  57. package/src/lib/helpers/isRouteWithDataRoute.js +0 -13
  58. package/src/lib/helpers/isRouteWithFallback.js +0 -12
  59. package/src/lib/helpers/logger.js +0 -44
  60. package/src/lib/helpers/removeFileExtension.js +0 -4
  61. package/src/lib/helpers/runJobsQueue.js +0 -18
  62. package/src/lib/helpers/setupNetlifyFunctionForPage.js +0 -44
  63. package/src/lib/helpers/setupStaticFileForPage.js +0 -18
  64. package/src/lib/pages/api/pages.js +0 -22
  65. package/src/lib/pages/api/redirects.js +0 -13
  66. package/src/lib/pages/api/setup.js +0 -15
  67. package/src/lib/pages/getInitialProps/pages.js +0 -40
  68. package/src/lib/pages/getInitialProps/redirects.js +0 -26
  69. package/src/lib/pages/getInitialProps/setup.js +0 -15
  70. package/src/lib/pages/getServerSideProps/pages.js +0 -43
  71. package/src/lib/pages/getServerSideProps/redirects.js +0 -44
  72. package/src/lib/pages/getServerSideProps/setup.js +0 -15
  73. package/src/lib/pages/getStaticProps/pages.js +0 -26
  74. package/src/lib/pages/getStaticProps/redirects.js +0 -70
  75. package/src/lib/pages/getStaticProps/setup.js +0 -68
  76. package/src/lib/pages/getStaticPropsWithFallback/pages.js +0 -24
  77. package/src/lib/pages/getStaticPropsWithFallback/redirects.js +0 -51
  78. package/src/lib/pages/getStaticPropsWithFallback/setup.js +0 -29
  79. package/src/lib/pages/getStaticPropsWithRevalidate/pages.js +0 -45
  80. package/src/lib/pages/getStaticPropsWithRevalidate/redirects.js +0 -55
  81. package/src/lib/pages/getStaticPropsWithRevalidate/setup.js +0 -40
  82. package/src/lib/pages/withoutProps/pages.js +0 -27
  83. package/src/lib/pages/withoutProps/redirects.js +0 -51
  84. package/src/lib/pages/withoutProps/setup.js +0 -34
  85. package/src/lib/pages/worker.js +0 -19
  86. package/src/lib/steps/copyNextAssets.js +0 -31
  87. package/src/lib/steps/copyPublicFiles.js +0 -18
  88. package/src/lib/steps/prepareFolders.js +0 -39
  89. package/src/lib/steps/setupHeaders.js +0 -37
  90. package/src/lib/steps/setupImageFunction.js +0 -17
  91. package/src/lib/steps/setupPages.js +0 -25
  92. package/src/lib/steps/setupRedirects.js +0 -105
  93. package/src/lib/templates/getHandlerFunction.js +0 -209
  94. package/src/lib/templates/getTemplate.js +0 -15
  95. package/src/lib/templates/imageFunction.js +0 -135
  96. package/src/next-on-netlify.js +0 -22
@@ -0,0 +1,94 @@
1
+ const { existsSync, promises } = require('fs');
2
+ const path = require('path');
3
+ const { relative } = require('path');
4
+ const { yellowBright, greenBright, blueBright, redBright, reset } = require('chalk');
5
+ const { async: StreamZip } = require('node-stream-zip');
6
+ const outdent = require('outdent');
7
+ const prettyBytes = require('pretty-bytes');
8
+ const { satisfies } = require('semver');
9
+ // This is when nft support was added
10
+ const REQUIRED_BUILD_VERSION = '>=18.16.0';
11
+ exports.verifyNetlifyBuildVersion = ({ IS_LOCAL, NETLIFY_BUILD_VERSION, failBuild }) => {
12
+ // We check for build version because that's what's available to us, but prompt about the cli because that's what they can upgrade
13
+ if (IS_LOCAL && !satisfies(NETLIFY_BUILD_VERSION, REQUIRED_BUILD_VERSION, { includePrerelease: true })) {
14
+ return failBuild(outdent `
15
+ This version of the Essential Next.js plugin requires netlify-cli@6.12.4 or higher. Please upgrade and try again.
16
+ You can do this by running: "npm install -g netlify-cli@latest" or "yarn global add netlify-cli@latest"
17
+ `);
18
+ }
19
+ };
20
+ exports.checkForOldFunctions = async ({ functions }) => {
21
+ const allOldFunctions = await functions.list();
22
+ const oldFunctions = allOldFunctions.filter(({ name }) => name.startsWith('next_'));
23
+ if (oldFunctions.length !== 0) {
24
+ console.log(yellowBright(outdent `
25
+ We have found the following functions in your site that seem to be left over from the old Next.js plugin (v3). We have guessed this because the name starts with "next_".
26
+
27
+ ${reset(oldFunctions.map(({ name }) => `- ${name}`).join('\n'))}
28
+
29
+ If they were created by the old plugin, these functions are likely to cause errors so should be removed. You can do this by deleting the following directories:
30
+
31
+ ${reset(oldFunctions.map(({ mainFile }) => `- ${path.relative(process.cwd(), path.dirname(mainFile))}`).join('\n'))}
32
+ `));
33
+ }
34
+ };
35
+ exports.checkNextSiteHasBuilt = ({ publish, failBuild }) => {
36
+ if (!existsSync(path.join(publish, 'BUILD_ID'))) {
37
+ return failBuild(outdent `
38
+ The directory "${path.relative(process.cwd(), publish)}" does not contain a Next.js production build. Perhaps the build command was not run, or you specified the wrong publish directory.
39
+ In most cases it should be set to the site's ".next" directory path, unless you have chosen a custom "distDir" in your Next config.
40
+ If you are using "next export" then the Essential Next.js plugin should be removed. See https://ntl.fyi/remove-plugin for details.
41
+ `);
42
+ }
43
+ if (existsSync(path.join(publish, 'export-detail.json'))) {
44
+ failBuild(outdent `
45
+ Detected that "next export" was run, but site is incorrectly publishing the ".next" directory.
46
+ This plugin is not needed for "next export" so should be removed, and publish directory set to "out".
47
+ See https://ntl.fyi/remove-plugin for more details on how to remove this plugin.
48
+ `);
49
+ }
50
+ };
51
+ exports.checkForRootPublish = ({ publish, failBuild }) => {
52
+ if (path.resolve(publish) === path.resolve('.')) {
53
+ failBuild(outdent `
54
+ Your publish directory is pointing to the base directory of your site. This is not supported for Next.js sites, and is probably a mistake.
55
+ In most cases it should be set to ".next", unless you have chosen a custom "distDir" in your Next config, or the Next site is in a subdirectory.
56
+ `);
57
+ }
58
+ };
59
+ // 50MB, which is the documented max, though the hard max seems to be higher
60
+ const LAMBDA_MAX_SIZE = 1024 * 1024 * 50;
61
+ exports.checkZipSize = async (file, maxSize = LAMBDA_MAX_SIZE) => {
62
+ if (!existsSync(file)) {
63
+ console.warn(`Could not check zip size because ${file} does not exist`);
64
+ return;
65
+ }
66
+ const size = await promises.stat(file).then(({ size }) => size);
67
+ if (size < maxSize) {
68
+ return;
69
+ }
70
+ // We don't fail the build, because the actual hard max size is larger so it might still succeed
71
+ console.log(redBright(outdent `
72
+ The function zip ${yellowBright(relative(process.cwd(), file))} size is ${prettyBytes(size)}, which is larger than the maximum supported size of ${prettyBytes(maxSize)}.
73
+ There are a few reasons this could happen. You may have accidentally bundled a large dependency, or you might have a
74
+ large number of pre-rendered pages included.
75
+ `));
76
+ const zip = new StreamZip({ file });
77
+ console.log(`Contains ${await zip.entriesCount} files`);
78
+ const sortedFiles = Object.values(await zip.entries()).sort((a, b) => b.size - a.size);
79
+ const largest = {};
80
+ for (let i = 0; i < 10 && i < sortedFiles.length; i++) {
81
+ largest[`${i + 1}`] = {
82
+ File: sortedFiles[i].name,
83
+ 'Compressed Size': prettyBytes(sortedFiles[i].compressedSize),
84
+ 'Uncompressed Size': prettyBytes(sortedFiles[i].size),
85
+ };
86
+ }
87
+ console.log(yellowBright `\n\nThese are the largest files in the zip:`);
88
+ console.table(largest);
89
+ console.log(greenBright `\n\nFor more information on fixing this, see ${blueBright `https://ntl.fyi/large-next-functions`}`);
90
+ };
91
+ exports.logBetaMessage = () => console.log(greenBright(outdent `
92
+ Thank you for trying the Essential Next.js beta plugin.
93
+ Please share feedback (both good and bad) at ${blueBright `https://ntl.fyi/next-beta-feedback`}
94
+ `));
package/lib/index.js ADDED
@@ -0,0 +1,55 @@
1
+ const { join, relative } = require('path');
2
+ const { ODB_FUNCTION_NAME } = require('./constants');
3
+ const { restoreCache, saveCache } = require('./helpers/cache');
4
+ const { getNextConfig, configureHandlerFunctions, generateRedirects } = require('./helpers/config');
5
+ const { moveStaticPages, movePublicFiles, patchNextFiles, unpatchNextFiles } = require('./helpers/files');
6
+ const { generateFunctions, setupImageFunction, generatePagesResolver } = require('./helpers/functions');
7
+ const { verifyNetlifyBuildVersion, checkNextSiteHasBuilt, checkForRootPublish, logBetaMessage, checkZipSize, checkForOldFunctions, } = require('./helpers/verification');
8
+ /** @type import("@netlify/build").NetlifyPlugin */
9
+ module.exports = {
10
+ async onPreBuild({ constants, netlifyConfig, utils: { build: { failBuild }, cache, }, }) {
11
+ var _a;
12
+ logBetaMessage();
13
+ const { publish } = netlifyConfig.build;
14
+ checkForRootPublish({ publish, failBuild });
15
+ verifyNetlifyBuildVersion({ failBuild, ...constants });
16
+ await restoreCache({ cache, publish });
17
+ (_a = netlifyConfig.build).environment || (_a.environment = {});
18
+ // eslint-disable-next-line unicorn/consistent-destructuring
19
+ netlifyConfig.build.environment.NEXT_PRIVATE_TARGET = 'server';
20
+ },
21
+ async onBuild({ constants, netlifyConfig, utils: { build: { failBuild }, }, }) {
22
+ const { publish } = netlifyConfig.build;
23
+ checkNextSiteHasBuilt({ publish, failBuild });
24
+ const { appDir, basePath, i18n, images, target, ignore } = await getNextConfig({ publish, failBuild });
25
+ configureHandlerFunctions({ netlifyConfig, ignore, publish: relative(process.cwd(), publish) });
26
+ await generateFunctions(constants, appDir);
27
+ await generatePagesResolver({ netlifyConfig, target, constants });
28
+ await movePublicFiles({ appDir, publish });
29
+ if (process.env.EXPERIMENTAL_ODB_TTL) {
30
+ await patchNextFiles(basePath);
31
+ }
32
+ if (process.env.EXPERIMENTAL_MOVE_STATIC_PAGES) {
33
+ console.log("The flag 'EXPERIMENTAL_MOVE_STATIC_PAGES' is no longer required, as it is now the default. To disable this behavior, set the env var 'SERVE_STATIC_FILES_FROM_ORIGIN' to 'true'");
34
+ }
35
+ if (!process.env.SERVE_STATIC_FILES_FROM_ORIGIN) {
36
+ await moveStaticPages({ target, failBuild, netlifyConfig, i18n });
37
+ }
38
+ await setupImageFunction({ constants, imageconfig: images, netlifyConfig, basePath });
39
+ await generateRedirects({
40
+ netlifyConfig,
41
+ basePath,
42
+ i18n,
43
+ });
44
+ },
45
+ async onPostBuild({ netlifyConfig, utils: { cache, functions, failBuild }, constants: { FUNCTIONS_DIST } }) {
46
+ await saveCache({ cache, publish: netlifyConfig.build.publish });
47
+ await checkForOldFunctions({ functions });
48
+ await checkZipSize(join(FUNCTIONS_DIST, `${ODB_FUNCTION_NAME}.zip`));
49
+ const { basePath } = await getNextConfig({ publish: netlifyConfig.build.publish, failBuild });
50
+ await unpatchNextFiles(basePath);
51
+ },
52
+ onEnd() {
53
+ logBetaMessage();
54
+ },
55
+ };
@@ -0,0 +1,165 @@
1
+ const { promises, existsSync } = require('fs');
2
+ const { Server } = require('http');
3
+ const { tmpdir } = require('os');
4
+ const path = require('path');
5
+ const { Bridge } = require('@vercel/node/dist/bridge');
6
+ const { downloadFile, getMaxAge, getMultiValueHeaders } = require('./handlerUtils');
7
+ const makeHandler = () =>
8
+ // We return a function and then call `toString()` on it to serialise it as the launcher function
9
+ // eslint-disable-next-line max-params
10
+ (conf, app, pageRoot, staticManifest = [], mode = 'ssr') => {
11
+ // This is just so nft knows about the page entrypoints. It's not actually used
12
+ try {
13
+ // eslint-disable-next-line node/no-missing-require
14
+ require.resolve('./pages.js');
15
+ }
16
+ catch { }
17
+ // eslint-disable-next-line no-underscore-dangle
18
+ process.env._BYPASS_SSG = 'true';
19
+ const ONE_YEAR_IN_SECONDS = 31536000;
20
+ // We don't want to write ISR files to disk in the lambda environment
21
+ conf.experimental.isrFlushToDisk = false;
22
+ // Set during the request as it needs the host header. Hoisted so we can define the function once
23
+ let base;
24
+ // Only do this if we have some static files moved to the CDN
25
+ if (staticManifest.length !== 0) {
26
+ // These are static page files that have been removed from the function bundle
27
+ // In most cases these are served from the CDN, but for rewrites Next may try to read them
28
+ // from disk. We need to intercept these and load them from the CDN instead
29
+ // Sadly the only way to do this is to monkey-patch fs.promises. Yeah, I know.
30
+ const staticFiles = new Set(staticManifest);
31
+ // Yes, you can cache stuff locally in a Lambda
32
+ const cacheDir = path.join(tmpdir(), 'next-static-cache');
33
+ // Grab the real fs.promises.readFile...
34
+ const readfileOrig = promises.readFile;
35
+ // ...then money-patch it to see if it's requesting a CDN file
36
+ promises.readFile = async (file, options) => {
37
+ // We only care about page files
38
+ if (file.startsWith(pageRoot)) {
39
+ // We only want the part after `pages/`
40
+ const filePath = file.slice(pageRoot.length + 1);
41
+ // Is it in the CDN and not local?
42
+ if (staticFiles.has(filePath) && !existsSync(file)) {
43
+ // This name is safe to use, because it's one that was already created by Next
44
+ const cacheFile = path.join(cacheDir, filePath);
45
+ // Have we already cached it? We ignore the cache if running locally to avoid staleness
46
+ if ((!existsSync(cacheFile) || process.env.NETLIFY_DEV) && base) {
47
+ await promises.mkdir(path.dirname(cacheFile), { recursive: true });
48
+ // Append the path to our host and we can load it like a regular page
49
+ const url = `${base}/${filePath}`;
50
+ await downloadFile(url, cacheFile);
51
+ }
52
+ // Return the cache file
53
+ return readfileOrig(cacheFile, options);
54
+ }
55
+ }
56
+ return readfileOrig(file, options);
57
+ };
58
+ }
59
+ let NextServer;
60
+ try {
61
+ // next >= 11.0.1. Yay breaking changes in patch releases!
62
+ NextServer = require('next/dist/server/next-server').default;
63
+ }
64
+ catch (error) {
65
+ if (!error.message.includes("Cannot find module 'next/dist/server/next-server'")) {
66
+ // A different error, so rethrow it
67
+ throw error;
68
+ }
69
+ // Probably an old version of next
70
+ }
71
+ if (!NextServer) {
72
+ try {
73
+ // next < 11.0.1
74
+ // eslint-disable-next-line node/no-missing-require, import/no-unresolved
75
+ NextServer = require('next/dist/next-server/server/next-server').default;
76
+ }
77
+ catch (error) {
78
+ if (!error.message.includes("Cannot find module 'next/dist/next-server/server/next-server'")) {
79
+ throw error;
80
+ }
81
+ throw new Error('Could not find Next.js server');
82
+ }
83
+ }
84
+ const nextServer = new NextServer({
85
+ conf,
86
+ dir: path.resolve(__dirname, app),
87
+ customServer: false,
88
+ });
89
+ const requestHandler = nextServer.getRequestHandler();
90
+ const server = new Server(async (req, res) => {
91
+ try {
92
+ await requestHandler(req, res);
93
+ }
94
+ catch (error) {
95
+ console.error(error);
96
+ throw new Error('server function error');
97
+ }
98
+ });
99
+ const bridge = new Bridge(server);
100
+ bridge.listen();
101
+ return async (event, context) => {
102
+ var _a, _b, _c;
103
+ let requestMode = mode;
104
+ // Ensure that paths are encoded - but don't double-encode them
105
+ event.path = new URL(event.path, event.rawUrl).pathname;
106
+ // Next expects to be able to parse the query from the URL
107
+ const query = new URLSearchParams(event.queryStringParameters).toString();
108
+ event.path = query ? `${event.path}?${query}` : event.path;
109
+ // Only needed if we're intercepting static files
110
+ if (staticManifest.length !== 0) {
111
+ const { host } = event.headers;
112
+ const protocol = event.headers['x-forwarded-proto'] || 'http';
113
+ base = `${protocol}://${host}`;
114
+ }
115
+ const { headers, ...result } = await bridge.launcher(event, context);
116
+ /** @type import("@netlify/functions").HandlerResponse */
117
+ // Convert all headers to multiValueHeaders
118
+ const multiValueHeaders = getMultiValueHeaders(headers);
119
+ if ((_b = (_a = multiValueHeaders['set-cookie']) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.includes('__prerender_bypass')) {
120
+ delete multiValueHeaders.etag;
121
+ multiValueHeaders['cache-control'] = ['no-cache'];
122
+ }
123
+ // Sending SWR headers causes undefined behaviour with the Netlify CDN
124
+ const cacheHeader = (_c = multiValueHeaders['cache-control']) === null || _c === void 0 ? void 0 : _c[0];
125
+ if (cacheHeader === null || cacheHeader === void 0 ? void 0 : cacheHeader.includes('stale-while-revalidate')) {
126
+ if (requestMode === 'odb' && process.env.EXPERIMENTAL_ODB_TTL) {
127
+ requestMode = 'isr';
128
+ const ttl = getMaxAge(cacheHeader);
129
+ // Long-expiry TTL is basically no TTL
130
+ if (ttl > 0 && ttl < ONE_YEAR_IN_SECONDS) {
131
+ result.ttl = ttl;
132
+ }
133
+ multiValueHeaders['x-rendered-at'] = [new Date().toISOString()];
134
+ }
135
+ multiValueHeaders['cache-control'] = ['public, max-age=0, must-revalidate'];
136
+ }
137
+ multiValueHeaders['x-render-mode'] = [requestMode];
138
+ return {
139
+ ...result,
140
+ multiValueHeaders,
141
+ isBase64Encoded: result.encoding === 'base64',
142
+ };
143
+ };
144
+ };
145
+ const getHandler = ({ isODB = false, publishDir = '../../../.next', appDir = '../../..' }) => `
146
+ const { Server } = require("http");
147
+ const { tmpdir } = require('os')
148
+ const { promises, existsSync } = require("fs");
149
+ // We copy the file here rather than requiring from the node module
150
+ const { Bridge } = require("./bridge");
151
+ const { downloadFile, getMaxAge, getMultiValueHeaders } = require('./handlerUtils')
152
+
153
+ const { builder } = require("@netlify/functions");
154
+ const { config } = require("${publishDir}/required-server-files.json")
155
+ let staticManifest
156
+ try {
157
+ staticManifest = require("${publishDir}/static-manifest.json")
158
+ } catch {}
159
+ const path = require("path");
160
+ const pageRoot = path.resolve(path.join(__dirname, "${publishDir}", config.target === "server" ? "server" : "serverless", "pages"));
161
+ exports.handler = ${isODB
162
+ ? `builder((${makeHandler().toString()})(config, "${appDir}", pageRoot, staticManifest, 'odb'));`
163
+ : `(${makeHandler().toString()})(config, "${appDir}", pageRoot, staticManifest, 'ssr');`}
164
+ `;
165
+ module.exports = getHandler;
@@ -0,0 +1,24 @@
1
+ const { posix: { resolve, join, relative }, } = require('path');
2
+ const { outdent } = require('outdent');
3
+ const slash = require('slash');
4
+ const glob = require('tiny-glob');
5
+ const { HANDLER_FUNCTION_NAME } = require('../constants');
6
+ // Generate a file full of require.resolve() calls for all the pages in the
7
+ // build. This is used by the nft bundler to find all the pages.
8
+ exports.getPageResolver = async ({ netlifyConfig, target }) => {
9
+ const functionDir = resolve(join('.netlify', 'functions', HANDLER_FUNCTION_NAME));
10
+ const root = join(netlifyConfig.build.publish, target === 'server' ? 'server' : 'serverless', 'pages');
11
+ const pages = await glob('**/*.js', {
12
+ cwd: root,
13
+ dot: true,
14
+ });
15
+ const pageFiles = pages.map((page) => `require.resolve('${relative(functionDir, join(root, slash(page)))}')`).sort();
16
+ return outdent `
17
+ // This file is purely to allow nft to know about these pages. It should be temporary.
18
+ exports.resolvePages = () => {
19
+ try {
20
+ ${pageFiles.join('\n ')}
21
+ } catch {}
22
+ }
23
+ `;
24
+ };
@@ -0,0 +1,66 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.getMultiValueHeaders = exports.getMaxAge = exports.downloadFile = void 0;
7
+ const fs_1 = require("fs");
8
+ const http_1 = __importDefault(require("http"));
9
+ const https_1 = __importDefault(require("https"));
10
+ const stream_1 = require("stream");
11
+ const util_1 = require("util");
12
+ const streamPipeline = (0, util_1.promisify)(stream_1.pipeline);
13
+ const downloadFile = async (url, destination) => {
14
+ console.log(`Downloading ${url} to ${destination}`);
15
+ const httpx = url.startsWith('https') ? https_1.default : http_1.default;
16
+ await new Promise((resolve, reject) => {
17
+ const req = httpx.get(url, { timeout: 10000 }, (response) => {
18
+ if (response.statusCode < 200 || response.statusCode > 299) {
19
+ reject(new Error(`Failed to download ${url}: ${response.statusCode} ${response.statusMessage || ''}`));
20
+ return;
21
+ }
22
+ const fileStream = (0, fs_1.createWriteStream)(destination);
23
+ streamPipeline(response, fileStream)
24
+ .then(resolve)
25
+ .catch((error) => {
26
+ console.log(`Error downloading ${url}`, error);
27
+ reject(error);
28
+ });
29
+ });
30
+ req.on('error', (error) => {
31
+ console.log(`Error downloading ${url}`, error);
32
+ reject(error);
33
+ });
34
+ });
35
+ };
36
+ exports.downloadFile = downloadFile;
37
+ const getMaxAge = (header) => {
38
+ const parts = header.split(',');
39
+ let maxAge;
40
+ for (const part of parts) {
41
+ const [key, value] = part.split('=');
42
+ if ((key === null || key === void 0 ? void 0 : key.trim()) === 's-maxage') {
43
+ maxAge = value === null || value === void 0 ? void 0 : value.trim();
44
+ }
45
+ }
46
+ if (maxAge) {
47
+ const result = Number.parseInt(maxAge);
48
+ return Number.isNaN(result) ? 0 : result;
49
+ }
50
+ return 0;
51
+ };
52
+ exports.getMaxAge = getMaxAge;
53
+ const getMultiValueHeaders = (headers) => {
54
+ const multiValueHeaders = {};
55
+ for (const key of Object.keys(headers)) {
56
+ const header = headers[key];
57
+ if (Array.isArray(header)) {
58
+ multiValueHeaders[key] = header;
59
+ }
60
+ else {
61
+ multiValueHeaders[key] = [header];
62
+ }
63
+ }
64
+ return multiValueHeaders;
65
+ };
66
+ exports.getMultiValueHeaders = getMultiValueHeaders;
@@ -0,0 +1,8 @@
1
+ const { createIPXHandler } = require('@netlify/ipx');
2
+ // Injected at build time
3
+ // eslint-disable-next-line import/no-unresolved, node/no-missing-require
4
+ const { basePath, domains } = require('./imageconfig.json');
5
+ exports.handler = createIPXHandler({
6
+ basePath,
7
+ domains,
8
+ });
package/manifest.yml CHANGED
@@ -1 +1 @@
1
- name: netlify-plugin-nextjs
1
+ name: netlify-plugin-nextjs-experimental
package/package.json CHANGED
@@ -1,26 +1,17 @@
1
1
  {
2
2
  "name": "@netlify/plugin-nextjs",
3
- "version": "3.9.2",
3
+ "version": "4.0.0-beta.12",
4
4
  "description": "Run Next.js seamlessly on Netlify",
5
- "main": "index.js",
6
- "bin": {
7
- "netlify-plugin-nextjs": "src/next-on-netlify.js"
8
- },
5
+ "main": "lib/index.js",
9
6
  "files": [
10
- "helpers/**/*.js",
11
- "src",
12
- "manifest.yml",
13
- "!src/cypress",
14
- "!src/tests"
7
+ "lib/**/*",
8
+ "manifest.yml"
15
9
  ],
16
10
  "scripts": {
17
- "build": "next build test/sample",
18
- "build:demo": "next build demo",
19
- "dev:demo": "next dev demo",
20
- "cypress:local": "env CYPRESS_DEPLOY=local cypress run --project ./src --config-file false --config video=false",
21
- "cypress:netlify": "env CYPRESS_DEPLOY=netlify cypress run --project ./src --config-file false --config video=false",
22
- "cypress:local:testonly": "env CYPRESS_SKIP_DEPLOY=true npm run cypress:local",
23
- "cypress:netlify:testonly": "env CYPRESS_SKIP_DEPLOY=true npm run cypress:netlify",
11
+ "build:demo": "next build demos/default",
12
+ "cy:open": "cypress open --config-file cypress/config/all.json",
13
+ "cy:run": "cypress run --config-file ../../cypress/config/ci.json",
14
+ "dev:demo": "next dev demos/default",
24
15
  "format": "run-s format:check-fix:*",
25
16
  "format:ci": "run-s format:check:*",
26
17
  "format:check-fix:lint": "run-e format:check:lint format:fix:lint",
@@ -29,14 +20,18 @@
29
20
  "format:check-fix:prettier": "run-e format:check:prettier format:fix:prettier",
30
21
  "format:check:prettier": "cross-env-shell prettier --check $npm_package_config_prettier",
31
22
  "format:fix:prettier": "cross-env-shell prettier --write $npm_package_config_prettier",
32
- "prepublishOnly": "run-s prepublishOnly:*",
33
- "prepublishOnly:checkout": "git checkout main",
34
- "prepublishOnly:pull": "git pull",
35
- "prepublishOnly:install": "npm ci",
36
- "prepublishOnly:test": "npm test",
37
- "test:plugin": "npm run build && jest",
38
- "test:src": "jest --config src/tests/jest.config.js",
39
- "test": "run-s test:plugin test:src"
23
+ "prepublishOnly": "run-s publish:pull publish:install clean build test",
24
+ "publish:pull": "git pull",
25
+ "publish:install": "npm ci",
26
+ "publish:test": "npm test",
27
+ "test": "run-s build build:demo test:jest",
28
+ "test:jest": "jest",
29
+ "test:jest:update": "jest --updateSnapshot",
30
+ "test:update": "run-s build build:demo test:jest:update",
31
+ "prepare": "npm run build",
32
+ "clean": "rimraf lib",
33
+ "build": "tsc",
34
+ "watch": "tsc --watch"
40
35
  },
41
36
  "config": {
42
37
  "eslint": "--cache --format=codeframe --max-warnings=0 \"{src,scripts,tests,.github}/**/*.{js,md,html}\" \"*.{js,md,html}\" \".*.{js,md,html}\"",
@@ -59,48 +54,48 @@
59
54
  },
60
55
  "homepage": "https://github.com/netlify/netlify-plugin-nextjs#readme",
61
56
  "dependencies": {
62
- "@babel/core": "^7.15.0",
63
- "@netlify/functions": "^0.7.2",
64
- "@netlify/parse-npm-script": "^0.1.2",
65
- "adm-zip": "^0.5.4",
66
- "chalk": "^4.1.0",
67
- "chokidar": "^3.5.1",
68
- "commander": "^8.0.0",
69
- "debounce-fn": "^4.0.0",
70
- "etag": "^1.8.1",
71
- "execa": "^5.0.0",
72
- "fastq": "^1.11.0",
73
- "find-cache-dir": "^3.3.1",
74
- "find-up": "^5.0.0",
75
- "fs-extra": "^9.1.0",
76
- "image-size": "^1.0.0",
77
- "image-type": "^4.1.0",
78
- "is-svg": "^4.3.1",
79
- "make-dir": "^3.1.0",
80
- "mime-types": "^2.1.30",
81
- "moize": "^6.0.0",
82
- "node-fetch": "^2.6.1",
57
+ "@netlify/functions": "^0.10.0",
58
+ "@netlify/ipx": "^0.0.7",
59
+ "@vercel/node": "^1.11.2-canary.4",
60
+ "chalk": "^4.1.2",
61
+ "fs-extra": "^10.0.0",
62
+ "globby": "^11.0.4",
63
+ "moize": "^6.1.0",
64
+ "node-fetch": "^2.6.6",
65
+ "node-stream-zip": "^1.15.0",
66
+ "outdent": "^0.8.0",
67
+ "p-limit": "^3.1.0",
68
+ "pathe": "^0.2.0",
69
+ "pretty-bytes": "^5.6.0",
83
70
  "semver": "^7.3.5",
84
- "sharp": "^0.29.0",
85
- "slash": "^2.0.0",
71
+ "slash": "^3.0.0",
86
72
  "tiny-glob": "^0.2.9"
87
73
  },
88
74
  "devDependencies": {
89
- "@netlify/eslint-config-node": "^3.3.0",
90
- "cpy": "^8.1.1",
91
- "cypress": "^7.0.0",
92
- "eslint-config-next": "^11.0.0",
93
- "folder-hash": "^4.0.0",
75
+ "@babel/core": "^7.15.8",
76
+ "@babel/preset-env": "^7.15.8",
77
+ "@babel/preset-typescript": "^7.16.0",
78
+ "@netlify/build": "^19.0.7",
79
+ "@netlify/eslint-config-node": "^3.3.9",
80
+ "@testing-library/cypress": "^8.0.1",
81
+ "@types/fs-extra": "^9.0.13",
82
+ "@types/jest": "^27.0.2",
83
+ "@types/mocha": "^9.0.0",
84
+ "babel-jest": "^27.2.5",
85
+ "cpy": "^8.1.2",
86
+ "cypress": "^9.0.0",
87
+ "eslint-config-next": "^12.0.0",
94
88
  "husky": "^4.3.0",
95
89
  "jest": "^27.0.0",
96
- "netlify-cli": "^5.4.16",
97
- "next": "^11.0.0",
98
- "path-exists": "^4.0.0",
90
+ "netlify-plugin-cypress": "^2.2.0",
91
+ "next": "^12.0.2",
92
+ "npm-run-all": "^4.1.5",
99
93
  "prettier": "^2.1.2",
100
94
  "react": "^17.0.1",
101
95
  "react-dom": "^17.0.1",
96
+ "rimraf": "^3.0.2",
102
97
  "tmp-promise": "^3.0.2",
103
- "wait-on": "^6.0.0"
98
+ "typescript": "^4.3.4"
104
99
  },
105
100
  "husky": {
106
101
  "hooks": {
@@ -109,7 +104,7 @@
109
104
  }
110
105
  },
111
106
  "engines": {
112
- "node": ">=10.13.0"
107
+ "node": ">=12.0.0"
113
108
  },
114
109
  "jest": {
115
110
  "testMatch": [
@@ -117,6 +112,9 @@
117
112
  "!**/test/fixtures/**",
118
113
  "!**/test/sample/**"
119
114
  ],
115
+ "transform": {
116
+ "\\.[jt]sx?$": "babel-jest"
117
+ },
120
118
  "verbose": true,
121
119
  "testTimeout": 60000
122
120
  }
package/LICENSE.md DELETED
@@ -1,7 +0,0 @@
1
- Copyright 2020 Netlify, Inc.
2
-
3
- Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
-
5
- The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6
-
7
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -1,31 +0,0 @@
1
- const path = require('path')
2
-
3
- const DEFAULT_DIST_DIR = '.next'
4
-
5
- // Account for possible custom distDir
6
- const getPath = (nextRoot, distDir, source) => path.join(nextRoot, distDir || DEFAULT_DIST_DIR, source)
7
-
8
- const restoreCache = async ({ cache, distDir, nextRoot }) => {
9
- const cacheDir = getPath(nextRoot, distDir, 'cache')
10
- if (await cache.restore(cacheDir)) {
11
- console.log('Next.js cache restored.')
12
- } else {
13
- console.log('No Next.js cache to restore.')
14
- }
15
- }
16
-
17
- const saveCache = async ({ cache, distDir, nextRoot }) => {
18
- const cacheDir = getPath(nextRoot, distDir, 'cache')
19
-
20
- const buildManifest = getPath(nextRoot, distDir, 'build-manifest.json')
21
- if (await cache.save(cacheDir, { digests: [buildManifest] })) {
22
- console.log('Next.js cache saved.')
23
- } else {
24
- console.log('No Next.js cache to save.')
25
- }
26
- }
27
-
28
- module.exports = {
29
- restoreCache,
30
- saveCache,
31
- }