feat: 更新去除之前的打包后端的模式
This commit is contained in:
@@ -18,9 +18,10 @@ const command = new Command('deploy')
|
||||
.option('-y, --yes <yes>', 'yes')
|
||||
.option('-o, --org <org>', 'org')
|
||||
.option('-u, --update', 'load current app. set current version in product')
|
||||
.option('-s, --showBackend', 'show backend url')
|
||||
.action(async (filePath, options) => {
|
||||
try {
|
||||
let { version, key, yes, update, org } = options;
|
||||
let { version, key, yes, update, org, showBackend } = options;
|
||||
if (!version || !key) {
|
||||
const answers = await inquirer.prompt([
|
||||
{
|
||||
@@ -80,18 +81,24 @@ const command = new Command('deploy')
|
||||
if (id && !update) {
|
||||
console.log(chalk.green('id: '), id);
|
||||
if (!org) {
|
||||
console.log(chalk.green(`run to load: envision deploy-load ${id}`));
|
||||
console.log(chalk.green(`更新为最新版本: envision deploy-load ${id}`));
|
||||
} else {
|
||||
console.log(chalk.green(`run to load: envision deploy-load ${id} -o ${org}`));
|
||||
console.log(chalk.green(`更新为最新版本: envision deploy-load ${id} -o ${org}`));
|
||||
}
|
||||
} else if (id && update) {
|
||||
deployLoadFn(id);
|
||||
} else {
|
||||
console.log('rest', JSON.stringify(rest, null, 2));
|
||||
console.log('rest error', JSON.stringify(rest, null, 2));
|
||||
}
|
||||
if (id && showBackend) {
|
||||
console.log('\n');
|
||||
console.log(chalk.blue('服务端应用部署: '), 'envision pack-deploy', id, '-k <key>');
|
||||
console.log('\n');
|
||||
}
|
||||
} else {
|
||||
console.error('File upload failed', res?.message);
|
||||
}
|
||||
return res;
|
||||
} catch (error) {
|
||||
console.error('error', error);
|
||||
}
|
||||
@@ -171,13 +178,13 @@ const deployLoadFn = async (id: string, org?: string) => {
|
||||
},
|
||||
});
|
||||
if (res.code === 200) {
|
||||
console.log('deploy-load success. current version:', res.data?.version);
|
||||
console.log(chalk.green('deploy-load success. current version:', res.data?.version));
|
||||
// /:username/:appName
|
||||
try {
|
||||
const { user, key } = res.data;
|
||||
const baseURL = getBaseURL();
|
||||
const deployURL = new URL(`/${user}/${key}`, baseURL);
|
||||
console.log('deployURL', deployURL.href);
|
||||
const deployURL = new URL(`/${user}/${key}/`, baseURL);
|
||||
console.log(chalk.blue('deployURL', deployURL.href));
|
||||
} catch (error) {}
|
||||
} else {
|
||||
console.error('deploy-load failed', res.message);
|
||||
|
||||
@@ -3,10 +3,9 @@ import path from 'path';
|
||||
import * as tar from 'tar';
|
||||
import glob from 'fast-glob';
|
||||
import { program, Command } from '@/program.ts';
|
||||
import { getBaseURL, getConfig, query } from '@/module/index.ts';
|
||||
import { getConfig, query } from '@/module/index.ts';
|
||||
import { fileIsExist } from '@/uitls/file.ts';
|
||||
import ignore from 'ignore';
|
||||
import FormData from 'form-data';
|
||||
import { chalk } from '@/module/chalk.ts';
|
||||
import * as backServices from '@/query/services/index.ts';
|
||||
import inquirer from 'inquirer';
|
||||
@@ -66,8 +65,61 @@ async function getFiles(cwd: string, patterns: string[]): Promise<string[]> {
|
||||
const filteredFiles = allFiles.filter((file) => !ig.ignores(file));
|
||||
return filteredFiles;
|
||||
}
|
||||
/**
|
||||
* 复制文件到 pack-dist
|
||||
* @param files 文件列表
|
||||
* @param cwd 当前工作目录
|
||||
* @param packDist 打包目录
|
||||
*/
|
||||
export const copyFilesToPackDist = async (files: string[], cwd: string, packDist = 'pack-dist') => {
|
||||
const packDistPath = path.join(cwd, packDist);
|
||||
if (!fileIsExist(packDistPath)) {
|
||||
fs.mkdirSync(packDistPath, { recursive: true });
|
||||
} else {
|
||||
fs.rmSync(packDistPath, { recursive: true, force: true });
|
||||
}
|
||||
files.forEach((file) => {
|
||||
const stat = fs.statSync(path.join(cwd, file));
|
||||
if (stat.isDirectory()) {
|
||||
fs.cpSync(path.join(cwd, file), path.join(packDistPath, file), { recursive: true });
|
||||
} else {
|
||||
fs.copyFileSync(path.join(cwd, file), path.join(packDistPath, file), fs.constants.COPYFILE_EXCL);
|
||||
}
|
||||
});
|
||||
const packageInfo = await getPackageInfo();
|
||||
// 根据所有文件,生成一个index.html
|
||||
const indexHtmlPath = path.join(packDistPath, 'index.html');
|
||||
const collectionFiles = (await Promise.all(files.map((file) => collectFileInfo(file)))).flat();
|
||||
const prettifySize = (size: number) => {
|
||||
if (size < 1024) {
|
||||
return `${size}B`;
|
||||
}
|
||||
if (size < 1024 * 1024) {
|
||||
return `${(size / 1024).toFixed(2)}kB`;
|
||||
}
|
||||
return `${(size / 1024 / 1024).toFixed(2)}MB`;
|
||||
};
|
||||
const filesString = collectionFiles.map((file) => `<li><a href="${file.path}">${file.path}</a><span>${prettifySize(file.size)}</span></li>`).join('\n');
|
||||
const indexHtmlContent = `
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
export const pack = async () => {
|
||||
<head>
|
||||
<title>${packageInfo.name}</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h1>${packageInfo.name}</h1>
|
||||
<ul>
|
||||
${filesString}
|
||||
</ul>
|
||||
<pre>${JSON.stringify(packageInfo, null, 2)}</pre>
|
||||
</body>
|
||||
|
||||
</html>`;
|
||||
fs.writeFileSync(indexHtmlPath, indexHtmlContent);
|
||||
};
|
||||
export const pack = async (opts: { isTar: boolean; packDist?: string }) => {
|
||||
const cwd = process.cwd();
|
||||
const collection: Record<string, any> = {};
|
||||
const packageJsonPath = path.join(cwd, 'package.json');
|
||||
@@ -89,6 +141,7 @@ export const pack = async () => {
|
||||
.replace('@', '') // 替换特殊字符 @
|
||||
.replace(/[\/\\:*?"<>|]/g, '-'); // 替换特殊字符
|
||||
|
||||
// 当 opts.isTar 为 true 时,输出文件为 tgz 文件
|
||||
const outputFilePath = path.join(cwd, outputFileName);
|
||||
|
||||
// 从 package.json 的 files 字段收集文件
|
||||
@@ -130,16 +183,20 @@ export const pack = async () => {
|
||||
console.log(`filename: ${outputFileName}`);
|
||||
console.log(`package size: ${packageSize}`);
|
||||
console.log(`total files: ${allFiles.length}`);
|
||||
console.log(`Created package: ${outputFileName}`);
|
||||
opts?.isTar && console.log(`Created package: ${outputFileName}`);
|
||||
try {
|
||||
await tar.c(
|
||||
{
|
||||
gzip: true,
|
||||
file: outputFilePath,
|
||||
cwd: cwd,
|
||||
},
|
||||
filesToInclude,
|
||||
);
|
||||
if (opts.isTar) {
|
||||
await tar.c(
|
||||
{
|
||||
gzip: true,
|
||||
file: outputFilePath,
|
||||
cwd: cwd,
|
||||
},
|
||||
filesToInclude,
|
||||
);
|
||||
} else {
|
||||
copyFilesToPackDist(filesToInclude, cwd, opts.packDist);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error creating tarball:', error);
|
||||
}
|
||||
@@ -150,7 +207,23 @@ export const pack = async () => {
|
||||
}
|
||||
return { collection, outputFilePath };
|
||||
};
|
||||
export const packByIgnore = async () => {
|
||||
export const getPackageInfo = async () => {
|
||||
const cwd = process.cwd();
|
||||
const packageJsonPath = path.join(cwd, 'package.json');
|
||||
try {
|
||||
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
|
||||
return packageJson;
|
||||
} catch (error) {
|
||||
console.error('Invalid package.json:', error);
|
||||
return {};
|
||||
}
|
||||
};
|
||||
|
||||
type PackByIgnoreOpts = {
|
||||
isTar: boolean;
|
||||
packDist?: string;
|
||||
};
|
||||
export const packByIgnore = async (opts: PackByIgnoreOpts) => {
|
||||
let collection: Record<string, any> = {};
|
||||
const cwd = process.cwd();
|
||||
const patterns = ['**/*']; // 匹配所有文件
|
||||
@@ -194,14 +267,18 @@ export const packByIgnore = async () => {
|
||||
console.log(`total files: ${allFiles.length}`);
|
||||
const filesToInclude = files.map((file) => path.relative(cwd, file));
|
||||
try {
|
||||
await tar.c(
|
||||
{
|
||||
gzip: true,
|
||||
file: outputFilePath,
|
||||
cwd: cwd,
|
||||
},
|
||||
filesToInclude,
|
||||
);
|
||||
if (opts.isTar) {
|
||||
await tar.c(
|
||||
{
|
||||
gzip: true,
|
||||
file: outputFilePath,
|
||||
cwd: cwd,
|
||||
},
|
||||
filesToInclude,
|
||||
);
|
||||
} else {
|
||||
copyFilesToPackDist(filesToInclude, cwd, opts.packDist);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error creating tarball:', error);
|
||||
}
|
||||
@@ -212,11 +289,16 @@ export const packByIgnore = async () => {
|
||||
}
|
||||
return { collection, outputFilePath };
|
||||
};
|
||||
export const packLib = async (ignore: boolean = false) => {
|
||||
/**
|
||||
* 打包应用
|
||||
* @param ignore 是否忽略 .npmignore 文件
|
||||
* @returns 打包结果
|
||||
*/
|
||||
export const packLib = async ({ ignore = false, tar = false, packDist = 'pack-dist' }: { ignore?: boolean; tar?: boolean; packDist?: string }) => {
|
||||
if (ignore) {
|
||||
return await packByIgnore();
|
||||
return await packByIgnore({ isTar: tar, packDist });
|
||||
}
|
||||
return await pack();
|
||||
return await pack({ isTar: tar, packDist });
|
||||
};
|
||||
export const unpackLib = async (filePath: string, cwd: string) => {
|
||||
try {
|
||||
@@ -237,60 +319,7 @@ const publishCommand = new Command('publish')
|
||||
const config = await getConfig();
|
||||
console.log('发布逻辑实现', { key, version, config });
|
||||
});
|
||||
const uploadFiles = async (filePath: string, collection: any): Promise<any> => {
|
||||
const config = await getConfig();
|
||||
const form = new FormData();
|
||||
const filename = path.basename(filePath);
|
||||
try {
|
||||
console.log('upload file', filePath);
|
||||
form.append('file', createReadStream(filePath));
|
||||
} catch (error) {
|
||||
console.error('Error reading file:', error);
|
||||
return;
|
||||
}
|
||||
form.append('collection', JSON.stringify(collection));
|
||||
console.log('upload file', filename);
|
||||
return await new Promise((resolve) => {
|
||||
const _baseURL = getBaseURL();
|
||||
const url = new URL(_baseURL);
|
||||
console.log('upload url', url.hostname, url.protocol, url.port);
|
||||
form.submit(
|
||||
{
|
||||
path: '/api/micro-app/upload',
|
||||
host: url.hostname,
|
||||
protocol: url.protocol as any,
|
||||
port: url.port,
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Authorization: 'Bearer ' + config.token,
|
||||
...form.getHeaders(),
|
||||
},
|
||||
},
|
||||
(err, res) => {
|
||||
if (err) {
|
||||
console.error('Error uploading file:', err.message);
|
||||
return;
|
||||
}
|
||||
console.log('upload success');
|
||||
// 处理服务器响应
|
||||
let body = '';
|
||||
res.on('data', (chunk) => {
|
||||
body += chunk;
|
||||
});
|
||||
|
||||
res.on('end', () => {
|
||||
try {
|
||||
const res = JSON.parse(body);
|
||||
console.log('upload success', res);
|
||||
resolve(res);
|
||||
} catch (e) {
|
||||
resolve({ code: 500, message: body });
|
||||
}
|
||||
});
|
||||
},
|
||||
);
|
||||
});
|
||||
};
|
||||
const deployLoadFn = async (id: string, fileKey: string, force = false, install = false) => {
|
||||
if (!id) {
|
||||
console.error(chalk.red('id is required'));
|
||||
@@ -329,31 +358,76 @@ const deployLoadFn = async (id: string, fileKey: string, force = false, install
|
||||
}
|
||||
return res;
|
||||
};
|
||||
|
||||
const packCommand = new Command('pack')
|
||||
.description('打包应用, 默认使用 package.json 中的 files 字段')
|
||||
.option('-i, --ignore', '使用 .npmignore 文件模式去忽略文件进行打包, 不需要package.json中的files字段')
|
||||
.option('-p, --publish', '打包并发布')
|
||||
.option('-u, --update', 'show command for deploy to server')
|
||||
.option('-u, --update', '发布后显示更新命令, show command for deploy to server')
|
||||
.option('-t, --tar', '打包为 tgz 文件')
|
||||
.option('-d, --packDist <dist>', '打包目录')
|
||||
.option('-y, --yes', '确定,直接打包', true)
|
||||
.action(async (opts) => {
|
||||
let value: { collection: Record<string, any>; outputFilePath: string } = await packLib(opts.ignore);
|
||||
if (opts.publish && value?.collection) {
|
||||
const { collection, outputFilePath } = value;
|
||||
try {
|
||||
const res = await uploadFiles(outputFilePath, collection);
|
||||
if (res.code === 200 && opts?.update) {
|
||||
const id = res.data.id;
|
||||
if (opts?.update) {
|
||||
console.log(chalk.blue('example: '), 'envision pack-deploy', id, '-k <key>');
|
||||
console.log('envision pack-deploy', id);
|
||||
}
|
||||
} else {
|
||||
console.error('Error uploading file:', res.message);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error uploading file:', error);
|
||||
}
|
||||
const packDist = opts.packDist || 'pack-dist';
|
||||
const packageInfo = await getPackageInfo();
|
||||
if (!packageInfo) {
|
||||
console.error('Invalid package.json:');
|
||||
return;
|
||||
}
|
||||
let basename = packageInfo.basename || '';
|
||||
let appKey: string | undefined;
|
||||
let version = packageInfo.version || '';
|
||||
if (!version) {
|
||||
const answers = await inquirer.prompt([
|
||||
{
|
||||
type: 'input',
|
||||
name: 'version',
|
||||
message: 'Enter your version:',
|
||||
},
|
||||
]);
|
||||
version = answers.version || version;
|
||||
}
|
||||
|
||||
if (basename) {
|
||||
if (basename.startsWith('/')) {
|
||||
basename = basename.slice(1);
|
||||
}
|
||||
const basenameArr = basename.split('/');
|
||||
appKey = basenameArr[1] || '';
|
||||
}
|
||||
if (!appKey) {
|
||||
const answers = await inquirer.prompt([
|
||||
{
|
||||
type: 'input',
|
||||
name: 'appKey',
|
||||
message: 'Enter your appKey:',
|
||||
},
|
||||
]);
|
||||
appKey = answers.appKey || appKey;
|
||||
}
|
||||
let value: { collection: Record<string, any>; outputFilePath: string } = await packLib({
|
||||
ignore: opts.ignore,
|
||||
tar: opts.tar,
|
||||
packDist,
|
||||
});
|
||||
if (opts.publish) {
|
||||
// 运行 deploy 命令
|
||||
const runDeployCommand = 'envision pack-deploy ' + value.outputFilePath + ' -k ' + appKey;
|
||||
const [_app, _command] = process.argv;
|
||||
console.log(chalk.blue('example: '), runDeployCommand);
|
||||
let deployDist = opts.isTar ? value.outputFilePath : packDist;
|
||||
const deployCommand = [_app, _command, 'deploy', deployDist, '-k', appKey, '-v', version, '-u'];
|
||||
if (opts.org) {
|
||||
deployCommand.push('-o', opts.org);
|
||||
}
|
||||
if (opts.update) {
|
||||
deployCommand.push('-s');
|
||||
}
|
||||
if (opts.yes) {
|
||||
deployCommand.push('-y', 'yes');
|
||||
}
|
||||
program.parse(deployCommand);
|
||||
}
|
||||
//
|
||||
});
|
||||
const packDeployCommand = new Command('pack-deploy')
|
||||
.argument('<id>', 'id')
|
||||
|
||||
@@ -16,3 +16,12 @@ const ls = new Command('ls').description('List files in the current directory').
|
||||
program.addCommand(ls);
|
||||
|
||||
export { program, Command };
|
||||
|
||||
/**
|
||||
* 在命令行中运行程序
|
||||
* @param args
|
||||
*/
|
||||
export const runProgram = (args: string[]) => {
|
||||
const [_app, _command] = process.argv;
|
||||
program.parse([_app, _command, ...args]);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user