@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 +24 -5
- package/dist/chunk-35T5DDFX.js +88 -0
- package/dist/chunk-Y2M6FMPR.js +87 -0
- package/dist/environment-detector-7AC3BRDB.js +6 -0
- package/dist/environment-detector-SV7DMPWT.js +6 -0
- package/dist/esm-BSZHJOVR.js +792 -0
- package/dist/index.cjs +2410 -244
- package/dist/index.js +1444 -241
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -37,13 +37,23 @@ pnpm build
|
|
|
37
37
|
# or
|
|
38
38
|
yarn build
|
|
39
39
|
|
|
40
|
-
# 2. Then initialize PWA
|
|
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
|
-
|
|
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
|
+
};
|