Skip to content

Commit 0b3fff6

Browse files
committed
fix: handle next imports
1 parent 71b5c65 commit 0b3fff6

8 files changed

+42
-19
lines changed

Diff for: helpers/getNextConfig.js

+4-2
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,15 @@ const { cwd: getCwd } = require('process')
44

55
const moize = require('moize')
66

7+
const requireNextModule = require('./requireNextModule')
8+
79
// We used to cache nextConfig for any cwd. Now we pass process.cwd() to cache
810
// (or memoize) nextConfig per cwd.
911
const getNextConfig = async function (failBuild = defaultFailBuild, cwd = getCwd()) {
1012
// We cannot load `next` at the top-level because we validate whether the
1113
// site is using `next` inside `onPreBuild`.
12-
const { PHASE_PRODUCTION_BUILD } = require('next/constants')
13-
const loadConfig = require('next/dist/next-server/server/config').default
14+
const { PHASE_PRODUCTION_BUILD } = requireNextModule('next/constants', cwd)
15+
const loadConfig = requireNextModule('next/dist/next-server/server/config', cwd).default
1416

1517
try {
1618
return await loadConfig(PHASE_PRODUCTION_BUILD, cwd)

Diff for: helpers/requireNextModule.js

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
/**
2+
* We can't require() these normally, because the "next" package might not be resolvable from the root of a monorepo
3+
*/
4+
const requireNextModule = (module, nextRoot) => {
5+
const resolved = require.resolve(module, { paths: [nextRoot, process.cwd()] })
6+
if (resolved) {
7+
// eslint-disable-next-line import/no-dynamic-require
8+
return require(resolved)
9+
}
10+
throw new Error(`Could not load module ${module}`)
11+
}
12+
13+
module.exports = requireNextModule

Diff for: helpers/validateNextUsage.js

+14-6
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,17 @@
11
const { yellowBright } = require('chalk')
22
const { lt: ltVersion, gte: gteVersion } = require('semver')
33

4+
const getNextRoot = require('./getNextRoot')
5+
46
// Ensure Next.js is available.
57
// We use `peerDependencies` instead of `dependencies` so that users can choose
68
// the Next.js version. However, this requires them to install "next" in their
79
// site.
8-
const validateNextUsage = function (failBuild) {
9-
if (!hasPackage('next')) {
10+
const validateNextUsage = function ({ failBuild, netlifyConfig }) {
11+
const nextRoot = getNextRoot({ netlifyConfig })
12+
// Because we don't know the monorepo structure, we try to resolve next both locally and in the next root
13+
const paths = [nextRoot, process.cwd()]
14+
if (!hasPackage('next', paths)) {
1015
return failBuild(
1116
'This site does not seem to be using Next.js. Please run "npm install next" or "yarn next" in the repository.',
1217
)
@@ -15,9 +20,12 @@ const validateNextUsage = function (failBuild) {
1520
// We cannot load `next` at the top-level because we validate whether the
1621
// site is using `next` inside `onPreBuild`.
1722
// Old Next.js versions are not supported
18-
const { version } = require('next/package.json')
23+
// eslint-disable-next-line node/no-unpublished-require
24+
const pkg = require.resolve(`next/package.json`, { paths })
25+
// eslint-disable-next-line import/no-dynamic-require
26+
const { version } = require(pkg)
1927
if (ltVersion(version, MIN_VERSION)) {
20-
return failBuild(`Please upgrade to Next.js ${MIN_VERSION} or later`)
28+
return failBuild(`Please upgrade to Next.js ${MIN_VERSION} or later. Found ${version}.`)
2129
}
2230

2331
// Recent Next.js versions are sometimes unstable and we might not officially
@@ -31,9 +39,9 @@ const validateNextUsage = function (failBuild) {
3139
const MIN_VERSION = '10.0.6'
3240
const MIN_EXPERIMENTAL_VERSION = '11.0.0'
3341

34-
const hasPackage = function (packageName) {
42+
const hasPackage = function (packageName, paths) {
3543
try {
36-
require(`${packageName}/package.json`)
44+
require.resolve(`${packageName}/package.json`, { paths })
3745
return true
3846
} catch (error) {
3947
return false

Diff for: helpers/verifyBuildTarget.js

+5-3
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,10 @@ const verifyBuildTarget = async ({ failBuild, netlifyConfig }) => {
3333
// https://github.com/vercel/next.js/blob/canary/packages/next/telemetry/ci-info.ts
3434
/* eslint-disable node/no-unpublished-require */
3535

36-
delete require.cache[require.resolve('next/dist/telemetry/ci-info')]
37-
delete require.cache[require.resolve('next/dist/next-server/server/config')]
36+
const paths = [nextRoot, process.cwd()]
37+
38+
delete require.cache[require.resolve('next/dist/telemetry/ci-info', { paths })]
39+
delete require.cache[require.resolve('next/dist/next-server/server/config', { paths })]
3840

3941
/* eslint-enable node/no-unpublished-require */
4042

@@ -45,7 +47,7 @@ const verifyBuildTarget = async ({ failBuild, netlifyConfig }) => {
4547

4648
if (!configFile) {
4749
await writeFile(
48-
path.resolve('next.config.js'),
50+
path.resolve(nextRoot, 'next.config.js'),
4951
`
5052
module.exports = {
5153
// Supported targets are "serverless" and "experimental-serverless-trace"

Diff for: index.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ module.exports = {
1919
async onPreBuild({ netlifyConfig, packageJson, utils, constants }) {
2020
const { failBuild } = utils.build
2121

22-
validateNextUsage(failBuild)
22+
validateNextUsage({ failBuild, netlifyConfig })
2323

2424
const hasNoPackageJson = Object.keys(packageJson).length === 0
2525
if (hasNoPackageJson) {

Diff for: src/lib/helpers/getI18n.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Get the i1i8n details specified in next.config.js, if any
1+
// Get the ii8n details specified in next.config.js, if any
22
const getNextConfig = require('../../../helpers/getNextConfig')
33

44
const getI18n = async () => {

Diff for: src/lib/helpers/getSortedRedirects.js

+3-4
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
const requireNextModule = require('../../../helpers/requireNextModule')
2+
13
const removeFileExtension = require('./removeFileExtension')
24

35
// Return an array of redirects sorted in order of specificity, i.e., more generic
@@ -8,11 +10,8 @@ const getSortedRedirects = (redirects) => {
810
// after sorting
911
const routesWithoutExtensions = redirects.map(({ route }) => removeFileExtension(route))
1012

11-
// We cannot load `next` at the top-level because we validate whether the
12-
// site is using `next` inside `onPreBuild`.
1313
// Sort the "naked" routes
14-
// eslint-disable-next-line node/no-unpublished-require
15-
const { getSortedRoutes } = require('next/dist/next-server/lib/router/utils/sorted-routes')
14+
const { getSortedRoutes } = requireNextModule('next/dist/next-server/lib/router/utils/sorted-routes', process.cwd())
1615
const sortedRoutes = getSortedRoutes(routesWithoutExtensions)
1716

1817
// Return original routes in the sorted order

Diff for: src/tests/fixtures/next.config.js-with-function.js

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
1-
const { PHASE_PRODUCTION_BUILD } = require('next/constants')
21

32
module.exports = (phase, { defaultConfig }) => {
43
// next-on-netlify uses settings from PHASE_PRODUCTION_BUILD
54
// This is the same phase that is used when running `next build`
6-
if (phase === PHASE_PRODUCTION_BUILD) {
5+
if (phase === "phase-production-build") {
76
return {
87
target: 'serverless',
98
distDir: '.myCustomDir',

0 commit comments

Comments
 (0)