@m00rl0ck/simple-builder 1.1.2 β 1.1.4
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 +141 -0
- package/bin/cli.js +0 -0
- package/bundler.js +32 -9
- package/dev-server.js +3 -2
- package/index.js +39 -23
- package/minify-css.js +1 -1
- package/minify-js.js +1 -1
- package/package.json +17 -19
package/README.md
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
# β‘ Simple Builder
|
|
2
|
+
|
|
3
|
+
> Zero-deps JavaScript bundler. Fast, minimal, under your control.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## π€ Why?
|
|
8
|
+
|
|
9
|
+
Modern tools like Webpack and Vite are powerful⦠but often **overkill**.
|
|
10
|
+
|
|
11
|
+
* Too many dependencies
|
|
12
|
+
* Hard to understand whatβs going on
|
|
13
|
+
* Configs become a mess
|
|
14
|
+
|
|
15
|
+
**Simple Builder** exists for one reason:
|
|
16
|
+
|
|
17
|
+
> Give you a bundler you actually understand.
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## π Features
|
|
22
|
+
|
|
23
|
+
* β‘ Zero dependencies
|
|
24
|
+
* π¦ ES Modules support
|
|
25
|
+
* π₯ Super fast builds
|
|
26
|
+
* π§ Simple and predictable behavior
|
|
27
|
+
* πͺΆ Lightweight (no bloat)
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## π¦ Installation
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
npm install simple-builder
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## βοΈ Usage
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
simple-builder build
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Or with config:
|
|
46
|
+
|
|
47
|
+
```js
|
|
48
|
+
import { build } from 'simple-builder';
|
|
49
|
+
|
|
50
|
+
build({
|
|
51
|
+
entry: './src/app.js',
|
|
52
|
+
output: './dist/bundle.js'
|
|
53
|
+
});
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## π§© Example
|
|
59
|
+
|
|
60
|
+
```js
|
|
61
|
+
// app.js
|
|
62
|
+
import { hello } from './hello.js';
|
|
63
|
+
|
|
64
|
+
hello();
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
π Run build β get a single bundled file.
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## π Why choose Simple Builder?
|
|
72
|
+
|
|
73
|
+
| Feature | Simple Builder | Webpack | Vite |
|
|
74
|
+
| ------------------ | -------------- | ------- | ---- |
|
|
75
|
+
| Zero deps | β
| β | β |
|
|
76
|
+
| Easy to understand | β
| β | β οΈ |
|
|
77
|
+
| Minimal config | β
| β | β
|
|
|
78
|
+
| Full control | β
| β οΈ | β οΈ |
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## π‘ Philosophy
|
|
83
|
+
|
|
84
|
+
* No magic
|
|
85
|
+
* No hidden behavior
|
|
86
|
+
* Just JavaScript
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
## π₯ Pro Version
|
|
91
|
+
|
|
92
|
+
Want more power?
|
|
93
|
+
|
|
94
|
+
### π Simple Builder Pro includes:
|
|
95
|
+
|
|
96
|
+
* π Watch mode
|
|
97
|
+
* β‘ Advanced caching
|
|
98
|
+
* π Plugin system
|
|
99
|
+
* π Built-in minifier
|
|
100
|
+
* π Production optimizations
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
## π³ Get Pro
|
|
105
|
+
|
|
106
|
+
Unlock all features and speed up your workflow:
|
|
107
|
+
|
|
108
|
+
π Get access to Pro version
|
|
109
|
+
|
|
110
|
+
(coming soon)
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
## π£ Roadmap
|
|
115
|
+
|
|
116
|
+
* [ ] Watch mode
|
|
117
|
+
* [ ] Plugin API
|
|
118
|
+
* [ ] Minifier
|
|
119
|
+
* [ ] Dev server improvements
|
|
120
|
+
|
|
121
|
+
---
|
|
122
|
+
|
|
123
|
+
## π€ Contributing
|
|
124
|
+
|
|
125
|
+
PRs are welcome. Keep it simple.
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
## β Support
|
|
130
|
+
|
|
131
|
+
If you like this project:
|
|
132
|
+
|
|
133
|
+
* Star the repo
|
|
134
|
+
* Share it
|
|
135
|
+
* Use it in your projects
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
|
|
139
|
+
## π§ Final thought
|
|
140
|
+
|
|
141
|
+
> Tools should work for you, not the other way around.
|
package/bin/cli.js
CHANGED
|
File without changes
|
package/bundler.js
CHANGED
|
@@ -7,17 +7,33 @@ let ID = 0;
|
|
|
7
7
|
// π FIND IMPORTS
|
|
8
8
|
// ======================
|
|
9
9
|
function getImports(code) {
|
|
10
|
-
|
|
10
|
+
// Named imports: import { X, Y } from 'z'
|
|
11
|
+
const namedRegex = /import\s+{([^}]+)}\s+from\s+['"](.+?)['"]/g;
|
|
12
|
+
// Default imports: import X from 'y'
|
|
13
|
+
const defaultRegex = /import\s+(\w+)\s+from\s+['"](.+?)['"]/g;
|
|
14
|
+
|
|
11
15
|
const imports = [];
|
|
12
16
|
let match;
|
|
13
17
|
|
|
14
|
-
while ((match =
|
|
18
|
+
while ((match = namedRegex.exec(code))) {
|
|
15
19
|
imports.push({
|
|
20
|
+
type: 'named',
|
|
16
21
|
names: match[1].split(',').map(s => s.trim()),
|
|
17
22
|
path: match[2]
|
|
18
23
|
});
|
|
19
24
|
}
|
|
20
25
|
|
|
26
|
+
while ((match = defaultRegex.exec(code))) {
|
|
27
|
+
// Skip if already matched by namedRegex
|
|
28
|
+
const already = imports.some(i => i.type === 'named' && i.path === match[2]);
|
|
29
|
+
if (already) continue;
|
|
30
|
+
imports.push({
|
|
31
|
+
type: 'default',
|
|
32
|
+
name: match[1],
|
|
33
|
+
path: match[2]
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
|
|
21
37
|
return imports;
|
|
22
38
|
}
|
|
23
39
|
|
|
@@ -45,12 +61,19 @@ function transform(code) {
|
|
|
45
61
|
});
|
|
46
62
|
|
|
47
63
|
// 3. import β require
|
|
48
|
-
code = code
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
64
|
+
code = code
|
|
65
|
+
.replace(
|
|
66
|
+
/import\s+{([^}]+)}\s+from\s+['"](.+?)['"]/g,
|
|
67
|
+
(match, names, path) => {
|
|
68
|
+
return `const { ${names} } = require('${path}')`;
|
|
69
|
+
}
|
|
70
|
+
)
|
|
71
|
+
.replace(
|
|
72
|
+
/import\s+(\w+)\s+from\s+['"](.+?)['"]/g,
|
|
73
|
+
(match, name, path) => {
|
|
74
|
+
return `const ${name} = require('${path}')`;
|
|
75
|
+
}
|
|
76
|
+
);
|
|
54
77
|
|
|
55
78
|
// 4. Π΄ΠΎΠ΄Π°ΡΠΌΠΎ exports
|
|
56
79
|
if (exports.length) {
|
|
@@ -148,4 +171,4 @@ ${mod.id}: [
|
|
|
148
171
|
require(${entryModule.id});
|
|
149
172
|
})({${modulesCode}});
|
|
150
173
|
`;
|
|
151
|
-
}
|
|
174
|
+
}
|
package/dev-server.js
CHANGED
|
@@ -71,6 +71,7 @@ function serveFile(req, res) {
|
|
|
71
71
|
res.writeHead(200, { 'Content-Type': contentType });
|
|
72
72
|
res.end(content);
|
|
73
73
|
}
|
|
74
|
+
|
|
74
75
|
// ======================
|
|
75
76
|
// π RELOAD CHANNEL (SSE)
|
|
76
77
|
// ======================
|
|
@@ -111,7 +112,7 @@ const server = http.createServer((req, res) => {
|
|
|
111
112
|
// βΆοΈ START
|
|
112
113
|
// ======================
|
|
113
114
|
|
|
114
|
-
function runServer({ isProd }) {
|
|
115
|
+
function runServer({ isProd } = {}) {
|
|
115
116
|
const watch = !isProd;
|
|
116
117
|
|
|
117
118
|
build({ watch, isProd });
|
|
@@ -121,4 +122,4 @@ function runServer({ isProd }) {
|
|
|
121
122
|
});
|
|
122
123
|
}
|
|
123
124
|
|
|
124
|
-
export { build, runServer };
|
|
125
|
+
export { build, runServer };
|
package/index.js
CHANGED
|
@@ -12,10 +12,21 @@ const ROOT = process.cwd();
|
|
|
12
12
|
const SRC_DIR = path.join(ROOT, 'src');
|
|
13
13
|
const DIST_DIR = path.join(ROOT, 'dist');
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
function resolveEntry() {
|
|
16
|
+
const envPath = path.join(ROOT, 'env.js');
|
|
17
|
+
if (fs.existsSync(envPath)) {
|
|
18
|
+
const envCode = fs.readFileSync(envPath, 'utf-8');
|
|
19
|
+
const match = envCode.match(/IN_POINT\s*=\s*["']([^"']+)["']/);
|
|
20
|
+
if (match) {
|
|
21
|
+
return path.join(SRC_DIR, `${match[1]}.js`);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return path.join(SRC_DIR, 'index.js');
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const ENTRY = resolveEntry();
|
|
16
28
|
const HTML_INPUT = path.join(SRC_DIR, 'index.html');
|
|
17
29
|
const HTML_OUTPUT = path.join(DIST_DIR, 'index.html');
|
|
18
|
-
const isWatch = process.argv.includes('--watch');
|
|
19
30
|
|
|
20
31
|
// ======================
|
|
21
32
|
// π§Ή UTILS
|
|
@@ -37,12 +48,10 @@ function cleanDist() {
|
|
|
37
48
|
// π¦ BUILD JS
|
|
38
49
|
// ======================
|
|
39
50
|
function buildJS(isProd) {
|
|
40
|
-
const
|
|
51
|
+
const bundle_result = bundle(ENTRY);
|
|
52
|
+
const result = isProd ? minifyJS(bundle_result) : bundle_result;
|
|
41
53
|
|
|
42
|
-
|
|
43
|
-
const result = isProd ? minifyJS(bundle_result) : bundle_result;
|
|
44
|
-
|
|
45
|
-
fs.writeFileSync('./dist/bundle.min.js', result);
|
|
54
|
+
fs.writeFileSync('./dist/bundle.min.js', result);
|
|
46
55
|
}
|
|
47
56
|
|
|
48
57
|
function buildCSS(isProd) {
|
|
@@ -74,10 +83,10 @@ function buildHTML(isProd) {
|
|
|
74
83
|
let html = fs.readFileSync(HTML_INPUT, 'utf-8');
|
|
75
84
|
|
|
76
85
|
if (isProd) {
|
|
77
|
-
// JS
|
|
78
|
-
html = html.replace(
|
|
86
|
+
// JS β Π²ΠΈΠ΄Π°Π»ΡΡΠΌΠΎ type="module" ΡΠ° Π·Π°ΠΌΡΠ½ΡΡΠΌΠΎ src Π½Π° bundle
|
|
87
|
+
html = html.replace(/<script[^>]*src="(.+?)\.js"[^>]*><\/script>/g, (match, p1) => {
|
|
79
88
|
if (p1.endsWith('.min')) return match;
|
|
80
|
-
return
|
|
89
|
+
return `<script src="bundle.min.js"></script>`;
|
|
81
90
|
});
|
|
82
91
|
|
|
83
92
|
// CSS
|
|
@@ -99,34 +108,41 @@ function buildHTML(isProd) {
|
|
|
99
108
|
function watchBuild() {
|
|
100
109
|
console.log('π Watch mode ON...\n');
|
|
101
110
|
|
|
111
|
+
// First build
|
|
112
|
+
buildTask(false);
|
|
113
|
+
|
|
114
|
+
// Then watch
|
|
102
115
|
fs.watch(SRC_DIR, { recursive: true }, (eventType, filename) => {
|
|
103
116
|
console.log(`π File changed: ${filename}`);
|
|
104
|
-
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
fs.watch(HTML_INPUT, () => {
|
|
108
|
-
console.log(`π HTML changed`);
|
|
109
|
-
build();
|
|
117
|
+
buildTask(false);
|
|
110
118
|
});
|
|
111
119
|
}
|
|
112
120
|
|
|
113
121
|
// ======================
|
|
114
|
-
// π BUILD
|
|
122
|
+
// π BUILD TASK
|
|
115
123
|
// ======================
|
|
116
124
|
|
|
117
|
-
|
|
118
|
-
if (!!watch) {
|
|
119
|
-
return watchBuild();
|
|
120
|
-
}
|
|
121
|
-
|
|
125
|
+
function buildTask(isProd) {
|
|
122
126
|
console.log(`\nπ Build started (${isProd ? 'production' : 'development'})`);
|
|
123
127
|
|
|
124
128
|
cleanDist();
|
|
125
129
|
ensureDir(DIST_DIR);
|
|
126
130
|
|
|
127
131
|
buildJS(isProd);
|
|
128
|
-
buildCSS(isProd);
|
|
132
|
+
buildCSS(isProd);
|
|
129
133
|
buildHTML(isProd);
|
|
130
134
|
|
|
131
135
|
console.log(`π Build finished\n`);
|
|
132
136
|
}
|
|
137
|
+
|
|
138
|
+
// ======================
|
|
139
|
+
// π BUILD (public API)
|
|
140
|
+
// ======================
|
|
141
|
+
|
|
142
|
+
export function build({ watch, isProd } = {}) {
|
|
143
|
+
if (watch) {
|
|
144
|
+
return watchBuild();
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
buildTask(isProd);
|
|
148
|
+
}
|
package/minify-css.js
CHANGED
package/minify-js.js
CHANGED
package/package.json
CHANGED
|
@@ -1,20 +1,25 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@m00rl0ck/simple-builder",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.4",
|
|
4
4
|
"description": "Zero-dependency JS and CSS bundler with dev server and minifier",
|
|
5
|
-
"
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
"changelog": {
|
|
6
|
+
"1.1.1": "Fix: small bugs",
|
|
7
|
+
"1.1.2": "Fix: ternary console.log",
|
|
8
|
+
"1.1.3": "Fix: crash on build() without args, unused vars, hardcoded entry, watchBuild initial build, default imports support"
|
|
8
9
|
},
|
|
9
10
|
"type": "module",
|
|
10
11
|
"main": "index.js",
|
|
11
12
|
"bin": {
|
|
12
|
-
"simple-builder": "
|
|
13
|
-
},
|
|
14
|
-
"scripts": {
|
|
15
|
-
"dev": "node dev-server.js",
|
|
16
|
-
"build": "node bundler.js"
|
|
13
|
+
"simple-builder": "bin/cli.js"
|
|
17
14
|
},
|
|
15
|
+
"files": [
|
|
16
|
+
"bundler.js",
|
|
17
|
+
"dev-server.js",
|
|
18
|
+
"index.js",
|
|
19
|
+
"minify-js.js",
|
|
20
|
+
"minify-css.js",
|
|
21
|
+
"bin/cli.js"
|
|
22
|
+
],
|
|
18
23
|
"keywords": [
|
|
19
24
|
"bundler",
|
|
20
25
|
"javascript",
|
|
@@ -22,13 +27,6 @@
|
|
|
22
27
|
"zero-deps",
|
|
23
28
|
"minifier"
|
|
24
29
|
],
|
|
25
|
-
"author": "
|
|
26
|
-
"license": "MIT"
|
|
27
|
-
|
|
28
|
-
"bundler.js",
|
|
29
|
-
"dev-server.js",
|
|
30
|
-
"index.js",
|
|
31
|
-
"minify-js.js",
|
|
32
|
-
"minify-css.js"
|
|
33
|
-
]
|
|
34
|
-
}
|
|
30
|
+
"author": "m00rl0ck",
|
|
31
|
+
"license": "MIT"
|
|
32
|
+
}
|