Skip to content
This repository has been archived by the owner on Sep 8, 2024. It is now read-only.

Commit

Permalink
feat(cli): rewrite cli with esbuild
Browse files Browse the repository at this point in the history
  • Loading branch information
xiaodong2008 committed Apr 27, 2024
1 parent 7e6eca0 commit f514961
Show file tree
Hide file tree
Showing 14 changed files with 24,395 additions and 275 deletions.
23,804 changes: 23,804 additions & 0 deletions cli/bin/index.cjs

Large diffs are not rendered by default.

27 changes: 27 additions & 0 deletions cli/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#!/usr/bin/env node
import { Command } from 'commander'
import pkg from './package.json' assert { type: 'json' }

import build from './src/build'
import create from './src/create-app'

const program = new Command()

program
.name('Newcar Cli')
.version(pkg.version)
.description('The offical cli to build local app')

program
.command('export <input> <duration> <target>')
.option('-f, --fps <fps>', 'Frames per second', '60')
.action(build)

program
.command('create')
.argument('[name]', 'Name of the project')
.action(async (name, options) => {
await create(name, options)
})

program.parse(process.argv)
20 changes: 17 additions & 3 deletions cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,35 @@
"description": "The cli tool of local Newcar",
"main": "src/index.mjs",
"type": "module",
"scripts": {
"build": "FLUENTFFMPEG_COV=false esbuild index.ts --bundle --platform=node --outfile=bin/index.cjs",
"run": "node bin/index.cjs",
"dev": "npm run build && npm run run",
"test:create": "ncli create"
},
"keywords": [
"Animation",
"CLI"
],
"author": "BugDuck Team",
"license": "Apache-2.0",
"dependencies": {
"clerc": "^0.42.2",
"fluent-ffmpeg": "^2.1.2"
"@inquirer/prompts": "^5.0.2",
"commander": "^12.0.0",
"fluent-ffmpeg": "^2.1.2",
"inquirer": "^9.2.20",
"ora": "^8.0.1",
"picocolors": "^1.0.0"
},
"devDependencies": {
"@newcar/core": "workspace:*",
"@types/fluent-ffmpeg": "^2.1.24",
"@types/inquirer": "^9.0.7",
"canvaskit-wasm": "0.39.1",
"esbuild": "^0.20.2",
"newcar": "workspace:*"
},
"bin": {
"ncli": "src/index.mjs"
"ncli": "bin/index.cjs"
}
}
4 changes: 0 additions & 4 deletions cli/src/assets/newcar.svg

This file was deleted.

Binary file removed cli/src/assets/newcar.webp
Binary file not shown.
52 changes: 52 additions & 0 deletions cli/src/build/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import fs from 'node:fs'
import { resolve } from 'node:path'

// @ts-ignore
import ffmpeg from 'fluent-ffmpeg/lib/fluent-ffmpeg.js'

import type { HandlerContext } from 'clerc/index'
import type { LocalApp as App } from '@newcar/core'

export default async function build(context: HandlerContext<any>) {
const app = await resolveApp(context.parameters.input as string)

const [duration, output, fps] = [
Number(context.parameters.duration as string),
context.parameters.target as string,
Number(context.flags.fps as string),
]

const imagesArray = app.getFrames(duration)
const tempFiles = imagesArray.map((content: Uint8Array | null, index) => {
const fileName = `temp_image_${index}.png`
if (content) fs.writeFileSync(resolve(fileName), Buffer.from(content))
return fileName
})

exportFile(resolve(output), tempFiles, fps)
}

async function resolveApp(path: string): Promise<App> {
const app = (await import(resolve(path))) as {
default: App
}
return app.default
}

async function exportFile(path: string, files: string[], fps: number) {
ffmpeg()
.on('error', (err: Error) => {
console.error(`An error occurred: ${err.message}`)
})
.on('end', () => {
// eslint-disable-next-line no-console
console.log('Processing finished!')
// clear image files
files.forEach((file) => fs.unlinkSync(file))
})
.input(resolve('./temp_image_%d.png'))
.inputFPS(fps)
.output(resolve(path as string))
.outputFPS(30)
.run()
}
19 changes: 19 additions & 0 deletions cli/src/create-app/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import * as iq from '@inquirer/prompts'

export async function projectName(): Promise<string> {
return (await iq.input({
message: 'Enter the name of the app:',
default: 'newcar-app',
})) as any
}

export async function projectPath(): Promise<boolean> {
return iq.select({
message: 'Choose the init path for the app:',
choices: [
{ name: 'Create a new directory with the app name', value: true },
{ name: 'Current directory', value: false },
],
default: true,
}) as any
}
41 changes: 41 additions & 0 deletions cli/src/create-app/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import ora from 'ora'
import fs from 'node:fs'
import pc from 'picocolors'
import { resolve } from 'node:path'
import { projectName, projectPath } from './config'

import { checkPath, fetchTemplate, setupProject } from './project'

export default async function create(name: string, options: any[]) {
if (!name) name = await projectName()
let newDir = await projectPath()
const path = resolveProjectPath(newDir ? name : '.')

await checkPath(path)

const startTime = Date.now()

console.log()
const spinner = ora('Downloading template').start()
await fetchTemplate(path)

spinner.text = 'Setting up project'
await setupProject(path, name)

spinner.succeed('Project created')

const duration = Date.now() - startTime
console.log()
console.log(pc.green(`Project created in ${pc.cyan(duration + 'ms')}`))
console.log()
console.log(`Now run the following commands:`)
if (newDir) console.log(pc.bold(`cd ${name}`))
console.log(pc.bold(`npm install`))
console.log(pc.bold(`npm run dev`))
}

export function resolveProjectPath(path: string): string {
path = resolve(path)
if (!fs.existsSync(path)) fs.mkdirSync(path)
return path
}
31 changes: 31 additions & 0 deletions cli/src/create-app/project.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import * as iq from '@inquirer/prompts'
import { existsSync, rmSync } from 'node:fs'
import { execSync } from 'node:child_process'

export async function checkPath(path: string) {
if (existsSync(path)) {
const overwrite = await iq.select({
message: 'Directory already exists. Overwrite?',
choices: [
{ name: 'Yes', value: true },
{ name: 'No', value: false },
],
default: false,
})
if (overwrite) {
rmSync(path, { recursive: true })
} else {
process.exit(1)
}
}
}

export function fetchTemplate(path: string) {
execSync(
`git clone https://github.com/dromara/newcar-local-template.git ${path} --depth 1`,
{ stdio: 'ignore' },
)
rmSync(`${path}/.git`, { recursive: true })
}

export function setupProject(path: string, name: string) {}
Binary file removed cli/src/fonts/bahnschrift.ttf
Binary file not shown.
79 changes: 0 additions & 79 deletions cli/src/index.mjs

This file was deleted.

File renamed without changes.
22 changes: 22 additions & 0 deletions cli/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"compilerOptions": {
"target": "ESNext",
"outDir": "./dist",
"strict": true,
"esModuleInterop": true,
"moduleResolution": "node",
"skipLibCheck": true,
"baseUrl": "./",
"module": "ESNext",
"paths": {
"@newcar/core": ["../packages/core/src/index.ts"],
},
"resolveJsonModule": true
},
"include": [
"**/*.ts"
],
"exclude": [
"node_modules"
]
}
Loading

0 comments on commit f514961

Please sign in to comment.