Skip to content

Commit d1f0fd0

Browse files
author
khanh2906
committed
update version 1.0.2
1 parent 41403f1 commit d1f0fd0

75 files changed

Lines changed: 8693 additions & 446 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

lib/handlers/generateElements.js

Lines changed: 46 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -184,47 +184,59 @@ module.exports = [
184184
* @param {string} options.job.name - The name of the job.
185185
* @returns {Promise<void>}
186186
*/
187-
async function generateEmail(targetPath, name, { templateEmail, job }) {
188-
try {
189-
let content;
190-
const stubPath = path.join(elementPath, 'emails/email.stub');
191187

192-
if (await fs.pathExists(stubPath)) {
193-
content = await fs.readFile(stubPath, 'utf8');
194-
} else {
195-
console.error('No template found');
188+
async function generateEmail(targetPath, name, options = {}) {
189+
const { templateEmail, job } = options;
190+
const stubPath = path.join(elementPath, "emails/email.stub"); // Giả sử elementPath đã được định nghĩa
191+
192+
try {
193+
const [stubContent, templateContent, jobResult] = await Promise.allSettled([
194+
fs.readFile(stubPath, "utf8"),
195+
templateEmail && templateEmail.path && templateEmail.name
196+
? fs.readFile(path.join(elementPath, "emails/template.stub"), "utf8")
197+
: Promise.resolve(""),
198+
job && job.path && job.name
199+
? generateJob(job.path, job.name, {
200+
importModule: `const { sendMail } = require("@iKernel/mail");`,
201+
handle: `await sendMail(job.data);`
202+
})
203+
: Promise.resolve("")
204+
]);
205+
206+
if (stubContent.status !== "fulfilled") {
207+
throw new Error(`Failed to read email stub: ${stubContent.reason}`);
196208
}
197-
let moreReplace = 'sendMail({to: data.email,subject: "Welcome to Bamimi land", // more});'
198-
let more = 'text: text'
209+
let content = stubContent.value;
210+
let template = { key: "html", value: `const html = 'Hello world!';` };
211+
199212
if (templateEmail && templateEmail.path && templateEmail.name) {
200-
more = 'html: html'
201-
const templatePath = path.join(elementPath, 'emails/template.stub');
202-
let contentTemplate = await fs.readFile(templatePath, 'utf8');
213+
if (templateContent.status !== "fulfilled") {
214+
throw new Error(`Failed to read email template: ${templateContent.reason}`);
215+
}
203216

204-
content = content.replace('// render', `const { renderTemplate } = require("../../utils/mail");`);
205-
content = content.replace('// content', `const html = renderTemplate("${templateEmail.name}.ejs");`);
217+
content = content.replace("// render", `const { renderTemplate } = require("@iKernel/mail");`);
218+
await fs.outputFile(templateEmail.path, templateContent.value);
206219

207-
moreReplace = moreReplace.replace('// more', more);
220+
template = {
221+
key: "html",
222+
value: `const html = renderTemplate("${templateEmail.name}.ejs");`
223+
};
208224

209-
await fs.outputFile(templateEmail.path, contentTemplate);
210225
console.log(`Email template ${templateEmail.name} created successfully at ${templateEmail.path}`);
211226
}
212227

213228
if (job && job.path && job.name) {
214-
await generateJob(job.path, job.name, {
215-
importModule: `const { sendMail } = require("../../utils/mail");`,
216-
handle: `await sendMail(job.data);`
217-
})
218-
content = content.replace('// more', `QueueManager.singleton().getQueue("${job.name}").add("${job.name}", {to: data.email, subject: "Welcome to Bamimi land", ${more}});`);
219-
content = content.replace('// queue\n', `const { QueueManager } = require("@knfs-tech/bamimi-schedule")`);
229+
if (jobResult.status !== "fulfilled") {
230+
throw new Error(`Failed to generate job: ${jobResult.reason}`);
231+
}
232+
content = content.replace("// queue", `const QueueManager = require("@iKernel/queue")();`)
233+
.replace("// more", `QueueManager.getQueue("${job.name}").add("${job.name}", {to: data.email, subject: "Welcome to Bamimi land", ${template.key} });`);
234+
} else {
235+
content = content.replace("// queue", `const { sendMail } = require("@iKernel/mail");`)
236+
.replace("// more", `sendMail({to: data.email, subject: "Welcome to Bamimi land", ${template.key} });`);
220237
}
221238

222-
content = content.replace('// render\n', ``);
223-
content = content.replace('// content', `const text = 'Hello word!';`);
224-
moreReplace = moreReplace.replace('// more', more);
225-
content = content.replace('// more', moreReplace);
226-
content = content.replace('// queue\n', ``);
227-
content = content.replace('// queueContent\n', ``);
239+
content = content.replace("// render", "").replace("// content", template.value);
228240

229241
await fs.outputFile(targetPath, content);
230242
console.log(`Email ${name} created successfully at ${targetPath}`);
@@ -233,7 +245,6 @@ async function generateEmail(targetPath, name, { templateEmail, job }) {
233245
throw error;
234246
}
235247
}
236-
237248
/**
238249
* Generates a job file.
239250
* @param {string} targetPath - The path where the job file will be created.
@@ -242,9 +253,10 @@ async function generateEmail(targetPath, name, { templateEmail, job }) {
242253
* @param {string} options.importModule - The module to import.
243254
* @param {string} options.handle - The handle function.
244255
* @param {boolean} options.isSchedule - create schedule
256+
* @param {string} options.queueManager - The name of queue manager
245257
* @returns {Promise<void>}
246258
*/
247-
async function generateJob(targetPath, name, options = { importModule, handle, isSchedule: false }) {
259+
async function generateJob(targetPath, name, options = { importModule, handle, isSchedule: false, queueManager: "bullmq" }) {
248260
try {
249261
moduleAlias.addAliases({
250262
'@iApp': path.resolve(process.cwd(), 'src/app'),
@@ -267,10 +279,11 @@ async function generateJob(targetPath, name, options = { importModule, handle, i
267279
console.error('No template found.');
268280
}
269281

270-
content = content.replace('// import\n', options.importModule ?? '');
271-
content = content.replace('// handle\n', options.handle ?? '');
282+
content = content.replace('// import\n', options.importModule || '');
283+
content = content.replace('// handle\n', options.handle || '');
272284
content = content.replace('// jobName', name);
273285
content = content.replace('// queueName', name);
286+
content = content.replace('// queueManager', options.queueManager || "bullmq");
274287

275288
await fs.outputFile(targetPath, content);
276289
console.log(`Job ${name} created successfully at ${targetPath}`);

lib/handlers/runTime.js

Lines changed: 74 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
1-
const { exec } = require('child_process');
1+
const { spawn } = require('child_process');
22
const fs = require('fs-extra');
33
const path = require('path');
4-
54
const moduleAlias = require('module-alias');
5+
const fg = require('fast-glob');
6+
const obfuscator = require('javascript-obfuscator');
7+
const esbuild = require('esbuild');
8+
const babel = require('@babel/core');
69

710
async function build() {
811
moduleAlias.addAliases({
@@ -16,33 +19,75 @@ async function build() {
1619
'@iUtils': path.resolve(process.cwd(), 'src/utils'),
1720
'@iInterfaces': path.resolve(process.cwd(), 'src/interfaces'),
1821
});
19-
const cmd = `npx ncp ./src ./dist && npx babel src --out-dir dist --extensions .js`;
20-
const projectPath = path.join(process.cwd());
21-
22-
const packageJsonPath = path.join(projectPath, 'package.json');
23-
if (fs.existsSync(packageJsonPath)) {
24-
const buildProcess = exec(cmd, { cwd: projectPath });
25-
26-
buildProcess.stdout.on('data', (data) => {
27-
console.log(data.toString());
28-
});
29-
30-
buildProcess.stderr.on('data', (data) => {
31-
console.error(data.toString());
32-
});
33-
34-
buildProcess.on('close', (code) => {
35-
if (code === 0) {
36-
console.log('Project is built successfully!');
37-
} else {
38-
console.error(`Project is built failed with exit code ${code}`);
39-
}
22+
23+
const projectPath = process.cwd();
24+
const srcDir = path.join(projectPath, 'src');
25+
const distDir = path.join(projectPath, 'dist');
26+
const configPath = path.join(projectPath, 'bamimi.build.js');
27+
const config = require(configPath);
28+
29+
await fs.remove(distDir);
30+
await fs.mkdirp(distDir);
31+
32+
console.log('🚀 Copying non-JS files...');
33+
await fs.copy(srcDir, distDir, { filter: (src) => !src.endsWith('.js') });
34+
35+
console.log('⚡ Transpiling JS files with Babel...');
36+
await transpileWithBabel(srcDir, distDir, config.babelOptions);
37+
38+
console.log('🎯 Minifying JavaScript files with Esbuild...');
39+
const files = await fg(`${distDir}/**/*.js`);
40+
41+
await Promise.all(
42+
files.map((file) =>
43+
esbuild.build({
44+
entryPoints: [file],
45+
outfile: file,
46+
...config.buildOptions,
47+
allowOverwrite: true,
48+
})
49+
)
50+
);
51+
52+
console.log('🔐 Obfuscating JavaScript files...');
53+
await Promise.all(
54+
files.map(async (file) => {
55+
const code = await fs.readFile(file, 'utf8');
56+
const obfuscatedCode = obfuscator.obfuscate(code, config.obfuscationOptions || {
57+
compact: true,
58+
controlFlowFlattening: false,
59+
deadCodeInjection: false,
60+
stringArrayEncoding: ['base64'],
61+
stringArrayThreshold: 0.1,
62+
}).getObfuscatedCode();
63+
await fs.writeFile(file, obfuscatedCode);
64+
})
65+
);
66+
67+
console.log('✅ Project is built successfully!');
68+
}
69+
70+
async function transpileWithBabel(srcDir, distDir, babelOptions) {
71+
const files = await fg(`${srcDir}/**/*.js`);
72+
73+
await Promise.all(
74+
files.map(async (file) => {
75+
const code = await fs.readFile(file, 'utf8');
76+
const result = babel.transformSync(code, {
77+
...babelOptions, // Use dynamic babel options here
78+
filename: file,
4079
});
41-
} else {
42-
console.log('No package.json found in this directory');
43-
}
80+
const outputPath = path.join(distDir, path.relative(srcDir, file));
81+
await fs.outputFile(outputPath, result.code);
82+
})
83+
);
84+
}
85+
86+
function runCommand(command, args) {
87+
return new Promise((resolve, reject) => {
88+
const proc = spawn(command, args, { stdio: 'inherit', shell: true });
89+
proc.on('close', (code) => (code === 0 ? resolve() : reject(new Error(`${command} failed`))));
90+
});
4491
}
4592

46-
module.exports = {
47-
build
48-
}
93+
module.exports = { build };

lib/stubs/elements/emails/email.stub

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
"use strict";
22

3-
const { sendMail } = require("../../utils/mail");
43
// render
54
// queue
65

lib/stubs/elements/job.stub

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
module.exports = {
1010
name: "// jobName",
1111
queue: "// queueName",
12+
queueManager: "// queueManager",
1213
handle: async function (job) {
1314
// handle
1415
}

lib/stubs/elements/scheduler.stub

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
module.exports = {
1010
name: "// jobName",
1111
queue: "// queueName",
12+
queueManager: "// queueManager",
1213
schedules: [
1314
{
1415
name: "", //type scheduleName

lib/stubs/template/.babelrc

Lines changed: 0 additions & 26 deletions
This file was deleted.

lib/stubs/template/.dockerignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
11
*.log
22
*.md
33
*.gitignore
4+
.env.example
5+
eslint.config.js
6+
jest.config.js
7+
nodemon.json

lib/stubs/template/.env.example

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ APP_ASSET=http://localhost:3000
99
APP_URL=http://localhost:3000
1010
# UV_THREADPOOL_SIZE=6
1111
USE_SOCKET=false
12-
BAMIMI_VER=0.6.23
12+
BAMIMI_VER=1.0.2
1313

1414
# Auth
1515
COOKIE_SECRET=
@@ -29,7 +29,8 @@ DB_PASSWORD=db_password
2929
DB_DATABASE=db
3030

3131
# Config Cache
32-
CACHE_DRIVER=redis
32+
CACHE_DRIVER=local
33+
3334
REDIS_CACHE_HOST=localhost
3435
REDIS_CACHE_PORT=6379
3536
REDIS_CACHE_USER=

lib/stubs/template/Dockerfile

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,31 +10,39 @@ RUN apt-get update && apt-get install -y \
1010

1111
WORKDIR /usr/src/app
1212

13+
# Copy package.json and yarn.lock for dependency installation
1314
COPY --chown=node:node package.json yarn.lock ./
1415

1516
# Install dependencies for building
1617
RUN yarn install --production=false
1718

18-
COPY --chown=node:node . .
19+
# Copy the application code
20+
COPY --chown=node:node . .
1921

20-
RUN yarn build
22+
# Set proper permissions for the storage folder
23+
RUN mkdir -p storage && chmod -R 775 storage && chown -R node:node storage
2124

25+
# Build the application
26+
RUN yarn build
2227

2328
# Stage 2: Development
2429
FROM node:20-slim as development
2530

26-
# Copy only the dist directory from the builder stage
27-
COPY --from=builder /usr/src/app/dist /usr/src/app/dist
31+
# Set working directory
32+
WORKDIR /usr/src/app
2833

34+
# Copy necessary files from builder stage
35+
COPY --from=builder /usr/src/app/dist /usr/src/app/dist
2936
COPY --from=builder /usr/src/app/package.json /usr/src/app/package.json
3037
COPY --from=builder /usr/src/app/node_modules /usr/src/app/node_modules
3138
COPY --from=builder /usr/src/app/.env /usr/src/app/.env
39+
COPY --from=builder /usr/src/app/storage /usr/src/app/storage
3240

33-
ENV NODE_ENV=development
34-
WORKDIR /usr/src/app
35-
41+
# Install all dependencies (including devDependencies)
3642
RUN yarn install --production=false --ignore-scripts
3743

44+
ENV NODE_ENV=development
45+
3846
EXPOSE 3000
3947

4048
CMD ["yarn", "start"]
@@ -43,17 +51,23 @@ CMD ["yarn", "start"]
4351
# Stage 3:
4452
FROM node:20-slim as production
4553

46-
# Copy only the dist directory from the builder stage
47-
COPY --from=builder /usr/src/app/dist /usr/src/app/dist
54+
# Set working directory
55+
WORKDIR /usr/src/app
4856

57+
# Copy only necessary files from builder stage
58+
COPY --from=builder /usr/src/app/dist /usr/src/app/dist
4959
COPY --from=builder /usr/src/app/package.json /usr/src/app/package.json
5060
COPY --from=builder /usr/src/app/.env /usr/src/app/.env
61+
COPY --from=builder /usr/src/app/storage /usr/src/app/storage
5162

52-
ENV NODE_ENV=production
53-
WORKDIR /usr/src/app
54-
63+
# Install production dependencies
5564
RUN yarn install --production
5665

66+
# Set environment variables
67+
ENV NODE_ENV=production
68+
69+
# Expose the application port
5770
EXPOSE 3000
5871

59-
CMD ["yarn", "start"]
72+
# Run the application
73+
CMD ["yarn", "start"]

0 commit comments

Comments
 (0)