adminforth 2.25.0-test.2 → 2.25.0-test.21

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.
@@ -16,7 +16,8 @@ async function bundle() {
16
16
  `);
17
17
 
18
18
  } catch (e) {
19
- console.log(`Running budndle failed`, e);
19
+ console.log(`Running bundle failed`, e);
20
+ throw new Error(`Failed to bundle admin SPA: ${e.message}`);
20
21
  }
21
22
  }
22
23
 
@@ -1,3 +1,14 @@
1
+
2
+ {{#unless useNpm}}
3
+ FROM devforth/node20-pnpm:latest
4
+ WORKDIR /code/
5
+ ADD package.json pnpm-lock.yaml pnpm-workspace.yaml /code/
6
+ RUN pnpm i
7
+ ADD . /code/
8
+ RUN pnpm exec adminforth bundle
9
+ CMD ["sh", "-c", "pnpm migrate:prod && pnpm prod"]
10
+ {{/unless}}
11
+ {{#if useNpm}}
1
12
  FROM node:{{nodeMajor}}-slim
2
13
  WORKDIR /code/
3
14
  ADD package.json package-lock.json /code/
@@ -5,3 +16,4 @@ RUN npm ci
5
16
  ADD . /code/
6
17
  RUN npx adminforth bundle
7
18
  CMD ["sh", "-c", "npm run migrate:prod && npm run prod"]
19
+ {{/if}}
@@ -8,6 +8,7 @@
8
8
  "license": "ISC",
9
9
  "description": "",
10
10
  "scripts": {
11
+ {{#unless useNpm}}
11
12
  "dev": "pnpm _env:dev tsx watch index.ts",
12
13
  "prod": "pnpm _env:prod tsx index.ts",
13
14
  "start": "pnpm dev",
@@ -16,6 +17,17 @@
16
17
  "migrate:prod": "pnpm _env:prod npx --yes prisma migrate deploy",
17
18
  "_env:dev": "dotenvx run -f .env -f .env.local --",
18
19
  "_env:prod": "dotenvx run -f .env.prod --"
20
+ {{/unless}}
21
+ {{#if useNpm}}
22
+ "dev": "npm run _env:dev -- tsx watch index.ts",
23
+ "prod": "npm run _env:prod -- tsx index.ts",
24
+ "start": "npm run dev",
25
+ "makemigration": "npm run _env:dev -- npx --yes prisma migrate dev --create-only",
26
+ "migrate:local": "npm run _env:dev -- npx --yes prisma migrate deploy",
27
+ "migrate:prod": "npm run _env:prod -- npx --yes prisma migrate deploy",
28
+ "_env:dev": "dotenvx run -f .env -f .env.local --",
29
+ "_env:prod": "dotenvx run -f .env.prod --"
30
+ {{/if}}
19
31
  },
20
32
  "engines": {
21
33
  "node": ">=20"
@@ -0,0 +1,8 @@
1
+ lockfileVersion: '9.0'
2
+
3
+ settings:
4
+ autoInstallPeers: true
5
+ excludeLinksFromLockfile: false
6
+
7
+ importers:
8
+ .: {}
@@ -1,7 +1,25 @@
1
1
  ## Starting the application
2
2
 
3
3
  Install dependencies:
4
+ {{#if useNpm}}
5
+ ```bash
6
+ npm i
7
+ ```
8
+
9
+ Migrate the database:
10
+
11
+ ```bash
12
+ npm run migrate:local
13
+ ```
14
+
15
+ Start the server:
16
+
17
+ ```bash
18
+ npm run dev
19
+ ```
20
+ {{/if}}
4
21
 
22
+ {{#unless useNpm}}
5
23
  ```bash
6
24
  pnpm i
7
25
  ```
@@ -17,6 +35,7 @@ Start the server:
17
35
  ```bash
18
36
  pnpm dev
19
37
  ```
38
+ {{/unless}}
20
39
 
21
40
  {{#if prismaDbUrl}}
22
41
  ## Changing schema
@@ -26,7 +45,7 @@ Open `schema.prisma` and change schema as needed: add new tables, columns, etc (
26
45
  Run the following command to generate a new migration and apply it instantly in local database:
27
46
 
28
47
  ```bash
29
- pnpm makemigration -- --name <name_of_changes>
48
+ pnpm makemigration --name <name_of_changes>
30
49
  ```
31
50
 
32
51
  Your colleagues will need to pull the changes and run `pnpm migrate:local` to apply the migration in their local database.
@@ -44,6 +44,7 @@ export function parseArgumentsIntoOptions(rawArgs) {
44
44
  {
45
45
  '--app-name': String,
46
46
  '--db': String,
47
+ '--use-npm': Boolean,
47
48
  // you can add more flags here if needed
48
49
  },
49
50
  {
@@ -54,6 +55,7 @@ export function parseArgumentsIntoOptions(rawArgs) {
54
55
  return {
55
56
  appName: args['--app-name'],
56
57
  db: args['--db'],
58
+ useNpm: args['--use-npm'],
57
59
  };
58
60
  }
59
61
 
@@ -78,11 +80,25 @@ export async function promptForMissingOptions(options) {
78
80
  });
79
81
  };
80
82
 
83
+ if (!options.useNpm) {
84
+ questions.push({
85
+ type: 'select',
86
+ name: 'useNpm',
87
+ message: 'Select your package manager >',
88
+ choices: [
89
+ { name: 'pnpm', value: false },
90
+ { name: 'npm', value: true },
91
+ ],
92
+ default: false,
93
+ });
94
+ }
95
+
81
96
  const answers = await inquirer.prompt(questions);
82
97
  return {
83
98
  ...options,
84
99
  appName: options.appName || answers.appName,
85
100
  db: options.db || answers.db,
101
+ useNpm: options.useNpm || answers.useNpm,
86
102
  };
87
103
  }
88
104
 
@@ -230,7 +246,7 @@ async function scaffoldProject(ctx, options, cwd) {
230
246
  await fse.copy(sourceAssetsDir, targetAssetsDir);
231
247
 
232
248
  // Write templated files
233
- await writeTemplateFiles(dirname, projectDir, {
249
+ await writeTemplateFiles(dirname, projectDir, options.useNpm, {
234
250
  dbUrl: connectionString.toString(),
235
251
  dbUrlProd: connectionStringProd,
236
252
  prismaDbUrl,
@@ -244,7 +260,7 @@ async function scaffoldProject(ctx, options, cwd) {
244
260
  return projectDir; // Return the new directory path
245
261
  }
246
262
 
247
- async function writeTemplateFiles(dirname, cwd, options) {
263
+ async function writeTemplateFiles(dirname, cwd, useNpm, options) {
248
264
  const {
249
265
  dbUrl, prismaDbUrl, appName, provider, nodeMajor,
250
266
  dbUrlProd, prismaDbUrlProd, sqliteFile
@@ -268,14 +284,6 @@ async function writeTemplateFiles(dirname, cwd, options) {
268
284
  dest: 'prisma.config.ts',
269
285
  data: {},
270
286
  },
271
- {
272
- src: 'package.json.hbs',
273
- dest: 'package.json',
274
- data: {
275
- appName,
276
- adminforthVersion: adminforthVersion,
277
- },
278
- },
279
287
  {
280
288
  src: 'index.ts.hbs',
281
289
  dest: 'index.ts',
@@ -304,7 +312,7 @@ async function writeTemplateFiles(dirname, cwd, options) {
304
312
  {
305
313
  src: 'readme.md.hbs',
306
314
  dest: 'README.md',
307
- data: { dbUrl, prismaDbUrl, appName, sqliteFile },
315
+ data: { dbUrl, prismaDbUrl, appName, sqliteFile, useNpm },
308
316
  },
309
317
  {
310
318
  // We'll write .env using the same content as .env.sample
@@ -317,21 +325,11 @@ async function writeTemplateFiles(dirname, cwd, options) {
317
325
  dest: 'resources/adminuser.ts',
318
326
  data: {},
319
327
  },
320
- {
321
- src: 'custom/package.json.hbs',
322
- dest: 'custom/package.json',
323
- data: {},
324
- },
325
328
  {
326
329
  src: 'custom/tsconfig.json.hbs',
327
330
  dest: 'custom/tsconfig.json',
328
331
  data: {},
329
332
  },
330
- {
331
- src: 'Dockerfile.hbs',
332
- dest: 'Dockerfile',
333
- data: { nodeMajor },
334
- },
335
333
  {
336
334
  src: '.dockerignore.hbs',
337
335
  dest: '.dockerignore',
@@ -340,12 +338,41 @@ async function writeTemplateFiles(dirname, cwd, options) {
340
338
  },
341
339
  },
342
340
  {
343
- src: 'pnpm-workspace.yaml.hbs',
344
- dest: 'pnpm-workspace.yaml',
345
- data: {},
341
+ src: 'Dockerfile.hbs',
342
+ dest: 'Dockerfile',
343
+ data: { nodeMajor, useNpm },
344
+ },
345
+ {
346
+ src: 'package.json.hbs',
347
+ dest: 'package.json',
348
+ data: {
349
+ appName,
350
+ adminforthVersion: adminforthVersion,
351
+ useNpm
352
+ },
353
+ },
354
+ {
355
+ src: 'custom/package.json.hbs',
356
+ dest: 'custom/package.json',
357
+ data: {}
346
358
  }
347
359
  ];
348
360
 
361
+ if (!useNpm) {
362
+ templateTasks.push(
363
+ {
364
+ src: 'pnpm_templates/pnpm-workspace.yaml.hbs',
365
+ dest: 'pnpm-workspace.yaml',
366
+ data: {},
367
+ },
368
+ {
369
+ src: 'pnpm_templates/pnpm-lock.yaml.hbs',
370
+ dest: 'custom/pnpm-lock.yaml',
371
+ data: {},
372
+ }
373
+ )
374
+ }
375
+
349
376
  for (const task of templateTasks) {
350
377
  // If a condition is specified and false, skip this file
351
378
  if (task.condition === false) continue;
@@ -363,7 +390,7 @@ async function writeTemplateFiles(dirname, cwd, options) {
363
390
  }
364
391
  }
365
392
 
366
- async function installDependencies(ctx, cwd) {
393
+ async function installDependenciesPnpm(ctx, cwd) {
367
394
  const isWindows = process.platform === 'win32';
368
395
 
369
396
  const nodeBinary = process.execPath;
@@ -380,10 +407,28 @@ async function installDependencies(ctx, cwd) {
380
407
  await execAsync(`${nodeBinary} ${npmPath} install`, { cwd: customDir, env: { PATH: process.env.PATH } }),
381
408
  ]);
382
409
  }
383
- // console.log(chalk.dim(`Dependencies installed in ${cwd} and ${customDir}: \n${res[0].stdout}${res[1].stdout}`));
384
410
  }
385
411
 
386
- function generateFinalInstructions(skipPrismaSetup, options) {
412
+ async function installDependenciesNpm(ctx, cwd) {
413
+ const isWindows = process.platform === 'win32';
414
+
415
+ const nodeBinary = process.execPath;
416
+ const npmPath = path.join(path.dirname(nodeBinary), isWindows ? 'npm.cmd' : 'npm');
417
+ const customDir = ctx.customDir;
418
+ if (isWindows) {
419
+ const res = await Promise.all([
420
+ await execAsync(`npm install`, { cwd, env: { PATH: process.env.PATH } }),
421
+ await execAsync(`npm install`, { cwd: customDir, env: { PATH: process.env.PATH } }),
422
+ ]);
423
+ } else {
424
+ const res = await Promise.all([
425
+ await execAsync(`${nodeBinary} ${npmPath} install`, { cwd, env: { PATH: process.env.PATH } }),
426
+ await execAsync(`${nodeBinary} ${npmPath} install`, { cwd: customDir, env: { PATH: process.env.PATH } }),
427
+ ]);
428
+ }
429
+ }
430
+
431
+ function generateFinalInstructionsPnpm(skipPrismaSetup, options) {
387
432
  let instruction = '⏭️ Run the following commands to get started:\n';
388
433
  if (!skipPrismaSetup)
389
434
  instruction += `
@@ -404,6 +449,27 @@ function generateFinalInstructions(skipPrismaSetup, options) {
404
449
  return instruction;
405
450
  }
406
451
 
452
+ function generateFinalInstructionsNpm(skipPrismaSetup, options) {
453
+ let instruction = '⏭️ Run the following commands to get started:\n';
454
+ if (!skipPrismaSetup)
455
+ instruction += `
456
+ ${chalk.dim('// Go to the project directory')}
457
+ ${chalk.dim('$')}${chalk.cyan(` cd ${options.appName}`)}\n`;
458
+
459
+ instruction += `
460
+ ${chalk.dim('// Generate and apply initial migration')}
461
+ ${chalk.dim('$')}${chalk.cyan(' npm run makemigration -- --name init && npm run migrate:local')}\n`;
462
+
463
+ instruction += `
464
+ ${chalk.dim('// Start dev server with tsx watch for hot-reloading')}
465
+ ${chalk.dim('$')}${chalk.cyan(' npm run dev')}\n
466
+ `;
467
+
468
+ instruction += '😉 Happy coding!';
469
+
470
+ return instruction;
471
+ }
472
+
407
473
  function renderHBSTemplate(templatePath, data) {
408
474
  // Example: renderHBRTemplate('path/to/template.hbs', {name: 'John Doe'})
409
475
  const template = fs.readFileSync(templatePath, 'utf-8');
@@ -430,13 +496,23 @@ export function prepareWorkflow(options) {
430
496
  },
431
497
  {
432
498
  title: '📦 Installing dependencies...',
433
- task: async (ctx) => installDependencies(ctx, ctx.projectDir)
499
+ task: async (ctx) => {
500
+ if (options.useNpm) {
501
+ await installDependenciesNpm(ctx, ctx.projectDir);
502
+ } else {
503
+ await installDependenciesPnpm(ctx, ctx.projectDir);
504
+ }
505
+ }
434
506
  },
435
507
  {
436
508
  title: '📝 Preparing final instructions...',
437
509
  task: (ctx) => {
438
510
  console.log(chalk.green(`✅ Successfully created your new Adminforth project in ${ctx.projectDir}!\n`));
439
- console.log(generateFinalInstructions(ctx.skipPrismaSetup, options));
511
+ if (options.useNpm) {
512
+ console.log(generateFinalInstructionsNpm(ctx.skipPrismaSetup, options));
513
+ } else {
514
+ console.log(generateFinalInstructionsPnpm(ctx.skipPrismaSetup, options));
515
+ }
440
516
  console.log('\n\n');
441
517
  }
442
518
  }
@@ -158,7 +158,7 @@ async function installDependencies(ctx, cwd) {
158
158
  const customDir = ctx.customDir;
159
159
 
160
160
  await Promise.all([
161
- await execa("pnpm", ["install", "--no-package-lock"], { cwd }),
161
+ await execa("pnpm", ["install"], { cwd }),
162
162
  await execa("pnpm", ["install"], { cwd: customDir }),
163
163
  ]);
164
164
  }
@@ -15,7 +15,8 @@ declare class CodeInjector implements ICodeInjector {
15
15
  registerCustomComponent(filePath: string): void;
16
16
  cleanup(): void;
17
17
  constructor(adminforth: any);
18
- runPnpmShell({ command, cwd, envOverrides }: {
18
+ doesUserHasPnpmLockFile(dir: string): Promise<boolean>;
19
+ runPackageManagerShell({ command, cwd, envOverrides }: {
19
20
  command: string;
20
21
  cwd: string;
21
22
  envOverrides?: {
@@ -1 +1 @@
1
- {"version":3,"file":"codeInjector.d.ts","sourceRoot":"","sources":["../../modules/codeInjector.ts"],"names":[],"mappings":"AAQA,OAAO,UAAwC,MAAM,aAAa,CAAC;AAEnE,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAmEjD,cAAM,YAAa,YAAW,aAAa;IAEzC,WAAW,QAAM;IACjB,UAAU,EAAE,UAAU,CAAC;IACvB,iBAAiB,EAAE;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,CAAM;IAClD,gBAAgB,EAAE;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,CAAM;IACjD,aAAa,EAAE,MAAM,CAAQ;IAE7B,UAAU,IAAI,MAAM;IAQd,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE;IA8BpC,uBAAuB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAK/C,OAAO;gBAMK,UAAU,KAAA;IAWhB,YAAY,CAAC,EAAC,OAAO,EAAE,GAAG,EAAE,YAAiB,EAAC,EAAE;QACpD,OAAO,EAAE,MAAM,CAAC;QAChB,GAAG,EAAE,MAAM,CAAC;QACZ,YAAY,CAAC,EAAE;YAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAA;SAAE,CAAA;KACzC;IA8CK,QAAQ;IAUd,WAAW;IAIL,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IAgFhE,SAAS;IAQH,cAAc,CAAC,EAAE,YAAY,EAAE,EAAE;QAAE,YAAY,EAAE,MAAM,EAAE,CAAA;KAAE;IAgB3D,yBAAyB,CAAC,OAAO,KAAA;IAMjC,cAAc;IA4cd,iBAAiB,CAAC,EAAE,IAAA;IA4CpB,4BAA4B,CAAC,EAAE,mBAAmB,EAAE,WAAW,EAAE;;;KAAA;IAwEjE,WAAW,CAAC,QAAQ,EAAE,MAAM;IAW5B,kBAAkB,CAAC,UAAU,GAAE,MAA0B,EAAE,QAAQ,GAAE,MAAM,EAAO;IAyBlF,SAAS,CAAC,EAAE,SAAiB,EAAE,EAAE;QAAE,SAAS,EAAE,OAAO,CAAA;KAAE;CA0H9D;AAED,eAAe,YAAY,CAAC"}
1
+ {"version":3,"file":"codeInjector.d.ts","sourceRoot":"","sources":["../../modules/codeInjector.ts"],"names":[],"mappings":"AAQA,OAAO,UAAwC,MAAM,aAAa,CAAC;AAEnE,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAmEjD,cAAM,YAAa,YAAW,aAAa;IAEzC,WAAW,QAAM;IACjB,UAAU,EAAE,UAAU,CAAC;IACvB,iBAAiB,EAAE;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,CAAM;IAClD,gBAAgB,EAAE;QAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,CAAM;IACjD,aAAa,EAAE,MAAM,CAAQ;IAE7B,UAAU,IAAI,MAAM;IAQd,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE;IAmCpC,uBAAuB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IAK/C,OAAO;gBAMK,UAAU,KAAA;IAYhB,uBAAuB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAqBtD,sBAAsB,CAAC,EAAC,OAAO,EAAE,GAAG,EAAE,YAAiB,EAAC,EAAE;QAC9D,OAAO,EAAE,MAAM,CAAC;QAChB,GAAG,EAAE,MAAM,CAAC;QACZ,YAAY,CAAC,EAAE;YAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAA;SAAE,CAAA;KACzC;IAuDK,QAAQ;IAUd,WAAW;IAIL,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IAgFhE,SAAS;IAQH,cAAc,CAAC,EAAE,YAAY,EAAE,EAAE;QAAE,YAAY,EAAE,MAAM,EAAE,CAAA;KAAE;IAgB3D,yBAAyB,CAAC,OAAO,KAAA;IAMjC,cAAc;IA8cd,iBAAiB,CAAC,EAAE,IAAA;IA4CpB,4BAA4B,CAAC,EAAE,mBAAmB,EAAE,WAAW,EAAE;;;KAAA;IAwEjE,WAAW,CAAC,QAAQ,EAAE,MAAM;IAW5B,kBAAkB,CAAC,UAAU,GAAE,MAA0B,EAAE,QAAQ,GAAE,MAAM,EAAO;IAyBlF,SAAS,CAAC,EAAE,SAAiB,EAAE,EAAE;QAAE,SAAS,EAAE,OAAO,CAAA;KAAE;CA2H9D;AAED,eAAe,YAAY,CAAC"}
@@ -77,11 +77,14 @@ class CodeInjector {
77
77
  const uniqueIcons = Array.from(new Set(icons));
78
78
  const collections = new Set(icons.map((icon) => icon.split(':')[0]));
79
79
  const iconPackageNames = Array.from(collections).map((collection) => `@iconify-prerendered/vue-${collection}`);
80
- const iconPackages = (await Promise.allSettled(iconPackageNames.map(async (pkg) => ({ pkg: await import(this.spaTmpPath() + '/node_modules/' + pkg), name: pkg }))));
80
+ console.log('iconPackageNames', iconPackageNames);
81
+ const iconPackages = (await Promise.allSettled(iconPackageNames.map(async (pkg) => ({ pkg: await import(path.join(this.spaTmpPath(), 'node_modules', pkg)), name: pkg }))));
82
+ console.log('iconPackages', iconPackages);
81
83
  const loadedIconPackages = iconPackages.filter(isFulfilled).map((res) => res.value).reduce((acc, { pkg, name }) => {
82
84
  acc[name.slice(`@iconify-prerendered/vue-`.length)] = pkg;
83
85
  return acc;
84
86
  }, {});
87
+ console.log('loadedIconPackages', loadedIconPackages);
85
88
  uniqueIcons.forEach((icon) => {
86
89
  const [collection, iconName] = icon.split(':');
87
90
  const PascalIconName = 'Icon' + iconName.split('-').map((part, index) => {
@@ -117,25 +120,56 @@ class CodeInjector {
117
120
  process.exit();
118
121
  }));
119
122
  }
120
- async runPnpmShell({ command, cwd, envOverrides = {} }) {
123
+ async doesUserHasPnpmLockFile(dir) {
124
+ const usersPackagePath = path.join(dir, 'package.json');
125
+ let packageContent = null;
126
+ try {
127
+ packageContent = JSON.parse(await fs.promises.readFile(usersPackagePath, 'utf-8'));
128
+ }
129
+ catch (e) {
130
+ // user package.json does not exist, user does not have custom components
131
+ }
132
+ if (packageContent) {
133
+ const lockPath = path.join(dir, 'pnpm-lock.yaml');
134
+ let lock = null;
135
+ try {
136
+ lock = yaml.parse(await fs.promises.readFile(lockPath, 'utf-8'));
137
+ return true;
138
+ }
139
+ catch (e) {
140
+ return false;
141
+ }
142
+ }
143
+ return false;
144
+ }
145
+ async runPackageManagerShell({ command, cwd, envOverrides = {} }) {
121
146
  const nodeBinary = process.execPath; // Path to the Node.js binary running this script
122
- // On Windows, pnpm is pnpm.cmd, on Unix systems it's pnpm
123
- const pnpmExecutable = process.platform === 'win32' ? 'pnpm.cmd' : 'pnpm';
124
- const pnpmPath = path.join(path.dirname(nodeBinary), pnpmExecutable); // Path to the pnpm executable
147
+ const doesUserHavePnpmLock = await this.doesUserHasPnpmLockFile(this.adminforth.config.customization.customComponentsDir);
148
+ // On Windows, npm/pnpm is npm/pnpm.cmd, on Unix systems it's npm/pnpm
149
+ let packageExecutable;
150
+ if (doesUserHavePnpmLock) {
151
+ afLogger.trace(`User has pnpm-lock.yaml, using pnpm for installing custom components`);
152
+ packageExecutable = process.platform === 'win32' ? 'pnpm.cmd' : 'pnpm';
153
+ }
154
+ else {
155
+ afLogger.trace(`User does not have pnpm-lock.yaml, falling back to npm for installing custom components`);
156
+ packageExecutable = process.platform === 'win32' ? 'npm.cmd' : 'npm';
157
+ }
158
+ const packagePath = path.join(path.dirname(nodeBinary), packageExecutable); // Path to the package executable
125
159
  const env = Object.assign(Object.assign({ VITE_ADMINFORTH_PUBLIC_PATH: this.adminforth.config.baseUrl, FORCE_COLOR: '1' }, process.env), envOverrides);
126
- afLogger.trace(`⚙️ exec: pnpm ${command}`);
127
- afLogger.trace(`🪲 pnpm ${command} cwd: ${cwd}`);
160
+ afLogger.trace(`⚙️ exec: ${packageExecutable} ${command}`);
161
+ afLogger.trace(`🪲 ${packageExecutable} ${command} cwd: ${cwd}`);
128
162
  let execCommand;
129
163
  if (process.platform === 'win32') {
130
164
  // Quote path if it contains spaces
131
- const quotedPnpmPath = pnpmPath.includes(' ') ? `"${pnpmPath}"` : pnpmPath;
132
- execCommand = `${quotedPnpmPath} ${command}`;
165
+ const quotedPackagePath = packagePath.includes(' ') ? `"${packagePath}"` : packagePath;
166
+ execCommand = `${quotedPackagePath} ${command}`;
133
167
  }
134
168
  else {
135
169
  // Quote paths that contain spaces (for Unix systems)
136
170
  const quotedNodeBinary = nodeBinary.includes(' ') ? `"${nodeBinary}"` : nodeBinary;
137
- const quotedPnpmPath = pnpmPath.includes(' ') ? `"${pnpmPath}"` : pnpmPath;
138
- execCommand = `${quotedNodeBinary} ${quotedPnpmPath} ${command}`;
171
+ const quotedPackagePath = packagePath.includes(' ') ? `"${packagePath}"` : packagePath;
172
+ execCommand = `${quotedNodeBinary} ${quotedPackagePath} ${command}`;
139
173
  }
140
174
  const execOptions = {
141
175
  cwd,
@@ -145,9 +179,9 @@ class CodeInjector {
145
179
  execOptions.shell = true;
146
180
  }
147
181
  const { stderr: err } = await execAsync(execCommand, execOptions);
148
- afLogger.trace(`pnpm ${command} done in`);
182
+ afLogger.trace(`${packageExecutable} ${command} done in`);
149
183
  if (err) {
150
- afLogger.trace(`🪲pnpm ${command} errors/warnings: ${err}`);
184
+ afLogger.trace(`🪲${packageExecutable} ${command} errors/warnings: ${err}`);
151
185
  }
152
186
  }
153
187
  async rmTmpDir() {
@@ -187,7 +221,7 @@ class CodeInjector {
187
221
  npmLock = JSON.parse(await fs.promises.readFile(npmLockPath, 'utf-8'));
188
222
  }
189
223
  catch (npmLockError) {
190
- throw new Error(`Custom pnpm-lock.yaml does not exist in ${dir}, but package.json does.
224
+ throw new Error(`Custom pnpm-lock.yaml or package-lock.json does not exist in ${dir}, but package.json does.
191
225
  We can't determine version of packages without pnpm-lock.yaml or package-lock.json. Please run pnpm install or npm install in ${dir}`);
192
226
  }
193
227
  lockHash = hashify(npmLock);
@@ -583,6 +617,7 @@ class CodeInjector {
583
617
  routerVueContent = routerVueContent.replace('/* IMPORTANT:ADMINFORTH ROUTES */', routes);
584
618
  await fs.promises.writeFile(routerVuePath, routerVueContent);
585
619
  /* hash checking */
620
+ // Here we use pnpm-lock.yaml, because this file will be anywat, even if user doesn't use it
586
621
  const spaPnpmLockPath = path.join(this.spaTmpPath(), 'pnpm-lock.yaml');
587
622
  const spaPnpmLock = yaml.parse(await fs.promises.readFile(spaPnpmLockPath, 'utf-8'));
588
623
  const spaLockHash = hashify(spaPnpmLock);
@@ -625,7 +660,8 @@ class CodeInjector {
625
660
  // ignore
626
661
  afLogger.trace(`🪲Hash file does not exist, proceeding with pnpm install, ${e}`);
627
662
  }
628
- await this.runPnpmShell({ command: 'install --frozen-lockfile', cwd: this.spaTmpPath(), envOverrides: {
663
+ // install --frozen-lockfile works for npm and pnpm
664
+ await this.runPackageManagerShell({ command: 'install --frozen-lockfile', cwd: this.spaTmpPath(), envOverrides: {
629
665
  NODE_ENV: 'development' // otherwise it will not install devDependencies which we still need, e.g for extract
630
666
  } });
631
667
  const allPacks = [
@@ -642,9 +678,9 @@ class CodeInjector {
642
678
  });
643
679
  const allPacksUnique = Array.from(new Set(allPacksFiltered));
644
680
  if (allPacks.length) {
645
- const pnpmInstallCommand = `install ${allPacksUnique.join(' ')}`;
646
- await this.runPnpmShell({
647
- command: pnpmInstallCommand, cwd: this.spaTmpPath(),
681
+ const packageManagerInstallCommand = `install ${allPacksUnique.join(' ')}`;
682
+ await this.runPackageManagerShell({
683
+ command: packageManagerInstallCommand, cwd: this.spaTmpPath(),
648
684
  envOverrides: {
649
685
  NODE_ENV: 'development' // otherwise it will not install devDependencies which we still need, e.g for extract
650
686
  }
@@ -818,7 +854,7 @@ class CodeInjector {
818
854
  await fs.promises.mkdir(serveDir, { recursive: true });
819
855
  }
820
856
  if (!skipExtract) {
821
- await this.runPnpmShell({ command: 'run i18n:extract', cwd });
857
+ await this.runPackageManagerShell({ command: 'run i18n:extract', cwd });
822
858
  // create serveDir if not exists
823
859
  await fs.promises.mkdir(serveDir, { recursive: true });
824
860
  // copy i18n messages to serve dir
@@ -832,7 +868,7 @@ class CodeInjector {
832
868
  if (!hotReload) {
833
869
  if (!skipBuild) {
834
870
  // TODO probably add option to build with tsh check (plain 'build')
835
- await this.runPnpmShell({ command: 'run build-only', cwd });
871
+ await this.runPackageManagerShell({ command: 'run build-only', cwd });
836
872
  // coy dist to serveDir
837
873
  await fsExtra.copy(path.join(cwd, 'dist'), serveDir, { recursive: true });
838
874
  // save hash
@@ -844,19 +880,20 @@ class CodeInjector {
844
880
  }
845
881
  else {
846
882
  const command = 'run dev';
847
- afLogger.info(`⚙️ spawn: pnpm ${command}...`);
883
+ const usersPackageManager = await this.doesUserHasPnpmLockFile(this.adminforth.config.customization.customComponentsDir) ? 'pnpm' : 'npm';
884
+ afLogger.info(`⚙️ spawn: ${usersPackageManager} ${command}...`);
848
885
  if (process.env.VITE_ADMINFORTH_PUBLIC_PATH) {
849
886
  afLogger.info(`⚠️ Your VITE_ADMINFORTH_PUBLIC_PATH: ${process.env.VITE_ADMINFORTH_PUBLIC_PATH} has no effect`);
850
887
  }
851
888
  const env = Object.assign({ VITE_ADMINFORTH_PUBLIC_PATH: this.adminforth.config.baseUrl, FORCE_COLOR: '1' }, process.env);
852
889
  const nodeBinary = process.execPath;
853
- const pnpmPath = path.join(path.dirname(nodeBinary), 'pnpm');
890
+ const packageManagerPath = path.join(path.dirname(nodeBinary), usersPackageManager);
854
891
  let devServer;
855
892
  if (process.platform === 'win32') {
856
- devServer = spawn('pnpm', command.split(' '), { cwd, env, shell: true });
893
+ devServer = spawn(usersPackageManager, command.split(' '), { cwd, env, shell: true });
857
894
  }
858
895
  else {
859
- devServer = spawn(`${nodeBinary}`, [`${pnpmPath}`, ...command.split(' ')], { cwd, env });
896
+ devServer = spawn(`${nodeBinary}`, [`${packageManagerPath}`, ...command.split(' ')], { cwd, env });
860
897
  }
861
898
  devServer.stdout.on('data', (data) => {
862
899
  if (data.includes('➜')) {