express-modular-monolith 1.1.3 → 1.2.0
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 +58 -5
- package/bin/boilerPlateCodes.js +19 -0
- package/bin/cli.js +102 -23
- package/bin/cliQuestions.js +38 -0
- package/bin/config.js +272 -0
- package/bin/packages.js +51 -0
- package/package.json +3 -2
- package/templates/javascript/src/app.js +2 -1
- package/templates/javascript/src/server.js +3 -3
- package/templates/typescript/package.json +2 -1
- package/templates/typescript/src/app.ts +6 -3
- package/templates/typescript/src/server.ts +3 -3
- package/templates/typescript/tsconfig.json +3 -0
package/README.md
CHANGED
|
@@ -1,14 +1,67 @@
|
|
|
1
1
|
# Express Modular Monolith
|
|
2
2
|
|
|
3
|
-
Generate an Express modular monolith boilerplate.
|
|
3
|
+
Generate an Express modular monolith boilerplate with JavaScript or TypeScript.
|
|
4
|
+
|
|
5
|
+
> **Note:** This architecture is not opinionated or prescriptive. You can modify, extend, or completely rewrite it to fit your project's requirements.
|
|
4
6
|
|
|
5
7
|
## Usage
|
|
8
|
+
|
|
6
9
|
```bash
|
|
7
10
|
npx express-modular-monolith
|
|
8
11
|
```
|
|
12
|
+
|
|
9
13
|
## Features
|
|
10
14
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
+
* JavaScript template
|
|
16
|
+
* TypeScript template
|
|
17
|
+
* Modular monolith structure
|
|
18
|
+
* Express
|
|
19
|
+
* MongoDB with Mongoose
|
|
20
|
+
* PostgreSQL with Drizzle ORM
|
|
21
|
+
* Automatic Git repository initialization
|
|
22
|
+
* Automatic initial Git commit
|
|
23
|
+
|
|
24
|
+
## What's New in v1.2.0
|
|
25
|
+
|
|
26
|
+
* Added MongoDB + Mongoose support
|
|
27
|
+
* Added PostgreSQL + Drizzle ORM support
|
|
28
|
+
* Added database and ORM/ODM selection during project generation
|
|
29
|
+
* Both JavaScript and TypeScript templates support the available database configurations
|
|
30
|
+
|
|
31
|
+
## How It Works
|
|
32
|
+
|
|
33
|
+
Run:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
npx express-modular-monolith
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Choose your preferred language, database, and ORM/ODM. The CLI will:
|
|
40
|
+
|
|
41
|
+
1. Generate the selected boilerplate
|
|
42
|
+
2. Configure the selected database and ORM/ODM
|
|
43
|
+
3. Install the required dependencies
|
|
44
|
+
4. Initialize a Git repository
|
|
45
|
+
5. Add the generated files to Git
|
|
46
|
+
6. Create an initial commit
|
|
47
|
+
|
|
48
|
+
Currently supported configurations:
|
|
49
|
+
|
|
50
|
+
| Language | Database | ORM/ODM |
|
|
51
|
+
| ---------- | ---------- | -------- |
|
|
52
|
+
| JavaScript | MongoDB | Mongoose |
|
|
53
|
+
| JavaScript | PostgreSQL | Drizzle |
|
|
54
|
+
| TypeScript | MongoDB | Mongoose |
|
|
55
|
+
| TypeScript | PostgreSQL | Drizzle |
|
|
56
|
+
|
|
57
|
+
Your generated project will be ready for development with the selected database configuration and Git already initialized.
|
|
58
|
+
|
|
59
|
+
## Requirements
|
|
60
|
+
|
|
61
|
+
* Node.js
|
|
62
|
+
* npm
|
|
63
|
+
* Git
|
|
64
|
+
|
|
65
|
+
## License
|
|
66
|
+
|
|
67
|
+
MIT
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export const mongodbConBoilerplateCode = `import mongoose from "mongoose"
|
|
2
|
+
|
|
3
|
+
const MONGODB_URI = process.env.MONGODB_URI;
|
|
4
|
+
|
|
5
|
+
export const connectionDB = async () => {
|
|
6
|
+
try{
|
|
7
|
+
await mongoose.connect(MONGODB_URI)
|
|
8
|
+
}catch (error) {
|
|
9
|
+
console.error("MongoDB connection failed", error)
|
|
10
|
+
process.exit(1)
|
|
11
|
+
}
|
|
12
|
+
}`
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
export const drizzlePostgresBoilerPlate = `import "dotenv/config";
|
|
16
|
+
import { drizzle } from "drizzle-orm/node-postgres";
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
export const db = drizzle(process.env.POSTGRES_URL);`
|
package/bin/cli.js
CHANGED
|
@@ -5,28 +5,52 @@ import { fileURLToPath } from "node:url";
|
|
|
5
5
|
import { exec as execCallback } from "node:child_process";
|
|
6
6
|
import { promisify } from "node:util";
|
|
7
7
|
import fs from "node:fs/promises";
|
|
8
|
-
import
|
|
8
|
+
import process from "node:process";
|
|
9
|
+
import { select } from "@inquirer/prompts";
|
|
10
|
+
import { projectName, language, DB } from "./cliQuestions.js";
|
|
11
|
+
import { dbPackages } from "./packages.js";
|
|
12
|
+
import ora from "ora";
|
|
13
|
+
import { addEnvBasedOnDBs, JSboilerPlateCodeSetUp, DBboilerCodeSetUp, TSboilerPlateCodeSetUp } from "./config.js";
|
|
14
|
+
|
|
9
15
|
|
|
10
16
|
const exec = promisify(execCallback);
|
|
11
17
|
|
|
12
|
-
const
|
|
13
|
-
|
|
18
|
+
const spinnerDiscardingStdin = ora({
|
|
19
|
+
text: "Loading Packages",
|
|
20
|
+
spinner: process.argv[2],
|
|
21
|
+
color: "cyan"
|
|
14
22
|
});
|
|
15
23
|
|
|
16
|
-
const language = await select({
|
|
17
|
-
message: "Choose a language:",
|
|
18
|
-
choices: [
|
|
19
|
-
{
|
|
20
|
-
name: "JavaScript",
|
|
21
|
-
value: "javascript"
|
|
22
|
-
},
|
|
23
|
-
{
|
|
24
|
-
name: "TypeScript",
|
|
25
|
-
value: "typescript"
|
|
26
|
-
}
|
|
27
|
-
]
|
|
28
|
-
});
|
|
29
24
|
|
|
25
|
+
let modelTool;
|
|
26
|
+
|
|
27
|
+
if (DB === "mongodb") {
|
|
28
|
+
modelTool = await select({
|
|
29
|
+
message: "Choose ODM:",
|
|
30
|
+
choices: [
|
|
31
|
+
{
|
|
32
|
+
name: "Mongoose",
|
|
33
|
+
value: "mongoose"
|
|
34
|
+
}
|
|
35
|
+
]
|
|
36
|
+
});
|
|
37
|
+
} else {
|
|
38
|
+
modelTool = await select({
|
|
39
|
+
message: "Choose ORM:",
|
|
40
|
+
choices: [
|
|
41
|
+
{
|
|
42
|
+
name: "Drizzle",
|
|
43
|
+
value: "drizzle"
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
name: "Prisma",
|
|
47
|
+
value: "prisma"
|
|
48
|
+
}
|
|
49
|
+
]
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
spinnerDiscardingStdin.start("Installing required packages, wait for a while");
|
|
30
54
|
|
|
31
55
|
const __filename = fileURLToPath(import.meta.url);
|
|
32
56
|
const __dirname = path.dirname(__filename);
|
|
@@ -48,29 +72,84 @@ if (projectName === ".") {
|
|
|
48
72
|
packageJson.name = projectName;
|
|
49
73
|
}
|
|
50
74
|
|
|
75
|
+
const selectedPackages = dbPackages[DB][modelTool];
|
|
76
|
+
|
|
77
|
+
packageJson.dependencies = {
|
|
78
|
+
...packageJson.dependencies,
|
|
79
|
+
...selectedPackages.dependencies
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
packageJson.devDependencies = {
|
|
83
|
+
...packageJson.devDependencies,
|
|
84
|
+
...selectedPackages.devDependencies
|
|
85
|
+
};
|
|
86
|
+
|
|
51
87
|
await fs.writeFile(
|
|
52
88
|
packageJsonPath,
|
|
53
89
|
JSON.stringify(packageJson, null, 2)
|
|
54
|
-
)
|
|
90
|
+
).catch((err)=>{
|
|
91
|
+
spinnerDiscardingStdin.fail(err)
|
|
92
|
+
spinnerDiscardingStdin.start()
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
let lang;
|
|
96
|
+
|
|
97
|
+
if (templatePath.includes("javascript")) {
|
|
98
|
+
await JSboilerPlateCodeSetUp(projectPath)
|
|
99
|
+
await DBboilerCodeSetUp(projectPath, DB, modelTool, lang = "javascript")
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if (templatePath.includes("typescript")) {
|
|
103
|
+
await TSboilerPlateCodeSetUp(projectPath)
|
|
104
|
+
await DBboilerCodeSetUp(projectPath, DB, modelTool, lang = "typescript")
|
|
105
|
+
if(modelTool === "mongoose"){
|
|
106
|
+
await exec("npm install @types/mongoose -D", {
|
|
107
|
+
cwd: projectPath
|
|
108
|
+
})
|
|
109
|
+
}
|
|
110
|
+
}
|
|
55
111
|
|
|
56
112
|
await exec("npx gitignore node", {
|
|
57
113
|
cwd: projectPath
|
|
58
|
-
})
|
|
114
|
+
}).catch((err)=>{
|
|
115
|
+
spinnerDiscardingStdin.fail("Failed to load .gitignore, run 'npx gitignore node in project root directory to load .gitignore")
|
|
116
|
+
spinnerDiscardingStdin.start()
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
await fs.writeFile(".env", "PORT=8000\n").catch((err)=>{
|
|
120
|
+
spinnerDiscardingStdin.fail("Failed to create .env file")
|
|
121
|
+
spinnerDiscardingStdin.start()
|
|
122
|
+
}).then(async ()=>{
|
|
123
|
+
await addEnvBasedOnDBs(projectPath, DB)
|
|
124
|
+
});
|
|
59
125
|
|
|
60
|
-
await fs.writeFile(".env", "PORT=8000\n")
|
|
61
126
|
|
|
62
127
|
await exec("npm install", {
|
|
63
128
|
cwd: projectPath
|
|
64
|
-
})
|
|
129
|
+
}).catch((err)=>{
|
|
130
|
+
spinnerDiscardingStdin.fail("Failed to load required packeages, run 'npm install' to load packages")
|
|
131
|
+
spinnerDiscardingStdin.start()
|
|
132
|
+
});
|
|
65
133
|
|
|
66
134
|
await exec("git init", {
|
|
67
135
|
cwd: projectPath
|
|
68
|
-
})
|
|
136
|
+
}).catch((err)=>{
|
|
137
|
+
spinnerDiscardingStdin.fail("Failed to initialize the repo, run 'git init' to initialize the repo")
|
|
138
|
+
spinnerDiscardingStdin.start()
|
|
139
|
+
});
|
|
69
140
|
|
|
70
141
|
await exec("git add .", {
|
|
71
142
|
cwd: projectPath
|
|
72
|
-
})
|
|
143
|
+
}).catch((err)=>{
|
|
144
|
+
spinnerDiscardingStdin.fail("Failed to get staged the files, run 'git add .' to get staged")
|
|
145
|
+
spinnerDiscardingStdin.start()
|
|
146
|
+
});
|
|
73
147
|
|
|
74
148
|
await exec(`git commit -m "Initial commit"`, {
|
|
75
149
|
cwd: projectPath
|
|
76
|
-
})
|
|
150
|
+
}).catch((err)=>{
|
|
151
|
+
spinnerDiscardingStdin.fail(`Failed to commit, run 'git commit -m "Inital commit"`)
|
|
152
|
+
spinnerDiscardingStdin.start()
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
spinnerDiscardingStdin.succeed("Packages successfully installed");
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { input, select } from "@inquirer/prompts";
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
export const projectName = await input({
|
|
5
|
+
message: "Project name:"
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
export const language = await select({
|
|
9
|
+
message: "Choose a language:",
|
|
10
|
+
choices: [
|
|
11
|
+
{
|
|
12
|
+
name: "JavaScript",
|
|
13
|
+
value: "javascript"
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
name: "TypeScript",
|
|
17
|
+
value: "typescript"
|
|
18
|
+
}
|
|
19
|
+
]
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
export const DB = await select({
|
|
23
|
+
message: "Choose a database:",
|
|
24
|
+
choices: [
|
|
25
|
+
{
|
|
26
|
+
name: "PostgreSQL",
|
|
27
|
+
value: "postgresql"
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
name: "MySQL",
|
|
31
|
+
value: "mysql"
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
name: "MongoDB",
|
|
35
|
+
value: "mongodb"
|
|
36
|
+
}
|
|
37
|
+
]
|
|
38
|
+
});
|
package/bin/config.js
ADDED
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import fs from "node:fs/promises";
|
|
3
|
+
import ora from "ora";
|
|
4
|
+
import { drizzlePostgresBoilerPlate, mongodbConBoilerplateCode } from "./boilerPlateCodes.js";
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
const spinnerDiscardingStdin = ora({
|
|
8
|
+
text: "Loading Packages",
|
|
9
|
+
spinner: process.argv[2],
|
|
10
|
+
color: "cyan"
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
export const JSboilerPlateCodeSetUp = async (projectPath) => {
|
|
15
|
+
const appJsPath = path.join(projectPath, "/src/app.js")
|
|
16
|
+
|
|
17
|
+
const targetLine = 8
|
|
18
|
+
const insertedData = `app.get("/", (req, res)=> {
|
|
19
|
+
res.json("Server is up and running")
|
|
20
|
+
})`
|
|
21
|
+
|
|
22
|
+
const data = await fs.readFile(appJsPath, "utf-8")
|
|
23
|
+
|
|
24
|
+
const lines = data.split(/\r?\n/);
|
|
25
|
+
lines.splice(targetLine - 1, 0, insertedData);
|
|
26
|
+
const updatedContent = lines.join("\n");
|
|
27
|
+
|
|
28
|
+
fs.writeFile(appJsPath, updatedContent, "utf-8", (err) => {
|
|
29
|
+
if (err) {
|
|
30
|
+
spinnerDiscardingStdin.fail(err?.message)
|
|
31
|
+
spinnerDiscardingStdin.start()
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export const TSboilerPlateCodeSetUp = async (projectPath) => {
|
|
40
|
+
const appTsPath = path.join(projectPath, "/src/app.ts")
|
|
41
|
+
|
|
42
|
+
const targetLine = [2, 8]
|
|
43
|
+
|
|
44
|
+
const insertedData = [
|
|
45
|
+
`import type { Express, Request, Response } from "express"`,
|
|
46
|
+
`app.get("/", (req:Request, res:Response)=> {
|
|
47
|
+
res.json("Server is up and running")
|
|
48
|
+
})`
|
|
49
|
+
]
|
|
50
|
+
|
|
51
|
+
const data = await fs.readFile(appTsPath, "utf-8")
|
|
52
|
+
|
|
53
|
+
const lines = data.split(/\r?\n/);
|
|
54
|
+
|
|
55
|
+
lines.splice(targetLine[0] , 0, insertedData[0]);
|
|
56
|
+
lines.splice(1, 1)
|
|
57
|
+
lines.splice(targetLine[1] , 0, insertedData[1]);
|
|
58
|
+
|
|
59
|
+
const updatedContent = lines.join("\n");
|
|
60
|
+
|
|
61
|
+
fs.writeFile(appTsPath, updatedContent, "utf-8", (err) => {
|
|
62
|
+
if (err) {
|
|
63
|
+
spinnerDiscardingStdin.fail(err?.message)
|
|
64
|
+
spinnerDiscardingStdin.start()
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export const addEnvBasedOnDBs = async (projectPath, DB) => {
|
|
71
|
+
const targetLine = 2
|
|
72
|
+
|
|
73
|
+
if (DB === "mongodb") {
|
|
74
|
+
const envVar = "MONGODB_URI=mongodb+srv://<username>:<password>@<cluster-url>/<database_name>?retryWrites=true&w=majority"
|
|
75
|
+
|
|
76
|
+
const dotEnvPath = path.join(projectPath, ".env")
|
|
77
|
+
|
|
78
|
+
const envData = await fs.readFile(dotEnvPath, "utf-8")
|
|
79
|
+
|
|
80
|
+
const lines = envData.split(/\r?\n/);
|
|
81
|
+
lines.splice(targetLine - 1, 0, envVar);
|
|
82
|
+
|
|
83
|
+
const updatedContent = lines.join("\n");
|
|
84
|
+
|
|
85
|
+
fs.writeFile(dotEnvPath, updatedContent, "utf-8", (err) => {
|
|
86
|
+
if (err) {
|
|
87
|
+
spinnerDiscardingStdin.fail(err?.message)
|
|
88
|
+
spinnerDiscardingStdin.start()
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (DB === "postgresql" || DB === "mysql") {
|
|
95
|
+
const envVar = "DATABASE_URL=postgresql://user:password@localhost:5432/mydatabase?sslmode=prefer"
|
|
96
|
+
|
|
97
|
+
const dotEnvPath = path.join(projectPath, ".env")
|
|
98
|
+
|
|
99
|
+
const envData = await fs.readFile(dotEnvPath, "utf-8")
|
|
100
|
+
|
|
101
|
+
const lines = envData.split(/\r?\n/);
|
|
102
|
+
lines.splice(targetLine - 1, 0, envVar);
|
|
103
|
+
|
|
104
|
+
const updatedContent = lines.join("\n");
|
|
105
|
+
|
|
106
|
+
fs.writeFile(dotEnvPath, updatedContent, "utf-8", (err) => {
|
|
107
|
+
if (err) {
|
|
108
|
+
spinnerDiscardingStdin.fail(err?.message)
|
|
109
|
+
spinnerDiscardingStdin.start()
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export const DBboilerCodeSetUp = async (projectPath, DB, modelTool, language) => {
|
|
117
|
+
if (language === "javascript") {
|
|
118
|
+
if (DB === "mongodb") {
|
|
119
|
+
const dbJsPath = path.join(projectPath, "/src/common/config/db.js")
|
|
120
|
+
|
|
121
|
+
fs.writeFile(dbJsPath, mongodbConBoilerplateCode, "utf-8", (err)=>{
|
|
122
|
+
if (err) {
|
|
123
|
+
spinnerDiscardingStdin.fail(err?.message)
|
|
124
|
+
spinnerDiscardingStdin.start()
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
})
|
|
128
|
+
|
|
129
|
+
const serverJsPath = path.join(projectPath, "/src/server.js")
|
|
130
|
+
const serverJsData = await fs.readFile(serverJsPath, "utf-8");
|
|
131
|
+
|
|
132
|
+
const targetLine = [3, 9]
|
|
133
|
+
const insertedData = [`import { connectionDB } from "./common/config/db.js"`,
|
|
134
|
+
` await connectionDB()`];
|
|
135
|
+
|
|
136
|
+
const lines = serverJsData.split(/\r?\n/);
|
|
137
|
+
lines.splice(targetLine[0] - 1, 0, insertedData[0])
|
|
138
|
+
lines.splice(targetLine[1], 1)
|
|
139
|
+
lines.splice(targetLine[1], 0, insertedData[1])
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
const updatedContent = lines.join("\n");
|
|
144
|
+
|
|
145
|
+
fs.writeFile(serverJsPath, updatedContent, "utf-8", (err)=>{
|
|
146
|
+
if (err) {
|
|
147
|
+
spinnerDiscardingStdin.fail(err?.message)
|
|
148
|
+
spinnerDiscardingStdin.start()
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
})
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
if (DB === "postgresql" && modelTool === "drizzle") {
|
|
155
|
+
const dbJsPath = path.join(projectPath, "/src/common/config/db.js")
|
|
156
|
+
|
|
157
|
+
fs.writeFile(dbJsPath, drizzlePostgresBoilerPlate, "utf-8", (err)=>{
|
|
158
|
+
if (err) {
|
|
159
|
+
spinnerDiscardingStdin.fail(err?.message)
|
|
160
|
+
spinnerDiscardingStdin.start()
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
})
|
|
164
|
+
|
|
165
|
+
const serverJsPath = path.join(projectPath, "/src/server.js");
|
|
166
|
+
const serverJsData = await fs.readFile(serverJsPath, "utf-8");
|
|
167
|
+
|
|
168
|
+
const targetLine = [3, 9]
|
|
169
|
+
const insertedData = [`import { db } from "./common/config/db.js";
|
|
170
|
+
import { sql } from "drizzle-orm"`,
|
|
171
|
+
' await db.execute(sql`select 1`)'];
|
|
172
|
+
|
|
173
|
+
const lines = serverJsData.split(/\r?\n/);
|
|
174
|
+
lines.splice(targetLine[0] - 1, 0, insertedData[0])
|
|
175
|
+
lines.splice(targetLine[1], 1)
|
|
176
|
+
lines.splice(targetLine[1], 0, insertedData[1])
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
const updatedContent = lines.join("\n");
|
|
181
|
+
|
|
182
|
+
fs.writeFile(serverJsPath, updatedContent, "utf-8", (err)=>{
|
|
183
|
+
if (err) {
|
|
184
|
+
spinnerDiscardingStdin.fail(err?.message)
|
|
185
|
+
spinnerDiscardingStdin.start()
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
})
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
if (language === "typescript") {
|
|
193
|
+
if (DB === "mongodb") {
|
|
194
|
+
const dbTsPath = path.join(projectPath, "/src/common/config/db.ts")
|
|
195
|
+
|
|
196
|
+
const mongodbBoilerlines = mongodbConBoilerplateCode.split(/\r?\n/)
|
|
197
|
+
mongodbBoilerlines.splice(2, 1)
|
|
198
|
+
mongodbBoilerlines.splice(2, 0, 'const MONGODB_URI = process.env.MONGODB_URI!;')
|
|
199
|
+
|
|
200
|
+
const updatedmongodbBoiler = mongodbBoilerlines.join("\n")
|
|
201
|
+
|
|
202
|
+
fs.writeFile(dbTsPath, updatedmongodbBoiler, "utf-8", (err)=>{
|
|
203
|
+
if (err) {
|
|
204
|
+
spinnerDiscardingStdin.fail(err?.message)
|
|
205
|
+
spinnerDiscardingStdin.start()
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
})
|
|
209
|
+
|
|
210
|
+
const serverTsPath = path.join(projectPath, "/src/server.ts")
|
|
211
|
+
const serverTsData = await fs.readFile(serverTsPath, "utf-8");
|
|
212
|
+
|
|
213
|
+
const targetLine = [3, 9]
|
|
214
|
+
const insertedData = [`import { connectionDB } from "./common/config/db.ts"`,
|
|
215
|
+
` await connectionDB()`];
|
|
216
|
+
|
|
217
|
+
const lines = serverTsData.split(/\r?\n/);
|
|
218
|
+
lines.splice(targetLine[0] - 1, 0, insertedData[0])
|
|
219
|
+
lines.splice(targetLine[1], 1)
|
|
220
|
+
lines.splice(targetLine[1], 0, insertedData[1])
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
const updatedContent = lines.join("\n");
|
|
225
|
+
|
|
226
|
+
fs.writeFile(serverTsPath, updatedContent, "utf-8", (err)=>{
|
|
227
|
+
if (err) {
|
|
228
|
+
spinnerDiscardingStdin.fail(err?.message)
|
|
229
|
+
spinnerDiscardingStdin.start()
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
})
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
if (DB === "postgresql" && modelTool === "drizzle") {
|
|
236
|
+
const dbTsPath = path.join(projectPath, "/src/common/config/db.ts")
|
|
237
|
+
|
|
238
|
+
fs.writeFile(dbTsPath, drizzlePostgresBoilerPlate, "utf-8", (err)=>{
|
|
239
|
+
if (err) {
|
|
240
|
+
spinnerDiscardingStdin.fail(err?.message)
|
|
241
|
+
spinnerDiscardingStdin.start()
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
})
|
|
245
|
+
|
|
246
|
+
const serverTsPath = path.join(projectPath, "/src/server.ts");
|
|
247
|
+
const serverTsData = await fs.readFile(serverTsPath, "utf-8");
|
|
248
|
+
|
|
249
|
+
const targetLine = [3, 9]
|
|
250
|
+
const insertedData = [`import { db } from "./common/config/db.ts";
|
|
251
|
+
import { sql } from "drizzle-orm"`,
|
|
252
|
+
' await db.execute(sql`select 1`)'];
|
|
253
|
+
|
|
254
|
+
const lines = serverTsData.split(/\r?\n/);
|
|
255
|
+
lines.splice(targetLine[0] - 1, 0, insertedData[0])
|
|
256
|
+
lines.splice(targetLine[1], 1)
|
|
257
|
+
lines.splice(targetLine[1], 0, insertedData[1])
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
const updatedContent = lines.join("\n");
|
|
262
|
+
|
|
263
|
+
fs.writeFile(serverTsPath, updatedContent, "utf-8", (err)=>{
|
|
264
|
+
if (err) {
|
|
265
|
+
spinnerDiscardingStdin.fail(err?.message)
|
|
266
|
+
spinnerDiscardingStdin.start()
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
269
|
+
})
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
}
|
package/bin/packages.js
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
export const dbPackages = {
|
|
2
|
+
mongodb: {
|
|
3
|
+
mongoose: {
|
|
4
|
+
dependencies: {
|
|
5
|
+
"mongoose": "^9.9.4"
|
|
6
|
+
}
|
|
7
|
+
}
|
|
8
|
+
},
|
|
9
|
+
|
|
10
|
+
postgresql: {
|
|
11
|
+
drizzle: {
|
|
12
|
+
dependencies: {
|
|
13
|
+
"drizzle-orm": "^0.45.2",
|
|
14
|
+
"pg": "^8.20.0"
|
|
15
|
+
},
|
|
16
|
+
devDependencies: {
|
|
17
|
+
"drizzle-kit": "^0.31.10"
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
|
|
21
|
+
prisma: {
|
|
22
|
+
dependencies: {
|
|
23
|
+
"@prisma/client": "^7.10.0",
|
|
24
|
+
"pg": "^8.20.0"
|
|
25
|
+
},
|
|
26
|
+
devDependencies: {
|
|
27
|
+
"prisma": "^7.10.0"
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
|
|
32
|
+
mysql: {
|
|
33
|
+
drizzle: {
|
|
34
|
+
dependencies: {
|
|
35
|
+
"drizzle-orm": "^0.45.2"
|
|
36
|
+
},
|
|
37
|
+
devDependencies: {
|
|
38
|
+
"drizzle-kit": "^0.31.10"
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
|
|
42
|
+
prisma: {
|
|
43
|
+
dependencies: {
|
|
44
|
+
"@prisma/client": "^7.10.0"
|
|
45
|
+
},
|
|
46
|
+
devDependencies: {
|
|
47
|
+
"prisma": "^7.10.0"
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "express-modular-monolith",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "This is a modular monolith project generator for Express.js",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
"license": "MIT",
|
|
11
11
|
"author": "Md Khalid Hossain",
|
|
12
12
|
"dependencies": {
|
|
13
|
-
"@inquirer/prompts": "^8.6.0"
|
|
13
|
+
"@inquirer/prompts": "^8.6.0",
|
|
14
|
+
"ora": "^9.4.1"
|
|
14
15
|
}
|
|
15
16
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import
|
|
2
|
-
import app from
|
|
1
|
+
import "dotenv/config"
|
|
2
|
+
import app from "./app.js"
|
|
3
3
|
|
|
4
4
|
|
|
5
5
|
const PORT = process.env.PORT || 8000
|
|
@@ -11,7 +11,7 @@ const PORT = process.env.PORT || 8000
|
|
|
11
11
|
console.log(`Server is running at port ${PORT}`)
|
|
12
12
|
})
|
|
13
13
|
} catch (error) {
|
|
14
|
-
console.error(
|
|
14
|
+
console.error("Failed to start server", error)
|
|
15
15
|
process.exit(1)
|
|
16
16
|
}
|
|
17
17
|
})()
|
|
@@ -1,7 +1,10 @@
|
|
|
1
|
-
import express from
|
|
2
|
-
import type { Express } from
|
|
3
|
-
|
|
1
|
+
import express from "express"
|
|
2
|
+
import type { Express } from "express"
|
|
4
3
|
|
|
5
4
|
const app:Express = express()
|
|
6
5
|
|
|
6
|
+
app.use(express.json())
|
|
7
|
+
app.use(express.urlencoded({ extended: true }))
|
|
8
|
+
|
|
9
|
+
|
|
7
10
|
export default app
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import
|
|
2
|
-
import app from
|
|
1
|
+
import "dotenv/config"
|
|
2
|
+
import app from "./app.js"
|
|
3
3
|
|
|
4
4
|
|
|
5
5
|
const PORT = process.env.PORT || 8000
|
|
@@ -11,7 +11,7 @@ const PORT = process.env.PORT || 8000
|
|
|
11
11
|
console.log(`Server is running at port ${PORT}`)
|
|
12
12
|
})
|
|
13
13
|
} catch (error) {
|
|
14
|
-
console.error(
|
|
14
|
+
console.error("Failed to start server", error)
|
|
15
15
|
process.exit(1)
|
|
16
16
|
}
|
|
17
17
|
})()
|
|
@@ -32,6 +32,9 @@
|
|
|
32
32
|
// "noFallthroughCasesInSwitch": true,
|
|
33
33
|
// "noPropertyAccessFromIndexSignature": true,
|
|
34
34
|
|
|
35
|
+
// it's added to resolve import statements with .ts extension, you can configure your own way to fix the same issue
|
|
36
|
+
"rewriteRelativeImportExtensions": true,
|
|
37
|
+
|
|
35
38
|
// Recommended Options
|
|
36
39
|
"strict": true,
|
|
37
40
|
"jsx": "react-jsx",
|