From a720dbdc4c0411ff0384449d00e125b4d3f0f1c5 Mon Sep 17 00:00:00 2001 From: Tom Lienard Date: Sun, 7 Aug 2022 19:31:30 +0200 Subject: [PATCH] =?UTF-8?q?fix(next):=20dev=20server=20starting=20when=20i?= =?UTF-8?q?mporting=20a=20file=20using=20get-projec=E2=80=A6=20(#38274)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes: #38232 Fixes: https://github.com/vercel/next.js/issues/36893 Version [12.1.1-canary.5](https://github.com/vercel/next.js/releases/tag/v12.1.1-canary.5) introduced a bug, more specifically this PR: https://github.com/vercel/next.js/pull/34836 The issue described in #38232 is that the following code starts both the dev and prod servers: ```js const start = require('next/dist/cli/next-start') start.nextStart() ``` I searched a bit and found that `lib/get-project-dir.ts#getProjectDir()` now imports `bin/next.ts` https://github.com/vercel/next.js/blob/6b8e499c7bf13914cca92f9da1737d358133ee20/packages/next/lib/get-project-dir.ts#L3 and it calls a CLI command via https://github.com/vercel/next.js/blob/6b8e499c7bf13914cca92f9da1737d358133ee20/packages/next/bin/next.ts#L137 This `command` should not be defined, but it fallbacks to `defaultCommand`, which is `dev` (that explains why the dev server is also started) This PR moves the `cliCommand` types and `commands` variable to a new separate file instead of `bin/next.ts`, to avoid running a CLI command when we import any file that also imports `lib/get-project-dir.ts` Not sure how integration tests can be added for this issue, but feel free to tell me. Co-authored-by: JJ Kasper <22380829+ijjk@users.noreply.github.com> --- packages/next/bin/next.ts | 13 +------------ packages/next/cli/next-build.ts | 2 +- packages/next/cli/next-dev.ts | 2 +- packages/next/cli/next-export.ts | 2 +- packages/next/cli/next-info.ts | 2 +- packages/next/cli/next-lint.ts | 2 +- packages/next/cli/next-start.ts | 2 +- packages/next/cli/next-telemetry.ts | 2 +- packages/next/lib/commands.ts | 12 ++++++++++++ packages/next/lib/get-project-dir.ts | 2 +- test/unit/get-project-dir.test.ts | 5 +++++ 11 files changed, 26 insertions(+), 20 deletions(-) create mode 100644 packages/next/lib/commands.ts create mode 100644 test/unit/get-project-dir.test.ts diff --git a/packages/next/bin/next.ts b/packages/next/bin/next.ts index 65701856f19f..cbb26a0be798 100755 --- a/packages/next/bin/next.ts +++ b/packages/next/bin/next.ts @@ -2,6 +2,7 @@ import * as log from '../build/output/log' import arg from 'next/dist/compiled/arg/index.js' import { NON_STANDARD_NODE_ENV } from '../lib/constants' +import { commands } from '../lib/commands' ;['react', 'react-dom'].forEach((dependency) => { try { // When 'npm link' is used it checks the clone location. Not the project. @@ -14,18 +15,6 @@ import { NON_STANDARD_NODE_ENV } from '../lib/constants' }) const defaultCommand = 'dev' -export type cliCommand = (argv?: string[]) => void -export const commands: { [command: string]: () => Promise } = { - build: () => Promise.resolve(require('../cli/next-build').nextBuild), - start: () => Promise.resolve(require('../cli/next-start').nextStart), - export: () => Promise.resolve(require('../cli/next-export').nextExport), - dev: () => Promise.resolve(require('../cli/next-dev').nextDev), - lint: () => Promise.resolve(require('../cli/next-lint').nextLint), - telemetry: () => - Promise.resolve(require('../cli/next-telemetry').nextTelemetry), - info: () => Promise.resolve(require('../cli/next-info').nextInfo), -} - const args = arg( { // Types diff --git a/packages/next/cli/next-build.ts b/packages/next/cli/next-build.ts index af5ae2e51feb..d29852939bed 100755 --- a/packages/next/cli/next-build.ts +++ b/packages/next/cli/next-build.ts @@ -2,7 +2,7 @@ import { existsSync } from 'fs' import arg from 'next/dist/compiled/arg/index.js' import * as Log from '../build/output/log' -import { cliCommand } from '../bin/next' +import { cliCommand } from '../lib/commands' import build from '../build' import { printAndExit } from '../server/lib/utils' import isError from '../lib/is-error' diff --git a/packages/next/cli/next-dev.ts b/packages/next/cli/next-dev.ts index 5e0c22bb7f0b..9048fd028aed 100755 --- a/packages/next/cli/next-dev.ts +++ b/packages/next/cli/next-dev.ts @@ -5,7 +5,7 @@ import { startServer } from '../server/lib/start-server' import { printAndExit } from '../server/lib/utils' import * as Log from '../build/output/log' import { startedDevelopmentServer } from '../build/output' -import { cliCommand } from '../bin/next' +import { cliCommand } from '../lib/commands' import isError from '../lib/is-error' import { getProjectDir } from '../lib/get-project-dir' import { CONFIG_FILES } from '../shared/lib/constants' diff --git a/packages/next/cli/next-export.ts b/packages/next/cli/next-export.ts index 151108bfcf79..9a5282c93a8e 100755 --- a/packages/next/cli/next-export.ts +++ b/packages/next/cli/next-export.ts @@ -4,7 +4,7 @@ import { existsSync } from 'fs' import arg from 'next/dist/compiled/arg/index.js' import exportApp from '../export' import { printAndExit } from '../server/lib/utils' -import { cliCommand } from '../bin/next' +import { cliCommand } from '../lib/commands' import { trace } from '../trace' import isError from '../lib/is-error' import { getProjectDir } from '../lib/get-project-dir' diff --git a/packages/next/cli/next-info.ts b/packages/next/cli/next-info.ts index 0a7b9673bac1..c9c468b26ff5 100755 --- a/packages/next/cli/next-info.ts +++ b/packages/next/cli/next-info.ts @@ -6,7 +6,7 @@ import chalk from 'next/dist/compiled/chalk' import arg from 'next/dist/compiled/arg/index.js' import fetch from 'next/dist/compiled/node-fetch' import { printAndExit } from '../server/lib/utils' -import { cliCommand } from '../bin/next' +import { cliCommand } from '../lib/commands' import isError from '../lib/is-error' const nextInfo: cliCommand = async (argv) => { diff --git a/packages/next/cli/next-lint.ts b/packages/next/cli/next-lint.ts index 439805dcfd3d..699c586e5e0b 100755 --- a/packages/next/cli/next-lint.ts +++ b/packages/next/cli/next-lint.ts @@ -4,7 +4,7 @@ import arg from 'next/dist/compiled/arg/index.js' import { join } from 'path' import chalk from 'next/dist/compiled/chalk' -import { cliCommand } from '../bin/next' +import { cliCommand } from '../lib/commands' import { ESLINT_DEFAULT_DIRS } from '../lib/constants' import { runLintCheck } from '../lib/eslint/runLintCheck' import { printAndExit } from '../server/lib/utils' diff --git a/packages/next/cli/next-start.ts b/packages/next/cli/next-start.ts index 02bb29fa903e..fc7cfe39369b 100755 --- a/packages/next/cli/next-start.ts +++ b/packages/next/cli/next-start.ts @@ -3,10 +3,10 @@ import arg from 'next/dist/compiled/arg/index.js' import { startServer } from '../server/lib/start-server' import { printAndExit } from '../server/lib/utils' -import { cliCommand } from '../bin/next' import * as Log from '../build/output/log' import isError from '../lib/is-error' import { getProjectDir } from '../lib/get-project-dir' +import { cliCommand } from '../lib/commands' const nextStart: cliCommand = (argv) => { const validArgs: arg.Spec = { diff --git a/packages/next/cli/next-telemetry.ts b/packages/next/cli/next-telemetry.ts index 34f6daccc84d..2df798e3ce4e 100755 --- a/packages/next/cli/next-telemetry.ts +++ b/packages/next/cli/next-telemetry.ts @@ -2,7 +2,7 @@ import chalk from 'next/dist/compiled/chalk' import arg from 'next/dist/compiled/arg/index.js' import { printAndExit } from '../server/lib/utils' -import { cliCommand } from '../bin/next' +import { cliCommand } from '../lib/commands' import { Telemetry } from '../telemetry/storage' import isError from '../lib/is-error' diff --git a/packages/next/lib/commands.ts b/packages/next/lib/commands.ts new file mode 100644 index 000000000000..63a41430f856 --- /dev/null +++ b/packages/next/lib/commands.ts @@ -0,0 +1,12 @@ +export type cliCommand = (argv?: string[]) => void + +export const commands: { [command: string]: () => Promise } = { + build: () => Promise.resolve(require('../cli/next-build').nextBuild), + start: () => Promise.resolve(require('../cli/next-start').nextStart), + export: () => Promise.resolve(require('../cli/next-export').nextExport), + dev: () => Promise.resolve(require('../cli/next-dev').nextDev), + lint: () => Promise.resolve(require('../cli/next-lint').nextLint), + telemetry: () => + Promise.resolve(require('../cli/next-telemetry').nextTelemetry), + info: () => Promise.resolve(require('../cli/next-info').nextInfo), +} diff --git a/packages/next/lib/get-project-dir.ts b/packages/next/lib/get-project-dir.ts index f132c846d0ce..a64aae5f9c3e 100644 --- a/packages/next/lib/get-project-dir.ts +++ b/packages/next/lib/get-project-dir.ts @@ -1,6 +1,6 @@ import fs from 'fs' import path from 'path' -import { commands } from '../bin/next' +import { commands } from './commands' import * as Log from '../build/output/log' import { detectTypo } from './detect-typo' diff --git a/test/unit/get-project-dir.test.ts b/test/unit/get-project-dir.test.ts new file mode 100644 index 000000000000..3953a0e4075e --- /dev/null +++ b/test/unit/get-project-dir.test.ts @@ -0,0 +1,5 @@ +describe('get-project-dir', () => { + it('should not start dev server on require', async () => { + require('next/dist/lib/get-project-dir') + }) +})