diff --git a/helpers/requirePeerDependency.js b/helpers/requirePeerDependency.js new file mode 100644 index 0000000000..dc80d60910 --- /dev/null +++ b/helpers/requirePeerDependency.js @@ -0,0 +1,13 @@ +// In production, Build plugins cannot currently require peer dependencies +// without this hack. +// See https://github.com/netlify/netlify-plugin-nextjs/issues/55 +// TODO: remove once https://github.com/netlify/pod-the-builder/issues/102 is solved +const requirePeerDependency = function (IS_LOCAL, modulePath) { + if (!IS_LOCAL) { + return require(require.resolve(modulePath, { paths: ['.'] })) + } + + return require(modulePath) +} + +module.exports = requirePeerDependency diff --git a/helpers/validateNextUsage.js b/helpers/validateNextUsage.js index 29b830f4a6..1c17653509 100644 --- a/helpers/validateNextUsage.js +++ b/helpers/validateNextUsage.js @@ -1,11 +1,13 @@ const { lt: ltVersion, gte: gteVersion } = require('semver') const { yellowBright } = require('chalk') +const requirePeerDependency = require('./requirePeerDependency') + // Ensure Next.js is available. // We use `peerDependencies` instead of `dependencies` so that users can choose // the Next.js version. However, this requires them to install "next" in their // site. -const validateNextUsage = function (failBuild) { +const validateNextUsage = function (failBuild, IS_LOCAL) { if (!hasPackage('next')) { return failBuild( 'This site does not seem to be using Next.js. Please run "npm install next" or "yarn next" in the repository.', @@ -13,7 +15,7 @@ const validateNextUsage = function (failBuild) { } // Old Next.js versions are not supported - const { version } = require('next/package.json') + const { version } = requirePeerDependency(IS_LOCAL, 'next/package.json') if (ltVersion(version, MIN_VERSION)) { return failBuild(`Please upgrade to Next.js ${MIN_VERSION} or later`) } diff --git a/index.js b/index.js index 2e7e37dca2..6f90b5453b 100644 --- a/index.js +++ b/index.js @@ -7,6 +7,7 @@ const makeDir = require('make-dir') const isStaticExportProject = require('./helpers/isStaticExportProject') const validateNextUsage = require('./helpers/validateNextUsage') +const requirePeerDependency = require('./helpers/requirePeerDependency') const pWriteFile = util.promisify(fs.writeFile) @@ -15,10 +16,10 @@ const pWriteFile = util.promisify(fs.writeFile) // - Between the build and postbuild steps, any functions are bundled module.exports = { - async onPreBuild({ netlifyConfig, packageJson, utils }) { + async onPreBuild({ netlifyConfig, packageJson, utils, constants: { IS_LOCAL } }) { const { failBuild } = utils.build - validateNextUsage(failBuild) + validateNextUsage(failBuild, IS_LOCAL) if (Object.keys(packageJson).length === 0) { return failBuild(`Could not find a package.json for this project`) @@ -45,8 +46,8 @@ module.exports = { if (nextConfigPath !== undefined) { // We cannot load `next` at the top-level because we validate whether the // site is using `next` inside `onPreBuild`. - const { PHASE_PRODUCTION_BUILD } = require('next/constants') - const { default: loadConfig } = require('next/dist/next-server/server/config') + const { PHASE_PRODUCTION_BUILD } = requirePeerDependency(IS_LOCAL, 'next/constants') + const { default: loadConfig } = requirePeerDependency(IS_LOCAL, 'next/dist/next-server/server/config') // If the next config exists, fail build if target isnt in acceptableTargets const acceptableTargets = ['serverless', 'experimental-serverless-trace'] @@ -66,7 +67,7 @@ module.exports = { console.log(`** Adding next.config.js with target set to 'serverless' **`) } }, - async onBuild({ constants: { PUBLISH_DIR, FUNCTIONS_SRC = DEFAULT_FUNCTIONS_SRC } }) { + async onBuild({ constants: { PUBLISH_DIR, FUNCTIONS_SRC = DEFAULT_FUNCTIONS_SRC, IS_LOCAL } }) { console.log(`** Running Next on Netlify package **`) await makeDir(PUBLISH_DIR) @@ -75,7 +76,11 @@ module.exports = { // top-level because we validate whether the site is using `next` // inside `onPreBuild`. const nextOnNetlify = require('next-on-netlify') - nextOnNetlify({ functionsDir: FUNCTIONS_SRC, publishDir: PUBLISH_DIR }) + nextOnNetlify({ + functionsDir: FUNCTIONS_SRC, + publishDir: PUBLISH_DIR, + requirePeerDependency: requirePeerDependency.bind(undefined, IS_LOCAL), + }) }, } diff --git a/test/index.js b/test/index.js index 101cc3ab3d..3c83d7331c 100644 --- a/test/index.js +++ b/test/index.js @@ -92,6 +92,7 @@ describe('preBuild()', () => { netlifyConfig: {}, packageJson, utils, + constants: {}, }), ).rejects.toThrow( `This plugin does not support sites that manually use next-on-netlify. Uninstall next-on-netlify as a dependency to resolve.`, @@ -107,6 +108,7 @@ describe('preBuild()', () => { netlifyConfig: {}, packageJson, utils, + constants: {}, }), ).rejects.toThrow( `This plugin does not support sites that manually use next-on-netlify. Uninstall next-on-netlify as a dependency to resolve.`,