From 2552f333d9a41910719271290d3042b13618c0a1 Mon Sep 17 00:00:00 2001 From: volare <867484528@qq.com> Date: Sun, 4 Dec 2022 15:51:36 +0800 Subject: [PATCH 1/3] =?UTF-8?q?chore:=20=E5=8E=8B=E7=BC=A9=E5=90=8E?= =?UTF-8?q?=E6=89=A7=E8=A1=8C=E6=8A=A5=E9=94=99=E6=8F=90=E7=A4=BA=E4=B8=8D?= =?UTF-8?q?=E5=8F=8B=E5=A5=BD=EF=BC=8C=E5=85=88=E5=8E=BB=E6=8E=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- rollup.config.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/rollup.config.js b/rollup.config.js index 13987e4..6fdfbba 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -4,9 +4,6 @@ import typescript from '@rollup/plugin-typescript'; import alias from '@rollup/plugin-alias'; import commonjs from '@rollup/plugin-commonjs'; import json from '@rollup/plugin-json'; -import terser from '@rollup/plugin-terser'; - -const isDev = process.env.NODE_ENV !== "production"; export default { input: 'bin/cli.ts', @@ -23,6 +20,5 @@ export default { alias({ entries: [{ find: '@', replacement: path.join(appRootPath.path, 'bin') }], }), - !isDev && terser(), ], }; From 93a79f482f96f69f4f9bca492548654bb6d0894a Mon Sep 17 00:00:00 2001 From: volare <867484528@qq.com> Date: Sun, 4 Dec 2022 15:52:49 +0800 Subject: [PATCH 2/3] =?UTF-8?q?feat:=20=E7=9B=B4=E6=8E=A5pake=E6=97=B6?= =?UTF-8?q?=E5=8F=AA=E5=87=BA=E7=8E=B0help=20&=20=E5=8C=85=E6=9B=B4?= =?UTF-8?q?=E6=96=B0=E6=A3=80=E6=B5=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .editorconfig | 3 +++ bin/cli.ts | 20 +++++++++++++++----- bin/helpers/updater.ts | 7 +++++++ 3 files changed, 25 insertions(+), 5 deletions(-) create mode 100644 bin/helpers/updater.ts diff --git a/.editorconfig b/.editorconfig index 8759d9b..5561adb 100644 --- a/.editorconfig +++ b/.editorconfig @@ -22,3 +22,6 @@ indent_size = 2 [*.md] trim_trailing_whitespace = false + +[*.ts] +quote_type= "single" diff --git a/bin/cli.ts b/bin/cli.ts index fddffdb..0cf97a6 100644 --- a/bin/cli.ts +++ b/bin/cli.ts @@ -1,16 +1,19 @@ -import { program } from 'commander'; +import { program, createArgument } from 'commander'; +import log from 'loglevel'; import { DEFAULT_PAKE_OPTIONS } from './defaults.js'; import { PakeCliOptions } from './types.js'; import { validateNumberInput, validateUrlInput } from './utils/validate.js'; import handleInputOptions from './options/index.js'; import BuilderFactory from './builders/BuilderFactory.js'; -import log from 'loglevel'; +import { checkUpdateTips } from './helpers/updater.js'; +// @ts-expect-error +import packageJson from '../../package.json'; -program.version('0.0.1').description('A cli application can package a web page to desktop application'); +program.version(packageJson.version).description('A cli application can package a web page to desktop application'); program .showHelpAfterError() - .argument('', 'the web url you want to package', validateUrlInput) + .argument('[url]', 'the web url you want to package', validateUrlInput) .option('--name ', 'application name') .option('--icon ', 'application icon', DEFAULT_PAKE_OPTIONS.icon) .option('--height ', 'window height', validateNumberInput, DEFAULT_PAKE_OPTIONS.height) @@ -20,7 +23,14 @@ program .option('--transparent', 'transparent title bar', DEFAULT_PAKE_OPTIONS.transparent) .option('--debug', 'debug', DEFAULT_PAKE_OPTIONS.transparent) .action(async (url: string, options: PakeCliOptions) => { - log.setDefaultLevel('info') + checkUpdateTips(); + + if (!url) { + // 直接 pake 不需要出现url提示 + program.help(); + } + + log.setDefaultLevel('info'); if (options.debug) { log.setLevel('debug'); } diff --git a/bin/helpers/updater.ts b/bin/helpers/updater.ts new file mode 100644 index 0000000..a0948b7 --- /dev/null +++ b/bin/helpers/updater.ts @@ -0,0 +1,7 @@ +import updateNotifier from 'update-notifier'; +// @ts-expect-error +import packageJson from '../../package.json'; + +export async function checkUpdateTips() { + updateNotifier({ pkg: packageJson }).notify(); +} From 84d749a54dc0ddb050626534edbbf6547740b0c0 Mon Sep 17 00:00:00 2001 From: volare <867484528@qq.com> Date: Sun, 4 Dec 2022 17:53:43 +0800 Subject: [PATCH 3/3] =?UTF-8?q?feat:=20=E5=AE=8C=E5=96=84=E4=B8=80?= =?UTF-8?q?=E6=B3=A2=E4=BB=A3=E7=A0=81=20&=20=E6=94=AF=E6=8C=81win?= =?UTF-8?q?=EF=BC=88=E5=BE=85=E6=B5=8B=E8=AF=95=E9=AA=8C=E8=AF=81=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bin/builders/BuilderFactory.ts | 1 + bin/builders/MacBuilder.ts | 38 +++++++++------------ bin/builders/WinBulider.ts | 60 ++++++++++++++++++++++++++++++++++ bin/builders/common.ts | 40 +++++++++++++++++++++++ bin/cli.ts | 6 ++-- bin/helpers/rust.ts | 8 +++-- bin/options/icon.ts | 4 +-- bin/options/logger.ts | 22 +++++++++++++ bin/utils/dir.ts | 8 +++++ package.json | 7 ++-- 10 files changed, 164 insertions(+), 30 deletions(-) create mode 100644 bin/options/logger.ts create mode 100644 bin/utils/dir.ts diff --git a/bin/builders/BuilderFactory.ts b/bin/builders/BuilderFactory.ts index 18ec650..908c78b 100644 --- a/bin/builders/BuilderFactory.ts +++ b/bin/builders/BuilderFactory.ts @@ -1,6 +1,7 @@ import { IS_MAC } from '@/utils/platform.js'; import { IBuilder } from './base.js'; import MacBuilder from './MacBuilder.js'; +import WinBuilder from './WinBulider.js'; export default class BuilderFactory { static create(): IBuilder { diff --git a/bin/builders/MacBuilder.ts b/bin/builders/MacBuilder.ts index b557cd9..4677eeb 100644 --- a/bin/builders/MacBuilder.ts +++ b/bin/builders/MacBuilder.ts @@ -7,8 +7,10 @@ import { IBuilder } from './base.js'; import { shellExec } from '@/utils/shell.js'; // @ts-expect-error 加上resolveJsonModule rollup会打包报错 import tauriConf from '../../src-tauri/tauri.conf.json'; -import { fileURLToPath } from 'url'; import log from 'loglevel'; +import { mergeTauriConfig } from './common.js'; +import { npmDirectory } from '@/utils/dir.js'; +import logger from '@/options/logger.js'; export default class MacBuilder implements IBuilder { async prepare() { @@ -33,34 +35,26 @@ export default class MacBuilder implements IBuilder { async build(url: string, options: PakeAppOptions) { log.debug('PakeAppOptions', options); + const { name } = options; - const { width, height, fullscreen, transparent, resizable, identifier, name } = options; - - const tauriConfWindowOptions = { - width, - height, - fullscreen, - transparent, - resizable, - }; - - // TODO 下面这块逻辑还可以再拆 目前比较简单 - Object.assign(tauriConf.tauri.windows[0], { url, ...tauriConfWindowOptions }); - tauriConf.package.productName = name; - tauriConf.tauri.bundle.identifier = identifier; - tauriConf.tauri.bundle.icon = [options.icon]; - - const npmDirectory = path.join(path.dirname(fileURLToPath(import.meta.url)), '..'); - const configJsonPath = path.join(npmDirectory, 'src-tauri/tauri.conf.json'); - await fs.writeFile(configJsonPath, Buffer.from(JSON.stringify(tauriConf), 'utf-8')); + await mergeTauriConfig(url, options, tauriConf); const code = await shellExec(`cd ${npmDirectory} && npm run build`); const dmgName = `${name}_${tauriConf.package.version}_universal.dmg`; const appPath = this.getBuildedAppPath(npmDirectory, dmgName); - await fs.copyFile(appPath, path.resolve(`${name}_universal.dmg`)); + const distPath = path.resolve(`${name}_universal.dmg`); + await fs.copyFile(appPath, distPath); + await fs.unlink(appPath); + + logger.success('Build success!'); + logger.success('You can find the app installer in', distPath); } getBuildedAppPath(npmDirectory: string, dmgName: string) { - return path.join(npmDirectory, 'src-tauri/target/universal-apple-darwin/release/bundle/dmg', dmgName); + return path.join( + npmDirectory, + 'src-tauri/target/universal-apple-darwin/release/bundle/dmg', + dmgName + ); } } diff --git a/bin/builders/WinBulider.ts b/bin/builders/WinBulider.ts index e69de29..d67ee29 100644 --- a/bin/builders/WinBulider.ts +++ b/bin/builders/WinBulider.ts @@ -0,0 +1,60 @@ +import fs from 'fs/promises'; +import path from 'path'; +import prompts from 'prompts'; +import { checkRustInstalled, installRust } from '@/helpers/rust.js'; +import { PakeAppOptions } from '@/types.js'; +import { IBuilder } from './base.js'; +import { shellExec } from '@/utils/shell.js'; +// @ts-expect-error 加上resolveJsonModule rollup会打包报错 +import tauriConf from '../../src-tauri/tauri.conf.json'; +import { fileURLToPath } from 'url'; +import logger from '@/options/logger.js'; +import { mergeTauriConfig } from './common.js'; +import { npmDirectory } from '@/utils/dir.js'; + +export default class WinBuilder implements IBuilder { + async prepare() { + logger.info( + 'To build the Windows app, you need to install Rust and VS Build Tools.' + ); + logger.info( + 'See more in https://tauri.app/v1/guides/getting-started/prerequisites#installing\n' + ); + if (checkRustInstalled()) { + return; + } + + const res = await prompts({ + type: 'confirm', + message: 'We detected that you have not installed Rust. Install it now?', + name: 'value', + }); + + if (res.value) { + // TODO 国内有可能会超时 + await installRust(); + } else { + logger.error('Error: Pake needs Rust to package your webapp!!!'); + process.exit(2); + } + } + + async build(url: string, options: PakeAppOptions) { + logger.debug('PakeAppOptions', options); + + await mergeTauriConfig(url, options, tauriConf); + + const code = await shellExec(`cd ${npmDirectory} && npm run build:windows`); + // const dmgName = `${name}_${tauriConf.package.version}_universal.dmg`; + // const appPath = this.getBuildedAppPath(npmDirectory, dmgName); + // await fs.copyFile(appPath, path.resolve(`${name}_universal.dmg`)); + } + + getBuildedAppPath(npmDirectory: string, dmgName: string) { + return path.join( + npmDirectory, + 'src-tauri/target/universal-apple-darwin/release/bundle/dmg', + dmgName + ); + } +} diff --git a/bin/builders/common.ts b/bin/builders/common.ts index 6f881d6..7fced8b 100644 --- a/bin/builders/common.ts +++ b/bin/builders/common.ts @@ -1,4 +1,8 @@ +import { PakeAppOptions } from '@/types.js'; import prompts from 'prompts'; +import path from 'path'; +import fs from 'fs/promises'; +import { npmDirectory } from '@/utils/dir.js'; export async function promptText(message: string, initial?: string) { const response = await prompts({ @@ -9,3 +13,39 @@ export async function promptText(message: string, initial?: string) { }); return response.content; } + +export async function mergeTauriConfig( + url: string, + options: PakeAppOptions, + tauriConf: any +) { + const { + width, + height, + fullscreen, + transparent, + resizable, + identifier, + name, + } = options; + + const tauriConfWindowOptions = { + width, + height, + fullscreen, + transparent, + resizable, + }; + + Object.assign(tauriConf.tauri.windows[0], { url, ...tauriConfWindowOptions }); + tauriConf.package.productName = name; + tauriConf.tauri.bundle.identifier = identifier; + tauriConf.tauri.bundle.icon = [options.icon]; + + + const configJsonPath = path.join(npmDirectory, 'src-tauri/tauri.conf.json'); + await fs.writeFile( + configJsonPath, + Buffer.from(JSON.stringify(tauriConf), 'utf-8') + ); +} diff --git a/bin/cli.ts b/bin/cli.ts index 0cf97a6..3e6490a 100644 --- a/bin/cli.ts +++ b/bin/cli.ts @@ -1,5 +1,6 @@ -import { program, createArgument } from 'commander'; +import { program } from 'commander'; import log from 'loglevel'; +import chalk from 'chalk'; import { DEFAULT_PAKE_OPTIONS } from './defaults.js'; import { PakeCliOptions } from './types.js'; import { validateNumberInput, validateUrlInput } from './utils/validate.js'; @@ -8,8 +9,9 @@ import BuilderFactory from './builders/BuilderFactory.js'; import { checkUpdateTips } from './helpers/updater.js'; // @ts-expect-error import packageJson from '../../package.json'; +import logger from './options/logger.js'; -program.version(packageJson.version).description('A cli application can package a web page to desktop application'); +program.version(packageJson.version).description('A cli application can package a web page to desktop application.'); program .showHelpAfterError() diff --git a/bin/helpers/rust.ts b/bin/helpers/rust.ts index af9811c..a626818 100644 --- a/bin/helpers/rust.ts +++ b/bin/helpers/rust.ts @@ -1,12 +1,16 @@ +import { IS_WIN } from '@/utils/platform.js'; import ora from 'ora'; import shelljs from 'shelljs'; import { shellExec } from '../utils/shell.js'; -const InstallRustScript = "curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y"; +const RustInstallScriptFocMac = + "curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y"; +const RustInstallScriptForWin = 'winget install --id Rustlang.Rustup'; + export async function installRust() { const spinner = ora('Downloading Rust').start(); try { - await shellExec(InstallRustScript); + await shellExec(IS_WIN ? RustInstallScriptForWin : RustInstallScriptFocMac); spinner.succeed(); } catch (error) { console.error('install rust return code', error.message); diff --git a/bin/options/icon.ts b/bin/options/icon.ts index 7e1c5d8..8b803b9 100644 --- a/bin/options/icon.ts +++ b/bin/options/icon.ts @@ -5,7 +5,7 @@ import { dir } from 'tmp-promise'; import path from 'path'; import fs from 'fs/promises'; import { fileURLToPath } from 'url'; -import log from 'loglevel'; +import logger from './logger.js'; export async function handleIcon(options: PakeAppOptions, url: string) { if (options.icon) { @@ -21,7 +21,7 @@ export async function handleIcon(options: PakeAppOptions, url: string) { } export async function inferIcon(name: string, url: string) { - log.info('You have not provided an app icon, use the default icon(can use --icon option to assign an icon)') + logger.info('You have not provided an app icon, use the default icon.(use --icon option to assign an icon)') const npmDirectory = path.join(path.dirname(fileURLToPath(import.meta.url)), '..'); return path.join(npmDirectory, 'pake-default.icns'); } diff --git a/bin/options/logger.ts b/bin/options/logger.ts new file mode 100644 index 0000000..da6cafa --- /dev/null +++ b/bin/options/logger.ts @@ -0,0 +1,22 @@ +import log from 'loglevel'; +import chalk from 'chalk'; + +const logger = { + info(...msg: any[]) { + log.info(...msg.map((m) => chalk.blue.bold(m))); + }, + debug(...msg: any[]) { + log.debug(...msg); + }, + error(...msg: any[]) { + log.error(...msg.map((m) => chalk.red.bold(m))); + }, + warn(...msg: any[]) { + log.info(...msg.map((m) => chalk.yellow.bold(m))); + }, + success(...msg: any[]) { + log.info(...msg.map((m) => chalk.green.bold(m))); + } +}; + +export default logger; diff --git a/bin/utils/dir.ts b/bin/utils/dir.ts new file mode 100644 index 0000000..76da5af --- /dev/null +++ b/bin/utils/dir.ts @@ -0,0 +1,8 @@ +import path from 'path'; +import { fileURLToPath } from 'url'; + + +export const npmDirectory = path.join( + path.dirname(fileURLToPath(import.meta.url)), + '..' +); diff --git a/package.json b/package.json index 935e6b2..2e1d2b0 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,7 @@ "build": "npm run tauri build -- --target universal-apple-darwin", "build:windows": "npm run tauri build -- --target x86_64-pc-windows-msvc", "build:linux": "npm run tauri build --release", - "build:all-unix":"chmod +x ./script/build.sh && ./script/build.sh", + "build:all-unix": "chmod +x ./script/build.sh && ./script/build.sh", "build:all-windows": ".\\script\\build.bat", "tauri": "tauri", "cli": "rollup -c rollup.config.js --watch", @@ -40,6 +40,7 @@ "@tauri-apps/api": "^1.2.0", "@tauri-apps/cli": "^1.2.1", "axios": "^1.1.3", + "chalk": "^5.1.2", "commander": "^9.4.1", "file-type": "^18.0.0", "is-url": "^1.2.4", @@ -47,7 +48,8 @@ "ora": "^6.1.2", "prompts": "^2.4.2", "shelljs": "^0.8.5", - "tmp-promise": "^3.0.3" + "tmp-promise": "^3.0.3", + "update-notifier": "^6.0.2" }, "devDependencies": { "@rollup/plugin-alias": "^4.0.2", @@ -60,6 +62,7 @@ "@types/prompts": "^2.4.1", "@types/shelljs": "^0.8.11", "@types/tmp": "^0.2.3", + "@types/update-notifier": "^6.0.1", "app-root-path": "^3.1.0", "concurrently": "^7.5.0", "cross-env": "^7.0.3",