@julien-lin/universal-pwa-cli 1.3.1 → 1.3.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 CHANGED
@@ -37,13 +37,23 @@ pnpm build
37
37
  # or
38
38
  yarn build
39
39
 
40
- # 2. Then initialize PWA (CLI will auto-detect dist/ directory)
40
+ # 2. Then initialize PWA
41
+ # In interactive mode, select "Production" when prompted
42
+ # The CLI will auto-detect dist/ directory and suggest it
43
+ universal-pwa init
44
+
45
+ # Or explicitly specify output directory
41
46
  universal-pwa init --output-dir dist
42
47
  ```
43
48
 
44
49
  **Why?** The service worker needs to precache all your built assets (JS/CSS with hashes). If you initialize before building, the service worker won't know about the hashed filenames.
45
50
 
46
- The CLI automatically detects `dist/` directory for React/Vite projects if it exists. You can also explicitly specify it with `--output-dir dist`.
51
+ **Environment Detection:**
52
+ - The CLI automatically detects your environment:
53
+ - **Production**: If `dist/` or `build/` exists with recent files (< 24h)
54
+ - **Local**: Otherwise, defaults to `public/`
55
+ - Detection indicators are displayed during interactive prompts
56
+ - You can override the detection by explicitly choosing Local or Production
47
57
 
48
58
  #### Interactive Mode (Recommended)
49
59
 
@@ -53,13 +63,22 @@ Simply run without arguments to launch interactive prompts:
53
63
  universal-pwa init
54
64
  ```
55
65
 
56
- The CLI will guide you through:
66
+ The CLI will guide you through a 2-phase workflow:
67
+
68
+ **Phase 1: Environment Selection**
69
+ - Choose between **Local** (development) or **Production** (build)
70
+ - The CLI automatically detects your environment based on the presence of `dist/` or `build/` directories
71
+ - Displays detection indicators (e.g., "dist/ directory exists with 15 built files")
72
+
73
+ **Phase 2: Application Configuration**
57
74
  - App name (auto-detected from `package.json`)
58
- - Short name (max 12 characters)
75
+ - Short name (max 12 characters, auto-generated from app name)
59
76
  - Icon source path (auto-detected from common locations)
60
- - Theme and background colors
77
+ - Theme and background colors (suggested based on detected framework)
61
78
  - Icon generation options
62
79
 
80
+ All prompts include smart defaults, validation, and contextual suggestions!
81
+
63
82
  #### Command Line Mode
64
83
 
