exportc 0.0.4 → 0.0.6

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.
Files changed (3) hide show
  1. package/README.md +33 -28
  2. package/commands/init.js +90 -37
  3. package/package.json +3 -2
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # exportc
2
2
 
3
- Add [export](https://github.com/ihasq/export) to existing Vite projects.
3
+ Add [export](https://github.com/ihasq/export) to existing Vite projects. One command sets up server-side functions with full TypeScript support.
4
4
 
5
5
  ## Quick Start
6
6
 
@@ -8,9 +8,6 @@ Add [export](https://github.com/ihasq/export) to existing Vite projects.
8
8
  # In your existing Vite project
9
9
  npx exportc init
10
10
 
11
- # Install export dependencies
12
- cd export && npm install && cd ..
13
-
14
11
  # Start development (Wrangler starts automatically!)
15
12
  npm run dev
16
13
 
@@ -18,6 +15,15 @@ npm run dev
18
15
  npm run export
19
16
  ```
20
17
 
18
+ That's it. Dependencies are installed automatically.
19
+
20
+ ## What You Get
21
+
22
+ - **Single command dev** -- `npm run dev` starts both Vite and Wrangler
23
+ - **Auto-generated types** -- TypeScript definitions from your actual code
24
+ - **Workers Sites deploy** -- Static assets + server exports in one deployment
25
+ - **Zero config** -- Production URL auto-detected from package name
26
+
21
27
  ## Usage
22
28
 
23
29
  After initialization, import your server exports using the `export/` prefix:
@@ -34,24 +40,17 @@ await counter.increment(); // 1
34
40
 
35
41
  ## Commands
36
42
 
37
- ### `exportc init`
38
-
39
- Initialize export in your Vite project:
40
- - Creates `export/` directory with example server code
41
- - Updates `vite.config.ts` with the export plugin
42
- - Adds npm scripts for development and deployment
43
-
44
- ### `exportc dev`
45
-
46
- Start the Wrangler development server for your exports.
47
-
48
- ### `exportc deploy`
49
-
50
- Deploy your exports to Cloudflare Workers.
43
+ | Command | Description |
44
+ |---------|-------------|
45
+ | `npm run dev` | Start Vite + Wrangler together, auto-generate types |
46
+ | `npm run export` | Build Vite app and deploy to Workers Sites |
47
+ | `exportc init` | Initialize export in your project |
48
+ | `exportc dev` | Start Wrangler dev server standalone |
49
+ | `exportc deploy` | Deploy exports only |
51
50
 
52
51
  ## Vite Plugin
53
52
 
54
- The `exportPlugin` automatically starts Wrangler and transforms `export/` imports:
53
+ The `exportPlugin` handles everything automatically:
55
54
 
56
55
  ```typescript
57
56
  // vite.config.ts
@@ -67,15 +66,20 @@ export default defineConfig({
67
66
  });
68
67
  ```
69
68
 
70
- **Development** (`npm run dev`):
71
- 1. Automatically starts Wrangler dev server
72
- 2. Waits for it to be ready
73
- 3. Transforms `export/` imports to `http://localhost:8787`
69
+ ### Development (`npm run dev`)
70
+
71
+ 1. Automatically starts Wrangler dev server in the background
72
+ 2. Waits for it to be ready before serving your app
73
+ 3. Generates `export-env.d.ts` with TypeScript declarations
74
+ 4. Watches for changes and regenerates types automatically
75
+ 5. Transforms `export/` imports to `http://localhost:8787`
76
+
77
+ ### Production (`npm run export`)
74
78
 
75
- **Production** (`npm run export`):
76
- 1. Builds Vite app
79
+ 1. Builds your Vite app
77
80
  2. Deploys to Workers Sites (static assets + server exports)
78
81
  3. `export/` imports resolve to `https://{worker-name}.workers.dev`
82
+ 4. Everything runs on Cloudflare's edge network
79
83
 
80
84
  ## Project Structure
81
85
 
@@ -83,11 +87,12 @@ After running `exportc init`:
83
87
 
84
88
  ```
85
89
  my-vite-app/
86
- ├── src/ # Your Vite app
90
+ ├── src/ # Your Vite app (unchanged)
87
91
  ├── export/ # Server exports (Cloudflare Worker)
88
92
  │ ├── index.ts # Your server code
89
- └── package.json # Worker configuration
90
- ├── export-env.d.ts # TypeScript declarations
93
+ ├── package.json # Worker configuration
94
+ │ └── .gitignore # Generated files excluded
95
+ ├── export-env.d.ts # TypeScript declarations (auto-generated)
91
96
  └── vite.config.ts # Updated with exportPlugin
92
97
  ```
93
98
 
package/commands/init.js CHANGED
@@ -3,19 +3,27 @@ import pc from "picocolors";
3
3
  import fs from "node:fs";
4
4
  import path from "node:path";
5
5
  import { fileURLToPath } from "node:url";
6
+ import { execSync } from "node:child_process";
6
7
 
7
8
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
8
9
 
9
10
  export async function init(argv) {
10
11
  const cwd = process.cwd();
12
+ const isNonInteractive = argv.yes || argv.y || process.env.CI === "true";
11
13
 
12
- p.intro(pc.bgCyan(pc.black(" exportc init ")));
14
+ if (!isNonInteractive) {
15
+ p.intro(pc.bgCyan(pc.black(" exportc init ")));
16
+ }
13
17
 
14
18
  // Check for Vite project
15
19
  const viteConfigFiles = ["vite.config.ts", "vite.config.js", "vite.config.mts", "vite.config.mjs"];
16
20
  const viteConfig = viteConfigFiles.find((f) => fs.existsSync(path.join(cwd, f)));
17
21
 
18
22
  if (!viteConfig) {
23
+ if (isNonInteractive) {
24
+ console.error("Error: No Vite config found. exportc currently only supports Vite projects.");
25
+ process.exit(1);
26
+ }
19
27
  p.cancel("No Vite config found. exportc currently only supports Vite projects.");
20
28
  process.exit(1);
21
29
  }
@@ -23,6 +31,10 @@ export async function init(argv) {
23
31
  // Check for package.json
24
32
  const pkgPath = path.join(cwd, "package.json");
25
33
  if (!fs.existsSync(pkgPath)) {
34
+ if (isNonInteractive) {
35
+ console.error("Error: No package.json found.");
36
+ process.exit(1);
37
+ }
26
38
  p.cancel("No package.json found.");
27
39
  process.exit(1);
28
40
  }
@@ -31,7 +43,7 @@ export async function init(argv) {
31
43
 
32
44
  // Check if already initialized
33
45
  const exportDir = path.join(cwd, "export");
34
- if (fs.existsSync(exportDir)) {
46
+ if (fs.existsSync(exportDir) && !isNonInteractive) {
35
47
  const overwrite = await p.confirm({
36
48
  message: "export/ directory already exists. Continue and overwrite?",
37
49
  initialValue: false,
@@ -42,28 +54,40 @@ export async function init(argv) {
42
54
  }
43
55
  }
44
56
 
45
- // Get worker name
46
- const workerName = await p.text({
47
- message: "Worker name:",
48
- placeholder: pkg.name ? `${pkg.name}-api` : "my-api",
49
- defaultValue: pkg.name ? `${pkg.name}-api` : "my-api",
50
- validate: (v) => {
51
- if (!v) return "Worker name is required";
52
- if (!/^[a-z0-9-]+$/.test(v)) return "Use lowercase letters, numbers, and hyphens only";
53
- },
54
- });
57
+ // Get worker name (use default in non-interactive mode)
58
+ const defaultWorkerName = pkg.name ? `${pkg.name}-api` : "my-api";
59
+ let workerName;
60
+
61
+ if (isNonInteractive) {
62
+ workerName = argv.name || defaultWorkerName;
63
+ } else {
64
+ workerName = await p.text({
65
+ message: "Worker name:",
66
+ placeholder: defaultWorkerName,
67
+ defaultValue: defaultWorkerName,
68
+ validate: (v) => {
69
+ if (!v) return "Worker name is required";
70
+ if (!/^[a-z0-9-]+$/.test(v)) return "Use lowercase letters, numbers, and hyphens only";
71
+ },
72
+ });
55
73
 
56
- if (p.isCancel(workerName)) {
57
- p.cancel("Operation cancelled.");
58
- process.exit(0);
74
+ if (p.isCancel(workerName)) {
75
+ p.cancel("Operation cancelled.");
76
+ process.exit(0);
77
+ }
59
78
  }
60
79
 
61
80
  // Check for TypeScript
62
81
  const isTypeScript = viteConfig.endsWith(".ts") || viteConfig.endsWith(".mts") ||
63
82
  fs.existsSync(path.join(cwd, "tsconfig.json"));
64
83
 
65
- const s = p.spinner();
66
- s.start("Initializing export...");
84
+ let s;
85
+ if (!isNonInteractive) {
86
+ s = p.spinner();
87
+ s.start("Initializing export...");
88
+ } else {
89
+ console.log("Initializing export...");
90
+ }
67
91
 
68
92
  // Create export directory
69
93
  if (!fs.existsSync(exportDir)) {
@@ -262,18 +286,22 @@ declare module "export/" {
262
286
  fs.writeFileSync(envDtsPath, envDtsContent);
263
287
  }
264
288
 
265
- // Update tsconfig.json to include the type declarations
289
+ // Update tsconfig to include the type declarations
290
+ // Modern Vite uses tsconfig.app.json for app code, older uses tsconfig.json directly
291
+ const tsconfigAppPath = path.join(cwd, "tsconfig.app.json");
266
292
  const tsconfigPath = path.join(cwd, "tsconfig.json");
267
- if (fs.existsSync(tsconfigPath)) {
293
+ const targetTsconfig = fs.existsSync(tsconfigAppPath) ? tsconfigAppPath : tsconfigPath;
294
+
295
+ if (fs.existsSync(targetTsconfig)) {
268
296
  try {
269
- const tsconfigContent = fs.readFileSync(tsconfigPath, "utf8");
297
+ const tsconfigContent = fs.readFileSync(targetTsconfig, "utf8");
270
298
  const tsconfig = JSON.parse(tsconfigContent);
271
299
 
272
300
  // Add export-env.d.ts to include if not already present
273
301
  tsconfig.include = tsconfig.include || [];
274
302
  if (!tsconfig.include.includes("export-env.d.ts")) {
275
303
  tsconfig.include.push("export-env.d.ts");
276
- fs.writeFileSync(tsconfigPath, JSON.stringify(tsconfig, null, 2) + "\n");
304
+ fs.writeFileSync(targetTsconfig, JSON.stringify(tsconfig, null, 2) + "\n");
277
305
  }
278
306
  } catch {
279
307
  // Ignore JSON parse errors (might have comments)
@@ -281,40 +309,65 @@ declare module "export/" {
281
309
  }
282
310
  }
283
311
 
284
- s.stop("Export initialized!");
312
+ // Install dependencies in export directory
313
+ if (!isNonInteractive) {
314
+ s.stop("Files created!");
315
+ s.start("Installing dependencies...");
316
+ } else {
317
+ console.log("Installing dependencies...");
318
+ }
319
+
320
+ try {
321
+ execSync("npm install", {
322
+ cwd: exportDir,
323
+ stdio: isNonInteractive ? "inherit" : "pipe",
324
+ });
325
+ } catch (err) {
326
+ if (!isNonInteractive) {
327
+ s.stop("Failed to install dependencies");
328
+ p.log.error(`Run ${pc.cyan("cd export && npm install")} manually.`);
329
+ } else {
330
+ console.error("Failed to install dependencies. Run 'cd export && npm install' manually.");
331
+ }
332
+ }
333
+
334
+ if (!isNonInteractive) {
335
+ s.stop("Export initialized!");
285
336
 
286
- const filesCreated = isTypeScript
287
- ? `${pc.cyan("export/")}
337
+ const filesCreated = isTypeScript
338
+ ? `${pc.cyan("export/")}
288
339
  ├── index.${ext} ${pc.dim("# Your server exports")}
289
340
  ├── package.json ${pc.dim("# Worker configuration")}
290
341
  └── .gitignore
291
342
 
292
343
  ${pc.cyan("export-env.d.ts")} ${pc.dim("# Type declarations for export/ imports")}`
293
- : `${pc.cyan("export/")}
344
+ : `${pc.cyan("export/")}
294
345
  ├── index.${ext} ${pc.dim("# Your server exports")}
295
346
  ├── package.json ${pc.dim("# Worker configuration")}
296
347
  └── .gitignore`;
297
348
 
298
- p.note(
299
- `${filesCreated}
349
+ p.note(
350
+ `${filesCreated}
300
351
 
301
352
  ${pc.bold("Next steps:")}
302
353
 
303
- 1. Install export dependencies:
304
- ${pc.cyan("cd export && npm install && cd ..")}
305
-
306
- 2. Start development (Vite + Wrangler auto-start):
354
+ 1. Start development (Vite + Wrangler auto-start):
307
355
  ${pc.cyan("npm run dev")}
308
356
 
309
- 3. Import in your client code:
357
+ 2. Import in your client code:
310
358
  ${pc.cyan(`import { hello } from "export/";`)}
311
359
  ${pc.cyan(`const message = await hello("World");`)}
312
360
 
313
- 4. Deploy to Cloudflare Workers Sites:
361
+ 3. Deploy to Cloudflare Workers Sites:
314
362
  ${pc.cyan("npm run export")}
315
363
  ${pc.dim("# Builds Vite + deploys everything to Workers")}`,
316
- "Created"
317
- );
318
-
319
- p.outro(`Run ${pc.cyan("cd export && npm install")} to get started!`);
364
+ "Ready"
365
+ );
366
+
367
+ p.outro(`Run ${pc.cyan("npm run dev")} to start!`);
368
+ } else {
369
+ console.log("Export initialized successfully!");
370
+ console.log("\nNext steps:");
371
+ console.log(" npm run dev");
372
+ }
320
373
  }
package/package.json CHANGED
@@ -1,9 +1,10 @@
1
1
  {
2
2
  "name": "exportc",
3
- "version": "0.0.4",
3
+ "version": "0.0.6",
4
4
  "description": "CLI to add export to existing projects",
5
5
  "scripts": {
6
- "test": "node --test test/*.test.mjs"
6
+ "test": "node --test test/init.test.mjs",
7
+ "test:e2e": "node --test test/e2e.test.mjs"
7
8
  },
8
9
  "keywords": [
9
10
  "cloudflare",