@netlify/plugin-nextjs 4.0.0-beta.3 → 4.0.0-beta.7
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 +28 -9
- package/lib/.DS_Store +0 -0
- package/lib/helpers/config.js +10 -7
- package/lib/helpers/files.js +23 -20
- package/lib/helpers/verification.js +16 -1
- package/lib/index.js +5 -5
- package/lib/templates/getHandler.js +2 -0
- package/package.json +7 -5
package/README.md
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
# Essential Next.js Build Plugin (beta)
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
:warning: This is the beta version of the Essential Next.js plugin. For the stable version, refer to
|
|
6
|
+
[Essential Next.js plugin v3](https://github.com/netlify/netlify-plugin-nextjs/tree/v3#readme) :warning:
|
|
7
7
|
|
|
8
8
|
<p align="center">
|
|
9
9
|
<a aria-label="npm version" href="https://www.npmjs.com/package/@netlify/plugin-nextjs">
|
|
@@ -14,15 +14,21 @@
|
|
|
14
14
|
</a>
|
|
15
15
|
</p>
|
|
16
16
|
|
|
17
|
+
## What's new in this version
|
|
17
18
|
|
|
18
|
-
|
|
19
|
+
Version 4 is a complete rewrite of the Essential Next.js plugin. For full details of everything that's new, check out
|
|
20
|
+
[the v4 release notes](https://github.com/netlify/netlify-plugin-nextjs/blob/main/docs/release-notes/v4.md)
|
|
19
21
|
|
|
22
|
+
## Installing the beta
|
|
20
23
|
|
|
21
24
|
- Install the module:
|
|
25
|
+
|
|
22
26
|
```shell
|
|
23
27
|
npm install -D @netlify/plugin-nextjs@beta
|
|
24
28
|
```
|
|
25
|
-
|
|
29
|
+
|
|
30
|
+
- Change the `publish` directory to `.next` and add the plugin to `netlify.toml` if not already installed:
|
|
31
|
+
|
|
26
32
|
```toml
|
|
27
33
|
[build]
|
|
28
34
|
publish = ".next"
|
|
@@ -31,14 +37,27 @@ publish = ".next"
|
|
|
31
37
|
package = "@netlify/plugin-nextjs"
|
|
32
38
|
```
|
|
33
39
|
|
|
34
|
-
If you previously set
|
|
40
|
+
If you previously set a custom `distDir` in your `next.config.js`, or set `node_bundler` or `external_node_modules` in
|
|
41
|
+
your `netlify.toml` these are no longer needed and can be removed.
|
|
42
|
+
|
|
43
|
+
The `serverless` and `experimental-serverless-trace` targets are deprecated in Next 12, and all builds with this plugin
|
|
44
|
+
will now use the default `server` target. If you previously set the target in your `next.config.js`, you should remove
|
|
45
|
+
it.
|
|
46
|
+
|
|
47
|
+
If you are using a monorepo you will need to change `publish` to point to the full path to the built `.next` directory,
|
|
48
|
+
which may be in a subdirectory. If you have changed your `distDir` then it will need to match that.
|
|
35
49
|
|
|
36
|
-
|
|
50
|
+
If you are using Nx, then you will need to point `publish` to the folder inside `dist`, e.g. `dist/apps/myapp/.next`.
|
|
37
51
|
|
|
38
|
-
If you
|
|
52
|
+
If you currently use redirects or rewrites on your site, see
|
|
53
|
+
[the Rewrites and Redirects guide](https://github.com/netlify/netlify-plugin-nextjs/blob/main/docs/redirects-rewrites.md)
|
|
54
|
+
for information on changes to how they are handled in this version.
|
|
39
55
|
|
|
40
|
-
If you
|
|
56
|
+
If you want to use Next 12's beta Middleware feature, this will mostly work as expected but please
|
|
57
|
+
[read the docs on some caveats and workarounds](https://github.com/netlify/netlify-plugin-nextjs/blob/main/docs/middleware.md)
|
|
58
|
+
that are currently needed.
|
|
41
59
|
|
|
42
60
|
## Beta feedback
|
|
43
61
|
|
|
44
|
-
Please share any thoughts, feedback or questions about the beta
|
|
62
|
+
Please share any thoughts, feedback or questions about the beta
|
|
63
|
+
[in our discussion](https://github.com/netlify/netlify-plugin-nextjs/discussions/706).
|
package/lib/.DS_Store
ADDED
|
Binary file
|
package/lib/helpers/config.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// @ts-check
|
|
2
|
-
const { readJSON } = require('fs-extra');
|
|
2
|
+
const { readJSON, existsSync } = require('fs-extra');
|
|
3
3
|
const { join, dirname, relative } = require('pathe');
|
|
4
4
|
const slash = require('slash');
|
|
5
5
|
const defaultFailBuild = (message, { error }) => {
|
|
@@ -64,8 +64,8 @@ exports.generateRedirects = async ({ netlifyConfig, basePath, i18n }) => {
|
|
|
64
64
|
from: `${basePath}/*`,
|
|
65
65
|
to: HANDLER_FUNCTION_PATH,
|
|
66
66
|
status: 200,
|
|
67
|
-
force: true,
|
|
68
67
|
conditions: { Cookie: ['__prerender_bypass', '__next_preview_data'] },
|
|
68
|
+
force: true,
|
|
69
69
|
}, ...redirects.map((redirect) => ({
|
|
70
70
|
from: `${basePath}${redirect}`,
|
|
71
71
|
to: ODB_FUNCTION_PATH,
|
|
@@ -92,6 +92,7 @@ const resolveModuleRoot = (moduleName) => {
|
|
|
92
92
|
return null;
|
|
93
93
|
}
|
|
94
94
|
};
|
|
95
|
+
const DEFAULT_EXCLUDED_MODULES = ['sharp', 'electron'];
|
|
95
96
|
exports.configureHandlerFunctions = ({ netlifyConfig, publish, ignore = [] }) => {
|
|
96
97
|
var _a;
|
|
97
98
|
/* eslint-disable no-underscore-dangle */
|
|
@@ -102,14 +103,16 @@ exports.configureHandlerFunctions = ({ netlifyConfig, publish, ignore = [] }) =>
|
|
|
102
103
|
(_a = netlifyConfig.functions)[functionName] || (_a[functionName] = { included_files: [], external_node_modules: [] });
|
|
103
104
|
netlifyConfig.functions[functionName].node_bundler = 'nft';
|
|
104
105
|
(_b = netlifyConfig.functions[functionName]).included_files || (_b.included_files = []);
|
|
105
|
-
netlifyConfig.functions[functionName].included_files.push(`${publish}/server/**`, `${publish}/serverless/**`, `${publish}/*.json`, `${publish}/BUILD_ID`, ...ignore.map((path) => `!${slash(path)}`));
|
|
106
|
+
netlifyConfig.functions[functionName].included_files.push(`${publish}/server/**`, `${publish}/serverless/**`, `${publish}/*.json`, `${publish}/BUILD_ID`, `${publish}/static/chunks/webpack-middleware*.js`, `!${publish}/server/**/*.js.nft.json`, ...ignore.map((path) => `!${slash(path)}`));
|
|
106
107
|
const nextRoot = resolveModuleRoot('next');
|
|
107
108
|
if (nextRoot) {
|
|
108
109
|
netlifyConfig.functions[functionName].included_files.push(`!${nextRoot}/dist/server/lib/squoosh/**/*.wasm`, `!${nextRoot}/dist/next-server/server/lib/squoosh/**/*.wasm`, `!${nextRoot}/dist/compiled/webpack/bundle4.js`, `!${nextRoot}/dist/compiled/webpack/bundle5.js`, `!${nextRoot}/dist/compiled/terser/bundle.min.js`);
|
|
109
110
|
}
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
111
|
+
DEFAULT_EXCLUDED_MODULES.forEach((moduleName) => {
|
|
112
|
+
const moduleRoot = resolveModuleRoot(moduleName);
|
|
113
|
+
if (moduleRoot) {
|
|
114
|
+
netlifyConfig.functions[functionName].included_files.push(`!${moduleRoot}/**/*`);
|
|
115
|
+
}
|
|
116
|
+
});
|
|
114
117
|
});
|
|
115
118
|
};
|
package/lib/helpers/files.js
CHANGED
|
@@ -1,43 +1,46 @@
|
|
|
1
1
|
// @ts-check
|
|
2
|
+
const { cpus } = require('os');
|
|
2
3
|
const { existsSync, readJson, move, cpSync, copy, writeJson } = require('fs-extra');
|
|
4
|
+
const globby = require('globby');
|
|
3
5
|
const pLimit = require('p-limit');
|
|
4
6
|
const { join } = require('pathe');
|
|
5
|
-
const
|
|
7
|
+
const slash = require('slash');
|
|
8
|
+
const TEST_ROUTE = /(|\/)\[[^/]+?](\/|\.html|$)/;
|
|
6
9
|
const isDynamicRoute = (route) => TEST_ROUTE.test(route);
|
|
7
10
|
exports.moveStaticPages = async ({ netlifyConfig, target, i18n, failBuild }) => {
|
|
8
|
-
|
|
9
|
-
const
|
|
10
|
-
if (!existsSync(pagesManifestPath)) {
|
|
11
|
-
failBuild(`Could not find pages manifest at ${pagesManifestPath}`);
|
|
12
|
-
}
|
|
11
|
+
console.log('Moving static page files to serve from CDN...');
|
|
12
|
+
const root = join(netlifyConfig.build.publish, target === 'server' ? 'server' : 'serverless', 'pages');
|
|
13
13
|
const files = [];
|
|
14
14
|
const moveFile = async (file) => {
|
|
15
15
|
const source = join(root, file);
|
|
16
|
-
|
|
17
|
-
const
|
|
18
|
-
files.push(filePath);
|
|
19
|
-
const dest = join(netlifyConfig.build.publish, filePath);
|
|
16
|
+
files.push(file);
|
|
17
|
+
const dest = join(netlifyConfig.build.publish, file);
|
|
20
18
|
await move(source, dest);
|
|
21
19
|
};
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
20
|
+
// Move all static files, except error documents and nft manifests
|
|
21
|
+
const pages = await globby(['**/*.{html,json}', '!**/(500|404|*.js.nft).{html,json}'], {
|
|
22
|
+
cwd: root,
|
|
23
|
+
dot: true,
|
|
24
|
+
});
|
|
25
|
+
// Limit concurrent file moves to number of cpus or 2 if there is only 1
|
|
26
|
+
const limit = pLimit(Math.max(2, cpus().length));
|
|
27
|
+
const promises = pages.map(async (rawPath) => {
|
|
28
|
+
const filePath = slash(rawPath);
|
|
29
|
+
if (isDynamicRoute(filePath)) {
|
|
30
30
|
return;
|
|
31
31
|
}
|
|
32
32
|
return limit(moveFile, filePath);
|
|
33
33
|
});
|
|
34
34
|
await Promise.all(promises);
|
|
35
|
-
console.log(`Moved ${files.length}
|
|
35
|
+
console.log(`Moved ${files.length} files`);
|
|
36
36
|
// Write the manifest for use in the serverless functions
|
|
37
37
|
await writeJson(join(netlifyConfig.build.publish, 'static-manifest.json'), files);
|
|
38
38
|
if (i18n === null || i18n === void 0 ? void 0 : i18n.defaultLocale) {
|
|
39
39
|
// Copy the default locale into the root
|
|
40
|
-
|
|
40
|
+
const defaultLocaleDir = join(netlifyConfig.build.publish, i18n.defaultLocale);
|
|
41
|
+
if (existsSync(defaultLocaleDir)) {
|
|
42
|
+
await copy(defaultLocaleDir, `${netlifyConfig.build.publish}/`);
|
|
43
|
+
}
|
|
41
44
|
}
|
|
42
45
|
};
|
|
43
46
|
exports.movePublicFiles = async ({ appDir, publish }) => {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const { existsSync, promises } = require('fs');
|
|
2
2
|
const path = require('path');
|
|
3
3
|
const { relative } = require('path');
|
|
4
|
-
const { yellowBright, greenBright, blueBright, redBright } = require('chalk');
|
|
4
|
+
const { yellowBright, greenBright, blueBright, redBright, reset } = require('chalk');
|
|
5
5
|
const { async: StreamZip } = require('node-stream-zip');
|
|
6
6
|
const outdent = require('outdent');
|
|
7
7
|
const prettyBytes = require('pretty-bytes');
|
|
@@ -17,6 +17,21 @@ exports.verifyNetlifyBuildVersion = ({ IS_LOCAL, NETLIFY_BUILD_VERSION, failBuil
|
|
|
17
17
|
`);
|
|
18
18
|
}
|
|
19
19
|
};
|
|
20
|
+
exports.checkForOldFunctions = async ({ functions }) => {
|
|
21
|
+
const oldFunctions = (await functions.list()).filter(({ name }) => name.startsWith('next_'));
|
|
22
|
+
if (oldFunctions.length !== 0) {
|
|
23
|
+
console.log(yellowBright(outdent `
|
|
24
|
+
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_".
|
|
25
|
+
|
|
26
|
+
${reset(oldFunctions.map(({ name }) => `- ${name}`).join('\n'))}
|
|
27
|
+
|
|
28
|
+
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:
|
|
29
|
+
|
|
30
|
+
${reset(oldFunctions.map(({ mainFile }) => `- ${path.relative(process.cwd(), path.dirname(mainFile))}`).join('\n'))}
|
|
31
|
+
|
|
32
|
+
`));
|
|
33
|
+
}
|
|
34
|
+
};
|
|
20
35
|
exports.checkNextSiteHasBuilt = ({ publish, failBuild }) => {
|
|
21
36
|
if (!existsSync(path.join(publish, 'BUILD_ID'))) {
|
|
22
37
|
return failBuild(outdent `
|
package/lib/index.js
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
// @ts-check
|
|
2
1
|
const { join, relative } = require('path');
|
|
3
|
-
const { copy, existsSync } = require('fs-extra');
|
|
4
2
|
const { ODB_FUNCTION_NAME } = require('./constants');
|
|
5
3
|
const { restoreCache, saveCache } = require('./helpers/cache');
|
|
6
4
|
const { getNextConfig, configureHandlerFunctions, generateRedirects } = require('./helpers/config');
|
|
7
5
|
const { moveStaticPages, movePublicFiles } = require('./helpers/files');
|
|
8
6
|
const { generateFunctions, setupImageFunction, generatePagesResolver } = require('./helpers/functions');
|
|
9
|
-
const { verifyNetlifyBuildVersion, checkNextSiteHasBuilt, checkForRootPublish, logBetaMessage, checkZipSize, } = require('./helpers/verification');
|
|
7
|
+
const { verifyNetlifyBuildVersion, checkNextSiteHasBuilt, checkForRootPublish, logBetaMessage, checkZipSize, checkForOldFunctions, } = require('./helpers/verification');
|
|
8
|
+
/** @type import("@netlify/build").NetlifyPlugin */
|
|
10
9
|
module.exports = {
|
|
11
10
|
async onPreBuild({ constants, netlifyConfig, utils: { build: { failBuild }, cache, }, }) {
|
|
12
11
|
var _a;
|
|
@@ -37,9 +36,10 @@ module.exports = {
|
|
|
37
36
|
i18n,
|
|
38
37
|
});
|
|
39
38
|
},
|
|
40
|
-
async onPostBuild({ netlifyConfig, utils: { cache }, constants }) {
|
|
39
|
+
async onPostBuild({ netlifyConfig, utils: { cache, functions }, constants: { FUNCTIONS_DIST } }) {
|
|
41
40
|
await saveCache({ cache, publish: netlifyConfig.build.publish });
|
|
42
|
-
await
|
|
41
|
+
await checkForOldFunctions({ functions });
|
|
42
|
+
await checkZipSize(join(FUNCTIONS_DIST, `${ODB_FUNCTION_NAME}.zip`));
|
|
43
43
|
},
|
|
44
44
|
onEnd() {
|
|
45
45
|
logBetaMessage();
|
|
@@ -103,6 +103,8 @@ const makeHandler = () =>
|
|
|
103
103
|
bridge.listen();
|
|
104
104
|
return async (event, context) => {
|
|
105
105
|
var _a, _b, _c, _d;
|
|
106
|
+
// Ensure that paths are encoded - but don't double-encode them
|
|
107
|
+
event.path = new URL(event.path, event.rawUrl).pathname;
|
|
106
108
|
// Next expects to be able to parse the query from the URL
|
|
107
109
|
const query = new URLSearchParams(event.queryStringParameters).toString();
|
|
108
110
|
event.path = query ? `${event.path}?${query}` : event.path;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@netlify/plugin-nextjs",
|
|
3
|
-
"version": "4.0.0-beta.
|
|
3
|
+
"version": "4.0.0-beta.7",
|
|
4
4
|
"description": "Run Next.js seamlessly on Netlify",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"files": [
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"scripts": {
|
|
11
11
|
"build:demo": "next build demo",
|
|
12
12
|
"cy:open": "cypress open --config-file cypress/config/all.json",
|
|
13
|
-
"cy:run": "cypress run --config-file cypress/config/
|
|
13
|
+
"cy:run": "cypress run --config-file ../cypress/config/ci.json",
|
|
14
14
|
"dev:demo": "next dev demo",
|
|
15
15
|
"format": "run-s format:check-fix:*",
|
|
16
16
|
"format:ci": "run-s format:check:*",
|
|
@@ -52,13 +52,14 @@
|
|
|
52
52
|
},
|
|
53
53
|
"homepage": "https://github.com/netlify/netlify-plugin-nextjs#readme",
|
|
54
54
|
"dependencies": {
|
|
55
|
-
"@netlify/functions": "^0.
|
|
55
|
+
"@netlify/functions": "^0.9.0",
|
|
56
56
|
"@netlify/ipx": "^0.0.7",
|
|
57
57
|
"@vercel/node": "^1.11.2-canary.4",
|
|
58
58
|
"chalk": "^4.1.2",
|
|
59
59
|
"fs-extra": "^10.0.0",
|
|
60
|
+
"globby": "^11.0.4",
|
|
60
61
|
"moize": "^6.1.0",
|
|
61
|
-
"node-fetch": "^2.6.
|
|
62
|
+
"node-fetch": "^2.6.6",
|
|
62
63
|
"node-stream-zip": "^1.15.0",
|
|
63
64
|
"outdent": "^0.8.0",
|
|
64
65
|
"p-limit": "^3.1.0",
|
|
@@ -71,6 +72,7 @@
|
|
|
71
72
|
"devDependencies": {
|
|
72
73
|
"@babel/core": "^7.15.8",
|
|
73
74
|
"@babel/preset-env": "^7.15.8",
|
|
75
|
+
"@netlify/build": "^18.23.0",
|
|
74
76
|
"@netlify/eslint-config-node": "^3.3.0",
|
|
75
77
|
"@testing-library/cypress": "^8.0.1",
|
|
76
78
|
"@types/fs-extra": "^9.0.13",
|
|
@@ -83,7 +85,7 @@
|
|
|
83
85
|
"husky": "^4.3.0",
|
|
84
86
|
"jest": "^27.0.0",
|
|
85
87
|
"netlify-plugin-cypress": "^2.2.0",
|
|
86
|
-
"next": "^
|
|
88
|
+
"next": "^12.0.2",
|
|
87
89
|
"npm-run-all": "^4.1.5",
|
|
88
90
|
"prettier": "^2.1.2",
|
|
89
91
|
"react": "^17.0.1",
|