Skip to content

Commit 0d10ea9

Browse files
committed
fix: cli no creates Dockerfile and .dockerignore for easier deployment
1 parent dc6eae0 commit 0d10ea9

File tree

8 files changed

+81
-25
lines changed

8 files changed

+81
-25
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
node_modules
2+
{{#if sqliteFile}}
3+
{{ sqliteFile }}
4+
{{/if}}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
NODE_ENV=production
2+
DATABASE_URL=sqlite://.db.sqlite
3+
DATABASE_URL={{dbUrl}}
4+
{{#if prismaDbUrl}}
5+
PRISMA_DATABASE_URL={{prismaDbUrl}}
6+
{{/if}}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
FROM node:{{nodeMajor}}-slim
2+
WORKDIR /code/
3+
ADD package.json package-lock.json /code/
4+
RUN npm ci
5+
ADD . /code/
6+
RUN --mount=type=cache,target=/tmp npx adminforth bundle
7+
CMD ["sh", "-c", "npm run migrate:prod && npm run prod"]

adminforth/commands/createApp/templates/index.ts.hbs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,9 @@ if (import.meta.url === `file://${process.argv[1]}`) {
6060
app.use(express.json());
6161

6262
const port = 3500;
63-
63+
6464
await admin.bundleNow({ hotReload: process.env.NODE_ENV === 'development' });
65-
console.log('Bundling AdminForth done. For faster serving consider calling bundleNow() from a build script.');
65+
console.log('Bundling AdminForth SPA done.');
6666

6767
admin.express.serve(app)
6868

adminforth/commands/createApp/templates/package.json.hbs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,14 @@
88
"license": "ISC",
99
"description": "",
1010
"scripts": {
11-
"env": "dotenvx run -f .env.local -f .env --overload --",
12-
"start": "npm run env -- tsx watch index.ts",
13-
"migrateLocal": "npm run env -- npx prisma migrate deploy",
14-
"makemigration": "npm run migrateLocal; npm run env -- npx --yes prisma migrate dev",
15-
"test": "echo \"Error: no test specified\" && exit 1"
11+
"dev": "npm run _env:dev -- tsx watch index.ts",
12+
"prod": "npm run _env:prod -- tsx index.ts",
13+
"start": "npm run dev",
14+
"makemigration": "npm run _env:dev -- npx --yes prisma migrate dev --create-only",
15+
"migrate:local": "npm run _env:dev -- npx --yes prisma migrate deploy",
16+
"migrate:prod": "npm run _env:prod -- npx --yes prisma migrate deploy",
17+
"_env:dev": "dotenvx run -f .env -f .env.local --",
18+
"_env:prod": "dotenvx run -f .env.prod --"
1619
},
1720
"engines": {
1821
"node": ">=20"

adminforth/commands/createApp/templates/readme.md.hbs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,13 @@ npm ci
99
Migrate the database:
1010

1111
```bash
12-
npm run migrateLocal
12+
npm run migrate:local
1313
```
1414

1515
Start the server:
1616

1717
```bash
18-
npm start
18+
npm run dev
1919
```
2020

2121
{{#if prismaDbUrl}}
@@ -32,6 +32,18 @@ npm run makemigration -- --name <name_of_changes>
3232
Your colleagues will need to pull the changes and run `npm run migrateLocal` to apply the migration in their local database.
3333
{{/if}}
3434

35+
## Deployment tips
36+
37+
You have Dockerfile ready for production deployment. You can test the build with:
38+
39+
```bash
40+
docker build -t {{appName}}-image .
41+
docker run -p 3500:3500 {{appName}}-image
42+
```
43+
44+
To set non-sensitive environment variables in production, use `.env.prod` file.
45+
For sensitive variables, use direct docker environment variables or secrets from your vault.
46+
3547
## Documentation
3648

3749
- [Customizing AdminForth Branding](https://adminforth.dev/docs/tutorial/Customization/branding/)

adminforth/commands/createApp/utils.js

Lines changed: 38 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,12 @@ import path from 'path';
77
import { Listr } from 'listr2'
88
import { fileURLToPath } from 'url';
99
import {ConnectionString} from 'connection-string';
10-
import {execa} from 'execa';
10+
import { exec } from 'child_process';
11+
1112
import Handlebars from 'handlebars';
13+
import { promisify } from 'util';
14+
15+
const execAsync = promisify(exec);
1216

1317
export function parseArgumentsIntoOptions(rawArgs) {
1418
const args = arg(
@@ -145,18 +149,19 @@ async function scaffoldProject(ctx, options, cwd) {
145149
await fse.copy(sourceAssetsDir, targetAssetsDir);
146150

147151
// Write templated files
148-
writeTemplateFiles(dirname, projectDir, {
152+
await writeTemplateFiles(dirname, projectDir, {
149153
dbUrl: connectionString.toString(),
150154
prismaDbUrl,
151155
appName,
152156
provider,
157+
nodeMajor: parseInt(process.versions.node.split('.')[0], 10),
153158
});
154159

155160
return projectDir; // Return the new directory path
156161
}
157162

158163
async function writeTemplateFiles(dirname, cwd, options) {
159-
const { dbUrl, prismaDbUrl, appName, provider } = options;
164+
const { dbUrl, prismaDbUrl, appName, provider, nodeMajor } = options;
160165

161166
// Build a list of files to generate
162167
const templateTasks = [
@@ -191,10 +196,15 @@ async function writeTemplateFiles(dirname, cwd, options) {
191196
dest: '.env.local',
192197
data: { dbUrl, prismaDbUrl },
193198
},
199+
{
200+
src: '.env.prod.hbs',
201+
dest: '.env.prod',
202+
data: { dbUrl, prismaDbUrl },
203+
},
194204
{
195205
src: 'readme.md.hbs',
196206
dest: 'README.md',
197-
data: { dbUrl, prismaDbUrl },
207+
data: { dbUrl, prismaDbUrl, appName },
198208
},
199209
{
200210
// We'll write .env using the same content as .env.sample
@@ -218,6 +228,18 @@ async function writeTemplateFiles(dirname, cwd, options) {
218228
dest: 'custom/tsconfig.json',
219229
data: {},
220230
},
231+
{
232+
src: 'Dockerfile.hbs',
233+
dest: 'Dockerfile',
234+
data: { nodeMajor },
235+
},
236+
{
237+
src: '.dockerignore.hbs',
238+
dest: '.dockerignore',
239+
data: {
240+
sqliteFile: detectDbProvider(options.db).startsWith('sqlite') ? options.db.split('://')[1] : null,
241+
},
242+
}
221243
];
222244

223245
for (const task of templateTasks) {
@@ -228,38 +250,41 @@ async function writeTemplateFiles(dirname, cwd, options) {
228250
// fse.ensureDirSync(path.dirname(destPath));
229251

230252
if (task.empty) {
231-
fs.writeFileSync(destPath, '');
253+
await fs.promises.writeFile(destPath, '');
232254
} else {
233255
const templatePath = path.join(dirname, 'templates', task.src);
234256
const compiled = renderHBSTemplate(templatePath, task.data);
235-
fs.writeFileSync(destPath, compiled);
257+
await fs.promises.writeFile(destPath, compiled);
236258
}
237259
}
238260
}
239261

240262
async function installDependencies(ctx, cwd) {
241-
const customDir = ctx.customDir;
263+
const nodeBinary = process.execPath; // Path to the Node.js binary running this script
264+
const npmPath = path.join(path.dirname(nodeBinary), 'npm'); // Path to the npm executable
242265

243-
await Promise.all([
244-
await execa('npm', ['install'], { cwd }),
245-
await execa('npm', ['install'], { cwd: customDir }),
266+
const customDir = ctx.customDir;
267+
const res = await Promise.all([
268+
await execAsync(`${nodeBinary} ${npmPath} install`, { cwd, env: { PATH: process.env.PATH } }),
269+
await execAsync(`${nodeBinary} ${npmPath} install`, { cwd: customDir, env: { PATH: process.env.PATH } }),
246270
]);
271+
// console.log(chalk.dim(`Dependencies installed in ${cwd} and ${customDir}: \n${res[0].stdout}${res[1].stdout}`));
247272
}
248273

249274
function generateFinalInstructions(skipPrismaSetup, options) {
250275
let instruction = '⏭️ Run the following commands to get started:\n';
251276
if (!skipPrismaSetup)
252277
instruction += `
253278
${chalk.dim('// Go to the project directory')}
254-
${chalk.cyan(`$ cd ${options.appName}`)}\n`;
279+
${chalk.dim('$')}${chalk.cyan(` cd ${options.appName}`)}\n`;
255280

256281
instruction += `
257282
${chalk.dim('// Generate and apply initial migration')}
258-
${chalk.cyan('$ npm run makemigration -- --name init')}\n`;
283+
${chalk.dim('$')}${chalk.cyan(' npm run makemigration -- --name init && npm run migrate:local')}\n`;
259284

260285
instruction += `
261286
${chalk.dim('// Start dev server with tsx watch for hot-reloading')}
262-
${chalk.cyan('$ npm start')}\n
287+
${chalk.dim('$')}${chalk.cyan(' npm run dev')}\n
263288
`;
264289

265290
instruction += '😉 Happy coding!';

dev-demo/package.json

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,9 @@
66
"type": "module",
77
"scripts": {
88
"env": "dotenvx run -f .env.local -f .env --overload --",
9-
"test": "echo \"Error: no test specified\" && exit 1",
109
"start": "npm run env -- tsx watch index.ts",
11-
"migrateLocal": "npm run env -- npx prisma migrate deploy",
12-
"makemigration": "npm run migrateLocal; npm run env -- npx --yes prisma migrate dev"
10+
"makemigration": "npm run _env:dev -- npx --yes prisma migrate dev --create-only",
11+
"migrate:local": "npm run _env:dev -- npx --yes prisma migrate deploy"
1312
},
1413
"author": "",
1514
"license": "ISC",

0 commit comments

Comments
 (0)