UNPKG

@rechunk/cli

Version:

Command-line interface for managing ReChunk projects, chunks, and deployments

178 lines (159 loc) • 5.13 kB
import withRechunk from '@rechunk/rollup-preset'; import chalk from 'chalk'; import {program} from 'commander'; import inquirer from 'inquirer'; import path from 'path'; import {rollup} from 'rollup'; import { aggregateUseRechunkFiles, configureReChunkChunksApi, getRechunkConfig, LOGO, } from '../lib'; /** * Registers the `publish` command to the CLI. * * This command aggregates all `.tsx` files containing the `"use rechunk"` directive, * prompts the user to select which components to publish, bundles the selected components * using Rollup, and publishes them to the ReChunk server. * * @example * ```bash * pnpm rechunk publish * ``` */ program .command('publish') .description('Aggregates and publishes selected ReChunk components') .action(async () => { console.log(); console.log(LOGO); const ora = await import('ora'); const spinner = ora.default('Aggregating ReChunk files...').start(); try { const files = await aggregateUseRechunkFiles(process.cwd()); if (files.length === 0) { spinner.fail('No files containing "use rechunk" directive found.'); return; } spinner.succeed(`Found ${files.length} files.`); const {selectedFiles} = await inquirer.prompt([ { type: 'checkbox', theme: { style: { renderSelectedChoices: ( selectedChoices: ReadonlyArray<{ value: any; name: string; description?: string; short: string; disabled: boolean | string; checked: boolean; }>, ) => selectedChoices .map((choice, index) => index !== 0 ? ` ${choice.short}` : ` ${choice.short}`, ) .join('\n'), }, }, name: 'selectedFiles', message: `${chalk.bold('Select the components to publish:\n')}`, choices: files.map(file => ({ name: ` ${chalk.cyan(file)}`, value: file, })), validate: choices => choices.length > 0 ? true : 'You must select at least one component.', }, ]); if (selectedFiles.length === 0) { console.log( chalk.yellow('No components selected for publishing. Exiting.'), ); return; } const confirm = await inquirer.prompt([ { type: 'confirm', name: 'proceed', message: `You selected ${selectedFiles.length} components. Do you want to proceed with publishing?`, default: true, }, ]); if (!confirm.proceed) { console.log(chalk.yellow('Publishing cancelled.')); return; } const rc = getRechunkConfig(); for (const file of selectedFiles) { const componentName = path.basename(file, path.extname(file)); const base64String = Buffer.from(file, 'utf8').toString('base64'); spinner.start( `Bundling and publishing ${componentName} as ${base64String}...`, ); try { const input = path.resolve(process.cwd(), file); const rollupBuild = await rollup(await withRechunk({input})); const { output: [{code}], } = await rollupBuild.generate({interop: 'auto', format: 'cjs'}); await publishChunk( rc.host, base64String, code, rc.project, rc.writeKey, ); spinner.succeed( `Successfully published ${componentName} as ${base64String}`, ); } catch (err) { spinner.fail( `Failed to publish ${componentName}: ${(err as Error).message}`, ); continue; // Continue to the next file instead of exiting } } console.log( chalk.green('\nšŸŽ‰ All selected components have been processed!'), ); } catch (error) { spinner.fail(`Error: ${(error as Error).message}`); } }); /** * Publishes the bundled code for a specified chunk to the ReChunk server. * * @param host - The URL of the ReChunk server. * @param chunk - The name of the chunk to publish. * @param code - The bundled code to publish. * @param project - The project ID used for authentication. * @param writeKey - The write key used for authentication. * @returns A promise that resolves upon successful publication of the chunk. * @throws {Error} If the server responds with an error or a non-OK status. */ async function publishChunk( host: string, chunk: string, code: string, project: string, writeKey: string, ): Promise<void> { const api = configureReChunkChunksApi(host, project, writeKey); try { await api.createChunkForProject({ projectId: project, chunkId: chunk, chunkCreate: { data: code, }, }); } catch (error) { throw new Error(`Failed to publish chunk: ${(error as Error).message}`); } }