create-vextro 0.1.2 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +99 -89
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/templates/shared/src/options/App.tsx +1 -1
package/README.md
CHANGED
|
@@ -1,136 +1,146 @@
|
|
|
1
1
|
# create-vextro
|
|
2
2
|
|
|
3
|
-
[](https://github.com/CodeCanvasCollective/vextro/actions/workflows/ci.yml)
|
|
4
4
|
[](https://www.npmjs.com/package/create-vextro)
|
|
5
5
|
[](https://www.npmjs.com/package/create-vextro)
|
|
6
|
-
[](https://github.com/
|
|
7
|
-
[](https://github.com/
|
|
6
|
+
[](https://github.com/CodeCanvasCollective/vextro/blob/main/LICENSE)
|
|
7
|
+
[](https://github.com/CodeCanvasCollective/vextro/stargazers)
|
|
8
|
+
[](https://github.com/CodeCanvasCollective/vextro/pulls)
|
|
9
9
|
|
|
10
|
-
>
|
|
10
|
+
> CLI for scaffolding modern browser extensions with Vite, React, and Tailwind CSS.
|
|
11
11
|
|
|
12
|
-
**Vextro**
|
|
12
|
+
**Vextro** creates a browser extension project on top of Vite's React + TypeScript template. It adds popup and options UIs, background and content scripts, storage helpers, icons, and browser-specific extension configuration for Chrome/Edge or Firefox.
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
- ⚛️ [React + TypeScript](https://reactjs.org/)
|
|
16
|
-
- 🎨 [Tailwind CSS](https://tailwindcss.com/)
|
|
17
|
-
- 🧩 [Manifest V3](https://developer.chrome.com/docs/extensions/mv3/intro/)
|
|
18
|
-
- 🔌 [CRXJS](https://crxjs.dev/) (Chrome/Edge) or [vite-plugin-web-extension](https://github.com/nicedoc/vite-plugin-web-extension) (Firefox)
|
|
14
|
+
## Features
|
|
19
15
|
|
|
20
|
-
|
|
16
|
+
- Fast Vite-based development workflow for popup and options pages.
|
|
17
|
+
- React, TypeScript, and Tailwind CSS preconfigured out of the box.
|
|
18
|
+
- Browser-specific extension setup:
|
|
19
|
+
Chrome and Edge use CRXJS with a typed `src/manifest.ts`.
|
|
20
|
+
Firefox uses `vite-plugin-web-extension` with `src/manifest.json`.
|
|
21
|
+
- Starter boilerplate for popup, options, background, content, and storage utilities.
|
|
21
22
|
|
|
22
|
-
##
|
|
23
|
+
## Prerequisites
|
|
23
24
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
| **Firefox** | ✅ Fully supported | `--firefox` | Uses vite-plugin-web-extension + `chrome.*` namespace |
|
|
29
|
-
| **Safari** | 📄 Documented | — | Convert Chrome output with `xcrun safari-web-extension-converter` |
|
|
25
|
+
- Node.js 20 or newer
|
|
26
|
+
- npm
|
|
27
|
+
- Chrome, Edge, or Firefox for local extension testing
|
|
28
|
+
- macOS with Xcode only if you plan to convert a Chrome build for Safari
|
|
30
29
|
|
|
31
|
-
|
|
30
|
+
## Browser Support
|
|
32
31
|
|
|
33
|
-
|
|
32
|
+
| Browser | Status | Flag | Notes |
|
|
33
|
+
| ----------- | ----------------- | ----------- | ----------------------------------------------------------------- |
|
|
34
|
+
| **Chrome** | Template included | `--chrome` | Uses CRXJS and typed `src/manifest.ts` |
|
|
35
|
+
| **Edge** | Template included | `--chrome` | Same Chromium template as Chrome |
|
|
36
|
+
| **Firefox** | Template included | `--firefox` | Uses `vite-plugin-web-extension` and `src/manifest.json` |
|
|
37
|
+
| **Safari** | Manual conversion | n/a | Convert Chrome output with `xcrun safari-web-extension-converter` |
|
|
34
38
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
39
|
+
## Quick Start
|
|
40
|
+
|
|
41
|
+
You can scaffold a new project with `npm create`. No global install is required.
|
|
38
42
|
|
|
39
|
-
|
|
40
|
-
|
|
43
|
+
```bash
|
|
44
|
+
# Provide a project name and choose the browser interactively
|
|
45
|
+
npm create vextro@latest my-extension
|
|
41
46
|
|
|
42
|
-
#
|
|
43
|
-
|
|
47
|
+
# Or skip the browser prompt
|
|
48
|
+
npm create vextro@latest my-extension -- --chrome
|
|
49
|
+
npm create vextro@latest my-extension -- --firefox
|
|
44
50
|
```
|
|
45
51
|
|
|
46
|
-
|
|
52
|
+
`npm create` automatically inserts `--` before package-specific flags. You can also run the package directly with `npx`, for example `npx create-vextro@latest create my-extension --chrome`.
|
|
53
|
+
|
|
54
|
+
Vextro scaffolds the project and installs dependencies for you. Then start the dev workflow:
|
|
47
55
|
|
|
48
56
|
```bash
|
|
49
57
|
cd my-extension
|
|
50
58
|
npm run dev
|
|
51
59
|
```
|
|
52
60
|
|
|
53
|
-
###
|
|
54
|
-
|
|
55
|
-
**Chrome / Edge:**
|
|
61
|
+
### Load the Extension During Development
|
|
56
62
|
|
|
57
|
-
|
|
58
|
-
2. Enable **Developer mode**
|
|
59
|
-
3. Click **"Load unpacked"** → select the `dist/` folder
|
|
63
|
+
**Chrome / Edge**
|
|
60
64
|
|
|
61
|
-
|
|
65
|
+
1. Open `chrome://extensions` or `edge://extensions`.
|
|
66
|
+
2. Enable **Developer mode**.
|
|
67
|
+
3. Click **Load unpacked** and select the generated `dist/` folder.
|
|
62
68
|
|
|
63
|
-
|
|
64
|
-
2. Click **"Load Temporary Add-on"**
|
|
65
|
-
3. Select any file in the `dist/` folder
|
|
69
|
+
**Firefox**
|
|
66
70
|
|
|
67
|
-
|
|
71
|
+
1. Open `about:debugging#/runtime/this-firefox`.
|
|
72
|
+
2. Click **Load Temporary Add-on**.
|
|
73
|
+
3. Select any file inside the generated `dist/` folder.
|
|
68
74
|
|
|
69
|
-
|
|
70
|
-
2. Run `xcrun safari-web-extension-converter dist/` to create an Xcode project
|
|
71
|
-
3. Build and run from Xcode
|
|
75
|
+
**Safari (macOS only)**
|
|
72
76
|
|
|
73
|
-
|
|
77
|
+
1. Scaffold a Chrome project with `--chrome`.
|
|
78
|
+
2. Run `xcrun safari-web-extension-converter dist/`.
|
|
79
|
+
3. Build and run the generated Xcode project.
|
|
74
80
|
|
|
75
|
-
##
|
|
81
|
+
## CLI Commands
|
|
76
82
|
|
|
77
83
|
```bash
|
|
78
|
-
|
|
79
|
-
create-vextro create <name>
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
create-vextro
|
|
83
|
-
create-vextro
|
|
84
|
-
|
|
84
|
+
# Interactive setup
|
|
85
|
+
npx create-vextro@latest create <project-name>
|
|
86
|
+
|
|
87
|
+
# Target a specific browser
|
|
88
|
+
npx create-vextro@latest create <project-name> --chrome
|
|
89
|
+
npx create-vextro@latest create <project-name> --firefox
|
|
90
|
+
|
|
91
|
+
# Overwrite an existing directory
|
|
92
|
+
npx create-vextro@latest create <project-name> --chrome --force
|
|
93
|
+
|
|
94
|
+
# Global flags
|
|
95
|
+
npx create-vextro@latest --help
|
|
96
|
+
npx create-vextro@latest --version
|
|
97
|
+
npx create-vextro@latest --verbose create <project-name> --chrome
|
|
85
98
|
```
|
|
86
99
|
|
|
87
|
-
|
|
100
|
+
`--verbose` is a global flag, so place it before the explicit `create` command.
|
|
88
101
|
|
|
89
|
-
##
|
|
102
|
+
## What You Get
|
|
90
103
|
|
|
91
104
|
Every generated project includes:
|
|
92
105
|
|
|
93
|
-
| Feature | Description
|
|
94
|
-
| ------------------ |
|
|
95
|
-
| **Popup** | React popup with `chrome.storage` demo
|
|
96
|
-
| **Options page** | Settings page with save
|
|
97
|
-
| **Background** |
|
|
98
|
-
| **Content script** | Injected script with background messaging example
|
|
99
|
-
| **Storage utils** | Typed wrapper around
|
|
100
|
-
| **
|
|
101
|
-
| **TypeScript** |
|
|
102
|
-
| **Tailwind CSS** | Utility-first styling
|
|
106
|
+
| Feature | Description |
|
|
107
|
+
| ------------------ | --------------------------------------------------------------------------------------- |
|
|
108
|
+
| **Popup** | React popup with a `chrome.storage` demo |
|
|
109
|
+
| **Options page** | Settings page with save and load via storage sync |
|
|
110
|
+
| **Background** | Chrome template uses a service worker; Firefox template uses a module background script |
|
|
111
|
+
| **Content script** | Injected script with background messaging example |
|
|
112
|
+
| **Storage utils** | Typed wrapper around `chrome.storage.sync` |
|
|
113
|
+
| **Manifest setup** | Chrome gets `src/manifest.ts`; Firefox gets `src/manifest.json` |
|
|
114
|
+
| **TypeScript** | Type-safe React and extension code |
|
|
115
|
+
| **Tailwind CSS** | Utility-first styling preconfigured |
|
|
103
116
|
|
|
104
|
-
|
|
117
|
+
## What's Included
|
|
105
118
|
|
|
106
|
-
|
|
119
|
+
Each generated project follows this structure. The manifest file differs by browser target.
|
|
107
120
|
|
|
108
|
-
```
|
|
121
|
+
```text
|
|
109
122
|
my-extension/
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
123
|
+
|-- public/
|
|
124
|
+
| |-- icon.png
|
|
125
|
+
| `-- icons/
|
|
126
|
+
|-- src/
|
|
127
|
+
| |-- background/
|
|
128
|
+
| |-- content/
|
|
129
|
+
| |-- options/
|
|
130
|
+
| |-- popup/
|
|
131
|
+
| |-- utils/
|
|
132
|
+
| |-- styles.css
|
|
133
|
+
| `-- manifest.ts or manifest.json
|
|
134
|
+
|-- vite.config.ts
|
|
135
|
+
|-- tsconfig.app.json
|
|
136
|
+
|-- tsconfig.json
|
|
137
|
+
`-- package.json
|
|
124
138
|
```
|
|
125
139
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
## 🤝 Contributing
|
|
129
|
-
|
|
130
|
-
See [docs/CONTRIBUTING.md](docs/CONTRIBUTING.md) for development setup and contribution guidelines.
|
|
140
|
+
## Contributing
|
|
131
141
|
|
|
132
|
-
|
|
142
|
+
We welcome contributions. See [docs/CONTRIBUTING.md](docs/CONTRIBUTING.md) for development setup and contribution guidelines.
|
|
133
143
|
|
|
134
|
-
##
|
|
144
|
+
## License
|
|
135
145
|
|
|
136
|
-
MIT © [
|
|
146
|
+
MIT © [CodeCanvas Collective](https://github.com/CodeCanvasCollective)
|
package/dist/index.js
CHANGED
|
@@ -424,7 +424,7 @@ async function handleCreate(projectName, options) {
|
|
|
424
424
|
// package.json
|
|
425
425
|
var package_default = {
|
|
426
426
|
name: "create-vextro",
|
|
427
|
-
version: "0.1.
|
|
427
|
+
version: "0.1.3",
|
|
428
428
|
description: "Scaffold modern browser extensions (Chrome, Edge, Firefox) with Vite + React + Tailwind",
|
|
429
429
|
type: "module",
|
|
430
430
|
bin: {
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli.ts","../src/commands/create.ts","../src/prompts/index.ts","../src/constants.ts","../src/utils/logger.ts","../src/utils/file.ts","../src/utils/validator.ts","../src/generators/extension.ts","../package.json","../src/index.ts"],"sourcesContent":["import { Command } from 'commander';\nimport { createCommand } from './commands/create.js';\nimport { setVerbose } from './utils/logger.js';\nimport pkg from '../package.json' with { type: 'json' };\n\nconst CLI_VERSION = pkg.version || '0.1.0';\n\nexport function createCli(): Command {\n const program = new Command();\n\n program\n .name('create-vextro')\n .description('Scaffold modern browser extensions with Vite + React + Tailwind')\n .version(CLI_VERSION)\n .option('--verbose', 'Enable verbose output')\n .hook('preAction', (thisCommand) => {\n const opts = thisCommand.opts();\n if (opts.verbose) {\n setVerbose(true);\n }\n });\n\n program.addCommand(createCommand(), { isDefault: true });\n\n return program;\n}\n","import { Command } from 'commander';\nimport path from 'node:path';\nimport fs from 'fs-extra';\nimport { promptProjectName, promptBrowser } from '../prompts/index.js';\nimport { ExtensionGenerator } from '../generators/extension.js';\nimport {\n validateProjectName,\n validateDirectory,\n error,\n success,\n newLine,\n banner,\n} from '../utils/index.js';\nimport { BROWSERS } from '../constants.js';\nimport type { CreateOptions, ProjectConfig, BrowserTarget } from '../types/index.js';\n\nexport function createCommand(): Command {\n const cmd = new Command('create')\n .description('Create a new browser extension project')\n .argument('[project-name]', 'Name of the extension project')\n .option('--chrome', 'Target Chrome / Edge (default)')\n .option('--firefox', 'Target Firefox')\n .option('--force', 'Overwrite existing directory')\n .action(async (projectName: string | undefined, options: CreateOptions) => {\n try {\n await handleCreate(projectName, options);\n } catch (err) {\n error(err instanceof Error ? err.message : String(err));\n process.exit(1);\n }\n });\n\n return cmd;\n}\n\nfunction resolveBrowserFromFlags(options: CreateOptions): BrowserTarget | null {\n if (options.chrome) return 'chrome';\n if (options.firefox) return 'firefox';\n return null;\n}\n\nasync function handleCreate(\n projectName: string | undefined,\n options: CreateOptions,\n): Promise<void> {\n // If no project name given as arg, prompt for it\n if (!projectName) {\n projectName = await promptProjectName();\n }\n\n // Validate the project name\n const nameValidation = validateProjectName(projectName);\n if (nameValidation !== true) {\n throw new Error(nameValidation);\n }\n\n // Resolve browser target\n let browser = resolveBrowserFromFlags(options);\n if (!browser) {\n browser = await promptBrowser();\n }\n\n const targetDir = path.resolve(process.cwd(), projectName);\n\n // Check if directory already exists\n if (!options.force) {\n const dirValidation = await validateDirectory(targetDir);\n if (dirValidation !== true) {\n throw new Error(dirValidation);\n }\n } else if (await fs.pathExists(targetDir)) {\n await fs.remove(targetDir);\n }\n\n const config: ProjectConfig = {\n name: projectName,\n targetDir,\n browser,\n };\n\n const browserMeta = BROWSERS[browser];\n\n newLine();\n banner(`🚀 Creating Vextro Extension for ${browserMeta.displayName} — \"${config.name}\"...`);\n newLine();\n\n // Handle SIGINT — clean up partial directory\n const cleanup = async () => {\n newLine();\n error('Interrupted! Cleaning up...');\n try {\n if (await fs.pathExists(targetDir)) {\n await fs.remove(targetDir);\n }\n } catch {\n // best-effort cleanup\n }\n process.exit(1);\n };\n process.on('SIGINT', cleanup);\n\n const generator = new ExtensionGenerator(config);\n await generator.generate();\n\n // Remove SIGINT handler after success\n process.removeListener('SIGINT', cleanup);\n\n newLine();\n success(\n `Vextro project \"${config.name}\" created successfully for ${browserMeta.displayName}! 🎉`,\n );\n newLine();\n console.log('Next steps:');\n console.log(` cd ${config.name}`);\n console.log(' npm run dev');\n newLine();\n\n if (browser === 'chrome') {\n console.log('Load extension:');\n console.log(' 1. Open chrome://extensions (or edge://extensions)');\n console.log(' 2. Enable \"Developer mode\"');\n console.log(' 3. Click \"Load unpacked\" → select the dist/ folder');\n } else if (browser === 'firefox') {\n console.log('Load extension:');\n console.log(' 1. Open about:debugging#/runtime/this-firefox');\n console.log(' 2. Click \"Load Temporary Add-on\"');\n console.log(' 3. Select any file in the dist/ folder');\n }\n\n newLine();\n console.log('Happy coding! 🚀');\n newLine();\n}\n","import inquirer from 'inquirer';\nimport { DEFAULT_PROJECT_NAME, BROWSERS } from '../constants.js';\nimport { validateProjectName } from '../utils/index.js';\nimport type { BrowserTarget } from '../types/index.js';\n\nexport async function promptProjectName(): Promise<string> {\n const { projectName } = await inquirer.prompt([\n {\n name: 'projectName',\n message: 'Enter your extension project name:',\n default: DEFAULT_PROJECT_NAME,\n validate: (input: string) => {\n const result = validateProjectName(input);\n return result === true ? true : result;\n },\n },\n ]);\n return projectName;\n}\n\nexport async function promptBrowser(): Promise<BrowserTarget> {\n const { browser } = await inquirer.prompt([\n {\n type: 'list',\n name: 'browser',\n message: 'Select target browser:',\n choices: Object.entries(BROWSERS).map(([value, meta]) => ({\n name: `${meta.displayName} — ${meta.description}`,\n value,\n })),\n default: 'chrome',\n },\n ]);\n return browser;\n}\n","import type { BrowserTarget } from './types/index.js';\n\nexport const PACKAGE_NAME = 'create-vextro';\nexport const BRAND_NAME = 'Vextro';\n\nexport const VALID_PROJECT_NAME = /^(?:@[a-z0-9-~][a-z0-9-._~]*\\/)?[a-z0-9-~][a-z0-9-._~]*$/;\n\nexport const DEFAULT_PROJECT_NAME = 'my-extension';\nexport const DEFAULT_BROWSER: BrowserTarget = 'chrome';\n\nexport const FILES_TO_REMOVE = [\n 'src/App.tsx',\n 'src/main.tsx',\n 'src/index.css',\n 'src/App.css',\n 'src/assets',\n 'index.html',\n];\n\nexport const BROWSERS: Record<BrowserTarget, { displayName: string; description: string }> = {\n chrome: {\n displayName: 'Chrome / Edge',\n description: 'Google Chrome & Microsoft Edge (Chromium-based, uses CRXJS)',\n },\n firefox: {\n displayName: 'Firefox',\n description: 'Mozilla Firefox (uses vite-plugin-web-extension)',\n },\n};\n\nexport const CHROME_DEV_DEPS = [\n '@types/chrome',\n '@types/node',\n '@crxjs/vite-plugin',\n 'tailwindcss',\n '@tailwindcss/vite',\n];\n\nexport const FIREFOX_DEV_DEPS = [\n '@types/chrome',\n '@types/node',\n 'vite-plugin-web-extension',\n 'tailwindcss',\n '@tailwindcss/vite',\n];\n","import chalk from 'chalk';\nimport ora, { type Ora } from 'ora';\n\nlet verbose = false;\n\nexport function setVerbose(value: boolean): void {\n verbose = value;\n}\n\nexport function info(message: string): void {\n console.log(chalk.blue('ℹ'), message);\n}\n\nexport function success(message: string): void {\n console.log(chalk.green('✔'), message);\n}\n\nexport function warn(message: string): void {\n console.log(chalk.yellow('⚠'), message);\n}\n\nexport function error(message: string): void {\n console.log(chalk.red('✖'), message);\n}\n\nexport function debug(message: string): void {\n if (verbose) {\n console.log(chalk.gray('⬥'), chalk.gray(message));\n }\n}\n\nexport function spinner(text: string): Ora {\n return ora({ text, color: 'cyan' });\n}\n\nexport function newLine(): void {\n console.log();\n}\n\nexport function banner(text: string): void {\n console.log(chalk.bold.cyan(text));\n}\n","import path from 'node:path';\nimport fs from 'fs-extra';\nimport { fileURLToPath } from 'node:url';\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = path.dirname(__filename);\n\nexport function getTemplatesDir(): string {\n // When bundled with tsup, __dirname is dist/ → go up 1 level to project root\n // When running unbundled (vitest), __dirname is src/utils/ → go up 2 levels to project root\n const isBundled =\n __dirname.replace(/\\\\/g, '/').endsWith('/dist') ||\n __dirname.replace(/\\\\/g, '/').includes('/dist/');\n const projectRoot = isBundled\n ? path.resolve(__dirname, '..')\n : path.resolve(__dirname, '..', '..');\n return path.resolve(projectRoot, 'src', 'templates');\n}\n\nexport async function createDir(dirPath: string): Promise<void> {\n await fs.ensureDir(dirPath);\n}\n\nexport async function directoryExists(dirPath: string): Promise<boolean> {\n try {\n const stat = await fs.stat(dirPath);\n return stat.isDirectory();\n } catch {\n return false;\n }\n}\n\nexport async function fileExists(filePath: string): Promise<boolean> {\n try {\n const stat = await fs.stat(filePath);\n return stat.isFile();\n } catch {\n return false;\n }\n}\n","import { VALID_PROJECT_NAME } from '../constants.js';\nimport { directoryExists } from './file.js';\n\nexport function validateProjectName(name: string): string | true {\n if (!name || name.trim().length === 0) {\n return 'Project name is required.';\n }\n\n if (!VALID_PROJECT_NAME.test(name)) {\n return 'Project name must be a valid npm package name (lowercase, no spaces, can use hyphens and dots).';\n }\n\n if (name.length > 214) {\n return 'Project name must be less than 214 characters.';\n }\n\n return true;\n}\n\nexport async function validateDirectory(dirPath: string): Promise<string | true> {\n if (await directoryExists(dirPath)) {\n return `Directory \"${dirPath}\" already exists. Use --force to overwrite.`;\n }\n return true;\n}\n\nexport function checkNodeVersion(minMajor: number = 20): string | true {\n const version = process.version;\n const major = parseInt(version.slice(1).split('.')[0], 10);\n\n if (major < minMajor) {\n return `Node.js ${minMajor}+ is required. You are using ${version}.`;\n }\n\n return true;\n}\n","import path from 'node:path';\nimport { execSync } from 'node:child_process';\nimport fs from 'fs-extra';\nimport { getTemplatesDir, spinner, success, debug } from '../utils/index.js';\nimport { FILES_TO_REMOVE, CHROME_DEV_DEPS, FIREFOX_DEV_DEPS } from '../constants.js';\nimport type { ProjectConfig } from '../types/index.js';\n\nexport class ExtensionGenerator {\n private config: ProjectConfig;\n private templatesDir: string;\n\n constructor(config: ProjectConfig) {\n this.config = config;\n this.templatesDir = getTemplatesDir();\n }\n\n async generate(): Promise<void> {\n await this.scaffoldVite();\n await this.installBaseDeps();\n await this.cleanViteDefaults();\n await this.copySharedFiles();\n await this.copyBrowserFiles();\n await this.overrideConfigs();\n await this.patchTsConfig();\n await this.injectProjectName();\n await this.installExtensionDeps();\n }\n\n private async scaffoldVite(): Promise<void> {\n const s = spinner('Creating base Vite + React + TS project...');\n s.start();\n try {\n execSync(`npm exec --yes -- create-vite@latest ${this.config.name} --template react-ts`, {\n cwd: path.dirname(this.config.targetDir),\n stdio: 'pipe',\n maxBuffer: 10 * 1024 * 1024,\n });\n s.stop();\n success('Created base Vite + React + TS project');\n } catch (err) {\n s.stop();\n throw new Error(\n `Failed to scaffold Vite project: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n\n private async installBaseDeps(): Promise<void> {\n const s = spinner('Installing base dependencies...');\n s.start();\n try {\n execSync('npm install', {\n cwd: this.config.targetDir,\n stdio: 'pipe',\n maxBuffer: 10 * 1024 * 1024,\n });\n s.stop();\n success('Installed base dependencies');\n } catch (err) {\n s.stop();\n throw new Error(\n `Failed to install dependencies: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n\n private async cleanViteDefaults(): Promise<void> {\n const s = spinner('Removing default Vite template files...');\n s.start();\n\n for (const file of FILES_TO_REMOVE) {\n const fullPath = path.join(this.config.targetDir, file);\n if (await fs.pathExists(fullPath)) {\n await fs.remove(fullPath);\n debug(`Removed: ${file}`);\n }\n }\n\n const publicPath = path.join(this.config.targetDir, 'public');\n if (await fs.pathExists(publicPath)) {\n await fs.emptyDir(publicPath);\n }\n\n s.stop();\n success('Cleaned default Vite template files');\n }\n\n private async copySharedFiles(): Promise<void> {\n const s = spinner('Copying shared extension files...');\n s.start();\n\n const sharedDir = path.join(this.templatesDir, 'shared');\n\n // Copy shared src files (popup, options, utils, styles)\n const sharedSrcDir = path.join(sharedDir, 'src');\n if (await fs.pathExists(sharedSrcDir)) {\n await fs.copy(sharedSrcDir, path.join(this.config.targetDir, 'src'));\n }\n\n // Copy shared public files (icons)\n const sharedPublicDir = path.join(sharedDir, 'public');\n if (await fs.pathExists(sharedPublicDir)) {\n await fs.copy(sharedPublicDir, path.join(this.config.targetDir, 'public'));\n }\n\n s.stop();\n success('Copied shared extension files');\n }\n\n private async copyBrowserFiles(): Promise<void> {\n const s = spinner(`Copying ${this.config.browser} browser files...`);\n s.start();\n\n const browserDir = path.join(this.templatesDir, this.config.browser);\n\n // Copy browser-specific src files (manifest, background, content)\n const browserSrcDir = path.join(browserDir, 'src');\n if (await fs.pathExists(browserSrcDir)) {\n await fs.copy(browserSrcDir, path.join(this.config.targetDir, 'src'), {\n overwrite: true,\n });\n }\n\n s.stop();\n success(`Copied ${this.config.browser} browser files`);\n }\n\n private async overrideConfigs(): Promise<void> {\n const s = spinner('Overriding config files...');\n s.start();\n\n const browserDir = path.join(this.templatesDir, this.config.browser);\n const viteConfigFrom = path.join(browserDir, 'vite.config.ts');\n const viteConfigTo = path.join(this.config.targetDir, 'vite.config.ts');\n\n if (await fs.pathExists(viteConfigFrom)) {\n await fs.copy(viteConfigFrom, viteConfigTo, { overwrite: true });\n debug('Overrode: vite.config.ts');\n }\n\n s.stop();\n success('Overrode config files');\n }\n\n private async patchTsConfig(): Promise<void> {\n const s = spinner('Patching tsconfig for extension types...');\n s.start();\n\n const tsconfigAppPath = path.join(this.config.targetDir, 'tsconfig.app.json');\n\n if (await fs.pathExists(tsconfigAppPath)) {\n let content = await fs.readFile(tsconfigAppPath, 'utf-8');\n\n // Both Chrome and Firefox use @types/chrome (Firefox MV3 supports chrome.* namespace)\n const typeToAdd = 'chrome';\n\n // Inject the type into the \"types\" array using string replacement\n // This preserves comments and formatting in the JSONC file\n content = content.replace(\n /(\"types\"\\s*:\\s*\\[)([\\s\\S]*?)(\\])/,\n (match, prefix, existing, suffix) => {\n const trimmed = existing.trim();\n if (trimmed.includes(`\"${typeToAdd}\"`)) return match; // already present\n if (trimmed.length === 0) {\n return `${prefix}\"${typeToAdd}\"${suffix}`;\n }\n return `${prefix}${existing.trimEnd()}, \"${typeToAdd}\"${suffix}`;\n },\n );\n\n await fs.writeFile(tsconfigAppPath, content, 'utf-8');\n debug(`Patched tsconfig.app.json with type: ${typeToAdd}`);\n }\n\n s.stop();\n success('Patched tsconfig for extension types');\n }\n\n private async injectProjectName(): Promise<void> {\n const s = spinner('Injecting project name...');\n s.start();\n\n if (this.config.browser === 'chrome') {\n // Chrome uses manifest.ts\n const manifestPath = path.join(this.config.targetDir, 'src', 'manifest.ts');\n if (await fs.pathExists(manifestPath)) {\n let manifest = await fs.readFile(manifestPath, 'utf-8');\n manifest = manifest.replace(/__EXT_NAME__/g, this.config.name);\n await fs.writeFile(manifestPath, manifest, 'utf-8');\n }\n } else if (this.config.browser === 'firefox') {\n // Firefox uses manifest.json\n const manifestPath = path.join(this.config.targetDir, 'src', 'manifest.json');\n if (await fs.pathExists(manifestPath)) {\n let manifest = await fs.readFile(manifestPath, 'utf-8');\n manifest = manifest.replace(/__EXT_NAME__/g, this.config.name);\n await fs.writeFile(manifestPath, manifest, 'utf-8');\n }\n }\n\n // Update package.json name\n const pkgPath = path.join(this.config.targetDir, 'package.json');\n if (await fs.pathExists(pkgPath)) {\n let pkg = await fs.readFile(pkgPath, 'utf-8');\n pkg = pkg.replace(/\"__EXT_NAME__\"/g, `\"${this.config.name}\"`);\n await fs.writeFile(pkgPath, pkg, 'utf-8');\n }\n\n s.stop();\n success('Injected project name');\n }\n\n private async installExtensionDeps(): Promise<void> {\n const deps = this.config.browser === 'firefox' ? FIREFOX_DEV_DEPS : CHROME_DEV_DEPS;\n\n const s = spinner(`Installing ${this.config.browser} extension dev dependencies...`);\n s.start();\n try {\n execSync(`npm install --save-dev ${deps.join(' ')}`, {\n cwd: this.config.targetDir,\n stdio: 'pipe',\n maxBuffer: 10 * 1024 * 1024,\n });\n s.stop();\n success(`Installed ${this.config.browser} extension dev dependencies`);\n } catch (err) {\n s.stop();\n throw new Error(\n `Failed to install extension dependencies: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n}\n","{\n \"name\": \"create-vextro\",\n \"version\": \"0.1.2\",\n \"description\": \"Scaffold modern browser extensions (Chrome, Edge, Firefox) with Vite + React + Tailwind\",\n \"type\": \"module\",\n \"bin\": {\n \"create-vextro\": \"./dist/index.js\"\n },\n \"engines\": {\n \"node\": \">=20.0.0\"\n },\n \"scripts\": {\n \"build\": \"tsup\",\n \"dev\": \"tsup --watch\",\n \"test\": \"vitest run\",\n \"test:watch\": \"vitest\",\n \"lint\": \"eslint src/\",\n \"format\": \"prettier --write .\",\n \"format:check\": \"prettier --check .\",\n \"prepublishOnly\": \"npm run build && npm test\",\n \"typecheck\": \"tsc --noEmit\"\n },\n \"dependencies\": {\n \"chalk\": \"^5.3.0\",\n \"commander\": \"^12.1.0\",\n \"fs-extra\": \"^11.2.0\",\n \"inquirer\": \"^9.2.8\",\n \"ora\": \"^8.0.0\"\n },\n \"devDependencies\": {\n \"@changesets/cli\": \"^2.27.0\",\n \"@types/fs-extra\": \"^11.0.4\",\n \"@types/inquirer\": \"^9.0.7\",\n \"@types/node\": \"^20.0.0\",\n \"eslint\": \"^9.0.0\",\n \"prettier\": \"^3.3.0\",\n \"tsup\": \"^8.0.0\",\n \"typescript\": \"^5.5.0\",\n \"typescript-eslint\": \"^8.0.0\",\n \"vitest\": \"^2.0.0\"\n },\n \"files\": [\n \"dist\",\n \"src/templates\"\n ],\n \"keywords\": [\n \"vite\",\n \"chrome-extension\",\n \"firefox-extension\",\n \"browser-extension\",\n \"vite-plugin\",\n \"react\",\n \"tailwind\",\n \"crxjs\",\n \"manifest-v3\",\n \"scaffold\",\n \"cli\",\n \"generator\",\n \"starter-kit\"\n ],\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"https://github.com/CodeCanvasCollective/vextro.git\"\n },\n \"author\": \"Lasantha <lasanthaslakmal@gmail.com>\",\n \"license\": \"MIT\",\n \"bugs\": {\n \"url\": \"https://github.com/CodeCanvasCollective/vextro/issues\"\n },\n \"homepage\": \"https://github.com/CodeCanvasCollective/vextro#readme\"\n}\n","import { createCli } from './cli.js';\n\nconst program = createCli();\nprogram.parse();\n"],"mappings":"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","names":["Command","path","fs","__filename","__dirname","path","fs","path","fs","path","fs","program","Command"]}
|
|
1
|
+
{"version":3,"sources":["../src/cli.ts","../src/commands/create.ts","../src/prompts/index.ts","../src/constants.ts","../src/utils/logger.ts","../src/utils/file.ts","../src/utils/validator.ts","../src/generators/extension.ts","../package.json","../src/index.ts"],"sourcesContent":["import { Command } from 'commander';\nimport { createCommand } from './commands/create.js';\nimport { setVerbose } from './utils/logger.js';\nimport pkg from '../package.json' with { type: 'json' };\n\nconst CLI_VERSION = pkg.version || '0.1.0';\n\nexport function createCli(): Command {\n const program = new Command();\n\n program\n .name('create-vextro')\n .description('Scaffold modern browser extensions with Vite + React + Tailwind')\n .version(CLI_VERSION)\n .option('--verbose', 'Enable verbose output')\n .hook('preAction', (thisCommand) => {\n const opts = thisCommand.opts();\n if (opts.verbose) {\n setVerbose(true);\n }\n });\n\n program.addCommand(createCommand(), { isDefault: true });\n\n return program;\n}\n","import { Command } from 'commander';\nimport path from 'node:path';\nimport fs from 'fs-extra';\nimport { promptProjectName, promptBrowser } from '../prompts/index.js';\nimport { ExtensionGenerator } from '../generators/extension.js';\nimport {\n validateProjectName,\n validateDirectory,\n error,\n success,\n newLine,\n banner,\n} from '../utils/index.js';\nimport { BROWSERS } from '../constants.js';\nimport type { CreateOptions, ProjectConfig, BrowserTarget } from '../types/index.js';\n\nexport function createCommand(): Command {\n const cmd = new Command('create')\n .description('Create a new browser extension project')\n .argument('[project-name]', 'Name of the extension project')\n .option('--chrome', 'Target Chrome / Edge (default)')\n .option('--firefox', 'Target Firefox')\n .option('--force', 'Overwrite existing directory')\n .action(async (projectName: string | undefined, options: CreateOptions) => {\n try {\n await handleCreate(projectName, options);\n } catch (err) {\n error(err instanceof Error ? err.message : String(err));\n process.exit(1);\n }\n });\n\n return cmd;\n}\n\nfunction resolveBrowserFromFlags(options: CreateOptions): BrowserTarget | null {\n if (options.chrome) return 'chrome';\n if (options.firefox) return 'firefox';\n return null;\n}\n\nasync function handleCreate(\n projectName: string | undefined,\n options: CreateOptions,\n): Promise<void> {\n // If no project name given as arg, prompt for it\n if (!projectName) {\n projectName = await promptProjectName();\n }\n\n // Validate the project name\n const nameValidation = validateProjectName(projectName);\n if (nameValidation !== true) {\n throw new Error(nameValidation);\n }\n\n // Resolve browser target\n let browser = resolveBrowserFromFlags(options);\n if (!browser) {\n browser = await promptBrowser();\n }\n\n const targetDir = path.resolve(process.cwd(), projectName);\n\n // Check if directory already exists\n if (!options.force) {\n const dirValidation = await validateDirectory(targetDir);\n if (dirValidation !== true) {\n throw new Error(dirValidation);\n }\n } else if (await fs.pathExists(targetDir)) {\n await fs.remove(targetDir);\n }\n\n const config: ProjectConfig = {\n name: projectName,\n targetDir,\n browser,\n };\n\n const browserMeta = BROWSERS[browser];\n\n newLine();\n banner(`🚀 Creating Vextro Extension for ${browserMeta.displayName} — \"${config.name}\"...`);\n newLine();\n\n // Handle SIGINT — clean up partial directory\n const cleanup = async () => {\n newLine();\n error('Interrupted! Cleaning up...');\n try {\n if (await fs.pathExists(targetDir)) {\n await fs.remove(targetDir);\n }\n } catch {\n // best-effort cleanup\n }\n process.exit(1);\n };\n process.on('SIGINT', cleanup);\n\n const generator = new ExtensionGenerator(config);\n await generator.generate();\n\n // Remove SIGINT handler after success\n process.removeListener('SIGINT', cleanup);\n\n newLine();\n success(\n `Vextro project \"${config.name}\" created successfully for ${browserMeta.displayName}! 🎉`,\n );\n newLine();\n console.log('Next steps:');\n console.log(` cd ${config.name}`);\n console.log(' npm run dev');\n newLine();\n\n if (browser === 'chrome') {\n console.log('Load extension:');\n console.log(' 1. Open chrome://extensions (or edge://extensions)');\n console.log(' 2. Enable \"Developer mode\"');\n console.log(' 3. Click \"Load unpacked\" → select the dist/ folder');\n } else if (browser === 'firefox') {\n console.log('Load extension:');\n console.log(' 1. Open about:debugging#/runtime/this-firefox');\n console.log(' 2. Click \"Load Temporary Add-on\"');\n console.log(' 3. Select any file in the dist/ folder');\n }\n\n newLine();\n console.log('Happy coding! 🚀');\n newLine();\n}\n","import inquirer from 'inquirer';\nimport { DEFAULT_PROJECT_NAME, BROWSERS } from '../constants.js';\nimport { validateProjectName } from '../utils/index.js';\nimport type { BrowserTarget } from '../types/index.js';\n\nexport async function promptProjectName(): Promise<string> {\n const { projectName } = await inquirer.prompt([\n {\n name: 'projectName',\n message: 'Enter your extension project name:',\n default: DEFAULT_PROJECT_NAME,\n validate: (input: string) => {\n const result = validateProjectName(input);\n return result === true ? true : result;\n },\n },\n ]);\n return projectName;\n}\n\nexport async function promptBrowser(): Promise<BrowserTarget> {\n const { browser } = await inquirer.prompt([\n {\n type: 'list',\n name: 'browser',\n message: 'Select target browser:',\n choices: Object.entries(BROWSERS).map(([value, meta]) => ({\n name: `${meta.displayName} — ${meta.description}`,\n value,\n })),\n default: 'chrome',\n },\n ]);\n return browser;\n}\n","import type { BrowserTarget } from './types/index.js';\n\nexport const PACKAGE_NAME = 'create-vextro';\nexport const BRAND_NAME = 'Vextro';\n\nexport const VALID_PROJECT_NAME = /^(?:@[a-z0-9-~][a-z0-9-._~]*\\/)?[a-z0-9-~][a-z0-9-._~]*$/;\n\nexport const DEFAULT_PROJECT_NAME = 'my-extension';\nexport const DEFAULT_BROWSER: BrowserTarget = 'chrome';\n\nexport const FILES_TO_REMOVE = [\n 'src/App.tsx',\n 'src/main.tsx',\n 'src/index.css',\n 'src/App.css',\n 'src/assets',\n 'index.html',\n];\n\nexport const BROWSERS: Record<BrowserTarget, { displayName: string; description: string }> = {\n chrome: {\n displayName: 'Chrome / Edge',\n description: 'Google Chrome & Microsoft Edge (Chromium-based, uses CRXJS)',\n },\n firefox: {\n displayName: 'Firefox',\n description: 'Mozilla Firefox (uses vite-plugin-web-extension)',\n },\n};\n\nexport const CHROME_DEV_DEPS = [\n '@types/chrome',\n '@types/node',\n '@crxjs/vite-plugin',\n 'tailwindcss',\n '@tailwindcss/vite',\n];\n\nexport const FIREFOX_DEV_DEPS = [\n '@types/chrome',\n '@types/node',\n 'vite-plugin-web-extension',\n 'tailwindcss',\n '@tailwindcss/vite',\n];\n","import chalk from 'chalk';\nimport ora, { type Ora } from 'ora';\n\nlet verbose = false;\n\nexport function setVerbose(value: boolean): void {\n verbose = value;\n}\n\nexport function info(message: string): void {\n console.log(chalk.blue('ℹ'), message);\n}\n\nexport function success(message: string): void {\n console.log(chalk.green('✔'), message);\n}\n\nexport function warn(message: string): void {\n console.log(chalk.yellow('⚠'), message);\n}\n\nexport function error(message: string): void {\n console.log(chalk.red('✖'), message);\n}\n\nexport function debug(message: string): void {\n if (verbose) {\n console.log(chalk.gray('⬥'), chalk.gray(message));\n }\n}\n\nexport function spinner(text: string): Ora {\n return ora({ text, color: 'cyan' });\n}\n\nexport function newLine(): void {\n console.log();\n}\n\nexport function banner(text: string): void {\n console.log(chalk.bold.cyan(text));\n}\n","import path from 'node:path';\nimport fs from 'fs-extra';\nimport { fileURLToPath } from 'node:url';\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = path.dirname(__filename);\n\nexport function getTemplatesDir(): string {\n // When bundled with tsup, __dirname is dist/ → go up 1 level to project root\n // When running unbundled (vitest), __dirname is src/utils/ → go up 2 levels to project root\n const isBundled =\n __dirname.replace(/\\\\/g, '/').endsWith('/dist') ||\n __dirname.replace(/\\\\/g, '/').includes('/dist/');\n const projectRoot = isBundled\n ? path.resolve(__dirname, '..')\n : path.resolve(__dirname, '..', '..');\n return path.resolve(projectRoot, 'src', 'templates');\n}\n\nexport async function createDir(dirPath: string): Promise<void> {\n await fs.ensureDir(dirPath);\n}\n\nexport async function directoryExists(dirPath: string): Promise<boolean> {\n try {\n const stat = await fs.stat(dirPath);\n return stat.isDirectory();\n } catch {\n return false;\n }\n}\n\nexport async function fileExists(filePath: string): Promise<boolean> {\n try {\n const stat = await fs.stat(filePath);\n return stat.isFile();\n } catch {\n return false;\n }\n}\n","import { VALID_PROJECT_NAME } from '../constants.js';\nimport { directoryExists } from './file.js';\n\nexport function validateProjectName(name: string): string | true {\n if (!name || name.trim().length === 0) {\n return 'Project name is required.';\n }\n\n if (!VALID_PROJECT_NAME.test(name)) {\n return 'Project name must be a valid npm package name (lowercase, no spaces, can use hyphens and dots).';\n }\n\n if (name.length > 214) {\n return 'Project name must be less than 214 characters.';\n }\n\n return true;\n}\n\nexport async function validateDirectory(dirPath: string): Promise<string | true> {\n if (await directoryExists(dirPath)) {\n return `Directory \"${dirPath}\" already exists. Use --force to overwrite.`;\n }\n return true;\n}\n\nexport function checkNodeVersion(minMajor: number = 20): string | true {\n const version = process.version;\n const major = parseInt(version.slice(1).split('.')[0], 10);\n\n if (major < minMajor) {\n return `Node.js ${minMajor}+ is required. You are using ${version}.`;\n }\n\n return true;\n}\n","import path from 'node:path';\nimport { execSync } from 'node:child_process';\nimport fs from 'fs-extra';\nimport { getTemplatesDir, spinner, success, debug } from '../utils/index.js';\nimport { FILES_TO_REMOVE, CHROME_DEV_DEPS, FIREFOX_DEV_DEPS } from '../constants.js';\nimport type { ProjectConfig } from '../types/index.js';\n\nexport class ExtensionGenerator {\n private config: ProjectConfig;\n private templatesDir: string;\n\n constructor(config: ProjectConfig) {\n this.config = config;\n this.templatesDir = getTemplatesDir();\n }\n\n async generate(): Promise<void> {\n await this.scaffoldVite();\n await this.installBaseDeps();\n await this.cleanViteDefaults();\n await this.copySharedFiles();\n await this.copyBrowserFiles();\n await this.overrideConfigs();\n await this.patchTsConfig();\n await this.injectProjectName();\n await this.installExtensionDeps();\n }\n\n private async scaffoldVite(): Promise<void> {\n const s = spinner('Creating base Vite + React + TS project...');\n s.start();\n try {\n execSync(`npm exec --yes -- create-vite@latest ${this.config.name} --template react-ts`, {\n cwd: path.dirname(this.config.targetDir),\n stdio: 'pipe',\n maxBuffer: 10 * 1024 * 1024,\n });\n s.stop();\n success('Created base Vite + React + TS project');\n } catch (err) {\n s.stop();\n throw new Error(\n `Failed to scaffold Vite project: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n\n private async installBaseDeps(): Promise<void> {\n const s = spinner('Installing base dependencies...');\n s.start();\n try {\n execSync('npm install', {\n cwd: this.config.targetDir,\n stdio: 'pipe',\n maxBuffer: 10 * 1024 * 1024,\n });\n s.stop();\n success('Installed base dependencies');\n } catch (err) {\n s.stop();\n throw new Error(\n `Failed to install dependencies: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n\n private async cleanViteDefaults(): Promise<void> {\n const s = spinner('Removing default Vite template files...');\n s.start();\n\n for (const file of FILES_TO_REMOVE) {\n const fullPath = path.join(this.config.targetDir, file);\n if (await fs.pathExists(fullPath)) {\n await fs.remove(fullPath);\n debug(`Removed: ${file}`);\n }\n }\n\n const publicPath = path.join(this.config.targetDir, 'public');\n if (await fs.pathExists(publicPath)) {\n await fs.emptyDir(publicPath);\n }\n\n s.stop();\n success('Cleaned default Vite template files');\n }\n\n private async copySharedFiles(): Promise<void> {\n const s = spinner('Copying shared extension files...');\n s.start();\n\n const sharedDir = path.join(this.templatesDir, 'shared');\n\n // Copy shared src files (popup, options, utils, styles)\n const sharedSrcDir = path.join(sharedDir, 'src');\n if (await fs.pathExists(sharedSrcDir)) {\n await fs.copy(sharedSrcDir, path.join(this.config.targetDir, 'src'));\n }\n\n // Copy shared public files (icons)\n const sharedPublicDir = path.join(sharedDir, 'public');\n if (await fs.pathExists(sharedPublicDir)) {\n await fs.copy(sharedPublicDir, path.join(this.config.targetDir, 'public'));\n }\n\n s.stop();\n success('Copied shared extension files');\n }\n\n private async copyBrowserFiles(): Promise<void> {\n const s = spinner(`Copying ${this.config.browser} browser files...`);\n s.start();\n\n const browserDir = path.join(this.templatesDir, this.config.browser);\n\n // Copy browser-specific src files (manifest, background, content)\n const browserSrcDir = path.join(browserDir, 'src');\n if (await fs.pathExists(browserSrcDir)) {\n await fs.copy(browserSrcDir, path.join(this.config.targetDir, 'src'), {\n overwrite: true,\n });\n }\n\n s.stop();\n success(`Copied ${this.config.browser} browser files`);\n }\n\n private async overrideConfigs(): Promise<void> {\n const s = spinner('Overriding config files...');\n s.start();\n\n const browserDir = path.join(this.templatesDir, this.config.browser);\n const viteConfigFrom = path.join(browserDir, 'vite.config.ts');\n const viteConfigTo = path.join(this.config.targetDir, 'vite.config.ts');\n\n if (await fs.pathExists(viteConfigFrom)) {\n await fs.copy(viteConfigFrom, viteConfigTo, { overwrite: true });\n debug('Overrode: vite.config.ts');\n }\n\n s.stop();\n success('Overrode config files');\n }\n\n private async patchTsConfig(): Promise<void> {\n const s = spinner('Patching tsconfig for extension types...');\n s.start();\n\n const tsconfigAppPath = path.join(this.config.targetDir, 'tsconfig.app.json');\n\n if (await fs.pathExists(tsconfigAppPath)) {\n let content = await fs.readFile(tsconfigAppPath, 'utf-8');\n\n // Both Chrome and Firefox use @types/chrome (Firefox MV3 supports chrome.* namespace)\n const typeToAdd = 'chrome';\n\n // Inject the type into the \"types\" array using string replacement\n // This preserves comments and formatting in the JSONC file\n content = content.replace(\n /(\"types\"\\s*:\\s*\\[)([\\s\\S]*?)(\\])/,\n (match, prefix, existing, suffix) => {\n const trimmed = existing.trim();\n if (trimmed.includes(`\"${typeToAdd}\"`)) return match; // already present\n if (trimmed.length === 0) {\n return `${prefix}\"${typeToAdd}\"${suffix}`;\n }\n return `${prefix}${existing.trimEnd()}, \"${typeToAdd}\"${suffix}`;\n },\n );\n\n await fs.writeFile(tsconfigAppPath, content, 'utf-8');\n debug(`Patched tsconfig.app.json with type: ${typeToAdd}`);\n }\n\n s.stop();\n success('Patched tsconfig for extension types');\n }\n\n private async injectProjectName(): Promise<void> {\n const s = spinner('Injecting project name...');\n s.start();\n\n if (this.config.browser === 'chrome') {\n // Chrome uses manifest.ts\n const manifestPath = path.join(this.config.targetDir, 'src', 'manifest.ts');\n if (await fs.pathExists(manifestPath)) {\n let manifest = await fs.readFile(manifestPath, 'utf-8');\n manifest = manifest.replace(/__EXT_NAME__/g, this.config.name);\n await fs.writeFile(manifestPath, manifest, 'utf-8');\n }\n } else if (this.config.browser === 'firefox') {\n // Firefox uses manifest.json\n const manifestPath = path.join(this.config.targetDir, 'src', 'manifest.json');\n if (await fs.pathExists(manifestPath)) {\n let manifest = await fs.readFile(manifestPath, 'utf-8');\n manifest = manifest.replace(/__EXT_NAME__/g, this.config.name);\n await fs.writeFile(manifestPath, manifest, 'utf-8');\n }\n }\n\n // Update package.json name\n const pkgPath = path.join(this.config.targetDir, 'package.json');\n if (await fs.pathExists(pkgPath)) {\n let pkg = await fs.readFile(pkgPath, 'utf-8');\n pkg = pkg.replace(/\"__EXT_NAME__\"/g, `\"${this.config.name}\"`);\n await fs.writeFile(pkgPath, pkg, 'utf-8');\n }\n\n s.stop();\n success('Injected project name');\n }\n\n private async installExtensionDeps(): Promise<void> {\n const deps = this.config.browser === 'firefox' ? FIREFOX_DEV_DEPS : CHROME_DEV_DEPS;\n\n const s = spinner(`Installing ${this.config.browser} extension dev dependencies...`);\n s.start();\n try {\n execSync(`npm install --save-dev ${deps.join(' ')}`, {\n cwd: this.config.targetDir,\n stdio: 'pipe',\n maxBuffer: 10 * 1024 * 1024,\n });\n s.stop();\n success(`Installed ${this.config.browser} extension dev dependencies`);\n } catch (err) {\n s.stop();\n throw new Error(\n `Failed to install extension dependencies: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n }\n}\n","{\n \"name\": \"create-vextro\",\n \"version\": \"0.1.3\",\n \"description\": \"Scaffold modern browser extensions (Chrome, Edge, Firefox) with Vite + React + Tailwind\",\n \"type\": \"module\",\n \"bin\": {\n \"create-vextro\": \"./dist/index.js\"\n },\n \"engines\": {\n \"node\": \">=20.0.0\"\n },\n \"scripts\": {\n \"build\": \"tsup\",\n \"dev\": \"tsup --watch\",\n \"test\": \"vitest run\",\n \"test:watch\": \"vitest\",\n \"lint\": \"eslint src/\",\n \"format\": \"prettier --write .\",\n \"format:check\": \"prettier --check .\",\n \"prepublishOnly\": \"npm run build && npm test\",\n \"typecheck\": \"tsc --noEmit\"\n },\n \"dependencies\": {\n \"chalk\": \"^5.3.0\",\n \"commander\": \"^12.1.0\",\n \"fs-extra\": \"^11.2.0\",\n \"inquirer\": \"^9.2.8\",\n \"ora\": \"^8.0.0\"\n },\n \"devDependencies\": {\n \"@changesets/cli\": \"^2.27.0\",\n \"@types/fs-extra\": \"^11.0.4\",\n \"@types/inquirer\": \"^9.0.7\",\n \"@types/node\": \"^20.0.0\",\n \"eslint\": \"^9.0.0\",\n \"prettier\": \"^3.3.0\",\n \"tsup\": \"^8.0.0\",\n \"typescript\": \"^5.5.0\",\n \"typescript-eslint\": \"^8.0.0\",\n \"vitest\": \"^2.0.0\"\n },\n \"files\": [\n \"dist\",\n \"src/templates\"\n ],\n \"keywords\": [\n \"vite\",\n \"chrome-extension\",\n \"firefox-extension\",\n \"browser-extension\",\n \"vite-plugin\",\n \"react\",\n \"tailwind\",\n \"crxjs\",\n \"manifest-v3\",\n \"scaffold\",\n \"cli\",\n \"generator\",\n \"starter-kit\"\n ],\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"https://github.com/CodeCanvasCollective/vextro.git\"\n },\n \"author\": \"Lasantha <lasanthaslakmal@gmail.com>\",\n \"license\": \"MIT\",\n \"bugs\": {\n \"url\": \"https://github.com/CodeCanvasCollective/vextro/issues\"\n },\n \"homepage\": \"https://github.com/CodeCanvasCollective/vextro#readme\"\n}\n","import { createCli } from './cli.js';\n\nconst program = createCli();\nprogram.parse();\n"],"mappings":"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","names":["Command","path","fs","__filename","__dirname","path","fs","path","fs","path","fs","program","Command"]}
|
package/package.json
CHANGED
|
@@ -53,7 +53,7 @@ export default function App() {
|
|
|
53
53
|
<p className="text-sm text-blue-700">
|
|
54
54
|
This extension was scaffolded with{' '}
|
|
55
55
|
<a
|
|
56
|
-
href="https://github.com/
|
|
56
|
+
href="https://github.com/CodeCanvasCollective/vextro"
|
|
57
57
|
target="_blank"
|
|
58
58
|
rel="noopener noreferrer"
|
|
59
59
|
className="underline"
|