#!/usr/bin/env node import { resolve } from 'path' import arg from 'next/dist/compiled/arg/index.js' import { existsSync } from 'fs' 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' const nextDev: cliCommand = (argv) => { const validArgs: arg.Spec = { // Types '--help': Boolean, '--port': Number, '--hostname': String, // Aliases '-h': '--help', '-p': '--port', '-H': '--hostname', } let args: arg.Result try { args = arg(validArgs, { argv }) } catch (error) { if (error.code === 'ARG_UNKNOWN_OPTION') { return printAndExit(error.message, 1) } throw error } if (args['--help']) { console.log(` Description Starts the application in development mode (hot-code reloading, error reporting, etc) Usage $ next dev -p represents the directory of the Next.js application. If no directory is provided, the current directory will be used. Options --port, -p A port number on which to start the application --hostname, -H Hostname on which to start the application (default: 0.0.0.0) --help, -h Displays this message `) process.exit(0) } const dir = resolve(args._[0] || '.') // Check if pages dir exists and warn if not if (!existsSync(dir)) { printAndExit(`> No such directory exists as the project root: ${dir}`) } async function preflight() { const { getPackageVersion } = await import('../lib/get-package-version') const [sassVersion, nodeSassVersion] = await Promise.all([ getPackageVersion({ cwd: dir, name: 'sass' }), getPackageVersion({ cwd: dir, name: 'node-sass' }), ]) if (sassVersion && nodeSassVersion) { Log.warn( 'Your project has both `sass` and `node-sass` installed as dependencies, but should only use one or the other. ' + 'Please remove the `node-sass` dependency from your project. ' + ' Read more: https://nextjs.org/docs/messages/duplicate-sass' ) } } const port = args['--port'] || (process.env.PORT && parseInt(process.env.PORT)) || 3000 // We do not set a default host value here to prevent breaking // some set-ups that rely on listening on other interfaces const host = args['--hostname'] const appUrl = `http://${ !host || host === '0.0.0.0' ? 'localhost' : host }:${port}` startServer({ dir, dev: true, isNextDevCommand: true }, port, host) .then(async (app) => { startedDevelopmentServer(appUrl, `${host || '0.0.0.0'}:${port}`) // Start preflight after server is listening and ignore errors: preflight().catch(() => {}) // Finalize server bootup: await app.prepare() }) .catch((err) => { if (err.code === 'EADDRINUSE') { let errorMessage = `Port ${port} is already in use.` const pkgAppPath = require('next/dist/compiled/find-up').sync( 'package.json', { cwd: dir, } ) const appPackage = require(pkgAppPath) if (appPackage.scripts) { const nextScript = Object.entries(appPackage.scripts).find( (scriptLine) => scriptLine[1] === 'next' ) if (nextScript) { errorMessage += `\nUse \`npm run ${nextScript[0]} -- -p \`.` } } console.error(errorMessage) } else { console.error(err) } process.nextTick(() => process.exit(1)) }) } export { nextDev }