@netlify/plugin-nextjs 3.9.2 → 4.0.0-beta.4
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.
- package/README.md +20 -55
- package/lib/constants.js +21 -0
- package/lib/helpers/cache.js +20 -0
- package/lib/helpers/config.js +119 -0
- package/lib/helpers/files.js +48 -0
- package/lib/helpers/functions.js +64 -0
- package/lib/helpers/verification.js +79 -0
- package/lib/index.js +47 -0
- package/lib/templates/getHandler.js +164 -0
- package/lib/templates/getPageResolver.js +24 -0
- package/lib/templates/ipx.js +8 -0
- package/manifest.yml +1 -1
- package/package.json +47 -54
- package/LICENSE.md +0 -7
- package/helpers/cacheBuild.js +0 -31
- package/helpers/checkNxConfig.js +0 -56
- package/helpers/copyUnstableIncludedDirs.js +0 -27
- package/helpers/doesNotNeedPlugin.js +0 -49
- package/helpers/doesSiteUseNextOnNetlify.js +0 -20
- package/helpers/getNextConfig.js +0 -46
- package/helpers/getNextRoot.js +0 -20
- package/helpers/isStaticExportProject.js +0 -20
- package/helpers/resolveNextModule.js +0 -30
- package/helpers/usesBuildCommand.js +0 -37
- package/helpers/validateNextUsage.js +0 -53
- package/helpers/verifyBuildTarget.js +0 -69
- package/index.js +0 -175
- package/src/index.js +0 -94
- package/src/lib/config.js +0 -58
- package/src/lib/constants/regex.js +0 -9
- package/src/lib/helpers/addDefaultLocaleRedirect.js +0 -25
- package/src/lib/helpers/addLocaleRedirects.js +0 -19
- package/src/lib/helpers/asyncForEach.js +0 -7
- package/src/lib/helpers/convertToBasePathRedirects.js +0 -80
- package/src/lib/helpers/copyDynamicImportChunks.js +0 -39
- package/src/lib/helpers/formatRedirectTarget.js +0 -9
- package/src/lib/helpers/getDataRouteForRoute.js +0 -30
- package/src/lib/helpers/getFilePathForRoute.js +0 -10
- package/src/lib/helpers/getI18n.js +0 -10
- package/src/lib/helpers/getNetlifyFunctionName.js +0 -38
- package/src/lib/helpers/getNetlifyRoutes.js +0 -45
- package/src/lib/helpers/getNextDistDir.js +0 -12
- package/src/lib/helpers/getNextSrcDir.js +0 -5
- package/src/lib/helpers/getPagesManifest.js +0 -19
- package/src/lib/helpers/getPrerenderManifest.js +0 -40
- package/src/lib/helpers/getPreviewModeFunctionName.js +0 -5
- package/src/lib/helpers/getRoutesManifest.js +0 -12
- package/src/lib/helpers/getSortedRedirects.js +0 -37
- package/src/lib/helpers/handleFileTracking.js +0 -61
- package/src/lib/helpers/isApiRoute.js +0 -4
- package/src/lib/helpers/isDynamicRoute.js +0 -6
- package/src/lib/helpers/isFrameworkRoute.js +0 -5
- package/src/lib/helpers/isHtmlFile.js +0 -4
- package/src/lib/helpers/isRootCatchAllRedirect.js +0 -6
- package/src/lib/helpers/isRouteInPrerenderManifest.js +0 -23
- package/src/lib/helpers/isRouteWithDataRoute.js +0 -13
- package/src/lib/helpers/isRouteWithFallback.js +0 -12
- package/src/lib/helpers/logger.js +0 -44
- package/src/lib/helpers/removeFileExtension.js +0 -4
- package/src/lib/helpers/runJobsQueue.js +0 -18
- package/src/lib/helpers/setupNetlifyFunctionForPage.js +0 -44
- package/src/lib/helpers/setupStaticFileForPage.js +0 -18
- package/src/lib/pages/api/pages.js +0 -22
- package/src/lib/pages/api/redirects.js +0 -13
- package/src/lib/pages/api/setup.js +0 -15
- package/src/lib/pages/getInitialProps/pages.js +0 -40
- package/src/lib/pages/getInitialProps/redirects.js +0 -26
- package/src/lib/pages/getInitialProps/setup.js +0 -15
- package/src/lib/pages/getServerSideProps/pages.js +0 -43
- package/src/lib/pages/getServerSideProps/redirects.js +0 -44
- package/src/lib/pages/getServerSideProps/setup.js +0 -15
- package/src/lib/pages/getStaticProps/pages.js +0 -26
- package/src/lib/pages/getStaticProps/redirects.js +0 -70
- package/src/lib/pages/getStaticProps/setup.js +0 -68
- package/src/lib/pages/getStaticPropsWithFallback/pages.js +0 -24
- package/src/lib/pages/getStaticPropsWithFallback/redirects.js +0 -51
- package/src/lib/pages/getStaticPropsWithFallback/setup.js +0 -29
- package/src/lib/pages/getStaticPropsWithRevalidate/pages.js +0 -45
- package/src/lib/pages/getStaticPropsWithRevalidate/redirects.js +0 -55
- package/src/lib/pages/getStaticPropsWithRevalidate/setup.js +0 -40
- package/src/lib/pages/withoutProps/pages.js +0 -27
- package/src/lib/pages/withoutProps/redirects.js +0 -51
- package/src/lib/pages/withoutProps/setup.js +0 -34
- package/src/lib/pages/worker.js +0 -19
- package/src/lib/steps/copyNextAssets.js +0 -31
- package/src/lib/steps/copyPublicFiles.js +0 -18
- package/src/lib/steps/prepareFolders.js +0 -39
- package/src/lib/steps/setupHeaders.js +0 -37
- package/src/lib/steps/setupImageFunction.js +0 -17
- package/src/lib/steps/setupPages.js +0 -25
- package/src/lib/steps/setupRedirects.js +0 -105
- package/src/lib/templates/getHandlerFunction.js +0 -209
- package/src/lib/templates/getTemplate.js +0 -15
- package/src/lib/templates/imageFunction.js +0 -135
- package/src/next-on-netlify.js +0 -22
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
const { promises, createWriteStream, existsSync } = require('fs');
|
|
2
|
+
const { Server } = require('http');
|
|
3
|
+
const { tmpdir } = require('os');
|
|
4
|
+
const path = require('path');
|
|
5
|
+
const { promisify } = require('util');
|
|
6
|
+
const streamPipeline = promisify(require('stream').pipeline);
|
|
7
|
+
const { Bridge } = require('@vercel/node/dist/bridge');
|
|
8
|
+
const fetch = require('node-fetch');
|
|
9
|
+
const makeHandler = () =>
|
|
10
|
+
// We return a function and then call `toString()` on it to serialise it as the launcher function
|
|
11
|
+
(conf, app, pageRoot, staticManifest = []) => {
|
|
12
|
+
// This is just so nft knows about the page entrypoints. It's not actually used
|
|
13
|
+
try {
|
|
14
|
+
// eslint-disable-next-line node/no-missing-require
|
|
15
|
+
require.resolve('./pages.js');
|
|
16
|
+
}
|
|
17
|
+
catch { }
|
|
18
|
+
// Set during the request as it needs the host header. Hoisted so we can define the function once
|
|
19
|
+
let base;
|
|
20
|
+
// Only do this if we have some static files moved to the CDN
|
|
21
|
+
if (staticManifest.length !== 0) {
|
|
22
|
+
// These are static page files that have been removed from the function bundle
|
|
23
|
+
// In most cases these are served from the CDN, but for rewrites Next may try to read them
|
|
24
|
+
// from disk. We need to intercept these and load them from the CDN instead
|
|
25
|
+
// Sadly the only way to do this is to monkey-patch fs.promises. Yeah, I know.
|
|
26
|
+
const staticFiles = new Set(staticManifest);
|
|
27
|
+
// Yes, you can cache stuff locally in a Lambda
|
|
28
|
+
const cacheDir = path.join(tmpdir(), 'next-static-cache');
|
|
29
|
+
// Grab the real fs.promises.readFile...
|
|
30
|
+
const readfileOrig = promises.readFile;
|
|
31
|
+
// ...then money-patch it to see if it's requesting a CDN file
|
|
32
|
+
promises.readFile = async (file, options) => {
|
|
33
|
+
// We only care about page files
|
|
34
|
+
if (file.startsWith(pageRoot)) {
|
|
35
|
+
// We only want the part after `pages/`
|
|
36
|
+
const filePath = file.slice(pageRoot.length + 1);
|
|
37
|
+
// Is it in the CDN and not local?
|
|
38
|
+
if (staticFiles.has(filePath) && !existsSync(file)) {
|
|
39
|
+
// This name is safe to use, because it's one that was already created by Next
|
|
40
|
+
const cacheFile = path.join(cacheDir, filePath);
|
|
41
|
+
// Have we already cached it? We ignore the cache if running locally to avoid staleness
|
|
42
|
+
if ((!existsSync(cacheFile) || process.env.NETLIFY_DEV) && base) {
|
|
43
|
+
await promises.mkdir(path.dirname(cacheFile), { recursive: true });
|
|
44
|
+
// Append the path to our host and we can load it like a regular page
|
|
45
|
+
const url = `${base}/${filePath}`;
|
|
46
|
+
console.log(`Downloading ${url} to ${cacheFile}`);
|
|
47
|
+
const response = await fetch(url);
|
|
48
|
+
if (!response.ok) {
|
|
49
|
+
// Next catches this and returns it as a not found file
|
|
50
|
+
throw new Error(`Failed to fetch ${url}`);
|
|
51
|
+
}
|
|
52
|
+
// Stream it to disk
|
|
53
|
+
await streamPipeline(response.body, createWriteStream(cacheFile));
|
|
54
|
+
}
|
|
55
|
+
// Return the cache file
|
|
56
|
+
return readfileOrig(cacheFile, options);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return readfileOrig(file, options);
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
let NextServer;
|
|
63
|
+
try {
|
|
64
|
+
// next >= 11.0.1. Yay breaking changes in patch releases!
|
|
65
|
+
NextServer = require('next/dist/server/next-server').default;
|
|
66
|
+
}
|
|
67
|
+
catch (error) {
|
|
68
|
+
if (!error.message.includes("Cannot find module 'next/dist/server/next-server'")) {
|
|
69
|
+
// A different error, so rethrow it
|
|
70
|
+
throw error;
|
|
71
|
+
}
|
|
72
|
+
// Probably an old version of next
|
|
73
|
+
}
|
|
74
|
+
if (!NextServer) {
|
|
75
|
+
try {
|
|
76
|
+
// next < 11.0.1
|
|
77
|
+
// eslint-disable-next-line node/no-missing-require, import/no-unresolved
|
|
78
|
+
NextServer = require('next/dist/next-server/server/next-server').default;
|
|
79
|
+
}
|
|
80
|
+
catch (error) {
|
|
81
|
+
if (!error.message.includes("Cannot find module 'next/dist/next-server/server/next-server'")) {
|
|
82
|
+
throw error;
|
|
83
|
+
}
|
|
84
|
+
throw new Error('Could not find Next.js server');
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
const nextServer = new NextServer({
|
|
88
|
+
conf,
|
|
89
|
+
dir: path.resolve(__dirname, app),
|
|
90
|
+
customServer: false,
|
|
91
|
+
});
|
|
92
|
+
const requestHandler = nextServer.getRequestHandler();
|
|
93
|
+
const server = new Server(async (req, res) => {
|
|
94
|
+
try {
|
|
95
|
+
await requestHandler(req, res);
|
|
96
|
+
}
|
|
97
|
+
catch (error) {
|
|
98
|
+
console.error(error);
|
|
99
|
+
throw new Error('server function error');
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
const bridge = new Bridge(server);
|
|
103
|
+
bridge.listen();
|
|
104
|
+
return async (event, context) => {
|
|
105
|
+
var _a, _b, _c, _d;
|
|
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 = {};
|
|
119
|
+
for (const key of Object.keys(headers)) {
|
|
120
|
+
if (Array.isArray(headers[key])) {
|
|
121
|
+
multiValueHeaders[key] = headers[key];
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
multiValueHeaders[key] = [headers[key]];
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
if ((_b = (_a = multiValueHeaders['set-cookie']) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.includes('__prerender_bypass')) {
|
|
128
|
+
delete multiValueHeaders.etag;
|
|
129
|
+
multiValueHeaders['cache-control'] = ['no-cache'];
|
|
130
|
+
}
|
|
131
|
+
// Sending SWR headers causes undefined behaviour with the Netlify CDN
|
|
132
|
+
if ((_d = (_c = multiValueHeaders['cache-control']) === null || _c === void 0 ? void 0 : _c[0]) === null || _d === void 0 ? void 0 : _d.includes('stale-while-revalidate')) {
|
|
133
|
+
multiValueHeaders['cache-control'] = ['public, max-age=0, must-revalidate'];
|
|
134
|
+
}
|
|
135
|
+
return {
|
|
136
|
+
...result,
|
|
137
|
+
multiValueHeaders,
|
|
138
|
+
isBase64Encoded: result.encoding === 'base64',
|
|
139
|
+
};
|
|
140
|
+
};
|
|
141
|
+
};
|
|
142
|
+
const getHandler = ({ isODB = false, publishDir = '../../../.next', appDir = '../../..' }) => `
|
|
143
|
+
const { Server } = require("http");
|
|
144
|
+
const { tmpdir } = require('os')
|
|
145
|
+
const { promises, createWriteStream, existsSync } = require("fs");
|
|
146
|
+
const { promisify } = require('util')
|
|
147
|
+
const streamPipeline = promisify(require('stream').pipeline)
|
|
148
|
+
// We copy the file here rather than requiring from the node module
|
|
149
|
+
const { Bridge } = require("./bridge");
|
|
150
|
+
const fetch = require('node-fetch')
|
|
151
|
+
|
|
152
|
+
const { builder } = require("@netlify/functions");
|
|
153
|
+
const { config } = require("${publishDir}/required-server-files.json")
|
|
154
|
+
let staticManifest
|
|
155
|
+
try {
|
|
156
|
+
staticManifest = require("${publishDir}/static-manifest.json")
|
|
157
|
+
} catch {}
|
|
158
|
+
const path = require("path");
|
|
159
|
+
const pageRoot = path.resolve(path.join(__dirname, "${publishDir}", config.target === "server" ? "server" : "serverless", "pages"));
|
|
160
|
+
exports.handler = ${isODB
|
|
161
|
+
? `builder((${makeHandler().toString()})(config, "${appDir}", pageRoot, staticManifest));`
|
|
162
|
+
: `(${makeHandler().toString()})(config, "${appDir}", pageRoot, staticManifest);`}
|
|
163
|
+
`;
|
|
164
|
+
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,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
|
+
"version": "4.0.0-beta.4",
|
|
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
|
-
"
|
|
11
|
-
"
|
|
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
11
|
"build:demo": "next build demo",
|
|
12
|
+
"cy:open": "cypress open --config-file cypress/config/all.json",
|
|
13
|
+
"cy:run": "cypress run --config-file cypress/config/all.json",
|
|
19
14
|
"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",
|
|
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,16 @@
|
|
|
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
|
|
33
|
-
"
|
|
34
|
-
"
|
|
35
|
-
"
|
|
36
|
-
"
|
|
37
|
-
"test:
|
|
38
|
-
"
|
|
39
|
-
"
|
|
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
|
+
"prepare": "npm run build",
|
|
30
|
+
"clean": "rimraf lib",
|
|
31
|
+
"build": "tsc",
|
|
32
|
+
"watch": "tsc --watch"
|
|
40
33
|
},
|
|
41
34
|
"config": {
|
|
42
35
|
"eslint": "--cache --format=codeframe --max-warnings=0 \"{src,scripts,tests,.github}/**/*.{js,md,html}\" \"*.{js,md,html}\" \".*.{js,md,html}\"",
|
|
@@ -59,48 +52,45 @@
|
|
|
59
52
|
},
|
|
60
53
|
"homepage": "https://github.com/netlify/netlify-plugin-nextjs#readme",
|
|
61
54
|
"dependencies": {
|
|
62
|
-
"@
|
|
63
|
-
"@netlify/
|
|
64
|
-
"@
|
|
65
|
-
"
|
|
66
|
-
"
|
|
67
|
-
"
|
|
68
|
-
"
|
|
69
|
-
"
|
|
70
|
-
"
|
|
71
|
-
"
|
|
72
|
-
"
|
|
73
|
-
"
|
|
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",
|
|
55
|
+
"@netlify/functions": "^0.8.0",
|
|
56
|
+
"@netlify/ipx": "^0.0.7",
|
|
57
|
+
"@vercel/node": "^1.11.2-canary.4",
|
|
58
|
+
"chalk": "^4.1.2",
|
|
59
|
+
"fs-extra": "^10.0.0",
|
|
60
|
+
"moize": "^6.1.0",
|
|
61
|
+
"node-fetch": "^2.6.5",
|
|
62
|
+
"node-stream-zip": "^1.15.0",
|
|
63
|
+
"outdent": "^0.8.0",
|
|
64
|
+
"p-limit": "^3.1.0",
|
|
65
|
+
"pathe": "^0.2.0",
|
|
66
|
+
"pretty-bytes": "^5.6.0",
|
|
83
67
|
"semver": "^7.3.5",
|
|
84
|
-
"
|
|
85
|
-
"slash": "^2.0.0",
|
|
68
|
+
"slash": "^3.0.0",
|
|
86
69
|
"tiny-glob": "^0.2.9"
|
|
87
70
|
},
|
|
88
71
|
"devDependencies": {
|
|
72
|
+
"@babel/core": "^7.15.8",
|
|
73
|
+
"@babel/preset-env": "^7.15.8",
|
|
89
74
|
"@netlify/eslint-config-node": "^3.3.0",
|
|
90
|
-
"
|
|
91
|
-
"
|
|
75
|
+
"@testing-library/cypress": "^8.0.1",
|
|
76
|
+
"@types/fs-extra": "^9.0.13",
|
|
77
|
+
"@types/jest": "^27.0.2",
|
|
78
|
+
"@types/mocha": "^9.0.0",
|
|
79
|
+
"babel-jest": "^27.2.5",
|
|
80
|
+
"cpy": "^8.1.2",
|
|
81
|
+
"cypress": "^8.5.0",
|
|
92
82
|
"eslint-config-next": "^11.0.0",
|
|
93
|
-
"folder-hash": "^4.0.0",
|
|
94
83
|
"husky": "^4.3.0",
|
|
95
84
|
"jest": "^27.0.0",
|
|
96
|
-
"netlify-
|
|
97
|
-
"next": "^11.
|
|
98
|
-
"
|
|
85
|
+
"netlify-plugin-cypress": "^2.2.0",
|
|
86
|
+
"next": "^11.1.2",
|
|
87
|
+
"npm-run-all": "^4.1.5",
|
|
99
88
|
"prettier": "^2.1.2",
|
|
100
89
|
"react": "^17.0.1",
|
|
101
90
|
"react-dom": "^17.0.1",
|
|
91
|
+
"rimraf": "^3.0.2",
|
|
102
92
|
"tmp-promise": "^3.0.2",
|
|
103
|
-
"
|
|
93
|
+
"typescript": "^4.3.4"
|
|
104
94
|
},
|
|
105
95
|
"husky": {
|
|
106
96
|
"hooks": {
|
|
@@ -109,7 +99,7 @@
|
|
|
109
99
|
}
|
|
110
100
|
},
|
|
111
101
|
"engines": {
|
|
112
|
-
"node": ">=
|
|
102
|
+
"node": ">=12.0.0"
|
|
113
103
|
},
|
|
114
104
|
"jest": {
|
|
115
105
|
"testMatch": [
|
|
@@ -117,6 +107,9 @@
|
|
|
117
107
|
"!**/test/fixtures/**",
|
|
118
108
|
"!**/test/sample/**"
|
|
119
109
|
],
|
|
110
|
+
"transform": {
|
|
111
|
+
"\\.[jt]sx?$": "babel-jest"
|
|
112
|
+
},
|
|
120
113
|
"verbose": true,
|
|
121
114
|
"testTimeout": 60000
|
|
122
115
|
}
|
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.
|
package/helpers/cacheBuild.js
DELETED
|
@@ -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
|
-
}
|
package/helpers/checkNxConfig.js
DELETED
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
const { existsSync } = require('fs')
|
|
2
|
-
const { EOL } = require('os')
|
|
3
|
-
const path = require('path')
|
|
4
|
-
|
|
5
|
-
const checkNxConfig = ({ netlifyConfig, nextConfig, failBuild, constants: { PUBLISH_DIR = 'out' } }) => {
|
|
6
|
-
const errors = []
|
|
7
|
-
if (nextConfig.distDir === '.next') {
|
|
8
|
-
errors.push(
|
|
9
|
-
"- When using Nx you must set a value for 'distDir' in your next.config.js, and the value cannot be '.next'",
|
|
10
|
-
)
|
|
11
|
-
}
|
|
12
|
-
// The PUBLISH_DIR constant is normalized, so no leading slash is needed
|
|
13
|
-
if (!PUBLISH_DIR.startsWith('apps/')) {
|
|
14
|
-
errors.push(
|
|
15
|
-
"Please set the 'publish' value in your Netlify build config to a folder inside your app directory. e.g. 'apps/myapp/out'",
|
|
16
|
-
)
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
// Look for the config file as a sibling of the publish dir
|
|
20
|
-
const expectedConfigFile = path.resolve(netlifyConfig.build.publish || PUBLISH_DIR, '..', 'next.config.js')
|
|
21
|
-
|
|
22
|
-
if (expectedConfigFile !== nextConfig.configFile) {
|
|
23
|
-
const confName = path.relative(process.cwd(), nextConfig.configFile)
|
|
24
|
-
errors.push(
|
|
25
|
-
`- Using incorrect config file '${confName}'. Expected to use '${path.relative(
|
|
26
|
-
process.cwd(),
|
|
27
|
-
expectedConfigFile,
|
|
28
|
-
)}'`,
|
|
29
|
-
)
|
|
30
|
-
|
|
31
|
-
if (existsSync(expectedConfigFile)) {
|
|
32
|
-
errors.push(
|
|
33
|
-
`Please move or delete '${confName}'${confName === 'next.config.js' ? ' from the root of your site' : ''}.`,
|
|
34
|
-
)
|
|
35
|
-
} else {
|
|
36
|
-
errors.push(
|
|
37
|
-
`Please move or delete '${confName}'${
|
|
38
|
-
confName === 'next.config.js' ? ' from the root of your site' : ''
|
|
39
|
-
}, and create '${path.relative(process.cwd(), expectedConfigFile)}' instead.`,
|
|
40
|
-
)
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
if (errors.length !== 0) {
|
|
45
|
-
failBuild(
|
|
46
|
-
// TODO: Add ntl.fyi link to docs
|
|
47
|
-
[
|
|
48
|
-
'Invalid configuration',
|
|
49
|
-
...errors,
|
|
50
|
-
'See the docs on using Nx with Netlify for more information: https://ntl.fyi/nx-next',
|
|
51
|
-
].join(EOL),
|
|
52
|
-
)
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
module.exports = checkNxConfig
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
const path = require('path')
|
|
2
|
-
const fs = require('fs')
|
|
3
|
-
const AdmZip = require('adm-zip')
|
|
4
|
-
const getNetlifyFunctionName = require('../src/lib/helpers/getNetlifyFunctionName')
|
|
5
|
-
|
|
6
|
-
// This is UNSTABLE support for special use cases needing files served with their Next.js
|
|
7
|
-
// pages that become Netlify functions. Eventually this will be supported internally.
|
|
8
|
-
const copyUnstableIncludedDirs = ({ nextConfig, functionsDist }) => {
|
|
9
|
-
for (const name in nextConfig.unstableNetlifyFunctionsSupport || {}) {
|
|
10
|
-
const includeDirs = nextConfig.unstableNetlifyFunctionsSupport[name].includeDirs || []
|
|
11
|
-
console.log('Processing included dirs for ', name)
|
|
12
|
-
|
|
13
|
-
const zipName = path.join(functionsDist, getNetlifyFunctionName(name) + '.zip')
|
|
14
|
-
const zip = new AdmZip(zipName)
|
|
15
|
-
includeDirs.forEach((includes) => {
|
|
16
|
-
if (fs.lstatSync(includes).isDirectory()) {
|
|
17
|
-
// We add the files at the root of the ZIP because process.cwd()
|
|
18
|
-
// points to `/` in serverless functions
|
|
19
|
-
zip.addLocalFolder(includes, includes)
|
|
20
|
-
console.log(`Added ${includes} to ${zipName}`)
|
|
21
|
-
}
|
|
22
|
-
})
|
|
23
|
-
zip.writeZip(zipName)
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
module.exports = copyUnstableIncludedDirs
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
// Checks all the cases for which the plugin should do nothing
|
|
2
|
-
const { redBright, yellowBright } = require('chalk')
|
|
3
|
-
|
|
4
|
-
const doesSiteUseNextOnNetlify = require('./doesSiteUseNextOnNetlify')
|
|
5
|
-
const isStaticExportProject = require('./isStaticExportProject')
|
|
6
|
-
const usesBuildCommand = require('./usesBuildCommand')
|
|
7
|
-
|
|
8
|
-
const doesNotNeedPlugin = ({ netlifyConfig, packageJson }) => {
|
|
9
|
-
// The env var skips the auto-detection
|
|
10
|
-
const envVar = process.env.NEXT_PLUGIN_FORCE_RUN
|
|
11
|
-
if (envVar === 'false' || envVar === '0' || envVar === false) {
|
|
12
|
-
console.log(
|
|
13
|
-
yellowBright`The env var NEXT_PLUGIN_FORCE_RUN was set to ${JSON.stringify(
|
|
14
|
-
envVar,
|
|
15
|
-
)}, so auto-detection is disabled and the plugin will not run`,
|
|
16
|
-
)
|
|
17
|
-
return true
|
|
18
|
-
}
|
|
19
|
-
if (envVar === 'true' || envVar === '1' || envVar === true) {
|
|
20
|
-
console.log(
|
|
21
|
-
yellowBright`The env var NEXT_PLUGIN_FORCE_RUN was set to ${JSON.stringify(
|
|
22
|
-
envVar,
|
|
23
|
-
)}, so auto-detection is disabled and the plugin will run regardless`,
|
|
24
|
-
)
|
|
25
|
-
return false
|
|
26
|
-
}
|
|
27
|
-
// Otherwise use auto-detection
|
|
28
|
-
|
|
29
|
-
const { build } = netlifyConfig
|
|
30
|
-
const { scripts = {} } = packageJson
|
|
31
|
-
|
|
32
|
-
if (!build.command) {
|
|
33
|
-
console.log(
|
|
34
|
-
redBright`⚠️ Warning: No build command specified in the site's Netlify config, so plugin will not run. This deploy will fail unless you have already exported the site. ⚠️`,
|
|
35
|
-
)
|
|
36
|
-
return true
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
if (usesBuildCommand({ build, scripts, command: 'build-storybook' })) {
|
|
40
|
-
console.log(
|
|
41
|
-
yellowBright`Site seems to be building a Storybook rather than the Next.js site, so the Essential Next.js plugin will not run. If this is incorrect, set NEXT_PLUGIN_FORCE_RUN to true`,
|
|
42
|
-
)
|
|
43
|
-
return true
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
return isStaticExportProject({ build, scripts }) || doesSiteUseNextOnNetlify({ packageJson })
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
module.exports = doesNotNeedPlugin
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
// Checks if site is already using next-on-netlify
|
|
2
|
-
const { name: pluginName } = require('../package.json')
|
|
3
|
-
|
|
4
|
-
const doesSiteUseNextOnNetlify = ({ packageJson }) => {
|
|
5
|
-
const { name, scripts = {}, dependencies = {} } = packageJson
|
|
6
|
-
|
|
7
|
-
const hasNextOnNetlifyInstalled = dependencies['next-on-netlify'] !== undefined
|
|
8
|
-
const hasNextOnNetlifyPostbuildScript =
|
|
9
|
-
typeof scripts.postbuild === 'string' && scripts.postbuild.includes('next-on-netlify')
|
|
10
|
-
const isUsingNextOnNetlify = (hasNextOnNetlifyInstalled || hasNextOnNetlifyPostbuildScript) && pluginName !== name
|
|
11
|
-
if (isUsingNextOnNetlify) {
|
|
12
|
-
console.log(
|
|
13
|
-
`This plugin does not support sites that manually use next-on-netlify. Uninstall next-on-netlify as a dependency and/or remove it from your postbuild script to allow this plugin to run.`,
|
|
14
|
-
)
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
return isUsingNextOnNetlify
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
module.exports = doesSiteUseNextOnNetlify
|
package/helpers/getNextConfig.js
DELETED
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
const { cwd: getCwd } = require('process')
|
|
4
|
-
|
|
5
|
-
const moize = require('moize')
|
|
6
|
-
|
|
7
|
-
const resolveNextModule = require('./resolveNextModule')
|
|
8
|
-
|
|
9
|
-
// We used to cache nextConfig for any cwd. Now we pass process.cwd() to cache
|
|
10
|
-
// (or memoize) nextConfig per cwd.
|
|
11
|
-
const getNextConfig = async function (failBuild = defaultFailBuild, cwd = getCwd()) {
|
|
12
|
-
// We cannot load `next` at the top-level because we validate whether the
|
|
13
|
-
// site is using `next` inside `onPreBuild`.
|
|
14
|
-
/* eslint-disable import/no-dynamic-require */
|
|
15
|
-
const { PHASE_PRODUCTION_BUILD } = require(resolveNextModule('next/constants', cwd))
|
|
16
|
-
const loadConfig = require(resolveNextModule(
|
|
17
|
-
[
|
|
18
|
-
// next <= 11.0.1
|
|
19
|
-
'next/dist/next-server/server/config',
|
|
20
|
-
// next > 11.0.1
|
|
21
|
-
'next/dist/server/config',
|
|
22
|
-
],
|
|
23
|
-
cwd,
|
|
24
|
-
)).default
|
|
25
|
-
/* eslint-enable import/no-dynamic-require */
|
|
26
|
-
|
|
27
|
-
try {
|
|
28
|
-
return await loadConfig(PHASE_PRODUCTION_BUILD, cwd)
|
|
29
|
-
} catch (error) {
|
|
30
|
-
return failBuild('Error loading your next.config.js.', { error })
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
const moizedGetNextConfig = moize(getNextConfig, {
|
|
35
|
-
maxSize: 1e3,
|
|
36
|
-
isPromise: true,
|
|
37
|
-
// Memoization cache key. We need to use `transformArgs` so `process.cwd()`
|
|
38
|
-
// default value is assigned
|
|
39
|
-
transformArgs: ([, cwd = getCwd()]) => [cwd],
|
|
40
|
-
})
|
|
41
|
-
|
|
42
|
-
const defaultFailBuild = function (message, { error }) {
|
|
43
|
-
throw new Error(`${message}\n${error.stack}`)
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
module.exports = moizedGetNextConfig
|
package/helpers/getNextRoot.js
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
const { existsSync } = require('fs')
|
|
2
|
-
const path = require('path')
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* If we're in a monorepo then the Next root may not be the same as the base directory
|
|
6
|
-
* If there's no next.config.js in the root, we instead look for it as a sibling of the publish dir
|
|
7
|
-
*/
|
|
8
|
-
const getNextRoot = ({ netlifyConfig }) => {
|
|
9
|
-
let nextRoot = process.cwd()
|
|
10
|
-
if (
|
|
11
|
-
!existsSync(path.join(nextRoot, 'next.config.js')) &&
|
|
12
|
-
netlifyConfig.build.publish &&
|
|
13
|
-
netlifyConfig.build.publish !== nextRoot
|
|
14
|
-
) {
|
|
15
|
-
nextRoot = path.dirname(netlifyConfig.build.publish)
|
|
16
|
-
}
|
|
17
|
-
return nextRoot
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
module.exports = getNextRoot
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
const usesBuildCommand = require('./usesBuildCommand')
|
|
2
|
-
|
|
3
|
-
// Takes 1. Netlify config's build details and
|
|
4
|
-
// 2. the project's package.json scripts to determine if
|
|
5
|
-
// the Next.js app uses static HTML export
|
|
6
|
-
const isStaticExportProject = ({ build, scripts }) => {
|
|
7
|
-
const NEXT_EXPORT_COMMAND = 'next export'
|
|
8
|
-
|
|
9
|
-
const isStaticExport = usesBuildCommand({ build, scripts, command: NEXT_EXPORT_COMMAND })
|
|
10
|
-
|
|
11
|
-
if (isStaticExport) {
|
|
12
|
-
console.log(
|
|
13
|
-
'NOTE: Static HTML export Next.js projects (projects that use `next export`) do not require most of this plugin. For these sites, this plugin *only* caches builds.',
|
|
14
|
-
)
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
return isStaticExport
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
module.exports = isStaticExportProject
|