UNPKG

4.66 kBJavaScriptView Raw
1const fs = require('fs-extra');
2const isPortReachable = require('is-port-reachable');
3const inquirer = require('inquirer');
4// const osLocale = require('os-locale')
5
6const getPathnameDevServerStart = require('../utils/get-pathname-dev-server-start');
7const getFreePort = require('./get-free-port');
8
9/**
10 * @async
11 * @returns {Number|Boolean} 如果最终没有结果,返回 false,否则返回可用的端口数
12 */
13const doValidatePort = async () => {
14 // [开发环境] 如果 flag 文件中写有端口,直接使用该端口
15 if (__DEV__) {
16 let infos;
17 try {
18 infos = await fs.readJson(getPathnameDevServerStart());
19 } catch (e) {}
20 if (typeof infos === 'object') return infos.port;
21 }
22
23 // const locale = osLocale.sync()
24 // console.log('locale', locale)
25
26 // 如果环境变量中不存在 SERVER_PORT 同时全局变量 __SERVER_PORT__ 存在可用值,赋值环境变量
27 // __SERVER_PORT__ 为 webpack 打包时使用 definePlugin 替换入的全局变量值
28 if (
29 typeof process.env.SERVER_PORT === 'undefined' &&
30 typeof __SERVER_PORT__ !== 'undefined'
31 )
32 process.env.SERVER_PORT = __SERVER_PORT__;
33
34 /** @type {Boolean} 环境变量 SERVER_PORT 的端口号是否可用 */
35 const isPortInEnvFree = await isPortFree(process.env.SERVER_PORT);
36
37 // 如果可用,返回该端口号,结束
38 if (isPortInEnvFree) return process.env.SERVER_PORT;
39
40 // 如果不可用,输出日志
41 logPortTaken(process.env.SERVER_PORT);
42
43 // [开发环境] 修改 flag 文件,标记端口被占用,并结束
44 if (__DEV__) {
45 // 修改 flag 文件
46 await fs.writeFile(
47 getPathnameDevServerStart(),
48 `port ${process.env.SERVER_PORT} has been taken.`,
49 'utf-8'
50 );
51 // 跳出
52 return false;
53 }
54
55 /** @type {Boolean} 端口是否被占用 */
56 let isPortTaken = true;
57 /** @type {Number} 端口结果 */
58 let port;
59
60 while (isPortTaken) {
61 const askForPort = await inquirer.prompt([
62 {
63 type: 'input',
64 name: 'port',
65 message:
66 'Please input a new port number (leave empty for cancel)',
67 validate: input => {
68 if (!input) return true;
69 if (isNaN(input)) return 'Must be a number or null';
70 return true;
71 }
72 }
73 ]);
74 if (!askForPort.port) {
75 isPortTaken = false;
76 port = undefined;
77 } else {
78 port = await isPortFree(askForPort.port);
79 isPortTaken = !port ? true : false;
80 if (isPortTaken) logPortTaken(askForPort.port);
81 }
82 }
83
84 if (port) return port;
85 return false;
86};
87
88/**
89 * 验证目标端口是否可用
90 * @async
91 * @param {Number|String} port
92 * @returns {Number|Boolean} 如果端口可用,返回该端口;如果不可用,返回 false
93 */
94const isPortFree = async port => {
95 const isPortOpen = !(await isPortReachable(port));
96 if (isPortOpen) return port;
97 return false;
98};
99
100/**
101 * log: 目标端口被占用
102 * @param {Number|String} port
103 */
104const logPortTaken = port => {
105 console.log(
106 `\x1b[31m×\x1b[0m ` +
107 `\x1b[93m[koot/server]\x1b[0m port \x1b[32m${port}\x1b[0m has been taken.`
108 );
109};
110
111/**
112 * 验证服务器启动端口
113 *
114 * 依次检查以下变量/常量,当发现可用值时进入下一步
115 * - `__SERVER_PORT__`
116 * - `process.env.SERVER_PORT`
117 *
118 * 检查设定好的端口号是否可用
119 * - 如果可用,直接返回结果
120 * - 如果不可用,提示下一步操作
121 * - 如果不可用同时之后的操作取消,返回 false
122 *
123 * _生产环境_
124 * 设定环境变量
125 * - `SERVER_PORT` -> 指定的端口
126 *
127 * _开发环境_
128 * 设定环境变量
129 * - `SERVER_PORT` -> 随机端口
130 * - `SERVER_PORT_DEV_MAIN` -> 指定的端口
131 *
132 * @async
133 * @returns {Number|Boolean} 如果最终没有结果,返回 false,否则返回可用的端口数
134 */
135const validatePort = async () => {
136 const port = await doValidatePort();
137 if (!port) return false;
138 if (__DEV__) {
139 // 开发环境:在随机端口启用服务器
140 const portFree = await getFreePort(port);
141 process.env.SERVER_PORT = portFree;
142 process.env.SERVER_PORT_DEV_MAIN = port;
143 }
144 return port;
145};
146
147// export default validatePort;
148module.exports = validatePort;