Przeglądaj źródła

fix(create): Dynamically find open port if 3000 in use

Michael Bromley 1 rok temu
rodzic
commit
a40fbb16cb

+ 0 - 26
package-lock.json

@@ -9893,11 +9893,6 @@
             "dev": true,
             "license": "MIT"
         },
-        "node_modules/@types/detect-port": {
-            "version": "1.3.5",
-            "dev": true,
-            "license": "MIT"
-        },
         "node_modules/@types/duplexify": {
             "version": "3.6.4",
             "dev": true,
@@ -11588,13 +11583,6 @@
             "dev": true,
             "license": "MIT"
         },
-        "node_modules/address": {
-            "version": "1.2.2",
-            "license": "MIT",
-            "engines": {
-                "node": ">= 10.0.0"
-            }
-        },
         "node_modules/adjust-sourcemap-loader": {
             "version": "4.0.0",
             "license": "MIT",
@@ -15031,18 +15019,6 @@
             "version": "2.1.0",
             "license": "MIT"
         },
-        "node_modules/detect-port": {
-            "version": "1.5.1",
-            "license": "MIT",
-            "dependencies": {
-                "address": "^1.0.1",
-                "debug": "4"
-            },
-            "bin": {
-                "detect": "bin/detect-port.js",
-                "detect-port": "bin/detect-port.js"
-            }
-        },
         "node_modules/dev-server": {
             "resolved": "packages/dev-server",
             "link": true
@@ -32329,7 +32305,6 @@
                 "@vendure/common": "^3.0.0",
                 "commander": "^11.0.0",
                 "cross-spawn": "^7.0.3",
-                "detect-port": "^1.5.1",
                 "fs-extra": "^11.2.0",
                 "handlebars": "^4.7.8",
                 "picocolors": "^1.0.0",
@@ -32341,7 +32316,6 @@
             },
             "devDependencies": {
                 "@types/cross-spawn": "^6.0.6",
-                "@types/detect-port": "^1.3.5",
                 "@types/fs-extra": "^11.0.4",
                 "@types/handlebars": "^4.1.0",
                 "@types/semver": "^7.5.8",

+ 0 - 2
packages/create/package.json

@@ -24,7 +24,6 @@
     },
     "devDependencies": {
         "@types/cross-spawn": "^6.0.6",
-        "@types/detect-port": "^1.3.5",
         "@types/fs-extra": "^11.0.4",
         "@types/handlebars": "^4.1.0",
         "@types/semver": "^7.5.8",
@@ -38,7 +37,6 @@
         "@vendure/common": "^3.0.0",
         "commander": "^11.0.0",
         "cross-spawn": "^7.0.3",
-        "detect-port": "^1.5.1",
         "fs-extra": "^11.2.0",
         "handlebars": "^4.7.8",
         "picocolors": "^1.0.0",

+ 20 - 7
packages/create/src/create-vendure-app.ts

@@ -1,7 +1,6 @@
 /* eslint-disable no-console */
 import { intro, note, outro, select, spinner } from '@clack/prompts';
 import { program } from 'commander';
-import detectPort from 'detect-port';
 import fs from 'fs-extra';
 import os from 'os';
 import path from 'path';
@@ -20,7 +19,7 @@ import {
     scaffoldAlreadyExists,
     yarnIsAvailable,
 } from './helpers';
-import { CliLogLevel, DbType, PackageManager } from './types';
+import { CliLogLevel, PackageManager } from './types';
 
 // eslint-disable-next-line @typescript-eslint/no-var-requires
 const packageJson = require('../package.json');
@@ -63,15 +62,30 @@ export async function createVendureApp(
     if (!runPreChecks(name, useNpm)) {
         return;
     }
-    if (await isServerPortInUse()) {
-        console.log(pc.red(`Port ${SERVER_PORT} is in use. Please make it available and then re-try.`));
-        process.exit(1);
-    }
 
     intro(
         `Let's create a ${pc.blue(pc.bold('Vendure App'))} ✨ ${pc.dim(`v${packageJson.version as string}`)}`,
     );
 
+    const portSpinner = spinner();
+    let port = SERVER_PORT;
+    const attemptedPortRange = 20;
+    portSpinner.start(`Establishing port...`);
+    while (await isServerPortInUse(port)) {
+        const nextPort = port + 1;
+        portSpinner.message(pc.yellow(`Port ${port} is in use. Attempting to use ${nextPort}`));
+        port = nextPort;
+        if (port > SERVER_PORT + attemptedPortRange) {
+            portSpinner.stop(pc.red('Could not find an available port'));
+            outro(
+                `Please ensure there is a port available between ${SERVER_PORT} and ${SERVER_PORT + attemptedPortRange}`,
+            );
+            process.exit(1);
+        }
+    }
+    portSpinner.stop(`Using port ${port}`);
+    process.env.PORT = port.toString();
+
     const root = path.resolve(name);
     const appName = path.basename(root);
     const scaffoldExists = scaffoldAlreadyExists(root, name);
@@ -211,7 +225,6 @@ export async function createVendureApp(
         const assetsDir = path.join(__dirname, '../assets');
 
         const initialDataPath = path.join(assetsDir, 'initial-data.json');
-        const port = await detectPort(3000);
         const vendureLogLevel =
             logLevel === 'silent'
                 ? LogLevel.Error

+ 3 - 3
packages/create/src/helpers.ts

@@ -414,13 +414,13 @@ function throwDatabaseSchemaDoesNotExist(dbName: string, schemaName: string) {
     );
 }
 
-export function isServerPortInUse(): Promise<boolean> {
+export function isServerPortInUse(port: number): Promise<boolean> {
     // eslint-disable-next-line @typescript-eslint/no-var-requires
     const tcpPortUsed = require('tcp-port-used');
     try {
-        return tcpPortUsed.check(SERVER_PORT);
+        return tcpPortUsed.check(port);
     } catch (e: any) {
-        console.log(pc.yellow(`Warning: could not determine whether port ${SERVER_PORT} is available`));
+        console.log(pc.yellow(`Warning: could not determine whether port ${port} is available`));
         return Promise.resolve(false);
     }
 }

+ 1 - 0
packages/create/templates/.env.hbs

@@ -1,4 +1,5 @@
 APP_ENV=dev
+PORT=3000
 COOKIE_SECRET={{ cookieSecret }}
 SUPERADMIN_USERNAME={{{ escapeSingle superadminIdentifier }}}
 SUPERADMIN_PASSWORD={{{ escapeSingle superadminPassword }}}

+ 1 - 0
packages/create/templates/environment.d.hbs

@@ -6,6 +6,7 @@ declare global {
     namespace NodeJS {
         interface ProcessEnv {
             APP_ENV: string;
+            PORT: string;
             COOKIE_SECRET: string;
             SUPERADMIN_USERNAME: string;
             SUPERADMIN_PASSWORD: string;

+ 4 - 3
packages/create/templates/vendure-config.hbs

@@ -11,10 +11,11 @@ import 'dotenv/config';
 import path from 'path';
 
 const IS_DEV = process.env.APP_ENV === 'dev';
+const serverPort = +process.env.PORT || 3000;
 
 export const config: VendureConfig = {
     apiOptions: {
-        port: 3000,
+        port: serverPort,
         adminApiPath: 'admin-api',
         shopApiPath: 'shop-api',
         // The following options are useful in development mode,
@@ -100,9 +101,9 @@ export const config: VendureConfig = {
         }),
         AdminUiPlugin.init({
             route: 'admin',
-            port: 3002,
+            port: serverPort + 2,
             adminUiConfig: {
-                apiPort: 3000,
+                apiPort: serverPort,
             },
         }),
     ],