65
84
  ```bash
@@ -0,0 +1,88 @@
1
+ // src/utils/environment-detector.ts
2
+ import { existsSync, statSync } from "fs";
3
+ import { join } from "path";
4
+ import { glob } from "glob";
5
+ function detectEnvironment(projectPath, framework) {
6
+ const indicators = [];
7
+ let environment = "local";
8
+ let confidence = "low";
9
+ let suggestedOutputDir = "public";
10
+ const distDir = join(projectPath, "dist");
11
+ const publicDir = join(projectPath, "public");
12
+ const buildDir = join(projectPath, "build");
13
+ if (existsSync(distDir)) {
14
+ try {
15
+ const distFiles = glob.sync("**/*.{js,css,html}", {
16
+ cwd: distDir,
17
+ absolute: false,
18
+ maxDepth: 2
19
+ });
20
+ if (distFiles.length > 0) {
21
+ indicators.push(`dist/ directory exists with ${distFiles.length} built files`);
22
+ const recentFiles = distFiles.filter((file) => {
23
+ try {
24
+ const filePath = join(distDir, file);
25
+ const stats = statSync(filePath);
26
+ const ageInHours = (Date.now() - stats.mtimeMs) / (1e3 * 60 * 60);
27
+ return ageInHours < 24;
28
+ } catch {
29
+ return false;
30
+ }
31
+ });
32
+ if (recentFiles.length > 0) {
33
+ indicators.push(`${recentFiles.length} recent files in dist/ (last 24h)`);
34
+ environment = "production";
35
+ confidence = "high";
36
+ suggestedOutputDir = "dist";
37
+ } else {
38
+ indicators.push("dist/ exists but files are old (may be stale)");
39
+ environment = "production";
40
+ confidence = "medium";
41
+ suggestedOutputDir = "dist";
42
+ }
43
+ } else {
44
+ indicators.push("dist/ directory exists but is empty");
45
+ }
46
+ } catch {
47
+ }
48
+ }
49
+ if (existsSync(buildDir) && environment === "local") {
50
+ try {
51
+ const buildFiles = glob.sync("**/*.{js,css,html}", {
52
+ cwd: buildDir,
53
+ absolute: false,
54
+ maxDepth: 2
55
+ });
56
+ if (buildFiles.length > 0) {
57
+ indicators.push(`build/ directory exists with ${buildFiles.length} built files`);
58
+ environment = "production";
59
+ confidence = "high";
60
+ suggestedOutputDir = "build";
61
+ }
62
+ } catch {
63
+ }
64
+ }
65
+ if ((framework === "React" || framework === "Vite") && existsSync(distDir)) {
66
+ if (environment === "local") {
67
+ environment = "production";
68
+ confidence = "medium";
69
+ suggestedOutputDir = "dist";
70
+ indicators.push("React/Vite project with dist/ directory (likely production)");
71
+ }
72
+ }
73
+ if (environment === "local" && indicators.length === 0) {
74
+ indicators.push("No production build detected, using local mode");
75
+ confidence = "medium";
76
+ suggestedOutputDir = "public";
77
+ }
78
+ return {
79
+ environment,
80
+ confidence,
81
+ indicators,
82
+ suggestedOutputDir
83
+ };
84
+ }
85
+
86
+ export {
87
+ detectEnvironment
88
+ };
@@ -0,0 +1,87 @@
1
+ // src/utils/environment-detector.ts
2
+ import { existsSync, statSync } from "fs";
3
+ import { join } from "path";
4
+ import { glob } from "glob";
5
+ function detectEnvironment(projectPath, framework) {
6
+ const indicators = [];
7
+ let environment = "local";
8
+ let confidence = "low";
9
+ let suggestedOutputDir = "public";
10
+ const distDir = join(projectPath, "dist");
11
+ const buildDir = join(projectPath, "build");
12
+ if (existsSync(distDir)) {
13
+ try {
14
+ const distFiles = glob.sync("**/*.{js,css,html}", {
15
+ cwd: distDir,
16
+ absolute: false,
17
+ maxDepth: 2
18
+ });
19
+ if (distFiles.length > 0) {
20
+ indicators.push(`dist/ directory exists with ${distFiles.length} built files`);
21
+ const recentFiles = distFiles.filter((file) => {
22
+ try {
23
+ const filePath = join(distDir, file);
24
+ const stats = statSync(filePath);
25
+ const ageInHours = (Date.now() - stats.mtimeMs) / (1e3 * 60 * 60);
26
+ return ageInHours < 24;
27
+ } catch {
28
+ return false;
29
+ }
30
+ });
31
+ if (recentFiles.length > 0) {
32
+ indicators.push(`${recentFiles.length} recent files in dist/ (last 24h)`);
33
+ environment = "production";
34
+ confidence = "high";
35
+ suggestedOutputDir = "dist";
36
+ } else {
37
+ indicators.push("dist/ exists but files are old (may be stale)");
38
+ environment = "production";
39
+ confidence = "medium";
40
+ suggestedOutputDir = "dist";
41
+ }
42
+ } else {
43
+ indicators.push("dist/ directory exists but is empty");
44
+ }
45
+ } catch {
46
+ }
47
+ }
48
+ if (existsSync(buildDir) && environment === "local") {
49
+ try {
50
+ const buildFiles = glob.sync("**/*.{js,css,html}", {
51
+ cwd: buildDir,
52
+ absolute: false,
53
+ maxDepth: 2
54
+ });
55
+ if (buildFiles.length > 0) {
56
+ indicators.push(`build/ directory exists with ${buildFiles.length} built files`);
57
+ environment = "production";
58
+ confidence = "high";
59
+ suggestedOutputDir = "build";
60
+ }
61
+ } catch {
62
+ }
63
+ }
64
+ if ((framework === "React" || framework === "Vite") && existsSync(distDir)) {
65
+ if (environment === "local") {
66
+ environment = "production";
67
+ confidence = "medium";
68
+ suggestedOutputDir = "dist";
69
+ indicators.push("React/Vite project with dist/ directory (likely production)");
70
+ }
71
+ }
72
+ if (environment === "local" && indicators.length === 0) {
73
+ indicators.push("No production build detected, using local mode");
74
+ confidence = "medium";
75
+ suggestedOutputDir = "public";
76
+ }
77
+ return {
78
+ environment,
79
+ confidence,
80
+ indicators,
81
+ suggestedOutputDir
82
+ };
83
+ }
84
+
85
+ export {
86
+ detectEnvironment
87
+ };
@@ -0,0 +1,6 @@
1
+ import {
2
+ detectEnvironment
3
+ } from "./chunk-Y2M6FMPR.js";
4
+ export {
5
+ detectEnvironment
6
+ };
@@ -0,0 +1,6 @@
1
+ import {
2
+ detectEnvironment
3
+ } from "./chunk-35T5DDFX.js";
4
+ export {
5
+ detectEnvironment
6
+ };