@netlify/plugin-nextjs 3.9.1 → 4.0.0-beta.11
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 +32 -51
- package/lib/constants.js +21 -0
- package/lib/helpers/cache.js +20 -0
- package/lib/helpers/config.js +174 -0
- package/lib/helpers/files.js +187 -0
- package/lib/helpers/functions.js +65 -0
- package/lib/helpers/verification.js +93 -0
- package/lib/index.js +50 -0
- package/lib/templates/getHandler.js +161 -0
- package/lib/templates/getPageResolver.js +24 -0
- package/lib/templates/handlerUtils.js +36 -0
- package/lib/templates/ipx.js +8 -0
- package/manifest.yml +1 -1
- package/package.json +50 -55
- 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
|
@@ -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
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Try one or more Next.js imports until one is found.
|
|
3
|
-
* We can't require() these normally, because the "next" package might not be resolvable from the root of a monorepo
|
|
4
|
-
*/
|
|
5
|
-
const resolveNextModule = (modules, nextRoot) => {
|
|
6
|
-
if (!Array.isArray(modules)) {
|
|
7
|
-
// eslint-disable-next-line no-param-reassign
|
|
8
|
-
modules = [modules]
|
|
9
|
-
}
|
|
10
|
-
for (const key in modules) {
|
|
11
|
-
const module = modules[key]
|
|
12
|
-
// Get the default list of require paths...
|
|
13
|
-
const paths = require.resolve.paths(module)
|
|
14
|
-
// ...add the root of the Next site to the beginning of that list so we try it first...
|
|
15
|
-
paths.unshift(nextRoot)
|
|
16
|
-
// ...then resolve the module using that list of paths.
|
|
17
|
-
try {
|
|
18
|
-
const resolved = require.resolve(module, { paths })
|
|
19
|
-
if (resolved) {
|
|
20
|
-
return resolved
|
|
21
|
-
}
|
|
22
|
-
} catch (error) {
|
|
23
|
-
// Failed. Trying next.
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
throw new Error(`Could not resolve Next module. Tried "${modules.join(', ')}"`)
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
module.exports = resolveNextModule
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
const parseNpmScript = require('@netlify/parse-npm-script')
|
|
2
|
-
|
|
3
|
-
const COMMAND_PLACEHOLDER = '___netlifybuildcommand'
|
|
4
|
-
|
|
5
|
-
// Does the build command include this value, either directly or via an npm script?
|
|
6
|
-
const usesBuildCommand = ({ build, scripts, command }) => {
|
|
7
|
-
if (!build.command) return false
|
|
8
|
-
|
|
9
|
-
if (build.command.includes(command)) {
|
|
10
|
-
return true
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
if (!build.command.includes('npm run') && !build.command.includes('yarn')) {
|
|
14
|
-
return false
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
// Insert a fake script to represent the build command
|
|
18
|
-
|
|
19
|
-
const commands = { ...scripts, [COMMAND_PLACEHOLDER]: build.command }
|
|
20
|
-
|
|
21
|
-
// This resolves the npm script that is actually being run
|
|
22
|
-
try {
|
|
23
|
-
const { raw } = parseNpmScript({ scripts: commands }, COMMAND_PLACEHOLDER)
|
|
24
|
-
return raw.some((script) => script.includes(command))
|
|
25
|
-
} catch (error) {
|
|
26
|
-
console.error(
|
|
27
|
-
`Static export detection disabled because we could not parse your build command: ${error.message}
|
|
28
|
-
The build command is "${build.command}" and the available npm scripts are: ${Object.keys(scripts)
|
|
29
|
-
.map((script) => `"${script}"`)
|
|
30
|
-
.join(', ')}
|
|
31
|
-
|
|
32
|
-
If the site does use static export then you can set the env var NEXT_PLUGIN_FORCE_RUN to "false" or uninstall the plugin. See https://ntl.fyi/remove-plugin for instructions.`,
|
|
33
|
-
)
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
module.exports = usesBuildCommand
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
const { yellowBright } = require('chalk')
|
|
2
|
-
const { lt: ltVersion, gte: gteVersion } = require('semver')
|
|
3
|
-
|
|
4
|
-
const getNextRoot = require('./getNextRoot')
|
|
5
|
-
const resolveNextModule = require('./resolveNextModule')
|
|
6
|
-
|
|
7
|
-
// Ensure Next.js is available.
|
|
8
|
-
// We use `peerDependencies` instead of `dependencies` so that users can choose
|
|
9
|
-
// the Next.js version. However, this requires them to install "next" in their
|
|
10
|
-
// site.
|
|
11
|
-
const validateNextUsage = function ({ failBuild, netlifyConfig }) {
|
|
12
|
-
const nextRoot = getNextRoot({ netlifyConfig })
|
|
13
|
-
// Because we don't know the monorepo structure, we try to resolve next both locally and in the next root
|
|
14
|
-
if (!hasPackage('next', nextRoot)) {
|
|
15
|
-
return failBuild(
|
|
16
|
-
`This site does not seem to be using Next.js. Please run "npm install next" in the repository.
|
|
17
|
-
If you are using a monorepo, please see the docs on configuring your site: https://ntl.fyi/next-monorepos`,
|
|
18
|
-
)
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
// We cannot load `next` at the top-level because we validate whether the
|
|
22
|
-
// site is using `next` inside `onPreBuild`.
|
|
23
|
-
// Old Next.js versions are not supported
|
|
24
|
-
// eslint-disable-next-line import/no-dynamic-require
|
|
25
|
-
const { version } = require(resolveNextModule(`next/package.json`, nextRoot))
|
|
26
|
-
|
|
27
|
-
console.log(`Using Next.js ${yellowBright(version)}`)
|
|
28
|
-
|
|
29
|
-
if (ltVersion(version, MIN_VERSION)) {
|
|
30
|
-
return failBuild(`Please upgrade to Next.js ${MIN_VERSION} or later.`)
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
// Recent Next.js versions are sometimes unstable and we might not officially
|
|
34
|
-
// support them yet. However, they might still work for some users, so we
|
|
35
|
-
// only print a warning
|
|
36
|
-
if (gteVersion(version, MIN_EXPERIMENTAL_VERSION)) {
|
|
37
|
-
console.log(yellowBright(`Warning: support for Next.js >=${MIN_EXPERIMENTAL_VERSION} is experimental`))
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
const MIN_VERSION = '10.0.6'
|
|
42
|
-
const MIN_EXPERIMENTAL_VERSION = '11.1.0'
|
|
43
|
-
|
|
44
|
-
const hasPackage = function (packageName, nextRoot) {
|
|
45
|
-
try {
|
|
46
|
-
resolveNextModule(`${packageName}/package.json`, nextRoot)
|
|
47
|
-
return true
|
|
48
|
-
} catch (error) {
|
|
49
|
-
return false
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
module.exports = validateNextUsage
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
const path = require('path')
|
|
2
|
-
|
|
3
|
-
const { writeFile } = require('fs-extra')
|
|
4
|
-
|
|
5
|
-
const getNextConfig = require('./getNextConfig')
|
|
6
|
-
const getNextRoot = require('./getNextRoot')
|
|
7
|
-
const resolveNextModule = require('./resolveNextModule')
|
|
8
|
-
|
|
9
|
-
// Checks if site has the correct next.config.js
|
|
10
|
-
const verifyBuildTarget = async ({ failBuild, netlifyConfig }) => {
|
|
11
|
-
const nextRoot = getNextRoot({ netlifyConfig })
|
|
12
|
-
|
|
13
|
-
const { target, configFile } = await getNextConfig(failBuild, nextRoot)
|
|
14
|
-
|
|
15
|
-
if (!configFile) {
|
|
16
|
-
await writeFile(
|
|
17
|
-
path.resolve(nextRoot, 'next.config.js'),
|
|
18
|
-
`module.exports = {
|
|
19
|
-
// Supported targets are "serverless" and "experimental-serverless-trace"
|
|
20
|
-
target: "serverless",
|
|
21
|
-
generateBuildId: () => "build"
|
|
22
|
-
}`,
|
|
23
|
-
)
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
// If the next config exists, log warning if target isn't in acceptableTargets
|
|
27
|
-
const acceptableTargets = ['serverless', 'experimental-serverless-trace']
|
|
28
|
-
const isValidTarget = acceptableTargets.includes(target)
|
|
29
|
-
if (isValidTarget) {
|
|
30
|
-
return
|
|
31
|
-
}
|
|
32
|
-
console.log(
|
|
33
|
-
`The "target" config property must be one of "${acceptableTargets.join(
|
|
34
|
-
'", "',
|
|
35
|
-
)}". Building with "serverless" target.`,
|
|
36
|
-
)
|
|
37
|
-
|
|
38
|
-
// We emulate Vercel so that we can set target to serverless if needed
|
|
39
|
-
process.env.NOW_BUILDER = true
|
|
40
|
-
// If no valid target is set, we use an internal Next env var to force it
|
|
41
|
-
process.env.NEXT_PRIVATE_TARGET = 'serverless'
|
|
42
|
-
|
|
43
|
-
// 🐉 We need Next to recalculate "isZeitNow" var so we can set the target, but it's
|
|
44
|
-
// set as an import side effect so we need to clear the require cache first. 🐲
|
|
45
|
-
// https://github.com/vercel/next.js/blob/canary/packages/next/telemetry/ci-info.ts
|
|
46
|
-
|
|
47
|
-
delete require.cache[resolveNextModule('next/dist/telemetry/ci-info', nextRoot)]
|
|
48
|
-
delete require.cache[
|
|
49
|
-
resolveNextModule(
|
|
50
|
-
[
|
|
51
|
-
// next <= 11.0.1
|
|
52
|
-
'next/dist/next-server/server/config',
|
|
53
|
-
// next > 11.0.1
|
|
54
|
-
'next/dist/server/config',
|
|
55
|
-
],
|
|
56
|
-
nextRoot,
|
|
57
|
-
)
|
|
58
|
-
]
|
|
59
|
-
|
|
60
|
-
// Clear memoized cache
|
|
61
|
-
getNextConfig.clear()
|
|
62
|
-
|
|
63
|
-
// Force the new config to be generated
|
|
64
|
-
await getNextConfig(failBuild, nextRoot)
|
|
65
|
-
// Reset the value in case something else is looking for it
|
|
66
|
-
process.env.NOW_BUILDER = false
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
module.exports = verifyBuildTarget
|
package/index.js
DELETED
|
@@ -1,175 +0,0 @@
|
|
|
1
|
-
const { readdirSync, existsSync } = require('fs')
|
|
2
|
-
const path = require('path')
|
|
3
|
-
|
|
4
|
-
const { yellowBright, greenBright, green } = require('chalk')
|
|
5
|
-
const makeDir = require('make-dir')
|
|
6
|
-
const { satisfies } = require('semver')
|
|
7
|
-
const glob = require('tiny-glob')
|
|
8
|
-
|
|
9
|
-
const { restoreCache, saveCache } = require('./helpers/cacheBuild')
|
|
10
|
-
const checkNxConfig = require('./helpers/checkNxConfig')
|
|
11
|
-
const copyUnstableIncludedDirs = require('./helpers/copyUnstableIncludedDirs')
|
|
12
|
-
const doesNotNeedPlugin = require('./helpers/doesNotNeedPlugin')
|
|
13
|
-
const getNextConfig = require('./helpers/getNextConfig')
|
|
14
|
-
const getNextRoot = require('./helpers/getNextRoot')
|
|
15
|
-
const validateNextUsage = require('./helpers/validateNextUsage')
|
|
16
|
-
const verifyBuildTarget = require('./helpers/verifyBuildTarget')
|
|
17
|
-
const nextOnNetlify = require('./src')
|
|
18
|
-
|
|
19
|
-
// This is when the esbuild dynamic import support was added
|
|
20
|
-
const REQUIRED_BUILD_VERSION = '>=15.11.5'
|
|
21
|
-
|
|
22
|
-
// * Helpful Plugin Context *
|
|
23
|
-
// - Between the prebuild and build steps, the project's build command is run
|
|
24
|
-
// - Between the build and postbuild steps, any functions are bundled
|
|
25
|
-
|
|
26
|
-
module.exports = {
|
|
27
|
-
async onPreBuild({ netlifyConfig, packageJson, utils, constants = {} }) {
|
|
28
|
-
const { FUNCTIONS_SRC = DEFAULT_FUNCTIONS_SRC, INTERNAL_FUNCTIONS_SRC, IS_LOCAL, NETLIFY_BUILD_VERSION } = constants
|
|
29
|
-
|
|
30
|
-
const { failBuild } = utils.build
|
|
31
|
-
|
|
32
|
-
validateNextUsage({ failBuild, netlifyConfig })
|
|
33
|
-
|
|
34
|
-
const hasNoPackageJson = Object.keys(packageJson).length === 0
|
|
35
|
-
if (hasNoPackageJson) {
|
|
36
|
-
return failBuild('Could not find a package.json for this project')
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
if (doesNotNeedPlugin({ netlifyConfig, packageJson, failBuild })) {
|
|
40
|
-
return
|
|
41
|
-
}
|
|
42
|
-
// 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
|
|
43
|
-
if (IS_LOCAL && !satisfies(NETLIFY_BUILD_VERSION, REQUIRED_BUILD_VERSION, { includePrerelease: true })) {
|
|
44
|
-
return failBuild(
|
|
45
|
-
`This version of the Essential Next.js plugin requires netlify-cli@4.4.2 or higher. Please upgrade and try again.
|
|
46
|
-
You can do this by running: "npm install -g netlify-cli@latest" or "yarn global add netlify-cli@latest"`,
|
|
47
|
-
)
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
// Populates the correct config if needed
|
|
51
|
-
await verifyBuildTarget({ netlifyConfig, packageJson, failBuild })
|
|
52
|
-
const nextRoot = getNextRoot({ netlifyConfig })
|
|
53
|
-
|
|
54
|
-
// Because we memoize nextConfig, we need to do this after the write file
|
|
55
|
-
const nextConfig = await getNextConfig(utils.failBuild, nextRoot)
|
|
56
|
-
|
|
57
|
-
// Nx needs special config handling, so check for it specifically
|
|
58
|
-
const isNx = Boolean(
|
|
59
|
-
(packageJson.devDependencies && packageJson.devDependencies['@nrwl/next']) ||
|
|
60
|
-
(packageJson.dependencies && packageJson.dependencies['@nrwl/next']),
|
|
61
|
-
)
|
|
62
|
-
|
|
63
|
-
if (isNx) {
|
|
64
|
-
console.log('Detected Nx site. Checking configuration...')
|
|
65
|
-
checkNxConfig({ netlifyConfig, packageJson, nextConfig, failBuild, constants })
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
if (process.env.NEXT_IMAGE_ALLOWED_DOMAINS) {
|
|
69
|
-
console.log(
|
|
70
|
-
`The Essential Next.js plugin now supports reading image domains from your Next config, so using NEXT_IMAGE_ALLOWED_DOMAINS is now deprecated. Please set images.domains in next.config.js instead, and remove the NEXT_IMAGE_ALLOWED_DOMAINS variable.`,
|
|
71
|
-
)
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
if (INTERNAL_FUNCTIONS_SRC && existsSync(FUNCTIONS_SRC)) {
|
|
75
|
-
const oldFunctions = await glob('next_*', { cwd: FUNCTIONS_SRC })
|
|
76
|
-
|
|
77
|
-
if (oldFunctions.length !== 0) {
|
|
78
|
-
console.log(yellowBright`
|
|
79
|
-
Detected the following functions that seem to have been generated by an old version of the Essential Next.js plugin.
|
|
80
|
-
The plugin no longer uses these and they should be deleted to avoid conflicts.\n`)
|
|
81
|
-
console.log(greenBright`• ${oldFunctions.join('\n• ')}
|
|
82
|
-
`)
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
await restoreCache({ cache: utils.cache, distDir: nextConfig.distDir, nextRoot })
|
|
87
|
-
|
|
88
|
-
// Exit the build process on unhandled promise rejection. This is the default in Node 15+, but earlier versions just warn.
|
|
89
|
-
// This causes problems as it doesn't then know the build has failed until we try to copy the assets.
|
|
90
|
-
process.env.NODE_OPTIONS = [process.env.NODE_OPTIONS, '--unhandled-rejections=strict'].filter(Boolean).join(' ')
|
|
91
|
-
},
|
|
92
|
-
async onBuild({
|
|
93
|
-
netlifyConfig,
|
|
94
|
-
packageJson,
|
|
95
|
-
constants: { PUBLISH_DIR = DEFAULT_PUBLISH_DIR, INTERNAL_FUNCTIONS_SRC, FUNCTIONS_SRC = DEFAULT_FUNCTIONS_SRC },
|
|
96
|
-
utils,
|
|
97
|
-
}) {
|
|
98
|
-
const { failBuild } = utils.build
|
|
99
|
-
|
|
100
|
-
const nextRoot = getNextRoot({ netlifyConfig })
|
|
101
|
-
|
|
102
|
-
if (doesNotNeedPlugin({ netlifyConfig, packageJson, failBuild })) {
|
|
103
|
-
return
|
|
104
|
-
}
|
|
105
|
-
console.log('Detected Next.js site. Copying files...')
|
|
106
|
-
|
|
107
|
-
const { distDir, configFile } = await getNextConfig(failBuild, nextRoot)
|
|
108
|
-
const dist = path.resolve(nextRoot, distDir)
|
|
109
|
-
|
|
110
|
-
if (!existsSync(dist)) {
|
|
111
|
-
failBuild(`
|
|
112
|
-
Could not find "${distDir}" after building the site, which indicates that "next build" was not run or that we're looking in the wrong place.
|
|
113
|
-
We're using the config file ${configFile}, and looking for the dist directory at ${dist}. If this is incorrect, try deleting the config file, or
|
|
114
|
-
moving it to the correct place. Check that your build command includes "next build". If the site is a monorepo, see https://ntl.fyi/next-monorepo
|
|
115
|
-
for information on configuring the site. If this is not a Next.js site or if it uses static export, you should remove the Essential Next.js plugin.
|
|
116
|
-
See https://ntl.fyi/remove-plugin for instructions.
|
|
117
|
-
`)
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
console.log(`** Running Next on Netlify package **`)
|
|
121
|
-
|
|
122
|
-
await makeDir(PUBLISH_DIR)
|
|
123
|
-
await nextOnNetlify({
|
|
124
|
-
functionsDir: path.resolve(INTERNAL_FUNCTIONS_SRC || FUNCTIONS_SRC),
|
|
125
|
-
publishDir: netlifyConfig.build.publish || PUBLISH_DIR,
|
|
126
|
-
nextRoot,
|
|
127
|
-
})
|
|
128
|
-
|
|
129
|
-
if (!netlifyConfig.functions['*'].included_files) {
|
|
130
|
-
// eslint-disable-next-line no-param-reassign
|
|
131
|
-
netlifyConfig.functions['*'].included_files = []
|
|
132
|
-
}
|
|
133
|
-
netlifyConfig.functions['*'].included_files.push(
|
|
134
|
-
'!node_modules/@next/swc-*/**/*',
|
|
135
|
-
'!node_modules/next/dist/compiled/@ampproject/toolbox-optimizer/**/*',
|
|
136
|
-
)
|
|
137
|
-
},
|
|
138
|
-
|
|
139
|
-
async onPostBuild({ netlifyConfig, packageJson, constants: { FUNCTIONS_DIST = DEFAULT_FUNCTIONS_DIST }, utils }) {
|
|
140
|
-
if (doesNotNeedPlugin({ netlifyConfig, packageJson, utils })) {
|
|
141
|
-
utils.status.show({
|
|
142
|
-
title: 'Essential Next.js Build Plugin did not run',
|
|
143
|
-
summary: netlifyConfig.build.command
|
|
144
|
-
? 'The site either uses static export, manually runs next-on-netlify, or is not a Next.js site'
|
|
145
|
-
: 'The site config does not specify a build command',
|
|
146
|
-
})
|
|
147
|
-
return
|
|
148
|
-
}
|
|
149
|
-
const nextRoot = getNextRoot({ netlifyConfig })
|
|
150
|
-
|
|
151
|
-
const nextConfig = await getNextConfig(utils.failBuild, nextRoot)
|
|
152
|
-
const { distDir, generateBuildId } = nextConfig
|
|
153
|
-
await saveCache({ cache: utils.cache, distDir, nextRoot })
|
|
154
|
-
copyUnstableIncludedDirs({ nextConfig, functionsDist: path.resolve(FUNCTIONS_DIST) })
|
|
155
|
-
utils.status.show({
|
|
156
|
-
title: 'Essential Next.js Build Plugin ran successfully',
|
|
157
|
-
summary: 'Generated serverless functions and stored the Next.js cache',
|
|
158
|
-
})
|
|
159
|
-
|
|
160
|
-
// The default generateBuildId function returns null, which causes it to use a random value from nanoid
|
|
161
|
-
// eslint-disable-next-line no-self-compare
|
|
162
|
-
if (generateBuildId() === null || generateBuildId() !== generateBuildId()) {
|
|
163
|
-
console.warn(
|
|
164
|
-
yellowBright`
|
|
165
|
-
For faster deploy times, build IDs should be set to a static value.
|
|
166
|
-
To do this, set ${green`generateBuildId: () => 'build'`} in your next.config.js`,
|
|
167
|
-
// TODO: add shortlink when docs are updated
|
|
168
|
-
)
|
|
169
|
-
}
|
|
170
|
-
},
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
const DEFAULT_FUNCTIONS_SRC = 'netlify/functions'
|
|
174
|
-
const DEFAULT_FUNCTIONS_DIST = '.netlify/functions/'
|
|
175
|
-
const DEFAULT_PUBLISH_DIR = 'out'
|
package/src/index.js
DELETED
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
const { normalize } = require('path')
|
|
2
|
-
|
|
3
|
-
const chokidar = require('chokidar')
|
|
4
|
-
const debounceFn = require('debounce-fn')
|
|
5
|
-
const execa = require('execa')
|
|
6
|
-
|
|
7
|
-
const getNextConfig = require('../helpers/getNextConfig')
|
|
8
|
-
|
|
9
|
-
const { NETLIFY_PUBLISH_PATH, NETLIFY_FUNCTIONS_PATH, SRC_FILES } = require('./lib/config')
|
|
10
|
-
const { logTitle } = require('./lib/helpers/logger')
|
|
11
|
-
const copyNextAssets = require('./lib/steps/copyNextAssets')
|
|
12
|
-
const copyPublicFiles = require('./lib/steps/copyPublicFiles')
|
|
13
|
-
const prepareFolders = require('./lib/steps/prepareFolders')
|
|
14
|
-
const setupHeaders = require('./lib/steps/setupHeaders')
|
|
15
|
-
const setupImageFunction = require('./lib/steps/setupImageFunction')
|
|
16
|
-
const setupPages = require('./lib/steps/setupPages')
|
|
17
|
-
const setupRedirects = require('./lib/steps/setupRedirects')
|
|
18
|
-
|
|
19
|
-
const build = async (functionsPath, publishPath, nextRoot) => {
|
|
20
|
-
const trackNextOnNetlifyFiles = prepareFolders({
|
|
21
|
-
functionsPath,
|
|
22
|
-
publishPath,
|
|
23
|
-
})
|
|
24
|
-
|
|
25
|
-
// If we're in a monorepo we need to move into the Next site root
|
|
26
|
-
const oldCwd = process.cwd()
|
|
27
|
-
if (nextRoot !== oldCwd) {
|
|
28
|
-
process.chdir(nextRoot)
|
|
29
|
-
}
|
|
30
|
-
copyPublicFiles(publishPath)
|
|
31
|
-
|
|
32
|
-
await copyNextAssets(publishPath)
|
|
33
|
-
|
|
34
|
-
await setupPages({ functionsPath, publishPath })
|
|
35
|
-
|
|
36
|
-
const { images } = await getNextConfig()
|
|
37
|
-
|
|
38
|
-
await setupImageFunction(functionsPath, images)
|
|
39
|
-
|
|
40
|
-
await setupRedirects(publishPath)
|
|
41
|
-
|
|
42
|
-
setupHeaders(publishPath)
|
|
43
|
-
|
|
44
|
-
// ...and move back after
|
|
45
|
-
if (nextRoot !== oldCwd) {
|
|
46
|
-
process.chdir(oldCwd)
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
trackNextOnNetlifyFiles()
|
|
50
|
-
|
|
51
|
-
logTitle('✅ Success! All done!')
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
const watch = (functionsPath, publishPath, nextRoot) => {
|
|
55
|
-
logTitle(`👀 Watching source code for changes`)
|
|
56
|
-
|
|
57
|
-
const runBuild = debounceFn(
|
|
58
|
-
async () => {
|
|
59
|
-
try {
|
|
60
|
-
execa.sync('next', ['build'], { stdio: 'inherit', preferLocal: true, cwd: nextRoot })
|
|
61
|
-
await build(functionsPath, publishPath, nextRoot)
|
|
62
|
-
} catch (error) {
|
|
63
|
-
console.log(error)
|
|
64
|
-
}
|
|
65
|
-
},
|
|
66
|
-
{
|
|
67
|
-
wait: 3000,
|
|
68
|
-
},
|
|
69
|
-
)
|
|
70
|
-
|
|
71
|
-
chokidar.watch(SRC_FILES).on('all', runBuild)
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
// options param:
|
|
75
|
-
// {
|
|
76
|
-
// functionsDir: string to path
|
|
77
|
-
// publishDir: string to path
|
|
78
|
-
// watch: { directory: string to path }
|
|
79
|
-
// }
|
|
80
|
-
//
|
|
81
|
-
|
|
82
|
-
const nextOnNetlify = async (options = {}) => {
|
|
83
|
-
const functionsPath = normalize(options.functionsDir || NETLIFY_FUNCTIONS_PATH)
|
|
84
|
-
const publishPath = normalize(options.publishDir || NETLIFY_PUBLISH_PATH)
|
|
85
|
-
const nextRoot = normalize(options.nextRoot || process.cwd())
|
|
86
|
-
|
|
87
|
-
if (options.watch) {
|
|
88
|
-
watch(functionsPath, publishPath, nextRoot)
|
|
89
|
-
} else {
|
|
90
|
-
await build(functionsPath, publishPath, nextRoot)
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
module.exports = nextOnNetlify
|