diff --git a/cli/package.json b/cli/package.json index ca66bcd1b..8234453d6 100644 --- a/cli/package.json +++ b/cli/package.json @@ -1,7 +1,7 @@ { "name": "@embrace-io/web-cli", "bin": { - "embrace-web-cli": "dist/index.js" + "embrace-web-cli": "dist/index.mjs" }, "version": "2.9.0", "description": "Embrace Web CLI for uploading sourcemaps and versioning bundles", @@ -11,14 +11,12 @@ }, "scripts": { "clean": "npx rimraf dist", - "compile": "tsc && esbuild src/index.ts --bundle --format=esm --platform=node --target=es2022 --outfile=dist/index.js --external:commander", + "compile": "npm run clean && tsc && tsdown", "test": "tsx --test src/**/*.test.ts", - "validate": "bash scripts/validate-cli.sh" + "validate": "tsx scripts/validate-cli.ts" }, "files": [ - "dist", - "LICENSE", - "README.md" + "dist" ], "bugs": { "url": "https://github.com/embrace-io/embrace-web-sdk/issues", diff --git a/cli/scripts/validate-cli.sh b/cli/scripts/validate-cli.sh deleted file mode 100755 index 818d6e12e..000000000 --- a/cli/scripts/validate-cli.sh +++ /dev/null @@ -1,53 +0,0 @@ -#!/bin/bash -set -e - -CLI_FILE="dist/index.js" - -SIZE=$(wc -c < "$CLI_FILE" | tr -d ' ') -SIZE_KB=$((SIZE / 1024)) -echo " CLI size: ${SIZE_KB}KB (${SIZE} bytes)" - -echo "šŸ” Validating CLI build output..." - -# Run quick checks first (es-check and publint) -echo "Running es-check and publint..." -npx es-check es2022 "$CLI_FILE" --module --allow-hash-bang -npx publint -echo " āœ… ES compatibility and package checks passed" - -# 2. Verify CLI is executable -echo "Checking CLI is executable..." -if ! head -1 "$CLI_FILE" | grep -q "^#!/usr/bin/env node"; then - echo " āŒ Missing shebang in CLI" - exit 1 -else - echo " āœ… CLI has proper shebang" -fi - -# 3. Test CLI can be executed -echo "Testing CLI execution..." -TEMP_DIR=$(mktemp -d) -trap "rm -rf $TEMP_DIR" EXIT - -# Save current directory -ORIG_DIR=$(pwd) - -cd $TEMP_DIR -npm init -y --quiet > /dev/null 2>&1 - -# Link the CLI locally -npm install $ORIG_DIR --quiet 2>&1 - -# 4. Check that CLI has required commands -echo "Checking CLI commands..." -HELP_OUTPUT=$(npx embrace-web-cli --help 2>&1) - -# Check for expected commands (adjust based on your CLI) -if echo "$HELP_OUTPUT" | grep -q "Commands:"; then - echo " āœ… CLI has command structure" -else - echo " X No commands found in CLI help" - exit 1 -fi - -echo "āœ… All CLI validations passed!" diff --git a/cli/scripts/validate-cli.ts b/cli/scripts/validate-cli.ts new file mode 100644 index 000000000..16fa456c3 --- /dev/null +++ b/cli/scripts/validate-cli.ts @@ -0,0 +1,43 @@ +import { execSync } from 'node:child_process'; +import { mkdtempSync, rmSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import { join } from 'node:path'; +import { COLORS, log, logSection } from '../../scripts/build-config.js'; + +const CLI_FILE = 'dist/index.mjs'; +const cliDir = join(import.meta.dirname, '..'); + +function run(cmd: string, cwd = cliDir) { + return execSync(cmd, { cwd, encoding: 'utf-8', stdio: 'pipe' }); +} + +logSection('CLI Validation'); + +// ES compatibility check +log('Checking ES compatibility...', COLORS.blue); +run(`npx es-check es2022 ${CLI_FILE} --module --allow-hash-bang`); +log(' āœ“ ES2022 compatible', COLORS.green); + +// Integration test +log('Testing CLI execution...', COLORS.blue); +const tempDir = mkdtempSync(join(tmpdir(), 'embrace-cli-validate-')); + +try { + execSync('npm init -y', { cwd: tempDir, stdio: 'pipe' }); + execSync(`npm install ${cliDir}`, { cwd: tempDir, stdio: 'pipe' }); + + const helpOutput = execSync('npx embrace-web-cli --help', { + cwd: tempDir, + encoding: 'utf-8', + }); + + if (!helpOutput.includes('Commands:')) { + log(' āœ— No commands found in CLI help', COLORS.red); + process.exit(1); + } + log(' āœ“ CLI executes and has command structure', COLORS.green); +} finally { + rmSync(tempDir, { recursive: true, force: true }); +} + +log('\nāœ“ All CLI validations passed!', COLORS.green + COLORS.bold); diff --git a/cli/tsdown.config.ts b/cli/tsdown.config.ts new file mode 100644 index 000000000..938305a68 --- /dev/null +++ b/cli/tsdown.config.ts @@ -0,0 +1,12 @@ +import { defineConfig } from 'tsdown'; + +export default defineConfig({ + entry: ['src/index.ts'], + format: ['esm'], + target: 'es2022', + platform: 'node', + outDir: 'dist', + external: ['commander'], + clean: true, + publint: true, +}); diff --git a/package-lock.json b/package-lock.json index 098f71f2f..ae9f65258 100644 --- a/package-lock.json +++ b/package-lock.json @@ -97,7 +97,7 @@ "commander": "14.0.2" }, "bin": { - "embrace-web-cli": "dist/index.js" + "embrace-web-cli": "dist/index.mjs" }, "engines": { "node": ">=18.0.0" diff --git a/scripts/build-config.js b/scripts/build-config.js index 6af43ff8d..0534e8e6e 100644 --- a/scripts/build-config.js +++ b/scripts/build-config.js @@ -1,4 +1,4 @@ -// Shared build configuration for Embrace Web SDK +// Shared build configuration for SDK and CLI // Maximum bundle size (gzipped) to ensure fast load times export const MAX_BUNDLE_SIZE_KB = 100; diff --git a/scripts/measureSize.ts b/scripts/measureSize.ts deleted file mode 100644 index c976c3b44..000000000 --- a/scripts/measureSize.ts +++ /dev/null @@ -1,72 +0,0 @@ -import { createReadStream, readdirSync, statSync } from 'node:fs'; -import { join } from 'node:path'; -import { pipeline } from 'node:stream'; -import type { Gzip } from 'node:zlib'; -import { createGzip } from 'node:zlib'; - -const TARGET_DIRS = [ - { name: 'ESM', path: 'build/esm' }, - { name: 'CJS', path: 'build/cjs' }, - { name: 'CDN bundle', path: 'build/iife' }, -]; - -const walkDir = (dir: string, ext = '.js'): string[] => { - let files: string[] = []; - for (const item of readdirSync(dir, { withFileTypes: true })) { - const fullPath = join(dir, item.name); - if (item.isDirectory()) { - files = files.concat(walkDir(fullPath, ext)); - } else if (item.name.endsWith(ext)) { - files.push(fullPath); - } - } - return files; -}; - -const getSize = (file: string): number => statSync(file).size; - -const getGzipSize = (file: string): Promise => - new Promise((resolve, reject) => { - let size = 0; - pipeline( - createReadStream(file), - createGzip(), - async function* (source: AsyncIterable) { - for await (const chunk of source) size += chunk.length; - resolve(size); - yield size; - }, - (err) => { - if (err) reject(err); - }, - ); - }); - -const analyzeFolder = async (name: string, path: string) => { - try { - const files = walkDir(path); - let totalRaw = 0; - let totalGzip = 0; - - console.log(`šŸ“‚ ${name} — ${files.length} js files`); - - for (const file of files) { - const rawSize = getSize(file); - const gzipSize = await getGzipSize(file); - - totalRaw += rawSize; - totalGzip += gzipSize; - } - - console.log( - `šŸ“Š ${Math.round(totalRaw / 1024)} KB raw / ${Math.round(totalGzip / 1024)} KB gzip\n`, - ); - } catch (err) { - console.warn(`āš ļø Skipped "${name}" (${path}): ${err}`); - } -}; - -console.log('\nšŸ”Ž Measuring output sizes...\n'); -for (const { name, path } of TARGET_DIRS) { - await analyzeFolder(name, path); -}