@iselect/select 1.0.0 → 1.0.1
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/bin/select.js +4 -1
- package/lib/commands/build.js +246 -3
- package/lib/commands/deploy.js +3 -3
- package/package.json +1 -1
package/bin/select.js
CHANGED
|
@@ -33,7 +33,7 @@ program
|
|
|
33
33
|
.option('-t, --template <template>', 'Project template (react, vue, vanilla)', 'react')
|
|
34
34
|
.action(init);
|
|
35
35
|
|
|
36
|
-
// select - Interactive platform selection
|
|
36
|
+
// slct select - Interactive platform selection
|
|
37
37
|
program
|
|
38
38
|
.command('select')
|
|
39
39
|
.alias('s')
|
|
@@ -47,6 +47,8 @@ program
|
|
|
47
47
|
.option('--tauri', 'Use Tauri for desktop (default)')
|
|
48
48
|
.option('--electron', 'Use Electron for desktop')
|
|
49
49
|
.option('--release', 'Build for production release')
|
|
50
|
+
.option('--static', 'Copy files directly without bundling (vanilla HTML/CSS/JS)')
|
|
51
|
+
.option('--inline', 'Inline CSS and JS into a single HTML file')
|
|
50
52
|
.action(build);
|
|
51
53
|
|
|
52
54
|
// slct deploy - Deploy to Select marketplace
|
|
@@ -65,3 +67,4 @@ program
|
|
|
65
67
|
|
|
66
68
|
// Parse arguments
|
|
67
69
|
program.parse();
|
|
70
|
+
|
package/lib/commands/build.js
CHANGED
|
@@ -55,25 +55,268 @@ async function build(target, options) {
|
|
|
55
55
|
}
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
+
// ==================== PROJECT TYPE DETECTION ====================
|
|
59
|
+
async function detectProjectType(projectPath) {
|
|
60
|
+
const hasPackageJson = await fs.pathExists(path.join(projectPath, 'package.json'));
|
|
61
|
+
const hasViteConfig = await fs.pathExists(path.join(projectPath, 'vite.config.js')) ||
|
|
62
|
+
await fs.pathExists(path.join(projectPath, 'vite.config.ts'));
|
|
63
|
+
const hasIndexHtml = await fs.pathExists(path.join(projectPath, 'index.html'));
|
|
64
|
+
const hasSrcMain = await fs.pathExists(path.join(projectPath, 'src', 'main.js')) ||
|
|
65
|
+
await fs.pathExists(path.join(projectPath, 'src', 'main.jsx')) ||
|
|
66
|
+
await fs.pathExists(path.join(projectPath, 'src', 'main.ts')) ||
|
|
67
|
+
await fs.pathExists(path.join(projectPath, 'src', 'main.tsx'));
|
|
68
|
+
|
|
69
|
+
// Check if package.json has a build script
|
|
70
|
+
let hasBuildScript = false;
|
|
71
|
+
if (hasPackageJson) {
|
|
72
|
+
try {
|
|
73
|
+
const pkg = await fs.readJson(path.join(projectPath, 'package.json'));
|
|
74
|
+
hasBuildScript = !!(pkg.scripts && pkg.scripts.build);
|
|
75
|
+
} catch { }
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Static site: has index.html but no package.json or no build script
|
|
79
|
+
if (hasIndexHtml && (!hasPackageJson || !hasBuildScript)) {
|
|
80
|
+
return 'static';
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Vite project
|
|
84
|
+
if (hasViteConfig) {
|
|
85
|
+
return 'vite';
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Has package.json with build script
|
|
89
|
+
if (hasPackageJson && hasBuildScript) {
|
|
90
|
+
return 'bundled';
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Default to static if just has HTML
|
|
94
|
+
if (hasIndexHtml) {
|
|
95
|
+
return 'static';
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return 'unknown';
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// ==================== INLINE BUILD ====================
|
|
102
|
+
async function buildInline(projectPath, outputDir) {
|
|
103
|
+
const spinner = ora('Building inline HTML...').start();
|
|
104
|
+
|
|
105
|
+
// Ensure output dir exists
|
|
106
|
+
await fs.ensureDir(outputDir);
|
|
107
|
+
|
|
108
|
+
// Read index.html
|
|
109
|
+
const indexPath = path.join(projectPath, 'index.html');
|
|
110
|
+
if (!await fs.pathExists(indexPath)) {
|
|
111
|
+
spinner.fail('No index.html found');
|
|
112
|
+
throw new Error('index.html not found in project root');
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
let html = await fs.readFile(indexPath, 'utf8');
|
|
116
|
+
|
|
117
|
+
// Inline CSS files
|
|
118
|
+
const cssLinkRegex = /<link[^>]+rel=["']stylesheet["'][^>]+href=["']([^"']+)["'][^>]*>/gi;
|
|
119
|
+
const cssLinks = [];
|
|
120
|
+
let match;
|
|
121
|
+
while ((match = cssLinkRegex.exec(html)) !== null) {
|
|
122
|
+
cssLinks.push({ full: match[0], href: match[1] });
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
for (const link of cssLinks) {
|
|
126
|
+
const cssPath = path.join(projectPath, link.href);
|
|
127
|
+
if (await fs.pathExists(cssPath)) {
|
|
128
|
+
const cssContent = await fs.readFile(cssPath, 'utf8');
|
|
129
|
+
html = html.replace(link.full, `<style>\n${cssContent}\n</style>`);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Inline JS files
|
|
134
|
+
const jsScriptRegex = /<script[^>]+src=["']([^"']+)["'][^>]*><\/script>/gi;
|
|
135
|
+
const jsScripts = [];
|
|
136
|
+
while ((match = jsScriptRegex.exec(html)) !== null) {
|
|
137
|
+
jsScripts.push({ full: match[0], src: match[1] });
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
for (const script of jsScripts) {
|
|
141
|
+
const jsPath = path.join(projectPath, script.src);
|
|
142
|
+
if (await fs.pathExists(jsPath)) {
|
|
143
|
+
const jsContent = await fs.readFile(jsPath, 'utf8');
|
|
144
|
+
html = html.replace(script.full, `<script>\n${jsContent}\n</script>`);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Write output
|
|
149
|
+
await fs.writeFile(path.join(outputDir, 'index.html'), html);
|
|
150
|
+
|
|
151
|
+
spinner.succeed(`Created single-file HTML (${cssLinks.length} CSS, ${jsScripts.length} JS inlined)`);
|
|
152
|
+
|
|
153
|
+
return { cssInlined: cssLinks.length, jsInlined: jsScripts.length };
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// ==================== STATIC FILE COPY ====================
|
|
157
|
+
async function copyStaticFiles(projectPath, outputDir) {
|
|
158
|
+
const spinner = ora('Copying static files...').start();
|
|
159
|
+
|
|
160
|
+
// Ensure output dir exists and is clean
|
|
161
|
+
await fs.emptyDir(outputDir);
|
|
162
|
+
|
|
163
|
+
// Files and folders to copy
|
|
164
|
+
const filesToCopy = ['index.html', 'style.css', 'styles.css', 'main.css', 'app.css'];
|
|
165
|
+
const foldersToCheck = ['assets', 'css', 'js', 'images', 'fonts', 'src'];
|
|
166
|
+
|
|
167
|
+
let copiedFiles = 0;
|
|
168
|
+
let cssFound = false;
|
|
169
|
+
|
|
170
|
+
// Copy individual files
|
|
171
|
+
for (const file of filesToCopy) {
|
|
172
|
+
const srcPath = path.join(projectPath, file);
|
|
173
|
+
if (await fs.pathExists(srcPath)) {
|
|
174
|
+
await fs.copy(srcPath, path.join(outputDir, file));
|
|
175
|
+
copiedFiles++;
|
|
176
|
+
if (file.endsWith('.css')) cssFound = true;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// Copy .js files from root
|
|
181
|
+
const rootFiles = await fs.readdir(projectPath);
|
|
182
|
+
for (const file of rootFiles) {
|
|
183
|
+
if (file.endsWith('.js') && !file.includes('.config.')) {
|
|
184
|
+
await fs.copy(path.join(projectPath, file), path.join(outputDir, file));
|
|
185
|
+
copiedFiles++;
|
|
186
|
+
}
|
|
187
|
+
if (file.endsWith('.css')) {
|
|
188
|
+
await fs.copy(path.join(projectPath, file), path.join(outputDir, file));
|
|
189
|
+
copiedFiles++;
|
|
190
|
+
cssFound = true;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// Copy folders
|
|
195
|
+
for (const folder of foldersToCheck) {
|
|
196
|
+
const srcPath = path.join(projectPath, folder);
|
|
197
|
+
if (await fs.pathExists(srcPath)) {
|
|
198
|
+
await fs.copy(srcPath, path.join(outputDir, folder));
|
|
199
|
+
copiedFiles++;
|
|
200
|
+
|
|
201
|
+
// Check for CSS in folders
|
|
202
|
+
const folderFiles = await fs.readdir(srcPath);
|
|
203
|
+
if (folderFiles.some(f => f.endsWith('.css'))) {
|
|
204
|
+
cssFound = true;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
spinner.succeed(`Copied ${copiedFiles} files/folders to ${outputDir}`);
|
|
210
|
+
|
|
211
|
+
// Warning if no CSS found
|
|
212
|
+
if (!cssFound) {
|
|
213
|
+
console.log(chalk.yellow('\n⚠️ Warning: No CSS files found in build output'));
|
|
214
|
+
console.log(chalk.gray(' Ensure your HTML links to the CSS file correctly\n'));
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
return { copiedFiles, cssFound };
|
|
218
|
+
}
|
|
219
|
+
|
|
58
220
|
// ==================== WEB BUILD ====================
|
|
59
221
|
async function buildWeb(config, options) {
|
|
60
222
|
console.log(chalk.blue('\n📦 Building for Web...\n'));
|
|
61
223
|
|
|
224
|
+
const projectPath = process.cwd();
|
|
225
|
+
const outputDir = path.resolve(projectPath, config.build?.outDir || 'dist');
|
|
226
|
+
|
|
227
|
+
// Check for --static flag
|
|
228
|
+
if (options.static) {
|
|
229
|
+
console.log(chalk.gray(' Mode: Static (--static flag)'));
|
|
230
|
+
await copyStaticFiles(projectPath, outputDir);
|
|
231
|
+
console.log(chalk.green('\n✅ Static web build complete!'));
|
|
232
|
+
console.log(chalk.gray(` Output: ${outputDir}/\n`));
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// Check for --inline flag
|
|
237
|
+
if (options.inline) {
|
|
238
|
+
console.log(chalk.gray(' Mode: Inline (--inline flag)'));
|
|
239
|
+
await buildInline(projectPath, outputDir);
|
|
240
|
+
console.log(chalk.green('\n✅ Inline web build complete!'));
|
|
241
|
+
console.log(chalk.gray(` Output: ${outputDir}/index.html (single file)\n`));
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// Auto-detect project type
|
|
246
|
+
const projectType = await detectProjectType(projectPath);
|
|
247
|
+
console.log(chalk.gray(` Detected: ${projectType} project`));
|
|
248
|
+
|
|
249
|
+
if (projectType === 'static') {
|
|
250
|
+
console.log(chalk.gray(' Mode: Static site (copying files directly)\n'));
|
|
251
|
+
await copyStaticFiles(projectPath, outputDir);
|
|
252
|
+
console.log(chalk.green('\n✅ Static web build complete!'));
|
|
253
|
+
console.log(chalk.gray(` Output: ${outputDir}/\n`));
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
if (projectType === 'unknown') {
|
|
258
|
+
console.log(chalk.yellow('\n⚠️ Could not detect project type'));
|
|
259
|
+
console.log(chalk.gray(' No index.html or package.json found'));
|
|
260
|
+
console.log(chalk.gray(' Try: slct build web --static\n'));
|
|
261
|
+
process.exit(1);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// Run build command for bundled projects
|
|
62
265
|
const spinner = ora('Running build command...').start();
|
|
63
266
|
|
|
64
267
|
try {
|
|
65
|
-
|
|
268
|
+
const buildCommand = config.build?.command || 'npm run build';
|
|
269
|
+
execSync(buildCommand, {
|
|
66
270
|
stdio: 'inherit',
|
|
67
|
-
cwd:
|
|
271
|
+
cwd: projectPath
|
|
68
272
|
});
|
|
69
273
|
spinner.succeed('Web build complete!');
|
|
70
|
-
|
|
274
|
+
|
|
275
|
+
// Validate output
|
|
276
|
+
await validateBuildOutput(outputDir);
|
|
277
|
+
|
|
278
|
+
console.log(chalk.gray(` Output: ${outputDir}/\n`));
|
|
71
279
|
} catch (error) {
|
|
72
280
|
spinner.fail('Web build failed');
|
|
73
281
|
throw error;
|
|
74
282
|
}
|
|
75
283
|
}
|
|
76
284
|
|
|
285
|
+
// ==================== BUILD VALIDATION ====================
|
|
286
|
+
async function validateBuildOutput(outputDir) {
|
|
287
|
+
if (!await fs.pathExists(outputDir)) {
|
|
288
|
+
console.log(chalk.yellow('\n⚠️ Warning: Output directory not found'));
|
|
289
|
+
return;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
const files = await fs.readdir(outputDir);
|
|
293
|
+
|
|
294
|
+
// Check for index.html
|
|
295
|
+
if (!files.includes('index.html')) {
|
|
296
|
+
console.log(chalk.yellow('\n⚠️ Warning: No index.html found in build output'));
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// Check for CSS
|
|
300
|
+
const hasCss = files.some(f => f.endsWith('.css'));
|
|
301
|
+
const hasAssetsFolder = files.includes('assets');
|
|
302
|
+
|
|
303
|
+
if (!hasCss && hasAssetsFolder) {
|
|
304
|
+
const assetsPath = path.join(outputDir, 'assets');
|
|
305
|
+
if (await fs.pathExists(assetsPath)) {
|
|
306
|
+
const assetFiles = await fs.readdir(assetsPath);
|
|
307
|
+
if (assetFiles.some(f => f.endsWith('.css'))) {
|
|
308
|
+
return; // CSS is in assets folder, all good
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
if (!hasCss) {
|
|
314
|
+
console.log(chalk.yellow('\n⚠️ Warning: No CSS files found in build output'));
|
|
315
|
+
console.log(chalk.gray(' If using vanilla CSS, ensure it\'s imported in your JS entry point'));
|
|
316
|
+
console.log(chalk.gray(' Or use: slct build web --static\n'));
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
|
|
77
320
|
// ==================== DESKTOP BUILD ====================
|
|
78
321
|
async function buildDesktop(config, options) {
|
|
79
322
|
const framework = options.electron ? 'electron' : (config.desktop?.framework || 'tauri');
|
package/lib/commands/deploy.js
CHANGED
|
@@ -39,8 +39,8 @@ async function deploy(options) {
|
|
|
39
39
|
type: 'list',
|
|
40
40
|
name: 'category',
|
|
41
41
|
message: 'Category:',
|
|
42
|
-
choices: ['
|
|
43
|
-
default: config.category || '
|
|
42
|
+
choices: ['productivity', 'finance', 'developer-tools', 'education', 'entertainment', 'utilities', 'games', 'ai-tools', 'experiments'],
|
|
43
|
+
default: config.category || 'productivity'
|
|
44
44
|
},
|
|
45
45
|
{
|
|
46
46
|
type: 'password',
|
|
@@ -66,7 +66,7 @@ async function deploy(options) {
|
|
|
66
66
|
...config,
|
|
67
67
|
name: answers.name,
|
|
68
68
|
tagline: answers.tagline,
|
|
69
|
-
category: answers.category
|
|
69
|
+
category: answers.category,
|
|
70
70
|
platforms: []
|
|
71
71
|
};
|
|
72
72
|
|