feat: 添加publish

This commit is contained in:
熊潇 2024-12-05 17:31:32 +08:00
parent da6211299b
commit a117281b9e
7 changed files with 141 additions and 39 deletions

View File

@ -1,6 +1,6 @@
{
"name": "@kevisual/envision-cli",
"version": "0.0.10",
"version": "0.0.13",
"description": "envision command tools",
"main": "dist/index.js",
"type": "module",
@ -35,7 +35,6 @@
"fast-glob": "^3.3.2",
"filesize": "^10.1.6",
"form-data": "^4.0.1",
"glob": "^11.0.0",
"ignore": "^6.0.2",
"inquirer": "^12.1.0",
"rimraf": "^6.0.1",

3
pnpm-lock.yaml generated
View File

@ -66,9 +66,6 @@ importers:
form-data:
specifier: ^4.0.1
version: 4.0.1
glob:
specifier: ^11.0.0
version: 11.0.0
ignore:
specifier: ^6.0.2
version: 6.0.2

View File

@ -1,11 +1,14 @@
import { program as app, Command } from '@/program.ts';
import { glob } from 'glob';
import glob from 'fast-glob';
import path from 'path';
import fs from 'fs';
import FormData from 'form-data';
import { baseURL, getBaseURL } from '@/module/query.ts';
import { getBaseURL, query } from '@/module/query.ts';
import { getConfig } from '@/module/index.ts';
import inquirer from 'inquirer';
import { packLib, unpackLib } from './publish.ts';
import chalk from 'chalk';
import { installDeps } from '@/uitls/npm.ts';
const command = new Command('deploy')
.description('把前端文件传到服务器')
@ -37,8 +40,8 @@ const command = new Command('deploy')
const pwd = process.cwd();
const directory = path.join(pwd, filePath);
const gPath = path.join(directory, '**/*');
const files = await glob(gPath, { cwd: pwd, ignore: ['node_modules/**/*'], nodir: true });
const _relativeFiles = files.map((file) => file.replace(directory + '/', ''));
const files = await glob(gPath, { cwd: pwd, ignore: ['node_modules/**/*'], onlyFiles: true });
const _relativeFiles = files.map((file) => path.relative(directory, file));
console.log('upload Files', _relativeFiles);
console.log('upload Files Key', key, version);
if (!yes) {
@ -124,8 +127,40 @@ app.addCommand(command);
const local = new Command('local')
.description('本地部署')
.option('-k, --key <key>', 'key')
.action(() => {
.argument('<key>', 'key')
.option('-i, --ignore', '使用 .npmignore 文件模式去忽略文件进行打包, 不需要package.json中的files字段')
.option('-u, --update', 'query查询 127.0.0.1:11015/api/router?path=local-apps&key=detect')
.action(async (key, opts) => {
console.log('local deploy');
const { outputFilePath } = await packLib(opts?.ignore);
const mainAppPath = getConfig().mainAppPath;
const appsPath = getConfig().appsPath || path.join(mainAppPath, 'apps');
if (!key) {
console.error(chalk.red('key is required'));
return;
}
const appPath = path.join(appsPath, key);
if (!fs.existsSync(appPath)) {
fs.mkdirSync(appPath, { recursive: true });
}
// 复制应用到apps目录下
if (outputFilePath) {
await unpackLib(outputFilePath, appPath);
fs.unlinkSync(outputFilePath);
installDeps({ appPath });
if (opts?.update) {
const res = await query.post(
{ path: 'local-apps', key: 'detect' },
{
url: `http://127.0.0.1:11015/api/router?path=local-apps&key=detect`,
},
);
if (res.code === 200) {
console.log('local deploy success');
} else {
console.error('local deploy failed', res.message);
}
}
}
});
app.addCommand(local);

View File

@ -4,7 +4,8 @@ import path from 'path';
import fs from 'fs';
import { chalk } from '@/module/chalk.ts';
import inquirer from 'inquirer';
import { spawn, spawnSync } from 'child_process';
import { spawn } from 'child_process';
import { installDeps } from '@/uitls/npm.ts';
const command = new Command('init').description('初始化应用').action((optison) => {
console.log('init');
@ -17,6 +18,7 @@ const setMainAppConfig = async (mainAppPath: string) => {
config.mainAppPath = mainAppPath;
writeConfig(config);
};
const initMain = async () => {
const mainAppPath = path.join(envisionPath, 'main-app');
const pkgPath = path.join(mainAppPath, 'package.json');
@ -26,34 +28,29 @@ const initMain = async () => {
name: 'main-app',
version: '1.0.0',
type: 'module',
main: 'dist/app.mjs',
scripts: {
start: 'node dist/app.mjs',
},
dependencies: {
'@kevisual/router': 'latest',
'@kevisual/local-app-manager': 'latest',
'@kevisual/use-config': 'latest',
},
};
fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2));
console.log(chalk.green('初始化 main-app 成功'));
}
// 在对应的路径,安装依赖
const needDeps = ['@kevisual/router', '@kevisual/local-app-manager', '@kevisual/use-config'];
let hasPnpm = false;
try {
spawnSync('pnpm', ['--version']);
hasPnpm = true;
} catch (e) {
hasPnpm = false;
}
for (let dep of needDeps) {
console.log(chalk.green('安装依赖', dep));
const npm = hasPnpm ? 'pnpm' : 'npm';
spawnSync(npm, ['install', dep], { cwd: mainAppPath, stdio: 'inherit' });
}
installDeps({ appPath: mainAppPath, sync: true });
// 创建 dist/app.mjs
const code = `import { App } from '@kevisual/router';
import { app as LocalApp } from '@kevisual/local-app-manager';
import { useConfig } from '@kevisual/use-config';
const config = useConfig();
const app = new App();
app.importApp(LocalApp);
const host = config.host || '127.0.0.1';
app.listen(config.port, host, () => {
console.log(\`app is running on http://\${host}:\${config.port}\`);
LocalApp.listen(config.port, host, () => {
console.log(\`LocalApp is running on http://\${host}:\${config.port}\`);
});
`;
const codeDistPath = path.join(mainAppPath, 'dist');
@ -92,6 +89,7 @@ app.listen(config.port, host, () => {
//
console.log(chalk.green('创建 app.config.json5 成功'));
setMainAppConfig(mainAppPath);
writeConfig({ ...getConfig(), appsPath: answers.appsPath });
};
const checkPid = (pid: number) => {
try {
@ -124,6 +122,8 @@ const mainApp = new Command('main')
if (options.init) {
await initMain();
return;
} else {
console.warn(chalk.yellow('请使用 --init 初始化 main 应用'));
}
const runChild = () => {
const logDir = path.join(envisionPath, 'log');
@ -173,7 +173,7 @@ const mainApp = new Command('main')
}
}
runChild();
} else if (options.stop) {
} else if (options.exit) {
if (config.mainAppPid) {
// 检查是否有进程
if (checkPid(config.mainAppPid)) {

View File

@ -6,6 +6,7 @@ import { fileIsExist } from '@/uitls/file.ts';
import { getConfig } from '@/module/get-config.ts';
import fs from 'fs';
import inquirer from 'inquirer';
import { checkPnpm } from '@/uitls/npm.ts';
const command = new Command('npm').description('npm command show publish and set .npmrc').action(async (options) => {});
const publish = new Command('publish')
@ -165,5 +166,32 @@ const remove = new Command('remove').description('remove .npmrc').action(async (
});
command.addCommand(remove);
//
const install = new Command('install')
.option('-n, --noproxy', 'no proxy')
.description('npm install 使用 proxy代理去下载')
.action(async (options) => {
const cwd = process.cwd();
const config = getConfig();
let setEnv = {};
const proxyEnv = {
https_proxy: 'http://127.0.0.1:7890',
http_proxy: 'http://127.0.0.1:7890',
all_proxy: 'socks5://127.0.0.1:7890',
...config?.proxy,
};
setEnv = {
...proxyEnv,
};
if (options?.noproxy) {
setEnv = {};
}
if (checkPnpm()) {
spawn('pnpm', ['i'], { stdio: 'inherit', cwd: cwd, env: { ...process.env, ...setEnv } });
} else {
spawn('npm', ['i'], { stdio: 'inherit', cwd: cwd, env: { ...process.env, ...setEnv } });
}
});
command.addCommand(install);
// program 添加npm 的命令
program.addCommand(command);

View File

@ -65,7 +65,7 @@ async function getFiles(cwd: string, patterns: string[]): Promise<string[]> {
return filteredFiles;
}
const pack = async () => {
export const pack = async () => {
const cwd = process.cwd();
const collection: Record<string, any> = {};
const packageJsonPath = path.join(cwd, 'package.json');
@ -120,6 +120,7 @@ const pack = async () => {
collection.files = allFiles;
collection.packageJson = packageJson;
collection.totalSize = totalSize;
collection.tags = packageJson.app?.tags || packageJson.keywords || [];
console.log('\nTarball Details');
console.log(`name: ${packageJson.name}`);
@ -147,7 +148,7 @@ const pack = async () => {
}
return { collection, outputFilePath };
};
const packByIgnore = async () => {
export const packByIgnore = async () => {
let collection: Record<string, any> = {};
const cwd = process.cwd();
const patterns = ['**/*']; // 匹配所有文件
@ -184,6 +185,7 @@ const packByIgnore = async () => {
collection.files = allFiles;
collection.packageJson = packageJson;
collection.totalSize = totalSize;
collection.tags = packageJson.app?.tags || packageJson.keywords || [];
console.log('\nTarball Details');
console.log(`package size: ${packageSize}`);
@ -208,6 +210,22 @@ const packByIgnore = async () => {
}
return { collection, outputFilePath };
};
export const packLib = async (ignore: boolean = false) => {
if (ignore) {
return await packByIgnore();
}
return await pack();
};
export const unpackLib = async (filePath: string, cwd: string) => {
try {
await tar.x({
file: filePath,
cwd: cwd,
});
} catch (error) {
console.error('Error extracting tarball:', error);
}
};
const publishCommand = new Command('publish')
.description('发布应用')
.option('-k, --key <key>', '应用 key')
@ -276,12 +294,7 @@ const packCommand = new Command('pack')
.option('-i, --ignore', '使用 .npmignore 文件模式去忽略文件进行打包, 不需要package.json中的files字段')
.option('-p, --publish', '打包并发布')
.action(async (opts) => {
let value: { collection: Record<string, any>; outputFilePath: string };
if (opts.ignore) {
value = await packByIgnore();
} else {
value = await pack();
}
let value: { collection: Record<string, any>; outputFilePath: string } = await packLib(opts.ignore);
if (opts.publish && value?.collection) {
console.log('\n\npublish');
const { collection, outputFilePath } = value;

30
src/uitls/npm.ts Normal file
View File

@ -0,0 +1,30 @@
import { spawn, spawnSync } from 'child_process';
export const checkPnpm = () => {
try {
spawnSync('pnpm', ['--version']);
return true;
} catch (e) {
return false;
}
};
type InstallDepsOptions = {
appPath: string;
isProduction?: boolean;
sync?: boolean;
};
export const installDeps = (opts: InstallDepsOptions) => {
const { appPath } = opts;
const isProduction = opts.isProduction ?? true;
const params = ['i'];
if (isProduction) {
params.push('--production');
}
const syncSpawn = opts.sync ? spawnSync : spawn;
if (checkPnpm()) {
syncSpawn('pnpm', params, { cwd: appPath, stdio: 'inherit', env: process.env });
} else {
syncSpawn('npm', params, { cwd: appPath, stdio: 'inherit', env: process.env });
}
};