@enfyra/create 0.1.4 → 0.1.5
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 +3 -1
- package/components/project-setup.js +163 -81
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -10,10 +10,12 @@ The generated project contains:
|
|
|
10
10
|
|
|
11
11
|
- `app/` - Enfyra Nuxt admin app
|
|
12
12
|
- `server/` - Enfyra server
|
|
13
|
-
- Root
|
|
13
|
+
- Root scripts for running both together
|
|
14
14
|
- `app/.env` connected to `http://localhost:1105`
|
|
15
15
|
- `server/.env` with `PORT=1105`
|
|
16
16
|
|
|
17
|
+
`app/` and `server/` are installed as separate applications. Their dependencies and lockfiles stay inside each folder; the root folder only coordinates scripts.
|
|
18
|
+
|
|
17
19
|
The CLI prompts for:
|
|
18
20
|
|
|
19
21
|
- Package manager: npm, yarn, or pnpm
|
|
@@ -7,7 +7,6 @@ const { downloadTemplate } = require('giget');
|
|
|
7
7
|
const { generateEnvFiles } = require('./env-builder');
|
|
8
8
|
const {
|
|
9
9
|
getInstallCommand,
|
|
10
|
-
getPackageExecCommand,
|
|
11
10
|
getPackageRunCommand,
|
|
12
11
|
getWorkspaceRunCommand,
|
|
13
12
|
} = require('./package-managers');
|
|
@@ -36,14 +35,15 @@ async function createProject(config, projectPath) {
|
|
|
36
35
|
});
|
|
37
36
|
spinner.succeed(chalk.green('Server downloaded'));
|
|
38
37
|
|
|
39
|
-
spinner.start(chalk.blue(`Preparing ${config.packageManager}
|
|
38
|
+
spinner.start(chalk.blue(`Preparing ${config.packageManager} project...`));
|
|
40
39
|
await removeTemplateFiles(projectPath);
|
|
41
40
|
await cleanPackageManagerRestrictions(projectPath);
|
|
42
|
-
await updateWorkspacePackageJson(projectPath, config);
|
|
43
|
-
await writePackageManagerConfig(projectPath, config);
|
|
44
41
|
await updateAppPackageJson(path.join(projectPath, 'app'), config);
|
|
45
42
|
await updateServerPackageJson(path.join(projectPath, 'server'), config);
|
|
46
|
-
|
|
43
|
+
await updateWorkspacePackageJson(projectPath, config);
|
|
44
|
+
await writePackageManagerConfig(projectPath, config);
|
|
45
|
+
await writeRootScripts(projectPath, config);
|
|
46
|
+
spinner.succeed(chalk.green(`${config.packageManager} project prepared`));
|
|
47
47
|
|
|
48
48
|
spinner.start(chalk.blue('Generating environment files...'));
|
|
49
49
|
await generateEnvFiles(projectPath, config);
|
|
@@ -66,81 +66,62 @@ async function createProject(config, projectPath) {
|
|
|
66
66
|
async function updateWorkspacePackageJson(projectPath, config) {
|
|
67
67
|
const packageName = toPackageName(config.projectName);
|
|
68
68
|
const packageManager = config.packageManager;
|
|
69
|
-
const resolutions = await collectTemplateResolutions(projectPath);
|
|
70
|
-
const serverReadyTarget = `tcp:localhost:${config.serverPort}`;
|
|
71
|
-
const waitForServerCommand = getPackageExecCommand(packageManager, 'wait-on', [serverReadyTarget]);
|
|
72
69
|
const packageJson = {
|
|
73
70
|
name: packageName,
|
|
74
71
|
version: '0.1.0',
|
|
75
72
|
private: true,
|
|
76
|
-
workspaces: [
|
|
77
|
-
'app',
|
|
78
|
-
'server',
|
|
79
|
-
],
|
|
80
73
|
scripts: {
|
|
81
|
-
dev:
|
|
74
|
+
dev: 'node scripts/run-both.js dev',
|
|
82
75
|
'dev:app': getWorkspaceRunCommand(packageManager, 'app', 'dev'),
|
|
83
76
|
'dev:server': getWorkspaceRunCommand(packageManager, 'server', 'dev'),
|
|
84
77
|
build: `${getWorkspaceRunCommand(packageManager, 'server', 'build')} && ${getWorkspaceRunCommand(packageManager, 'app', 'build')}`,
|
|
85
78
|
'build:app': getWorkspaceRunCommand(packageManager, 'app', 'build'),
|
|
86
79
|
'build:server': getWorkspaceRunCommand(packageManager, 'server', 'build'),
|
|
87
|
-
start:
|
|
80
|
+
start: 'node scripts/run-both.js start',
|
|
88
81
|
'start:app': getWorkspaceRunCommand(packageManager, 'app', 'start'),
|
|
89
82
|
'start:server': getWorkspaceRunCommand(packageManager, 'server', 'start'),
|
|
90
83
|
serve: getPackageRunCommand(packageManager, 'start'),
|
|
91
84
|
'preview:app': getWorkspaceRunCommand(packageManager, 'app', 'preview'),
|
|
92
85
|
},
|
|
93
|
-
devDependencies: {
|
|
94
|
-
concurrently: '^9.2.1',
|
|
95
|
-
'wait-on': '^8.0.3',
|
|
96
|
-
},
|
|
97
86
|
};
|
|
98
87
|
|
|
99
88
|
if (config.packageManagerVersion) {
|
|
100
89
|
packageJson.packageManager = `${packageManager}@${config.packageManagerVersion}`;
|
|
101
90
|
}
|
|
102
91
|
|
|
103
|
-
if (packageManager === 'yarn' && Object.keys(resolutions).length > 0) {
|
|
104
|
-
packageJson.resolutions = resolutions;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
92
|
await fs.writeJson(path.join(projectPath, 'package.json'), packageJson, { spaces: 2 });
|
|
108
93
|
await fs.writeFile(path.join(projectPath, '.gitignore'), buildGitignore());
|
|
109
94
|
await ensureWorkspaceGitignores(projectPath);
|
|
110
|
-
if (packageManager === 'pnpm') {
|
|
111
|
-
await fs.writeFile(path.join(projectPath, 'pnpm-workspace.yaml'), buildPnpmWorkspaceYaml(resolutions, config.packageManagerVersion));
|
|
112
|
-
}
|
|
113
95
|
}
|
|
114
96
|
|
|
115
97
|
async function writePackageManagerConfig(projectPath, config) {
|
|
116
|
-
if (config.packageManager === '
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
);
|
|
98
|
+
if (config.packageManager === 'pnpm') {
|
|
99
|
+
for (const workspace of ['app', 'server']) {
|
|
100
|
+
await fs.writeFile(
|
|
101
|
+
path.join(projectPath, workspace, 'pnpm-workspace.yaml'),
|
|
102
|
+
buildPnpmProjectConfig(config.packageManagerVersion),
|
|
103
|
+
);
|
|
104
|
+
}
|
|
124
105
|
return;
|
|
125
106
|
}
|
|
126
107
|
|
|
127
108
|
if (config.packageManager !== 'yarn') return;
|
|
128
109
|
|
|
110
|
+
await fs.writeFile(path.join(projectPath, '.yarnrc.yml'), buildYarnConfig());
|
|
111
|
+
await fs.writeFile(path.join(projectPath, 'yarn.lock'), buildRootYarnLock(toPackageName(config.projectName)));
|
|
112
|
+
|
|
113
|
+
for (const workspace of ['app', 'server']) {
|
|
114
|
+
await fs.writeFile(path.join(projectPath, workspace, '.yarnrc.yml'), buildYarnConfig());
|
|
115
|
+
await fs.ensureFile(path.join(projectPath, workspace, 'yarn.lock'));
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
async function writeRootScripts(projectPath, config) {
|
|
120
|
+
const scriptsPath = path.join(projectPath, 'scripts');
|
|
121
|
+
await fs.ensureDir(scriptsPath);
|
|
129
122
|
await fs.writeFile(
|
|
130
|
-
path.join(
|
|
131
|
-
|
|
132
|
-
'approvedGitRepositories:',
|
|
133
|
-
' - "**"',
|
|
134
|
-
'',
|
|
135
|
-
'enableScripts: true',
|
|
136
|
-
'',
|
|
137
|
-
'nodeLinker: node-modules',
|
|
138
|
-
'',
|
|
139
|
-
'nmHoistingLimits: workspaces',
|
|
140
|
-
'',
|
|
141
|
-
'npmMinimalAgeGate: 0',
|
|
142
|
-
'',
|
|
143
|
-
].join('\n'),
|
|
123
|
+
path.join(scriptsPath, 'run-both.js'),
|
|
124
|
+
buildRunBothScript(config.packageManager, config.serverPort),
|
|
144
125
|
);
|
|
145
126
|
}
|
|
146
127
|
|
|
@@ -257,11 +238,16 @@ function ensureAppDirectDependencies(packageJson) {
|
|
|
257
238
|
}
|
|
258
239
|
}
|
|
259
240
|
|
|
260
|
-
function installDependencies(projectPath, packageManager) {
|
|
241
|
+
async function installDependencies(projectPath, packageManager) {
|
|
242
|
+
await installWorkspaceDependencies(path.join(projectPath, 'server'), packageManager);
|
|
243
|
+
await installWorkspaceDependencies(path.join(projectPath, 'app'), packageManager);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
function installWorkspaceDependencies(workspacePath, packageManager) {
|
|
261
247
|
return new Promise((resolve, reject) => {
|
|
262
248
|
const { command, args } = getInstallCommand(packageManager);
|
|
263
249
|
const install = spawn(command, args, {
|
|
264
|
-
cwd:
|
|
250
|
+
cwd: workspacePath,
|
|
265
251
|
stdio: 'pipe',
|
|
266
252
|
});
|
|
267
253
|
|
|
@@ -282,7 +268,7 @@ function installDependencies(projectPath, packageManager) {
|
|
|
282
268
|
return;
|
|
283
269
|
}
|
|
284
270
|
|
|
285
|
-
reject(new Error(stderr || stdout ||
|
|
271
|
+
reject(new Error(stderr || stdout || `${command} install failed with code ${code}`));
|
|
286
272
|
});
|
|
287
273
|
|
|
288
274
|
install.on('error', (error) => {
|
|
@@ -291,6 +277,127 @@ function installDependencies(projectPath, packageManager) {
|
|
|
291
277
|
});
|
|
292
278
|
}
|
|
293
279
|
|
|
280
|
+
function buildYarnConfig() {
|
|
281
|
+
return [
|
|
282
|
+
'approvedGitRepositories:',
|
|
283
|
+
' - "**"',
|
|
284
|
+
'',
|
|
285
|
+
'enableScripts: true',
|
|
286
|
+
'',
|
|
287
|
+
'nodeLinker: node-modules',
|
|
288
|
+
'',
|
|
289
|
+
'npmMinimalAgeGate: 0',
|
|
290
|
+
'',
|
|
291
|
+
].join('\n');
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
function buildRootYarnLock(packageName) {
|
|
295
|
+
return [
|
|
296
|
+
'# This file is generated by @enfyra/create for root scripts.',
|
|
297
|
+
'',
|
|
298
|
+
'__metadata:',
|
|
299
|
+
' version: 10',
|
|
300
|
+
' cacheKey: 10c0',
|
|
301
|
+
'',
|
|
302
|
+
`"${packageName}@workspace:.":`,
|
|
303
|
+
' version: 0.0.0-use.local',
|
|
304
|
+
` resolution: "${packageName}@workspace:."`,
|
|
305
|
+
' languageName: unknown',
|
|
306
|
+
' linkType: soft',
|
|
307
|
+
'',
|
|
308
|
+
].join('\n');
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
function buildRunBothScript(packageManager, serverPort) {
|
|
312
|
+
const escapedPackageManager = JSON.stringify(packageManager);
|
|
313
|
+
const escapedServerPort = JSON.stringify(serverPort);
|
|
314
|
+
|
|
315
|
+
return `const net = require('net');
|
|
316
|
+
const path = require('path');
|
|
317
|
+
const { spawn } = require('child_process');
|
|
318
|
+
|
|
319
|
+
const packageManager = ${escapedPackageManager};
|
|
320
|
+
const serverPort = ${escapedServerPort};
|
|
321
|
+
const script = process.argv[2] || 'dev';
|
|
322
|
+
const root = path.resolve(__dirname, '..');
|
|
323
|
+
const children = new Set();
|
|
324
|
+
let shuttingDown = false;
|
|
325
|
+
|
|
326
|
+
function runArgs(name) {
|
|
327
|
+
if (packageManager === 'yarn') return [name];
|
|
328
|
+
return ['run', name];
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
function spawnWorkspace(label, workspace, name) {
|
|
332
|
+
const child = spawn(packageManager, runArgs(name), {
|
|
333
|
+
cwd: path.join(root, workspace),
|
|
334
|
+
stdio: 'inherit',
|
|
335
|
+
shell: process.platform === 'win32',
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
children.add(child);
|
|
339
|
+
child.on('exit', (code, signal) => {
|
|
340
|
+
children.delete(child);
|
|
341
|
+
if (!shuttingDown && (code || signal)) {
|
|
342
|
+
console.error(\`\\n\${label} exited\${signal ? \` with signal \${signal}\` : \` with code \${code}\`}.\`);
|
|
343
|
+
shutdown(code || 1);
|
|
344
|
+
}
|
|
345
|
+
});
|
|
346
|
+
|
|
347
|
+
return child;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
function waitForPort(port, host = '127.0.0.1', timeoutMs = 120000) {
|
|
351
|
+
const startedAt = Date.now();
|
|
352
|
+
|
|
353
|
+
return new Promise((resolve, reject) => {
|
|
354
|
+
const attempt = () => {
|
|
355
|
+
const socket = net.createConnection({ port, host });
|
|
356
|
+
|
|
357
|
+
socket.once('connect', () => {
|
|
358
|
+
socket.destroy();
|
|
359
|
+
resolve();
|
|
360
|
+
});
|
|
361
|
+
|
|
362
|
+
socket.once('error', () => {
|
|
363
|
+
socket.destroy();
|
|
364
|
+
if (Date.now() - startedAt >= timeoutMs) {
|
|
365
|
+
reject(new Error(\`Timed out waiting for server on port \${port}\`));
|
|
366
|
+
return;
|
|
367
|
+
}
|
|
368
|
+
setTimeout(attempt, 500);
|
|
369
|
+
});
|
|
370
|
+
};
|
|
371
|
+
|
|
372
|
+
attempt();
|
|
373
|
+
});
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
function shutdown(code = 0) {
|
|
377
|
+
if (shuttingDown) return;
|
|
378
|
+
shuttingDown = true;
|
|
379
|
+
|
|
380
|
+
for (const child of children) {
|
|
381
|
+
if (!child.killed) child.kill('SIGTERM');
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
setTimeout(() => process.exit(code), 250);
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
process.on('SIGINT', () => shutdown(0));
|
|
388
|
+
process.on('SIGTERM', () => shutdown(0));
|
|
389
|
+
|
|
390
|
+
(async () => {
|
|
391
|
+
spawnWorkspace('server', 'server', script);
|
|
392
|
+
await waitForPort(serverPort);
|
|
393
|
+
spawnWorkspace('app', 'app', script);
|
|
394
|
+
})().catch((error) => {
|
|
395
|
+
console.error(error.message);
|
|
396
|
+
shutdown(1);
|
|
397
|
+
});
|
|
398
|
+
`;
|
|
399
|
+
}
|
|
400
|
+
|
|
294
401
|
function buildGitignore() {
|
|
295
402
|
return [
|
|
296
403
|
'node_modules',
|
|
@@ -326,21 +433,7 @@ function mergeGitignoreEntries(content, entries) {
|
|
|
326
433
|
return `${lines.join('\n').replace(/\n+$/, '')}\n`;
|
|
327
434
|
}
|
|
328
435
|
|
|
329
|
-
|
|
330
|
-
const resolutions = {};
|
|
331
|
-
|
|
332
|
-
for (const workspace of ['app', 'server']) {
|
|
333
|
-
const packageJsonPath = path.join(projectPath, workspace, 'package.json');
|
|
334
|
-
if (!fs.existsSync(packageJsonPath)) continue;
|
|
335
|
-
|
|
336
|
-
const packageJson = await fs.readJson(packageJsonPath);
|
|
337
|
-
Object.assign(resolutions, packageJson.resolutions || {});
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
return resolutions;
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
function buildPnpmWorkspaceYaml(resolutions, pnpmVersion) {
|
|
436
|
+
function buildPnpmProjectConfig(pnpmVersion) {
|
|
344
437
|
const allowedBuildDependencies = [
|
|
345
438
|
'@parcel/watcher',
|
|
346
439
|
'esbuild',
|
|
@@ -349,12 +442,7 @@ function buildPnpmWorkspaceYaml(resolutions, pnpmVersion) {
|
|
|
349
442
|
'sharp',
|
|
350
443
|
'vue-demi',
|
|
351
444
|
];
|
|
352
|
-
const lines = [
|
|
353
|
-
'packages:',
|
|
354
|
-
' - app',
|
|
355
|
-
' - server',
|
|
356
|
-
'',
|
|
357
|
-
];
|
|
445
|
+
const lines = [];
|
|
358
446
|
|
|
359
447
|
if (getMajorVersion(pnpmVersion) >= 11) {
|
|
360
448
|
lines.push('allowBuilds:');
|
|
@@ -368,14 +456,6 @@ function buildPnpmWorkspaceYaml(resolutions, pnpmVersion) {
|
|
|
368
456
|
}
|
|
369
457
|
}
|
|
370
458
|
|
|
371
|
-
const overrideEntries = Object.entries(resolutions);
|
|
372
|
-
if (overrideEntries.length > 0) {
|
|
373
|
-
lines.push('', 'overrides:');
|
|
374
|
-
for (const [name, version] of overrideEntries) {
|
|
375
|
-
lines.push(` ${yamlQuote(name)}: ${yamlQuote(version)}`);
|
|
376
|
-
}
|
|
377
|
-
}
|
|
378
|
-
|
|
379
459
|
return `${lines.join('\n')}\n`;
|
|
380
460
|
}
|
|
381
461
|
|
|
@@ -401,7 +481,9 @@ module.exports = {
|
|
|
401
481
|
cleanPackageManagerRestrictions,
|
|
402
482
|
rewritePackageManagerScripts,
|
|
403
483
|
toPackageName,
|
|
404
|
-
buildPnpmWorkspaceYaml,
|
|
405
|
-
ensureAppDirectDependencies,
|
|
406
484
|
mergeGitignoreEntries,
|
|
485
|
+
ensureAppDirectDependencies,
|
|
486
|
+
buildPnpmProjectConfig,
|
|
487
|
+
buildRunBothScript,
|
|
488
|
+
buildRootYarnLock,
|
|
407
489
|
};
|