lumpiajs 1.0.6 → 1.0.8
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 +36 -159
- package/bin/lumpia.js +8 -7
- package/index.js +4 -1
- package/lib/commands/build.js +246 -0
- package/lib/commands/create.js +151 -97
- package/lib/commands/serve.js +154 -27
- package/lib/core/Config.js +20 -0
- package/lib/core/DB.js +139 -0
- package/lib/core/Env.js +23 -0
- package/lib/core/Router.js +10 -3
- package/lib/core/View.js +21 -8
- package/package.json +4 -2
- package/templates/.env.example +6 -0
- package/templates/gitignore.txt +3 -0
package/README.md
CHANGED
|
@@ -1,195 +1,72 @@
|
|
|
1
1
|
# 🥟 LumpiaJS
|
|
2
2
|
|
|
3
|
-
**Bahasa Pemrograman Web dengan Kearifan Lokal Semarangan.**
|
|
4
|
-
_Framework ini dibuat untuk seru-seruan (have fun) dan biar bikin web jadi lebih cepat dan menyenangkan!_ (Rencananya sih gitu... wkwkwk)
|
|
5
|
-
|
|
6
|
-
## 🚀 Cara Pakai (Quick Start)
|
|
7
|
-
|
|
8
|
-
Kamu bisa pilih cara yang paling enak buat mulai bikin (masak) web:
|
|
9
|
-
|
|
10
|
-
### 1. Langsung Gas (Tanpa Install)
|
|
11
|
-
|
|
12
|
-
Kalau malas install-install, pastikan komputer kamu sudah ada Node.js, lalu langsung aja pakai `npx`:
|
|
13
|
-
|
|
14
|
-
**Langkah 1: Buat Project**
|
|
15
|
-
|
|
16
|
-
```bash
|
|
17
|
-
npx lumpiajs create-project warung-ku
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
_(Atau pakai istilah lokal: `npx lumpiajs buka-cabang warung-ku`)_
|
|
21
|
-
|
|
22
|
-
**Langkah 2: Masuk & Install Bumbu (Dependencies)**
|
|
23
|
-
Penting! Kamu harus install dependencies biar `import` framework-nya jalan.
|
|
24
|
-
|
|
25
|
-
```bash
|
|
26
|
-
cd warung-ku
|
|
27
|
-
npm install
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
**Langkah 3: Nyalakan Kompor (Server)**
|
|
31
|
-
|
|
32
|
-
```bash
|
|
33
|
-
npm start
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
_(Atau manual: `npx lumpia dodolan`)_
|
|
37
|
-
Websitemu bakal jalan di `http://localhost:3000`.
|
|
3
|
+
**Bahasa Pemrograman Web dengan Kearifan Lokal Semarangan.**
|
|
38
4
|
|
|
39
5
|
---
|
|
40
6
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
Kalau kamu pengen perintah `lumpia` bisa dipanggil dari mana saja di terminal:
|
|
44
|
-
|
|
45
|
-
```bash
|
|
46
|
-
# 1. Install dulu secara global
|
|
47
|
-
npm install -g lumpiajs
|
|
48
|
-
|
|
49
|
-
# 2. Bikin project baru
|
|
50
|
-
lumpia create-project toko-lumpia
|
|
7
|
+
## 🦄 Fitur Unik: Laravel Syntax di JavaScript! (`->`)
|
|
51
8
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
# 4. Jalanin server
|
|
57
|
-
lumpia dodolan
|
|
58
|
-
```
|
|
59
|
-
|
|
60
|
-
**Cara Update ke Versi Terbaru:**
|
|
61
|
-
|
|
62
|
-
```bash
|
|
63
|
-
npm install -g lumpiajs@latest
|
|
9
|
+
```javascript
|
|
10
|
+
// Valid di LumpiaJS (.lmp)
|
|
11
|
+
const users = await DB.table('users')->where('active', 1)->get();
|
|
12
|
+
Jalan->get('/', 'HomeController@index');
|
|
64
13
|
```
|
|
65
14
|
|
|
66
15
|
---
|
|
67
16
|
|
|
68
|
-
## 🏗️
|
|
17
|
+
## 🏗️ Cara Deploy ke Production (Server Asli)
|
|
69
18
|
|
|
70
|
-
|
|
19
|
+
Ini yang sering ditanyain: **"Mas, file mana yang harus saya upload ke hosting?"**
|
|
71
20
|
|
|
72
|
-
|
|
73
|
-
warung-ku/
|
|
74
|
-
├── app/
|
|
75
|
-
│ ├── controllers/ # Otak Logika (Controller)
|
|
76
|
-
│ └── models/ # Pengolah Data (Model)
|
|
77
|
-
├── routes/
|
|
78
|
-
│ └── web.js # Rute URL
|
|
79
|
-
├── views/ # Tampilan (.lmp)
|
|
80
|
-
├── package.json
|
|
81
|
-
└── ...
|
|
82
|
-
```
|
|
21
|
+
Tenang, LumpiaJS punya fitur **Goreng** (Build) biar kamu nggak bingung.
|
|
83
22
|
|
|
84
|
-
### 1.
|
|
23
|
+
### 1. Goreng Project (Build)
|
|
85
24
|
|
|
86
|
-
|
|
25
|
+
Jalankan perintah ini di komputermu:
|
|
87
26
|
|
|
88
|
-
```
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
// Jalan.gawe(url, 'NamaController@method')
|
|
92
|
-
Jalan.gawe("/", "HomeController@index");
|
|
93
|
-
Jalan.gawe("/api/products", "ProductController@index");
|
|
27
|
+
```bash
|
|
28
|
+
lumpia goreng
|
|
94
29
|
```
|
|
95
30
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
Otak dari aplikasimu. Class harus meng-extend `Controller`.
|
|
31
|
+
_(Atau: `lumpia build`)_
|
|
99
32
|
|
|
100
|
-
|
|
101
|
-
import { Controller } from "lumpiajs";
|
|
102
|
-
|
|
103
|
-
export default class HomeController extends Controller {
|
|
104
|
-
index() {
|
|
105
|
-
// Tampilkan file di folder views/home.lmp
|
|
106
|
-
// Kirim data 'pesan' ke view
|
|
107
|
-
return this.tampil("home", {
|
|
108
|
-
pesan: "Halo Dunia!",
|
|
109
|
-
tanggal: new Date().toLocaleDateString(),
|
|
110
|
-
});
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
```
|
|
33
|
+
Sistem akan memasak projectmu:
|
|
114
34
|
|
|
115
|
-
|
|
35
|
+
- Mentranspile sintaks `->` menjadi JS standard.
|
|
36
|
+
- Mengkompilasi CSS (minify Tailwind/Bootstrap).
|
|
37
|
+
- Menyiapkan folder `dist` yang siap saji.
|
|
116
38
|
|
|
117
|
-
|
|
118
|
-
Gunakan `{{ nama_variabel }}` untuk menampilkan data dari Controller.
|
|
39
|
+
### 2. Upload ke Server
|
|
119
40
|
|
|
120
|
-
|
|
121
|
-
<lump>
|
|
122
|
-
<klambi> /* CSS di sini */ h1 { color: #d35400; } </klambi>
|
|
41
|
+
Setelah digoreng, akan muncul folder **`dist`**.
|
|
123
42
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
<h1>{{ pesan }}</h1>
|
|
127
|
-
<p>Tanggal server: {{ tanggal }}</p>
|
|
128
|
-
</kulit>
|
|
43
|
+
👉 **HANYA ISI FOLDER `dist`** inilah yang perlu kamu upload ke server.
|
|
44
|
+
(Isinya: `server.js`, `package.json`, `.env`, folder `app`, `routes`, `views`, `public`)
|
|
129
45
|
|
|
130
|
-
|
|
131
|
-
// JavaScript Client-side (Bahasa Semarangan) gawe sapa() { alert("Halo,
|
|
132
|
-
Lur!"); }
|
|
133
|
-
</isi>
|
|
134
|
-
</lump>
|
|
135
|
-
```
|
|
46
|
+
### 3. Install & Start di Server
|
|
136
47
|
|
|
137
|
-
|
|
48
|
+
Di panel hosting (Terminal/SSH) atau VPS:
|
|
138
49
|
|
|
139
|
-
|
|
50
|
+
```bash
|
|
51
|
+
# Masuk ke folder yang barusan diupload
|
|
52
|
+
cd /path/to/your/app
|
|
140
53
|
|
|
141
|
-
|
|
142
|
-
|
|
54
|
+
# Install dependencies (LumpiaJS core, mysql driver, dll)
|
|
55
|
+
npm install --production
|
|
143
56
|
|
|
144
|
-
|
|
145
|
-
|
|
57
|
+
# Jalankan Aplikasi
|
|
58
|
+
npm start
|
|
146
59
|
```
|
|
147
60
|
|
|
148
61
|
---
|
|
149
62
|
|
|
150
|
-
##
|
|
151
|
-
|
|
152
|
-
Khusus di dalam tag **`<isi>`** (pada file `.lmp`), kamu bisa menggunakan sintaks unik ini:
|
|
153
|
-
|
|
154
|
-
- `ono` ➔ `let`
|
|
155
|
-
- `paten` ➔ `const`
|
|
156
|
-
- `gawe` ➔ `function`
|
|
157
|
-
- `yen` ➔ `if`
|
|
158
|
-
- `liyane` ➔ `else`
|
|
159
|
-
- `mandek` ➔ `return`
|
|
160
|
-
- `ora` ➔ `!`
|
|
161
|
-
- `panjang()` ➔ `.length`
|
|
162
|
-
|
|
163
|
-
---
|
|
164
|
-
|
|
165
|
-
## 🤝 Cara Lapor Masalah atau Kasih Saran
|
|
166
|
-
|
|
167
|
-
Baru nemu bug? Atau punya ide jenius biar LumpiaJS makin jos? Sampaikan saja!
|
|
168
|
-
|
|
169
|
-
Caranya gampang:
|
|
170
|
-
|
|
171
|
-
1. Buka link ini: [https://github.com/fastroware/lumpiajs/issues](https://github.com/fastroware/lumpiajs/issues)
|
|
172
|
-
2. Klik tombol warna hijau bertuliskan **"New Issue"**.
|
|
173
|
-
3. Isi Judul dengan jelas.
|
|
174
|
-
4. Jelaskan masalah atau saranmu di kolom deskripsi.
|
|
175
|
-
5. Klik **"Submit new issue"**.
|
|
176
|
-
|
|
177
|
-
Selesai! Masukanmu akan saya baca pas lagi senggang.
|
|
178
|
-
|
|
179
|
-
---
|
|
180
|
-
|
|
181
|
-
## ⚠️ DISCLAIMER (PENTING BANGET, WAJIB DIBACA!) ⚠️
|
|
182
|
-
|
|
183
|
-
**LumpiaJS ini 100% project _Have Fun_ & Eksperimen.**
|
|
184
|
-
|
|
185
|
-
Kami **TIDAK BERTANGGUNG JAWAB** atas segala bentuk kerugian yang mungkin terjadi akibat penggunaan software ini, termasuk tapi tidak terbatas pada:
|
|
63
|
+
## 🗄️ Database
|
|
186
64
|
|
|
187
|
-
|
|
188
|
-
- Hilangnya file penting.
|
|
189
|
-
- Komputer meledak (lebay, tapi tetap saja hati-hati).
|
|
190
|
-
- Kerugian materiil maupun immateriil lainnya.
|
|
65
|
+
Database (MySQL) itu **SERVICE**, bukan file. Jadi:
|
|
191
66
|
|
|
192
|
-
|
|
67
|
+
1. Export database dari localhost (phpMyAdmin -> Export .sql).
|
|
68
|
+
2. Import file .sql itu ke database di server production kamu.
|
|
69
|
+
3. Edit file `.env` yang sudah diupload, sesuaikan `DB_HOST`, `DB_USER`, `DB_PASSWORD` dengan credential server.
|
|
193
70
|
|
|
194
71
|
---
|
|
195
72
|
|
package/bin/lumpia.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createProject } from '../lib/commands/create.js';
|
|
3
3
|
import { serveProject } from '../lib/commands/serve.js';
|
|
4
|
+
import { buildProject } from '../lib/commands/build.js'; // Import build
|
|
4
5
|
|
|
5
6
|
async function main() {
|
|
6
7
|
const args = process.argv.slice(2);
|
|
@@ -10,18 +11,18 @@ async function main() {
|
|
|
10
11
|
if (perintah === 'create-project' || perintah === 'buka-cabang') {
|
|
11
12
|
createProject(parameter);
|
|
12
13
|
}
|
|
13
|
-
else if (perintah === 'dodolan' || perintah === 'serve') {
|
|
14
|
+
else if (perintah === 'dodolan' || perintah === 'serve' || perintah === 'kukus') {
|
|
14
15
|
serveProject();
|
|
15
16
|
}
|
|
16
|
-
else if (perintah === 'goreng') {
|
|
17
|
-
|
|
18
|
-
console.log(" Silakan gunake: lumpia dodolan");
|
|
17
|
+
else if (perintah === 'goreng' || perintah === 'build') {
|
|
18
|
+
buildProject(); // Activate functionality
|
|
19
19
|
}
|
|
20
20
|
else {
|
|
21
|
-
console.log('Perintah ora dikenal.');
|
|
21
|
+
console.log('Perintah ora dikenal / Command not recognized.');
|
|
22
22
|
console.log('------------------------------------------------');
|
|
23
|
-
console.log('1. lumpia create-project <nama>
|
|
24
|
-
console.log('2. lumpia
|
|
23
|
+
console.log('1. lumpia create-project <nama> (Alias: buka-cabang)');
|
|
24
|
+
console.log('2. lumpia serve (Alias: kukus, dodolan)');
|
|
25
|
+
console.log('3. lumpia build (Alias: goreng)');
|
|
25
26
|
console.log('------------------------------------------------');
|
|
26
27
|
}
|
|
27
28
|
}
|
package/index.js
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
|
|
2
2
|
export { Jalan, routes } from './lib/core/Router.js';
|
|
3
|
-
export { LumpiaModel as Model } from './lib/core/Model.js';
|
|
3
|
+
export { LumpiaModel as Model } from './lib/core/Model.js'; // Model (Array / Static)
|
|
4
|
+
export { DB } from './lib/core/DB.js'; // DB (MySQL)
|
|
4
5
|
export { Controller } from './lib/core/Controller.js';
|
|
6
|
+
export { loadEnv } from './lib/core/Env.js';
|
|
7
|
+
export { loadConfig } from './lib/core/Config.js';
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { spawnSync } from 'child_process';
|
|
4
|
+
import { loadConfig } from '../core/Config.js';
|
|
5
|
+
|
|
6
|
+
// Transpiler Logic (Sama kayak serve.js tapi ini permanen ke disk)
|
|
7
|
+
function transpileContent(content) {
|
|
8
|
+
let code = content;
|
|
9
|
+
// 1. Import: .lmp -> .js
|
|
10
|
+
code = code.replace(/from\s+['"](.+?)\.lmp['"]/g, "from '$1.js'");
|
|
11
|
+
// 2. Syntax: "->" -> "."
|
|
12
|
+
code = code.split('\n').map(line => {
|
|
13
|
+
if (line.trim().startsWith('//')) return line;
|
|
14
|
+
return line.replace(/->/g, '.');
|
|
15
|
+
}).join('\n');
|
|
16
|
+
return code;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function processDirectory(source, dest) {
|
|
20
|
+
if (!fs.existsSync(dest)) fs.mkdirSync(dest, { recursive: true });
|
|
21
|
+
|
|
22
|
+
const items = fs.readdirSync(source);
|
|
23
|
+
items.forEach(item => {
|
|
24
|
+
const srcPath = path.join(source, item);
|
|
25
|
+
const destPath = path.join(dest, item);
|
|
26
|
+
const stat = fs.statSync(srcPath);
|
|
27
|
+
|
|
28
|
+
if (stat.isDirectory()) {
|
|
29
|
+
processDirectory(srcPath, destPath);
|
|
30
|
+
} else {
|
|
31
|
+
if (item.endsWith('.lmp')) {
|
|
32
|
+
// Transpile .lmp to .js
|
|
33
|
+
const content = fs.readFileSync(srcPath, 'utf8');
|
|
34
|
+
const jsContent = transpileContent(content);
|
|
35
|
+
const jsDest = destPath.replace('.lmp', '.js');
|
|
36
|
+
fs.writeFileSync(jsDest, jsContent);
|
|
37
|
+
} else if (item.endsWith('.js') || item.endsWith('.json') || item.endsWith('.css') || item.endsWith('.html')) {
|
|
38
|
+
// Copy as is (but maybe transpile .js too for "->" support if mixed?)
|
|
39
|
+
// For safety, let's also transpile .js files just in case user used "->" there
|
|
40
|
+
if (item.endsWith('.js')) {
|
|
41
|
+
const content = fs.readFileSync(srcPath, 'utf8');
|
|
42
|
+
const jsContent = transpileContent(content);
|
|
43
|
+
fs.writeFileSync(destPath, jsContent);
|
|
44
|
+
} else {
|
|
45
|
+
fs.copyFileSync(srcPath, destPath);
|
|
46
|
+
}
|
|
47
|
+
} else {
|
|
48
|
+
fs.copyFileSync(srcPath, destPath);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const serverScript = `
|
|
55
|
+
import http from 'http';
|
|
56
|
+
import fs from 'fs';
|
|
57
|
+
import path from 'path';
|
|
58
|
+
import { routes, Jalan } from 'lumpiajs/lib/core/Router.js';
|
|
59
|
+
import { loadEnv } from 'lumpiajs/lib/core/Env.js';
|
|
60
|
+
import { loadConfig } from 'lumpiajs/lib/core/Config.js';
|
|
61
|
+
|
|
62
|
+
const root = process.cwd();
|
|
63
|
+
const env = loadEnv(root);
|
|
64
|
+
const config = loadConfig(root);
|
|
65
|
+
|
|
66
|
+
// ROUTE MATCHER (Copied from Core)
|
|
67
|
+
function matchRoute(definedRoute, method, pathname) {
|
|
68
|
+
if (definedRoute.method !== method) return null;
|
|
69
|
+
if (definedRoute.path === pathname) return { params: {} };
|
|
70
|
+
const paramNames = [];
|
|
71
|
+
const regexPath = definedRoute.path.replace(/\\{([a-zA-Z0-9_]+)\\}/g, (match, name) => {
|
|
72
|
+
paramNames.push(name);
|
|
73
|
+
return '([^/]+)';
|
|
74
|
+
});
|
|
75
|
+
if (regexPath === definedRoute.path) return null;
|
|
76
|
+
const regex = new RegExp('^' + regexPath + '$');
|
|
77
|
+
const match = pathname.match(regex);
|
|
78
|
+
if (match) {
|
|
79
|
+
const params = {};
|
|
80
|
+
paramNames.forEach((name, index) => params[name] = match[index + 1]);
|
|
81
|
+
return { params };
|
|
82
|
+
}
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
async function start() {
|
|
87
|
+
// 1. Load Routes (Compiled JS)
|
|
88
|
+
const routesUrl = path.join(root, 'routes', 'web.js');
|
|
89
|
+
if (fs.existsSync(routesUrl)) {
|
|
90
|
+
await import('file://' + routesUrl);
|
|
91
|
+
} else {
|
|
92
|
+
console.error("❌ Error: routes/web.js not found in build!");
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// 2. Start Server
|
|
96
|
+
const server = http.createServer(async (req, res) => {
|
|
97
|
+
const method = req.method;
|
|
98
|
+
const url = new URL(req.url, 'http://' + req.headers.host);
|
|
99
|
+
const pathname = url.pathname;
|
|
100
|
+
|
|
101
|
+
// Static Files
|
|
102
|
+
const publicMap = {
|
|
103
|
+
'/css/': path.join(root, 'public', 'css'),
|
|
104
|
+
'/vendor/': path.join(root, 'public', 'vendor')
|
|
105
|
+
};
|
|
106
|
+
for (const [prefix, localPath] of Object.entries(publicMap)) {
|
|
107
|
+
if (pathname.startsWith(prefix)) {
|
|
108
|
+
const relativePath = pathname.slice(prefix.length);
|
|
109
|
+
const filePath = path.join(localPath, relativePath);
|
|
110
|
+
if (fs.existsSync(filePath) && fs.lstatSync(filePath).isFile()) {
|
|
111
|
+
const ext = path.extname(filePath);
|
|
112
|
+
const mime = ext === '.css' ? 'text/css' : (ext === '.js' ? 'text/javascript' : 'application/octet-stream');
|
|
113
|
+
res.writeHead(200, {'Content-Type': mime});
|
|
114
|
+
res.end(fs.readFileSync(filePath));
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Routing
|
|
121
|
+
let match = null;
|
|
122
|
+
let params = {};
|
|
123
|
+
for (const route of routes) {
|
|
124
|
+
const result = matchRoute(route, method, pathname);
|
|
125
|
+
if (result) {
|
|
126
|
+
match = route;
|
|
127
|
+
params = result.params;
|
|
128
|
+
break;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if (match) {
|
|
133
|
+
try {
|
|
134
|
+
const [controllerName, methodName] = match.action.split('@');
|
|
135
|
+
const controllerPath = path.join(root, 'app', 'controllers', controllerName + '.js');
|
|
136
|
+
if (!fs.existsSync(controllerPath)) throw new Error('Controller ' + controllerName + ' not found');
|
|
137
|
+
|
|
138
|
+
const module = await import('file://' + controllerPath);
|
|
139
|
+
const ControllerClass = module.default;
|
|
140
|
+
const instance = new ControllerClass();
|
|
141
|
+
instance.env = env;
|
|
142
|
+
instance.params = params;
|
|
143
|
+
instance.config = config;
|
|
144
|
+
|
|
145
|
+
const result = await instance[methodName](...Object.values(params));
|
|
146
|
+
if (result.type === 'html') {
|
|
147
|
+
res.writeHead(200, {'Content-Type': 'text/html'});
|
|
148
|
+
res.end(result.content);
|
|
149
|
+
} else if (result.type === 'json') {
|
|
150
|
+
res.writeHead(200, {'Content-Type': 'application/json'});
|
|
151
|
+
res.end(result.content);
|
|
152
|
+
} else {
|
|
153
|
+
res.writeHead(200, {'Content-Type': 'text/plain'});
|
|
154
|
+
res.end(String(result));
|
|
155
|
+
}
|
|
156
|
+
} catch (e) {
|
|
157
|
+
console.error(e);
|
|
158
|
+
res.writeHead(500, {'Content-Type': 'text/html'});
|
|
159
|
+
res.end('<h1>500 Server Error</h1>');
|
|
160
|
+
}
|
|
161
|
+
} else {
|
|
162
|
+
res.writeHead(404);
|
|
163
|
+
res.end('404 Not Found');
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
const port = env.PORT || 3000;
|
|
168
|
+
server.listen(port, () => {
|
|
169
|
+
console.log('🚀 Production Server running on port ' + port);
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
start();
|
|
174
|
+
`;
|
|
175
|
+
|
|
176
|
+
export function buildProject() {
|
|
177
|
+
const root = process.cwd();
|
|
178
|
+
const dist = path.join(root, 'dist');
|
|
179
|
+
const config = loadConfig(root);
|
|
180
|
+
|
|
181
|
+
console.log('🍳 Mulai Menggoreng (Building Project)...');
|
|
182
|
+
|
|
183
|
+
// 1. Cleanup Old Dist
|
|
184
|
+
if (fs.existsSync(dist)) {
|
|
185
|
+
fs.rmSync(dist, { recursive: true, force: true });
|
|
186
|
+
}
|
|
187
|
+
fs.mkdirSync(dist);
|
|
188
|
+
|
|
189
|
+
// 2. Build Assets (Tailwind)
|
|
190
|
+
if (config.klambi === 'tailwindcss') {
|
|
191
|
+
console.log('🎨 Compiling Tailwind CSS (Minified)...');
|
|
192
|
+
const cmd = process.platform === 'win32' ? 'npx.cmd' : 'npx';
|
|
193
|
+
spawnSync(cmd, ['tailwindcss', '-i', './aset/css/style.css', '-o', './public/css/style.css', '--minify'], {
|
|
194
|
+
cwd: root, stdio: 'inherit', shell: true
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// 3. Copy & Transpile Code
|
|
199
|
+
console.log('📂 Copying & Transpiling (.lmp -> .js)...');
|
|
200
|
+
processDirectory(path.join(root, 'app'), path.join(dist, 'app'));
|
|
201
|
+
processDirectory(path.join(root, 'routes'), path.join(dist, 'routes'));
|
|
202
|
+
processDirectory(path.join(root, 'views'), path.join(dist, 'views')); // Views .lmp usually not imported, but kept as is? OR Transpiled?
|
|
203
|
+
// Wait, View.js reads raw .lmp file content. So views should strictly be copied AS IS, or renamed to .lmp but content untouched generally?
|
|
204
|
+
// Actually View.js `renderLumpia` expects file path.
|
|
205
|
+
// Let's COPY views folder AS IS (recursive copy), no renaming extensions usually needed for View Engine unless we change View.js to look for .html?
|
|
206
|
+
// Lumpia View Engine expects `<lump>` tags.
|
|
207
|
+
// Let's just copy views folder using simple copy to ensure .lmp extension stays for view engine to find it.
|
|
208
|
+
|
|
209
|
+
// RE-DO views copy: FORCE copy only
|
|
210
|
+
// Overwrite the 'processDirectory' for views to be simple copy
|
|
211
|
+
fs.cpSync(path.join(root, 'views'), path.join(dist, 'views'), { recursive: true });
|
|
212
|
+
|
|
213
|
+
// 4. Copy Static Assets
|
|
214
|
+
if (fs.existsSync(path.join(root, 'public'))) {
|
|
215
|
+
fs.cpSync(path.join(root, 'public'), path.join(dist, 'public'), { recursive: true });
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// 5. Configs & Env
|
|
219
|
+
fs.copyFileSync(path.join(root, 'package.json'), path.join(dist, 'package.json'));
|
|
220
|
+
fs.copyFileSync(path.join(root, 'config.lmp'), path.join(dist, 'config.lmp'));
|
|
221
|
+
if (fs.existsSync(path.join(root, '.env'))) {
|
|
222
|
+
fs.copyFileSync(path.join(root, '.env'), path.join(dist, '.env'));
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// 6. Generate Standalone Server Entry
|
|
226
|
+
fs.writeFileSync(path.join(dist, 'server.js'), serverScript);
|
|
227
|
+
|
|
228
|
+
// 7. Update package.json in dist
|
|
229
|
+
const pkg = JSON.parse(fs.readFileSync(path.join(dist, 'package.json'), 'utf8'));
|
|
230
|
+
pkg.scripts = {
|
|
231
|
+
"start": "node server.js"
|
|
232
|
+
};
|
|
233
|
+
// Ensure lumpiajs dependency is preserved
|
|
234
|
+
fs.writeFileSync(path.join(dist, 'package.json'), JSON.stringify(pkg, null, 2));
|
|
235
|
+
|
|
236
|
+
console.log('✅ Mateng! (Build Finished)');
|
|
237
|
+
console.log('----------------------------------------------------');
|
|
238
|
+
console.log('🎁 Yang harus dikirim ke Server (Production):');
|
|
239
|
+
console.log(' 📂 Folder: dist/');
|
|
240
|
+
console.log('');
|
|
241
|
+
console.log('👉 Cara Deploy:');
|
|
242
|
+
console.log(' 1. Upload isi folder "dist" ke server.');
|
|
243
|
+
console.log(' 2. Jalankan "npm install --production" di server.');
|
|
244
|
+
console.log(' 3. Jalankan "npm start".');
|
|
245
|
+
console.log('----------------------------------------------------');
|
|
246
|
+
}
|