🎨 CLI is more user-friendly.

This commit is contained in:
Tw93
2023-06-23 16:51:18 +08:00
parent 6a4bb69631
commit 0431bc7c12
10 changed files with 402 additions and 376 deletions

8
bin/README.md vendored
View File

@@ -107,14 +107,6 @@ Determine whether the application launches in full screen. Default is `false`. U
--fullscreen
```
#### [resize]
Determine whether the window is resizable. Default is `true`. Use the following command to disable window resizing.
```shell
--resizable
```
#### [multi-arch]
Package the application to support both Intel and M1 chips, exclusively for macOS. Default is `false`.

8
bin/README_CN.md vendored
View File

@@ -101,14 +101,6 @@ pake [url] [options]
--transparent
```
#### [resize]
设置应用窗口是否可以调整大小,默认为 `true`(可调整)。使用以下命令可以禁止调整窗口大小。
```shell
--resizable
```
#### [fullscreen]
设置应用程序是否在启动时自动全屏,默认为 `false`。使用以下命令可以设置应用程序启动时自动全屏。

View File

@@ -2,20 +2,25 @@ import path from 'path';
import fsExtra from "fs-extra";
import prompts from 'prompts';
import logger from '@/options/logger';
import { PakeAppOptions } from '@/types';
import { checkRustInstalled, installRust } from '@/helpers/rust';
import { mergeConfig } from "@/helpers/merge";
import tauriConfig from '@/helpers/tauriConfig';
import { npmDirectory } from '@/utils/dir';
import { getSpinner } from "@/utils/info";
import { shellExec } from '@/utils/shell';
import { isChinaDomain } from '@/utils/ip';
import { getSpinner } from "@/utils/info";
import { npmDirectory } from '@/utils/dir';
import { IS_MAC } from "@/utils/platform";
import { checkRustInstalled, installRust } from '@/helpers/rust';
import { PakeAppOptions } from '@/types';
import logger from '@/options/logger';
export default abstract class BaseBuilder {
abstract build(url: string, options: PakeAppOptions): Promise<void>;
protected options: PakeAppOptions;
protected constructor(options: PakeAppOptions) {
this.options = options;
}
async prepare() {
// Windows and Linux need to install necessary build tools.
if (!IS_MAC) {
logger.info('The first use requires installing system dependencies.');
logger.info('See more in https://tauri.app/v1/guides/getting-started/prerequisites#installing.');
@@ -52,9 +57,50 @@ export default abstract class BaseBuilder {
spinner.succeed('Package installed.');
}
protected async runBuildCommand(command: string = "npm run build") {
async buildAndCopy(url: string) {
const { name } = this.options;
await mergeConfig(url, this.options, tauriConfig);
await this.runBuildCommand();
const fileName = this.getFileName();
const appPath = this.getBuildAppPath(npmDirectory, fileName);
const distPath = path.resolve(`${name}.${this.getExtension()}`);
await fsExtra.copy(appPath, distPath);
await fsExtra.remove(appPath);
logger.success('✔ Build success!');
logger.success('✔ App installer located in', distPath);
}
abstract build(url: string): Promise<void>;
abstract getFileName(): string;
abstract getExtension(): string;
protected getArch() {
return process.arch === "x64" ? "amd64" : process.arch;
}
protected getBuildCommand(): string {
return "npm run build";
}
protected runBuildCommand() {
const spinner = getSpinner('Building app...');
setTimeout(() => spinner.stop(), 3000);
await shellExec(`cd "${npmDirectory}" && ${command}`);
return shellExec(`cd ${npmDirectory} && ${this.getBuildCommand()}`);
}
protected getBasePath(): string {
return 'src-tauri/target/release/bundle/';
}
protected getBuildAppPath(npmDirectory: string, fileName: string): string {
return path.join(
npmDirectory,
this.getBasePath(),
this.getExtension().toLowerCase(),
`${fileName}.${this.getExtension()}`
);
}
}

View File

@@ -2,21 +2,22 @@ import BaseBuilder from './BaseBuilder';
import MacBuilder from './MacBuilder';
import WinBuilder from './WinBuilder';
import LinuxBuilder from './LinuxBuilder';
import { PakeAppOptions } from '@/types';
const { platform } = process;
const buildersMap: Record<string, new () => BaseBuilder> = {
const buildersMap: Record<string, new (options: PakeAppOptions) => BaseBuilder> = {
darwin: MacBuilder,
win32: WinBuilder,
linux: LinuxBuilder,
};
export default class BuilderProvider {
static create(): BaseBuilder {
static create(options: PakeAppOptions): BaseBuilder {
const Builder = buildersMap[platform];
if (!Builder) {
throw new Error('The current system is not supported!');
}
return new Builder();
return new Builder(options);
}
}

View File

@@ -1,48 +1,31 @@
import path from 'path';
import fsExtra from "fs-extra";
import BaseBuilder from './BaseBuilder';
import logger from '@/options/logger';
import tauriConfig from '@/helpers/tauriConfig';
import { npmDirectory } from '@/utils/dir';
import { mergeConfig } from "@/helpers/merge";
import { PakeAppOptions } from '@/types';
import tauriConfig from '@/helpers/tauriConfig';
export default class LinuxBuilder extends BaseBuilder {
async build(url: string, options: PakeAppOptions) {
const { name } = options;
await mergeConfig(url, options, tauriConfig);
await this.runBuildCommand();
constructor(options: PakeAppOptions) {
super(options);
}
const arch = process.arch === "x64" ? "amd64" : process.arch;
if (options.targets === "deb" || options.targets === "all") {
const debName = `${name}_${tauriConfig.package.version}_${arch}.deb`;
const appPath = this.getBuildAppPath(npmDirectory, "deb", debName);
const distPath = path.resolve(`${name}.deb`);
await fsExtra.copy(appPath, distPath);
await fsExtra.remove(appPath);
logger.success('✔ Build Deb success!');
logger.success('✔ Deb app installer located in', distPath);
}
if (options.targets === "appimage" || options.targets === "all") {
const appImageName = `${name}_${tauriConfig.package.version}_${arch}.AppImage`;
const appImagePath = this.getBuildAppPath(npmDirectory, "appimage", appImageName);
const distAppPath = path.resolve(`${name}.AppImage`);
await fsExtra.copy(appImagePath, distAppPath);
await fsExtra.remove(appImagePath);
logger.success('✔ Build AppImage success!');
logger.success('✔ AppImage installer located in', distAppPath);
async build(url: string) {
const targetTypes = ['deb', 'appimage'];
for (const type of targetTypes) {
if (this.options.targets === type || this.options.targets === "all") {
await this.buildAndCopy(url);
}
}
}
getBuildAppPath(npmDirectory: string, packageType: string, packageName: string) {
return path.join(
npmDirectory,
'src-tauri/target/release/bundle/',
packageType,
packageName
);
getFileName(): string {
const { name } = this.options;
const arch = this.getArch();
return `${name}_${tauriConfig.package.version}_${arch}`;
}
getExtension(): string {
if (this.options.targets === 'appimage') {
return 'AppImage';
}
return this.options.targets;
}
}

View File

@@ -1,36 +1,38 @@
import path from 'path';
import fsExtra from "fs-extra";
import BaseBuilder from './BaseBuilder';
import logger from '@/options/logger';
import tauriConfig from '@/helpers/tauriConfig';
import { npmDirectory } from '@/utils/dir';
import { mergeConfig } from "@/helpers/merge";
import { PakeAppOptions } from '@/types';
import BaseBuilder from './BaseBuilder';
export default class MacBuilder extends BaseBuilder {
async build(url: string, options: PakeAppOptions) {
const { name } = options;
await mergeConfig(url, options, tauriConfig);
let dmgName: string;
if (options.multiArch) {
await this.runBuildCommand('npm run build:mac');
dmgName = `${name}_${tauriConfig.package.version}_universal.dmg`;
} else {
await this.runBuildCommand();
let arch = process.arch === "arm64" ? "aarch64" : process.arch;
dmgName = `${name}_${tauriConfig.package.version}_${arch}.dmg`;
}
const appPath = this.getBuildAppPath(npmDirectory, dmgName, options.multiArch);
const distPath = path.resolve(`${name}.dmg`);
await fsExtra.copy(appPath, distPath);
await fsExtra.remove(appPath);
logger.success('✔ Build success!');
logger.success('✔ App installer located in', distPath);
constructor(options: PakeAppOptions) {
super(options);
}
getBuildAppPath(npmDirectory: string, dmgName: string, multiArch: boolean) {
const dmgPath = multiArch ? 'src-tauri/target/universal-apple-darwin/release/bundle/dmg' : 'src-tauri/target/release/bundle/dmg';
return path.join(npmDirectory, dmgPath, dmgName);
async build(url: string) {
await this.buildAndCopy(url);
}
getFileName(): string {
const { name } = this.options;
let arch: string;
if (this.options.multiArch) {
arch = 'universal';
} else {
arch = process.arch === "arm64" ? "aarch64" : process.arch;
}
return `${name}_${tauriConfig.package.version}_${arch}`;
}
getExtension(): string {
return "dmg";
}
protected getBuildCommand(): string {
return this.options.multiArch ? 'npm run build:mac' : super.getBuildCommand();
}
protected getBasePath(): string {
return this.options.multiArch
? 'src-tauri/target/universal-apple-darwin/release/bundle'
: super.getBasePath();
}
}

View File

@@ -1,35 +1,24 @@
import path from 'path';
import fsExtra from 'fs-extra';
import BaseBuilder from './BaseBuilder';
import logger from '@/options/logger';
import tauriConfig from '@/helpers/tauriConfig';
import { npmDirectory } from '@/utils/dir';
import { mergeConfig } from '@/helpers/merge';
import { PakeAppOptions } from '@/types';
import tauriConfig from '@/helpers/tauriConfig';
export default class WinBuilder extends BaseBuilder {
async build(url: string, options: PakeAppOptions) {
const { name } = options;
await mergeConfig(url, options, tauriConfig);
await this.runBuildCommand();
const language = tauriConfig.tauri.bundle.windows.wix.language[0];
const arch = process.arch;
const msiName = `${name}_${tauriConfig.package.version}_${arch}_${language}.msi`;
const appPath = this.getBuildAppPath(npmDirectory, msiName);
const distPath = path.resolve(`${name}.msi`);
await fsExtra.copy(appPath, distPath);
await fsExtra.remove(appPath);
logger.success('✔ Build success!');
logger.success('✔ App installer located in', distPath);
constructor(options: PakeAppOptions) {
super(options);
}
getBuildAppPath(npmDirectory: string, msiName: string) {
return path.join(
npmDirectory,
'src-tauri/target/release/bundle/msi',
msiName
);
async build(url: string) {
await this.buildAndCopy(url);
}
getFileName(): string {
const { name } = this.options;
const arch = this.getArch();
const language = tauriConfig.tauri.bundle.windows.wix.language[0];
return `${name}_${tauriConfig.package.version}_${arch}_${language}`;
}
getExtension(): string {
return "msi";
}
}

5
bin/cli.ts vendored
View File

@@ -21,7 +21,6 @@ program
.option('--icon <string>', 'Application icon', DEFAULT.icon)
.option('--height <number>', 'Window height', validateNumberInput, DEFAULT.height)
.option('--width <number>', 'Window width', validateNumberInput, DEFAULT.width)
.option('--resizable', 'Whether the window can be resizable', DEFAULT.resizable)
.option('--fullscreen', 'Start the packaged app in full screen', DEFAULT.fullscreen)
.option('--transparent', 'Transparent title bar', DEFAULT.transparent)
.option('--user-agent <string>', 'Custom user agent', DEFAULT.userAgent)
@@ -55,9 +54,9 @@ program
const appOptions = await handleInputOptions(options, url);
log.debug('PakeAppOptions', appOptions);
const builder = BuilderProvider.create();
const builder = BuilderProvider.create(appOptions);
await builder.prepare();
await builder.build(url, appOptions);
await builder.build(url);
});
program.parse();

2
bin/utils/info.ts vendored
View File

@@ -27,7 +27,7 @@ export function capitalizeFirstLetter(string: string) {
export function getSpinner(text: string) {
const loadingType = {
"interval": 100,
"interval": 80,
"frames": [
"✶",
"✵",