@enfyra/create 0.1.3 → 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/package-managers.js +2 -3
- package/components/project-setup.js +166 -71
- 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
|
|
@@ -18,9 +18,8 @@ function detectPackageManagers() {
|
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
function getWorkspaceRunCommand(packageManager, workspace, script) {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
return `npm run ${script} -w ${workspace}`;
|
|
21
|
+
const runCommand = packageManager === 'yarn' ? `yarn ${script}` : `${packageManager} run ${script}`;
|
|
22
|
+
return `(cd ${workspace} && ${runCommand})`;
|
|
24
23
|
}
|
|
25
24
|
|
|
26
25
|
function getPackageRunCommand(packageManager, script) {
|
|
@@ -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,68 +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) {
|
|
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
|
+
}
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
|
|
116
108
|
if (config.packageManager !== 'yarn') return;
|
|
117
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);
|
|
118
122
|
await fs.writeFile(
|
|
119
|
-
path.join(
|
|
120
|
-
|
|
121
|
-
'approvedGitRepositories:',
|
|
122
|
-
' - "**"',
|
|
123
|
-
'',
|
|
124
|
-
'enableScripts: true',
|
|
125
|
-
'',
|
|
126
|
-
'nodeLinker: node-modules',
|
|
127
|
-
'',
|
|
128
|
-
'npmMinimalAgeGate: 0',
|
|
129
|
-
'',
|
|
130
|
-
].join('\n'),
|
|
123
|
+
path.join(scriptsPath, 'run-both.js'),
|
|
124
|
+
buildRunBothScript(config.packageManager, config.serverPort),
|
|
131
125
|
);
|
|
132
126
|
}
|
|
133
127
|
|
|
@@ -244,11 +238,16 @@ function ensureAppDirectDependencies(packageJson) {
|
|
|
244
238
|
}
|
|
245
239
|
}
|
|
246
240
|
|
|
247
|
-
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) {
|
|
248
247
|
return new Promise((resolve, reject) => {
|
|
249
248
|
const { command, args } = getInstallCommand(packageManager);
|
|
250
249
|
const install = spawn(command, args, {
|
|
251
|
-
cwd:
|
|
250
|
+
cwd: workspacePath,
|
|
252
251
|
stdio: 'pipe',
|
|
253
252
|
});
|
|
254
253
|
|
|
@@ -269,7 +268,7 @@ function installDependencies(projectPath, packageManager) {
|
|
|
269
268
|
return;
|
|
270
269
|
}
|
|
271
270
|
|
|
272
|
-
reject(new Error(stderr || stdout ||
|
|
271
|
+
reject(new Error(stderr || stdout || `${command} install failed with code ${code}`));
|
|
273
272
|
});
|
|
274
273
|
|
|
275
274
|
install.on('error', (error) => {
|
|
@@ -278,6 +277,127 @@ function installDependencies(projectPath, packageManager) {
|
|
|
278
277
|
});
|
|
279
278
|
}
|
|
280
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
|
+
|
|
281
401
|
function buildGitignore() {
|
|
282
402
|
return [
|
|
283
403
|
'node_modules',
|
|
@@ -313,21 +433,7 @@ function mergeGitignoreEntries(content, entries) {
|
|
|
313
433
|
return `${lines.join('\n').replace(/\n+$/, '')}\n`;
|
|
314
434
|
}
|
|
315
435
|
|
|
316
|
-
|
|
317
|
-
const resolutions = {};
|
|
318
|
-
|
|
319
|
-
for (const workspace of ['app', 'server']) {
|
|
320
|
-
const packageJsonPath = path.join(projectPath, workspace, 'package.json');
|
|
321
|
-
if (!fs.existsSync(packageJsonPath)) continue;
|
|
322
|
-
|
|
323
|
-
const packageJson = await fs.readJson(packageJsonPath);
|
|
324
|
-
Object.assign(resolutions, packageJson.resolutions || {});
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
return resolutions;
|
|
328
|
-
}
|
|
329
|
-
|
|
330
|
-
function buildPnpmWorkspaceYaml(resolutions, pnpmVersion) {
|
|
436
|
+
function buildPnpmProjectConfig(pnpmVersion) {
|
|
331
437
|
const allowedBuildDependencies = [
|
|
332
438
|
'@parcel/watcher',
|
|
333
439
|
'esbuild',
|
|
@@ -336,12 +442,7 @@ function buildPnpmWorkspaceYaml(resolutions, pnpmVersion) {
|
|
|
336
442
|
'sharp',
|
|
337
443
|
'vue-demi',
|
|
338
444
|
];
|
|
339
|
-
const lines = [
|
|
340
|
-
'packages:',
|
|
341
|
-
' - app',
|
|
342
|
-
' - server',
|
|
343
|
-
'',
|
|
344
|
-
];
|
|
445
|
+
const lines = [];
|
|
345
446
|
|
|
346
447
|
if (getMajorVersion(pnpmVersion) >= 11) {
|
|
347
448
|
lines.push('allowBuilds:');
|
|
@@ -355,14 +456,6 @@ function buildPnpmWorkspaceYaml(resolutions, pnpmVersion) {
|
|
|
355
456
|
}
|
|
356
457
|
}
|
|
357
458
|
|
|
358
|
-
const overrideEntries = Object.entries(resolutions);
|
|
359
|
-
if (overrideEntries.length > 0) {
|
|
360
|
-
lines.push('', 'overrides:');
|
|
361
|
-
for (const [name, version] of overrideEntries) {
|
|
362
|
-
lines.push(` ${yamlQuote(name)}: ${yamlQuote(version)}`);
|
|
363
|
-
}
|
|
364
|
-
}
|
|
365
|
-
|
|
366
459
|
return `${lines.join('\n')}\n`;
|
|
367
460
|
}
|
|
368
461
|
|
|
@@ -388,7 +481,9 @@ module.exports = {
|
|
|
388
481
|
cleanPackageManagerRestrictions,
|
|
389
482
|
rewritePackageManagerScripts,
|
|
390
483
|
toPackageName,
|
|
391
|
-
buildPnpmWorkspaceYaml,
|
|
392
|
-
ensureAppDirectDependencies,
|
|
393
484
|
mergeGitignoreEntries,
|
|
485
|
+
ensureAppDirectDependencies,
|
|
486
|
+
buildPnpmProjectConfig,
|
|
487
|
+
buildRunBothScript,
|
|
488
|
+
buildRootYarnLock,
|
|
394
489
|
};
|