@julien-lin/universal-pwa-cli 1.1.0 → 1.1.2
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/dist/index.cjs +60 -10
- package/dist/index.js +59 -10
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -26,6 +26,9 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
26
26
|
// src/index.ts
|
|
27
27
|
var import_commander = require("commander");
|
|
28
28
|
var import_chalk3 = __toESM(require("chalk"), 1);
|
|
29
|
+
var import_fs3 = require("fs");
|
|
30
|
+
var import_url = require("url");
|
|
31
|
+
var import_path3 = require("path");
|
|
29
32
|
|
|
30
33
|
// src/commands/init.ts
|
|
31
34
|
var import_universal_pwa_core = require("@julien-lin/universal-pwa-core");
|
|
@@ -93,7 +96,7 @@ async function initCommand(options = {}) {
|
|
|
93
96
|
const finalOutputDir = outputDir ?? (result.framework === "WordPress" ? (0, import_path.join)(result.projectPath, "public") : (0, import_path.join)(result.projectPath, "public"));
|
|
94
97
|
console.log(import_chalk.default.blue("\u{1F4DD} Generating manifest.json..."));
|
|
95
98
|
const appName = name ?? (result.framework ? `${result.framework} App` : "My PWA");
|
|
96
|
-
const appShortName = shortName
|
|
99
|
+
const appShortName = shortName && shortName.length > 0 && shortName.length <= 12 ? shortName : appName.substring(0, 12);
|
|
97
100
|
let iconPaths = [];
|
|
98
101
|
if (!skipIcons && iconSource) {
|
|
99
102
|
const iconSourcePath = (0, import_fs.existsSync)(iconSource) ? iconSource : (0, import_path.join)(result.projectPath, iconSource);
|
|
@@ -106,7 +109,14 @@ async function initCommand(options = {}) {
|
|
|
106
109
|
});
|
|
107
110
|
iconPaths = iconResult.icons.map((icon) => icon.src);
|
|
108
111
|
result.iconsGenerated = iconResult.icons.length;
|
|
112
|
+
const appleTouchIconPath = (0, import_path.join)(finalOutputDir, "apple-touch-icon.png");
|
|
113
|
+
if ((0, import_fs.existsSync)(appleTouchIconPath)) {
|
|
114
|
+
iconPaths.push("/apple-touch-icon.png");
|
|
115
|
+
}
|
|
109
116
|
console.log(import_chalk.default.green(`\u2713 Generated ${result.iconsGenerated} icons`));
|
|
117
|
+
if ((0, import_fs.existsSync)(appleTouchIconPath)) {
|
|
118
|
+
console.log(import_chalk.default.green(`\u2713 Generated apple-touch-icon.png`));
|
|
119
|
+
}
|
|
110
120
|
} catch (error) {
|
|
111
121
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
112
122
|
result.errors.push(`Failed to generate icons: ${errorMessage}`);
|
|
@@ -116,6 +126,7 @@ async function initCommand(options = {}) {
|
|
|
116
126
|
result.warnings.push(`Icon source not found: ${iconSourcePath}`);
|
|
117
127
|
}
|
|
118
128
|
}
|
|
129
|
+
let manifestPath;
|
|
119
130
|
if (iconPaths.length > 0) {
|
|
120
131
|
const manifestWithIcons = (0, import_universal_pwa_core2.generateManifest)({
|
|
121
132
|
name: appName,
|
|
@@ -131,11 +142,30 @@ async function initCommand(options = {}) {
|
|
|
131
142
|
type: "image/png"
|
|
132
143
|
}))
|
|
133
144
|
});
|
|
134
|
-
|
|
145
|
+
manifestPath = (0, import_universal_pwa_core2.generateAndWriteManifest)(manifestWithIcons, finalOutputDir);
|
|
135
146
|
result.manifestPath = manifestPath;
|
|
147
|
+
console.log(import_chalk.default.green(`\u2713 Manifest generated: ${manifestPath}`));
|
|
136
148
|
} else {
|
|
137
|
-
result.warnings.push("No icons provided. Manifest
|
|
138
|
-
console.log(import_chalk.default.yellow("\u26A0
|
|
149
|
+
result.warnings.push("No icons provided. Manifest generated with placeholder icon. Please provide an icon source with --icon-source for production.");
|
|
150
|
+
console.log(import_chalk.default.yellow("\u26A0 Generating manifest with placeholder icon"));
|
|
151
|
+
const manifestMinimal = (0, import_universal_pwa_core2.generateManifest)({
|
|
152
|
+
name: appName,
|
|
153
|
+
shortName: appShortName,
|
|
154
|
+
startUrl: "/",
|
|
155
|
+
scope: "/",
|
|
156
|
+
display: "standalone",
|
|
157
|
+
themeColor: themeColor ?? "#ffffff",
|
|
158
|
+
backgroundColor: backgroundColor ?? "#000000",
|
|
159
|
+
icons: [{
|
|
160
|
+
src: "/icon-192x192.png",
|
|
161
|
+
// Placeholder - l'utilisateur devra ajouter une vraie icône
|
|
162
|
+
sizes: "192x192",
|
|
163
|
+
type: "image/png"
|
|
164
|
+
}]
|
|
165
|
+
});
|
|
166
|
+
manifestPath = (0, import_universal_pwa_core2.generateAndWriteManifest)(manifestMinimal, finalOutputDir);
|
|
167
|
+
result.manifestPath = manifestPath;
|
|
168
|
+
console.log(import_chalk.default.green(`\u2713 Manifest generated: ${manifestPath}`));
|
|
139
169
|
}
|
|
140
170
|
if (!skipServiceWorker) {
|
|
141
171
|
console.log(import_chalk.default.blue("\u2699\uFE0F Generating service worker..."));
|
|
@@ -168,22 +198,30 @@ async function initCommand(options = {}) {
|
|
|
168
198
|
let injectedCount = 0;
|
|
169
199
|
for (const htmlFile of htmlFiles.slice(0, 10)) {
|
|
170
200
|
try {
|
|
171
|
-
const normalizePathForInjection = (fullPath, basePath, fallback) => {
|
|
201
|
+
const normalizePathForInjection = (fullPath, basePath, outputDir2, fallback) => {
|
|
172
202
|
if (!fullPath) return fallback;
|
|
173
203
|
try {
|
|
174
204
|
const rel = relativePath(fullPath, basePath);
|
|
175
|
-
|
|
205
|
+
let normalized = rel.startsWith("/") ? rel : `/${rel}`;
|
|
206
|
+
const outputDirName = outputDir2.replace(basePath, "").replace(/^\/+|\/+$/g, "");
|
|
207
|
+
if (outputDirName && normalized.startsWith(`/${outputDirName}/`)) {
|
|
208
|
+
normalized = normalized.replace(`/${outputDirName}/`, "/");
|
|
209
|
+
}
|
|
210
|
+
return normalized;
|
|
176
211
|
} catch {
|
|
177
212
|
return fallback;
|
|
178
213
|
}
|
|
179
214
|
};
|
|
215
|
+
const appleTouchIconFullPath = (0, import_path.join)(finalOutputDir, "apple-touch-icon.png");
|
|
216
|
+
const appleTouchIconExists = (0, import_fs.existsSync)(appleTouchIconFullPath);
|
|
180
217
|
const injectionResult = (0, import_universal_pwa_core5.injectMetaTagsInFile)(htmlFile, {
|
|
181
|
-
manifestPath: normalizePathForInjection(result.manifestPath, result.projectPath, "/manifest.json"),
|
|
218
|
+
manifestPath: normalizePathForInjection(result.manifestPath, result.projectPath, finalOutputDir, "/manifest.json"),
|
|
182
219
|
themeColor: themeColor ?? "#ffffff",
|
|
183
220
|
backgroundColor: backgroundColor ?? "#000000",
|
|
184
|
-
appleTouchIcon:
|
|
221
|
+
appleTouchIcon: appleTouchIconExists ? normalizePathForInjection(appleTouchIconFullPath, result.projectPath, finalOutputDir, "/apple-touch-icon.png") : "/apple-touch-icon.png",
|
|
222
|
+
// Placeholder si non généré
|
|
185
223
|
appleMobileWebAppCapable: true,
|
|
186
|
-
serviceWorkerPath: normalizePathForInjection(result.serviceWorkerPath, result.projectPath, "/sw.js")
|
|
224
|
+
serviceWorkerPath: normalizePathForInjection(result.serviceWorkerPath, result.projectPath, finalOutputDir, "/sw.js")
|
|
187
225
|
});
|
|
188
226
|
if (injectionResult.injected.length > 0) {
|
|
189
227
|
injectedCount++;
|
|
@@ -290,8 +328,20 @@ function previewCommand(options = {}) {
|
|
|
290
328
|
|
|
291
329
|
// src/index.ts
|
|
292
330
|
var import_universal_pwa_core8 = require("@julien-lin/universal-pwa-core");
|
|
331
|
+
var import_meta = {};
|
|
332
|
+
var __filename = (0, import_url.fileURLToPath)(import_meta.url);
|
|
333
|
+
var __dirname = (0, import_path3.dirname)(__filename);
|
|
334
|
+
var packageJsonPath = (0, import_path3.join)(__dirname, "../package.json");
|
|
335
|
+
var version = "0.0.0";
|
|
336
|
+
try {
|
|
337
|
+
const packageJsonContent = (0, import_fs3.readFileSync)(packageJsonPath, "utf-8");
|
|
338
|
+
const packageJson = JSON.parse(packageJsonContent);
|
|
339
|
+
version = packageJson.version || "0.0.0";
|
|
340
|
+
} catch {
|
|
341
|
+
version = "0.0.0";
|
|
342
|
+
}
|
|
293
343
|
var program = new import_commander.Command();
|
|
294
|
-
program.name("universal-pwa").description("Transform any web project into a PWA with one click").version(
|
|
344
|
+
program.name("universal-pwa").description("Transform any web project into a PWA with one click").version(version);
|
|
295
345
|
program.command("init").description("Initialize PWA in your project").option("-p, --project-path <path>", "Project path", process.cwd()).option("-n, --name <name>", "App name").option("-s, --short-name <shortName>", "App short name (max 12 chars)").option("-i, --icon-source <path>", "Source image for icons").option("-t, --theme-color <color>", "Theme color (hex)").option("-b, --background-color <color>", "Background color (hex)").option("--skip-icons", "Skip icon generation").option("--skip-service-worker", "Skip service worker generation").option("--skip-injection", "Skip HTML meta-tag injection").option("-o, --output-dir <dir>", "Output directory", "public").action(async (options) => {
|
|
296
346
|
try {
|
|
297
347
|
const result = await initCommand({
|
package/dist/index.js
CHANGED
|
@@ -3,6 +3,9 @@
|
|
|
3
3
|
// src/index.ts
|
|
4
4
|
import { Command } from "commander";
|
|
5
5
|
import chalk3 from "chalk";
|
|
6
|
+
import { readFileSync } from "fs";
|
|
7
|
+
import { fileURLToPath } from "url";
|
|
8
|
+
import { dirname, join as join3 } from "path";
|
|
6
9
|
|
|
7
10
|
// src/commands/init.ts
|
|
8
11
|
import { scanProject } from "@julien-lin/universal-pwa-core";
|
|
@@ -70,7 +73,7 @@ async function initCommand(options = {}) {
|
|
|
70
73
|
const finalOutputDir = outputDir ?? (result.framework === "WordPress" ? join(result.projectPath, "public") : join(result.projectPath, "public"));
|
|
71
74
|
console.log(chalk.blue("\u{1F4DD} Generating manifest.json..."));
|
|
72
75
|
const appName = name ?? (result.framework ? `${result.framework} App` : "My PWA");
|
|
73
|
-
const appShortName = shortName
|
|
76
|
+
const appShortName = shortName && shortName.length > 0 && shortName.length <= 12 ? shortName : appName.substring(0, 12);
|
|
74
77
|
let iconPaths = [];
|
|
75
78
|
if (!skipIcons && iconSource) {
|
|
76
79
|
const iconSourcePath = existsSync(iconSource) ? iconSource : join(result.projectPath, iconSource);
|
|
@@ -83,7 +86,14 @@ async function initCommand(options = {}) {
|
|
|
83
86
|
});
|
|
84
87
|
iconPaths = iconResult.icons.map((icon) => icon.src);
|
|
85
88
|
result.iconsGenerated = iconResult.icons.length;
|
|
89
|
+
const appleTouchIconPath = join(finalOutputDir, "apple-touch-icon.png");
|
|
90
|
+
if (existsSync(appleTouchIconPath)) {
|
|
91
|
+
iconPaths.push("/apple-touch-icon.png");
|
|
92
|
+
}
|
|
86
93
|
console.log(chalk.green(`\u2713 Generated ${result.iconsGenerated} icons`));
|
|
94
|
+
if (existsSync(appleTouchIconPath)) {
|
|
95
|
+
console.log(chalk.green(`\u2713 Generated apple-touch-icon.png`));
|
|
96
|
+
}
|
|
87
97
|
} catch (error) {
|
|
88
98
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
89
99
|
result.errors.push(`Failed to generate icons: ${errorMessage}`);
|
|
@@ -93,6 +103,7 @@ async function initCommand(options = {}) {
|
|
|
93
103
|
result.warnings.push(`Icon source not found: ${iconSourcePath}`);
|
|
94
104
|
}
|
|
95
105
|
}
|
|
106
|
+
let manifestPath;
|
|
96
107
|
if (iconPaths.length > 0) {
|
|
97
108
|
const manifestWithIcons = generateManifest({
|
|
98
109
|
name: appName,
|
|
@@ -108,11 +119,30 @@ async function initCommand(options = {}) {
|
|
|
108
119
|
type: "image/png"
|
|
109
120
|
}))
|
|
110
121
|
});
|
|
111
|
-
|
|
122
|
+
manifestPath = generateAndWriteManifest(manifestWithIcons, finalOutputDir);
|
|
112
123
|
result.manifestPath = manifestPath;
|
|
124
|
+
console.log(chalk.green(`\u2713 Manifest generated: ${manifestPath}`));
|
|
113
125
|
} else {
|
|
114
|
-
result.warnings.push("No icons provided. Manifest
|
|
115
|
-
console.log(chalk.yellow("\u26A0
|
|
126
|
+
result.warnings.push("No icons provided. Manifest generated with placeholder icon. Please provide an icon source with --icon-source for production.");
|
|
127
|
+
console.log(chalk.yellow("\u26A0 Generating manifest with placeholder icon"));
|
|
128
|
+
const manifestMinimal = generateManifest({
|
|
129
|
+
name: appName,
|
|
130
|
+
shortName: appShortName,
|
|
131
|
+
startUrl: "/",
|
|
132
|
+
scope: "/",
|
|
133
|
+
display: "standalone",
|
|
134
|
+
themeColor: themeColor ?? "#ffffff",
|
|
135
|
+
backgroundColor: backgroundColor ?? "#000000",
|
|
136
|
+
icons: [{
|
|
137
|
+
src: "/icon-192x192.png",
|
|
138
|
+
// Placeholder - l'utilisateur devra ajouter une vraie icône
|
|
139
|
+
sizes: "192x192",
|
|
140
|
+
type: "image/png"
|
|
141
|
+
}]
|
|
142
|
+
});
|
|
143
|
+
manifestPath = generateAndWriteManifest(manifestMinimal, finalOutputDir);
|
|
144
|
+
result.manifestPath = manifestPath;
|
|
145
|
+
console.log(chalk.green(`\u2713 Manifest generated: ${manifestPath}`));
|
|
116
146
|
}
|
|
117
147
|
if (!skipServiceWorker) {
|
|
118
148
|
console.log(chalk.blue("\u2699\uFE0F Generating service worker..."));
|
|
@@ -145,22 +175,30 @@ async function initCommand(options = {}) {
|
|
|
145
175
|
let injectedCount = 0;
|
|
146
176
|
for (const htmlFile of htmlFiles.slice(0, 10)) {
|
|
147
177
|
try {
|
|
148
|
-
const normalizePathForInjection = (fullPath, basePath, fallback) => {
|
|
178
|
+
const normalizePathForInjection = (fullPath, basePath, outputDir2, fallback) => {
|
|
149
179
|
if (!fullPath) return fallback;
|
|
150
180
|
try {
|
|
151
181
|
const rel = relativePath(fullPath, basePath);
|
|
152
|
-
|
|
182
|
+
let normalized = rel.startsWith("/") ? rel : `/${rel}`;
|
|
183
|
+
const outputDirName = outputDir2.replace(basePath, "").replace(/^\/+|\/+$/g, "");
|
|
184
|
+
if (outputDirName && normalized.startsWith(`/${outputDirName}/`)) {
|
|
185
|
+
normalized = normalized.replace(`/${outputDirName}/`, "/");
|
|
186
|
+
}
|
|
187
|
+
return normalized;
|
|
153
188
|
} catch {
|
|
154
189
|
return fallback;
|
|
155
190
|
}
|
|
156
191
|
};
|
|
192
|
+
const appleTouchIconFullPath = join(finalOutputDir, "apple-touch-icon.png");
|
|
193
|
+
const appleTouchIconExists = existsSync(appleTouchIconFullPath);
|
|
157
194
|
const injectionResult = injectMetaTagsInFile(htmlFile, {
|
|
158
|
-
manifestPath: normalizePathForInjection(result.manifestPath, result.projectPath, "/manifest.json"),
|
|
195
|
+
manifestPath: normalizePathForInjection(result.manifestPath, result.projectPath, finalOutputDir, "/manifest.json"),
|
|
159
196
|
themeColor: themeColor ?? "#ffffff",
|
|
160
197
|
backgroundColor: backgroundColor ?? "#000000",
|
|
161
|
-
appleTouchIcon:
|
|
198
|
+
appleTouchIcon: appleTouchIconExists ? normalizePathForInjection(appleTouchIconFullPath, result.projectPath, finalOutputDir, "/apple-touch-icon.png") : "/apple-touch-icon.png",
|
|
199
|
+
// Placeholder si non généré
|
|
162
200
|
appleMobileWebAppCapable: true,
|
|
163
|
-
serviceWorkerPath: normalizePathForInjection(result.serviceWorkerPath, result.projectPath, "/sw.js")
|
|
201
|
+
serviceWorkerPath: normalizePathForInjection(result.serviceWorkerPath, result.projectPath, finalOutputDir, "/sw.js")
|
|
164
202
|
});
|
|
165
203
|
if (injectionResult.injected.length > 0) {
|
|
166
204
|
injectedCount++;
|
|
@@ -267,8 +305,19 @@ function previewCommand(options = {}) {
|
|
|
267
305
|
|
|
268
306
|
// src/index.ts
|
|
269
307
|
import { scanProject as scanProject2 } from "@julien-lin/universal-pwa-core";
|
|
308
|
+
var __filename = fileURLToPath(import.meta.url);
|
|
309
|
+
var __dirname = dirname(__filename);
|
|
310
|
+
var packageJsonPath = join3(__dirname, "../package.json");
|
|
311
|
+
var version = "0.0.0";
|
|
312
|
+
try {
|
|
313
|
+
const packageJsonContent = readFileSync(packageJsonPath, "utf-8");
|
|
314
|
+
const packageJson = JSON.parse(packageJsonContent);
|
|
315
|
+
version = packageJson.version || "0.0.0";
|
|
316
|
+
} catch {
|
|
317
|
+
version = "0.0.0";
|
|
318
|
+
}
|
|
270
319
|
var program = new Command();
|
|
271
|
-
program.name("universal-pwa").description("Transform any web project into a PWA with one click").version(
|
|
320
|
+
program.name("universal-pwa").description("Transform any web project into a PWA with one click").version(version);
|
|
272
321
|
program.command("init").description("Initialize PWA in your project").option("-p, --project-path <path>", "Project path", process.cwd()).option("-n, --name <name>", "App name").option("-s, --short-name <shortName>", "App short name (max 12 chars)").option("-i, --icon-source <path>", "Source image for icons").option("-t, --theme-color <color>", "Theme color (hex)").option("-b, --background-color <color>", "Background color (hex)").option("--skip-icons", "Skip icon generation").option("--skip-service-worker", "Skip service worker generation").option("--skip-injection", "Skip HTML meta-tag injection").option("-o, --output-dir <dir>", "Output directory", "public").action(async (options) => {
|
|
273
322
|
try {
|
|
274
323
|
const result = await initCommand({
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@julien-lin/universal-pwa-cli",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.2",
|
|
4
4
|
"description": "CLI pour transformer n'importe quel projet web en PWA",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pwa",
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
"glob": "^13.0.0",
|
|
45
45
|
"pino": "^9.14.0",
|
|
46
46
|
"zod": "^4.2.1",
|
|
47
|
-
"@julien-lin/universal-pwa-core": "^1.1.
|
|
47
|
+
"@julien-lin/universal-pwa-core": "^1.1.2"
|
|
48
48
|
},
|
|
49
49
|
"devDependencies": {
|
|
50
50
|
"@vitest/coverage-v8": "^2.1.4",
|