从@abearxiong/config拷贝过来
This commit is contained in:
commit
9e1881d06e
7
.gitignore
vendored
Normal file
7
.gitignore
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
node_modules
|
||||||
|
dist
|
||||||
|
|
||||||
|
.DS_Store
|
||||||
|
|
||||||
|
app.config.json5
|
||||||
|
|
3
.npmrc
Normal file
3
.npmrc
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
//npm.xiongxiao.me/:_authToken=${ME_NPM_TOKEN}
|
||||||
|
@abearxiong:registry=https://npm.pkg.github.com
|
||||||
|
//registry.npmjs.org/:_authToken=${NPM_TOKEN}
|
87
config/app-schema.json
Normal file
87
config/app-schema.json
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "App Configuration Schema",
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"type": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"inline-app",
|
||||||
|
"micro-app"
|
||||||
|
],
|
||||||
|
"$comment": "Type must be either 'inline-app' or 'micro-app'"
|
||||||
|
},
|
||||||
|
"single": {
|
||||||
|
"type": "boolean",
|
||||||
|
"$comment": "是否单例模式,独立启动服务。"
|
||||||
|
},
|
||||||
|
"port": {
|
||||||
|
"type": "integer",
|
||||||
|
"minimum": 0,
|
||||||
|
"maximum": 65535,
|
||||||
|
"$comment": "开发和单例启动服务的端口"
|
||||||
|
},
|
||||||
|
"remote": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"host": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "hostname"
|
||||||
|
},
|
||||||
|
"path": {
|
||||||
|
"type": "string",
|
||||||
|
"pattern": "^/.*"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"host",
|
||||||
|
"path"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"micro": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"serve": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"name": {
|
||||||
|
"type": "string",
|
||||||
|
"pattern": "^[a-z0-9-]+$",
|
||||||
|
"$comment": "服务名称"
|
||||||
|
},
|
||||||
|
"port": {
|
||||||
|
"type": "integer",
|
||||||
|
"minimum": 0,
|
||||||
|
"maximum": 65535,
|
||||||
|
"$comment": "启动的服务端口"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": []
|
||||||
|
},
|
||||||
|
"remote": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"host": {
|
||||||
|
"type": "string",
|
||||||
|
"format": "hostname"
|
||||||
|
},
|
||||||
|
"port": {
|
||||||
|
"type": "integer",
|
||||||
|
"minimum": 0,
|
||||||
|
"maximum": 65535,
|
||||||
|
"$comment": "链接的远程地址的端口"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"host",
|
||||||
|
"port"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"type"
|
||||||
|
]
|
||||||
|
}
|
15
config/demo/inline-app.json
Normal file
15
config/demo/inline-app.json
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"$schema": "../schema.json",
|
||||||
|
"app": {
|
||||||
|
"type": "inline-app",
|
||||||
|
"port": 14000,
|
||||||
|
"remote": {
|
||||||
|
"host": "localhost",
|
||||||
|
"path": "/api/router"
|
||||||
|
},
|
||||||
|
"micro": {
|
||||||
|
"name": "micro-app",
|
||||||
|
"port": 3001
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
17
config/demo/micro-app.json
Normal file
17
config/demo/micro-app.json
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
{
|
||||||
|
"$schema": "../schema.json",
|
||||||
|
"app": {
|
||||||
|
"type": "micro-app",
|
||||||
|
"port": 14000,
|
||||||
|
"remote": {
|
||||||
|
"host": "localhost",
|
||||||
|
"path": "/api/router"
|
||||||
|
},
|
||||||
|
"micro": {
|
||||||
|
"remote": {
|
||||||
|
"host": "localhost",
|
||||||
|
"port": 3001
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
13
config/schema.json
Normal file
13
config/schema.json
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||||
|
"title": "Packages JSON Schema",
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"app": {
|
||||||
|
"$ref": "./app-schema.json"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": [
|
||||||
|
"app"
|
||||||
|
]
|
||||||
|
}
|
16
demo/package.json
Normal file
16
demo/package.json
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"name": "demo",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"description": "",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"keywords": [],
|
||||||
|
"author": "abearxiong <xiongxiao@xiongxiao.me>",
|
||||||
|
"license": "MIT",
|
||||||
|
"type": "module",
|
||||||
|
"dependencies": {
|
||||||
|
"@kevisual/user-config": "link:.."
|
||||||
|
}
|
||||||
|
}
|
5
demo/src/app/a.ts
Normal file
5
demo/src/app/a.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import { getApps } from '@kevisual/user-config/pkgs';
|
||||||
|
|
||||||
|
const apps = getApps();
|
||||||
|
|
||||||
|
// apps.micro
|
4
demo/src/index.ts
Normal file
4
demo/src/index.ts
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
import { useConfig } from '@kevisual/user-config';
|
||||||
|
|
||||||
|
// console.log(useConfig);
|
||||||
|
console.log(useConfig());
|
50
package.json
Normal file
50
package.json
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
{
|
||||||
|
"name": "@kevisual/user-config",
|
||||||
|
"version": "1.0.1",
|
||||||
|
"types": "dist/config.d.ts",
|
||||||
|
"scripts": {
|
||||||
|
"build": "npm run clean && rollup -c",
|
||||||
|
"watch": " rollup -c -w",
|
||||||
|
"clean": "rimraf dist"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"dist",
|
||||||
|
"src",
|
||||||
|
"config"
|
||||||
|
],
|
||||||
|
"keywords": [],
|
||||||
|
"author": "abearxiong <xiongxiao@xiongxiao.me>",
|
||||||
|
"license": "UNLICENSED",
|
||||||
|
"type": "module",
|
||||||
|
"devDependencies": {
|
||||||
|
"@rollup/plugin-alias": "^5.1.1",
|
||||||
|
"@rollup/plugin-commonjs": "^28.0.1",
|
||||||
|
"@rollup/plugin-json": "^6.1.0",
|
||||||
|
"@rollup/plugin-node-resolve": "^15.3.0",
|
||||||
|
"@rollup/plugin-replace": "^6.0.1",
|
||||||
|
"@rollup/plugin-typescript": "^12.1.1",
|
||||||
|
"@types/node": "^22.9.0",
|
||||||
|
"chalk": "^5.3.0",
|
||||||
|
"commander": "^12.1.0",
|
||||||
|
"glob": "^11.0.0",
|
||||||
|
"json-schema-to-ts": "^3.1.1",
|
||||||
|
"json5": "^2.2.3",
|
||||||
|
"rollup": "^4.26.0",
|
||||||
|
"rollup-plugin-copy": "^3.5.0",
|
||||||
|
"rollup-plugin-dts": "^6.1.1",
|
||||||
|
"rollup-plugin-esbuild": "^6.1.1",
|
||||||
|
"rollup-plugin-inject": "^3.0.2",
|
||||||
|
"tslib": "^2.8.1",
|
||||||
|
"typescript": "^5.6.2"
|
||||||
|
},
|
||||||
|
"exports": {
|
||||||
|
".": {
|
||||||
|
"import": "./dist/config.mjs",
|
||||||
|
"types": "./dist/config.d.ts"
|
||||||
|
},
|
||||||
|
"./pkgs": {
|
||||||
|
"import": "./dist/pkgs.mjs",
|
||||||
|
"types": "./dist/pkgs.d.ts"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
52
rollup.config.mjs
Normal file
52
rollup.config.mjs
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
// rollup.config.js
|
||||||
|
import typescript from '@rollup/plugin-typescript';
|
||||||
|
import resolve from '@rollup/plugin-node-resolve';
|
||||||
|
import commonjs from '@rollup/plugin-commonjs';
|
||||||
|
import { dts } from 'rollup-plugin-dts';
|
||||||
|
/**
|
||||||
|
* @type {import('rollup').RollupOptions}
|
||||||
|
*/
|
||||||
|
export default [
|
||||||
|
{
|
||||||
|
input: 'src/config.ts', // TypeScript 入口文件
|
||||||
|
output: {
|
||||||
|
file: 'dist/config.mjs', // 输出文件
|
||||||
|
format: 'es', // 输出格式设置为 ES 模块
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
resolve(), // 使用 @rollup/plugin-node-resolve 解析 node_modules 中的模块
|
||||||
|
commonjs(),
|
||||||
|
typescript(), // 使用 @rollup/plugin-typescript 处理 TypeScript 文件
|
||||||
|
],
|
||||||
|
external: [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: 'src/config.ts',
|
||||||
|
output: {
|
||||||
|
file: 'dist/config.d.ts',
|
||||||
|
format: 'es',
|
||||||
|
},
|
||||||
|
plugins: [dts()],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: 'src/pkgs.ts', // TypeScript 入口文件
|
||||||
|
output: {
|
||||||
|
file: 'dist/pkgs.mjs', // 输出文件
|
||||||
|
format: 'es', // 输出格式设置为 ES 模块
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
resolve(), // 使用 @rollup/plugin-node-resolve 解析 node_modules 中的模块
|
||||||
|
commonjs(),
|
||||||
|
typescript(), // 使用 @rollup/plugin-typescript 处理 TypeScript 文件
|
||||||
|
],
|
||||||
|
external: [],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: 'src/pkgs.ts',
|
||||||
|
output: {
|
||||||
|
file: 'dist/pkgs.d.ts',
|
||||||
|
format: 'es',
|
||||||
|
},
|
||||||
|
plugins: [dts()],
|
||||||
|
},
|
||||||
|
];
|
139
src/config.ts
Normal file
139
src/config.ts
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
import JSON5 from 'json5';
|
||||||
|
import fs from 'fs';
|
||||||
|
import path from 'path';
|
||||||
|
import { fileURLToPath } from 'url';
|
||||||
|
|
||||||
|
const __filename = fileURLToPath(import.meta.url); // 当前模块的文件路径
|
||||||
|
const __dirname = path.dirname(__filename); // 当前模块的目录路径
|
||||||
|
|
||||||
|
// 配置类型
|
||||||
|
export type Config = {
|
||||||
|
port: number;
|
||||||
|
tokenSecret?: string;
|
||||||
|
redis?: {
|
||||||
|
host?: string;
|
||||||
|
port?: number;
|
||||||
|
password?: string;
|
||||||
|
version?: string;
|
||||||
|
[key: string]: any;
|
||||||
|
};
|
||||||
|
posgtres?: {
|
||||||
|
host?: string;
|
||||||
|
port?: number;
|
||||||
|
user?: string;
|
||||||
|
password?: string;
|
||||||
|
database?: string;
|
||||||
|
[key: string]: any;
|
||||||
|
};
|
||||||
|
minio?: {
|
||||||
|
endPoint?: string;
|
||||||
|
bucketName?: string;
|
||||||
|
useSSL?: boolean;
|
||||||
|
accessKey?: string;
|
||||||
|
secretKey?: string;
|
||||||
|
[key: string]: any;
|
||||||
|
};
|
||||||
|
mongo?: {
|
||||||
|
uri?: string;
|
||||||
|
[key: string]: any;
|
||||||
|
};
|
||||||
|
[key: string]: any;
|
||||||
|
};
|
||||||
|
export const initConfig: Config = {
|
||||||
|
port: 3000,
|
||||||
|
};
|
||||||
|
export const fileIsExist = (path: string) => {
|
||||||
|
try {
|
||||||
|
fs.accessSync(path, fs.constants.F_OK);
|
||||||
|
return true;
|
||||||
|
} catch (e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
export const getDirname = () => {
|
||||||
|
const isDev = getNODE_ENV() === 'development';
|
||||||
|
if (isDev) {
|
||||||
|
return path.resolve();
|
||||||
|
}
|
||||||
|
return __dirname;
|
||||||
|
};
|
||||||
|
export const getConfigFile = (fileName = 'app.config.json5') => {
|
||||||
|
const dirname = getDirname();
|
||||||
|
// 本级
|
||||||
|
const benPath = dirname + '/' + fileName;
|
||||||
|
const ben = fileIsExist(benPath);
|
||||||
|
if (ben) return benPath;
|
||||||
|
// 上级
|
||||||
|
const lastPath = path.join(dirname, '../' + fileName);
|
||||||
|
const last = fileIsExist(lastPath);
|
||||||
|
if (last) return lastPath;
|
||||||
|
// 上上级
|
||||||
|
const lastLastPath = path.join(dirname, '../../' + fileName);
|
||||||
|
const lastLast = fileIsExist(lastLastPath);
|
||||||
|
if (lastLast) return lastLastPath;
|
||||||
|
return '';
|
||||||
|
};
|
||||||
|
// 初始化读取配置文件
|
||||||
|
export const init = (initConfigBase?: any): Config => {
|
||||||
|
const dirname = getDirname();
|
||||||
|
try {
|
||||||
|
// 配置读取路径,3级判断
|
||||||
|
const filePath = getConfigFile();
|
||||||
|
console.log('config pathname:', filePath);
|
||||||
|
if (!filePath) {
|
||||||
|
throw new Error('未找到配置文件');
|
||||||
|
}
|
||||||
|
const configString = fs.readFileSync(filePath, {
|
||||||
|
encoding: 'utf-8',
|
||||||
|
});
|
||||||
|
const value = JSON5.parse(configString);
|
||||||
|
return value;
|
||||||
|
} catch (e) {
|
||||||
|
const root = dirname + '/app.config.json5';
|
||||||
|
if (!fileIsExist(root)) {
|
||||||
|
fs.writeFileSync(root, JSON5.stringify(initConfigBase || initConfig, null, 2), {
|
||||||
|
encoding: 'utf8',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
console.error('未找到配置文件,初始化配置', root);
|
||||||
|
// console.error('error', e);
|
||||||
|
return initConfig;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从全局获取
|
||||||
|
* @param initConfig 在全局未找到配置时,初始化配置的内容
|
||||||
|
*
|
||||||
|
* @returns Config
|
||||||
|
*/
|
||||||
|
export const useConfig = <T>(initConfig?: any): Config & T => {
|
||||||
|
const config = (global as any).config;
|
||||||
|
const _config = config || init(initConfig);
|
||||||
|
!config && ((global as any)['config'] = _config);
|
||||||
|
return _config;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useContext = (key: string, value: any): any => {
|
||||||
|
const _context = global as any;
|
||||||
|
if (key && value) {
|
||||||
|
_context[key] = value;
|
||||||
|
return _context;
|
||||||
|
}
|
||||||
|
if (key) {
|
||||||
|
return _context[key];
|
||||||
|
}
|
||||||
|
return _context;
|
||||||
|
};
|
||||||
|
export const deleteContext = (key: string): any => {
|
||||||
|
const _context = global as any;
|
||||||
|
if (key && _context[key]) {
|
||||||
|
delete _context[key];
|
||||||
|
return _context;
|
||||||
|
}
|
||||||
|
return _context;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getNODE_ENV = (): string => {
|
||||||
|
return process?.env?.NODE_ENV || 'production';
|
||||||
|
};
|
23
src/pkgs.ts
Normal file
23
src/pkgs.ts
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import path from 'path';
|
||||||
|
import fs from 'fs';
|
||||||
|
import type { App } from './read-app-schema.ts';
|
||||||
|
import { fileURLToPath } from 'url';
|
||||||
|
import { getConfigFile } from './config.ts';
|
||||||
|
|
||||||
|
const __filename = fileURLToPath(import.meta.url); // 当前模块的文件路径
|
||||||
|
const __dirname = path.dirname(__filename); // 当前模块的目录路径
|
||||||
|
|
||||||
|
export const getPkgs = () => {
|
||||||
|
const configFile = getConfigFile();
|
||||||
|
if (!configFile) {
|
||||||
|
console.error('配置文件不存在');
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
const config = JSON.parse(fs.readFileSync(configFile, 'utf-8'));
|
||||||
|
return config;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getApps = (): App => {
|
||||||
|
const config = getPkgs();
|
||||||
|
return config.apps || {};
|
||||||
|
};
|
79
src/read-app-schema.ts
Normal file
79
src/read-app-schema.ts
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
import { FromSchema } from 'json-schema-to-ts';
|
||||||
|
const App = {
|
||||||
|
$schema: 'http://json-schema.org/draft-07/schema#',
|
||||||
|
title: 'App Configuration Schema',
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
type: {
|
||||||
|
type: 'string',
|
||||||
|
enum: ['inline-app', 'micro-app'],
|
||||||
|
$comment: "Type must be either 'inline-app' or 'micro-app'",
|
||||||
|
},
|
||||||
|
single: {
|
||||||
|
type: 'boolean',
|
||||||
|
$comment: '是否单例模式,独立启动服务。',
|
||||||
|
},
|
||||||
|
port: {
|
||||||
|
type: 'integer',
|
||||||
|
minimum: 0,
|
||||||
|
maximum: 65535,
|
||||||
|
$comment: '开发和单例启动服务的端口',
|
||||||
|
},
|
||||||
|
remote: {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
host: {
|
||||||
|
type: 'string',
|
||||||
|
format: 'hostname',
|
||||||
|
},
|
||||||
|
path: {
|
||||||
|
type: 'string',
|
||||||
|
pattern: '^/.*',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
required: ['host', 'path'],
|
||||||
|
},
|
||||||
|
micro: {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
serve: {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
name: {
|
||||||
|
type: 'string',
|
||||||
|
pattern: '^[a-z0-9-]+$',
|
||||||
|
$comment: '服务名称',
|
||||||
|
},
|
||||||
|
port: {
|
||||||
|
type: 'integer',
|
||||||
|
minimum: 0,
|
||||||
|
maximum: 65535,
|
||||||
|
$comment: '启动的服务端口',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
required: [],
|
||||||
|
},
|
||||||
|
remote: {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
host: {
|
||||||
|
type: 'string',
|
||||||
|
format: 'hostname',
|
||||||
|
},
|
||||||
|
port: {
|
||||||
|
type: 'integer',
|
||||||
|
minimum: 0,
|
||||||
|
maximum: 65535,
|
||||||
|
$comment: '链接的远程地址的端口',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
required: ['host', 'port'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
required: [],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
required: ['type'],
|
||||||
|
} as const;
|
||||||
|
|
||||||
|
export type App = FromSchema<typeof App>;
|
34
tsconfig.json
Normal file
34
tsconfig.json
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"module": "NodeNext",
|
||||||
|
"target": "esnext",
|
||||||
|
"noImplicitAny": false,
|
||||||
|
"outDir": "./dist",
|
||||||
|
"sourceMap": false,
|
||||||
|
"allowJs": true,
|
||||||
|
"newLine": "LF",
|
||||||
|
"baseUrl": "./",
|
||||||
|
"typeRoots": [
|
||||||
|
"node_modules/@types",
|
||||||
|
],
|
||||||
|
"declaration": false,
|
||||||
|
"noEmit": true,
|
||||||
|
"allowImportingTsExtensions": true,
|
||||||
|
"moduleResolution": "NodeNext",
|
||||||
|
"experimentalDecorators": true,
|
||||||
|
"emitDecoratorMetadata": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"paths": {
|
||||||
|
"@/*": [
|
||||||
|
"src/*"
|
||||||
|
],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"src/**/*.ts"
|
||||||
|
],
|
||||||
|
"exclude": [
|
||||||
|
"node_modules",
|
||||||
|
"rollup.config.js",
|
||||||
|
]
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user