quickjs-zig 1.0.2 → 1.0.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 +33 -6
- package/build.mjs +37 -12
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -5,9 +5,10 @@ A high-performance build system for **QuickJS**, powered by the **Zig** compiler
|
|
|
5
5
|
## Features
|
|
6
6
|
|
|
7
7
|
* **Zero Config Cross-Compilation**: Build for Windows, Linux, and macOS from any host (Intel or Apple Silicon).
|
|
8
|
-
* **Zig-Powered**: Uses **Zig 0.15.2**
|
|
8
|
+
* **Zig-Powered Optimization**: Uses **Zig 0.15.2** with LTO (Link Time Optimization) to produce small binaries.
|
|
9
9
|
* **Custom C Modules**: Easily inject and register your own C modules into the QuickJS engine.
|
|
10
10
|
* **Native Windows Support**: Includes a custom `exec` implementation for Windows, bypassing typical QuickJS POSIX limitations.
|
|
11
|
+
* **Platform-Specific Swapping**: Automatically replaces generic JS files with platform-specific ones (e.g., `index.mjs` → `index.darwin.mjs`) during build.
|
|
11
12
|
* **Clean Source Management**: Automatically patches and restores QuickJS source files to keep the core library pristine.
|
|
12
13
|
|
|
13
14
|
---
|
|
@@ -35,17 +36,40 @@ npm link
|
|
|
35
36
|
|
|
36
37
|
```
|
|
37
38
|
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## Platform-Specific File Swapping
|
|
42
|
+
|
|
43
|
+
The build system supports platform-specific file resolution. This is useful when you need different JS logic for different operating systems while maintaining a single development entry point for IDE completion.
|
|
44
|
+
|
|
45
|
+
### How it works
|
|
46
|
+
|
|
47
|
+
1. **Generic file**: Create a base file (e.g., `index.mjs` or `dialogs.mjs`). This is your reference for IDE completion and IntelliSense.
|
|
48
|
+
2. **Specific files**: Create files with the platform suffix:
|
|
49
|
+
* `filename.win32.mjs`
|
|
50
|
+
* `filename.darwin.mjs`
|
|
51
|
+
* `filename.linux.mjs`
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
3. **Build Logic**:
|
|
55
|
+
* The `build/` folder is cleaned at the start of each execution.
|
|
56
|
+
* If a platform-specific version exists, the generic version is **excluded** from the build folder to avoid duplicates.
|
|
57
|
+
* The script automatically rewrites `import` statements in your code to point to the correct suffix during the build process.
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
|
|
38
61
|
---
|
|
39
62
|
|
|
40
63
|
## Configuration
|
|
41
64
|
|
|
42
|
-
Configure your entry point and custom C modules in your project's `package.json`:
|
|
65
|
+
Configure your entry point, optimization, and custom C modules in your project's `package.json`:
|
|
43
66
|
|
|
44
67
|
```json
|
|
45
68
|
{
|
|
46
69
|
"name": "my-app",
|
|
47
70
|
"quickJs": {
|
|
48
71
|
"input": "app/index.mjs",
|
|
72
|
+
"optimization": true,
|
|
49
73
|
"modules": {
|
|
50
74
|
"my_module": "src/my_module.c"
|
|
51
75
|
}
|
|
@@ -55,8 +79,11 @@ Configure your entry point and custom C modules in your project's `package.json`
|
|
|
55
79
|
```
|
|
56
80
|
|
|
57
81
|
* **`input`**: The entry point of your JavaScript application (defaults to `app/index.mjs`).
|
|
82
|
+
* **`optimization`**: When `true`, enables **LTO**, aggressive inlining (`-O3`), and strips unused features like `eval` or `Promises` via `qjsc` flags.
|
|
58
83
|
* **`modules`**: A key-value map of custom C modules (Module Name -> C Source Path).
|
|
59
84
|
|
|
85
|
+
**Note**: The system always applies `-s` (strip symbols) regardless of the optimization flag to ensure no `.pdb` or debug tables are generated.
|
|
86
|
+
|
|
60
87
|
---
|
|
61
88
|
|
|
62
89
|
## Example Usage
|
|
@@ -130,9 +157,9 @@ The build system generates binaries for the following platforms in the `dist/` f
|
|
|
130
157
|
|
|
131
158
|
Zig is not just a language; it's a powerful C/C++ toolchain. It allows `quickjs-zig` to:
|
|
132
159
|
|
|
133
|
-
* Cross-compile to Windows (MinGW)
|
|
134
|
-
*
|
|
135
|
-
*
|
|
160
|
+
* **Cross-compile** to Windows (MinGW) or Linux from any host without installing complex toolchains.
|
|
161
|
+
* **Size matters**: By using `-flto` and `-O3`, Zig can discard unused parts of the engine, bringing the footprint down by nearly 95% compared to Node.js standalone binaries.
|
|
162
|
+
* **macOS LTO Support**: On Apple targets, we automatically force `-fuse-ld=lld` when optimized to ensure the LLVM Linker handles the bitcode correctly.
|
|
136
163
|
|
|
137
164
|
### Windows Patching
|
|
138
165
|
|
|
@@ -144,4 +171,4 @@ QuickJS is designed for POSIX systems. This tool automatically patches `quickjs-
|
|
|
144
171
|
|
|
145
172
|
MIT - Created by **eid-app**.
|
|
146
173
|
|
|
147
|
-
---
|
|
174
|
+
---
|
package/build.mjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { execSync } from 'child_process';
|
|
2
|
+
import { fileURLToPath } from 'url';
|
|
2
3
|
import { writeFileSync, mkdirSync, unlinkSync, existsSync, readdirSync, cpSync, readFileSync, renameSync, statSync, rmSync } from 'fs';
|
|
3
4
|
import path from 'path';
|
|
4
5
|
import os from 'os';
|
|
5
|
-
import { fileURLToPath } from 'url';
|
|
6
6
|
|
|
7
7
|
// --- PATH CONFIGURATION ---
|
|
8
8
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
@@ -24,19 +24,36 @@ if (!existsSync(USER_PKG_PATH)) {
|
|
|
24
24
|
|
|
25
25
|
const userPackageJson = JSON.parse(readFileSync(USER_PKG_PATH, 'utf8'));
|
|
26
26
|
const customModules = userPackageJson.quickJs?.modules || {};
|
|
27
|
+
|
|
28
|
+
for (const [name, relativePath] of Object.entries(customModules)) {
|
|
29
|
+
const absolutePath = path.resolve(USER_CWD, relativePath);
|
|
30
|
+
if (!existsSync(absolutePath)) {
|
|
31
|
+
console.error(`\n❌ Error: Custom module "${name}" source file not found!`);
|
|
32
|
+
console.error(` Expected path: ${absolutePath}`);
|
|
33
|
+
console.error(` Please check your package.json configuration.`);
|
|
34
|
+
process.exit(1);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
27
38
|
const APP_NAME = userPackageJson.name || 'app';
|
|
28
39
|
|
|
40
|
+
// Optimization flag from package.json
|
|
41
|
+
const IS_OPTIMIZED = userPackageJson.quickJs?.optimization === true;
|
|
42
|
+
|
|
29
43
|
// Input file from package.json or default to app/index.mjs
|
|
30
44
|
const INPUT_FILE_RELATIVE = userPackageJson.quickJs?.input || 'app/index.mjs';
|
|
31
45
|
|
|
32
46
|
/**
|
|
33
47
|
* Recursively scan and transform imports to platform-specific ones.
|
|
34
|
-
* Filters out files from other platforms and
|
|
48
|
+
* Filters out files from other platforms and ensures specific versions
|
|
49
|
+
* replace generic ones (like index.mjs) in the build folder.
|
|
35
50
|
*/
|
|
36
51
|
function processDirectory(currentDir, targetDir, targetPlat) {
|
|
37
52
|
if (!existsSync(targetDir)) mkdirSync(targetDir, { recursive: true });
|
|
38
53
|
|
|
39
|
-
readdirSync(currentDir)
|
|
54
|
+
const filesInSource = readdirSync(currentDir);
|
|
55
|
+
|
|
56
|
+
filesInSource.forEach(file => {
|
|
40
57
|
const fullPath = path.join(currentDir, file);
|
|
41
58
|
const destPath = path.join(targetDir, file);
|
|
42
59
|
|
|
@@ -56,17 +73,18 @@ function processDirectory(currentDir, targetDir, targetPlat) {
|
|
|
56
73
|
return;
|
|
57
74
|
}
|
|
58
75
|
|
|
59
|
-
// 2.
|
|
76
|
+
// 2. Logic for generic files (like index.mjs):
|
|
77
|
+
// If a specific version (index.darwin.mjs) exists, we skip the generic one.
|
|
60
78
|
if (!filePlat || !knownPlats.includes(filePlat)) {
|
|
61
79
|
const specFile = file.replace(/\.mjs$/, `.${targetPlat}.mjs`);
|
|
62
|
-
if (
|
|
80
|
+
if (filesInSource.includes(specFile)) {
|
|
63
81
|
return;
|
|
64
82
|
}
|
|
65
83
|
}
|
|
66
84
|
|
|
67
85
|
let content = readFileSync(fullPath, 'utf8');
|
|
68
86
|
|
|
69
|
-
// 3. Transform generic imports to platform-specific ones if they exist
|
|
87
|
+
// 3. Transform generic imports to platform-specific ones if they exist physically
|
|
70
88
|
content = content.replace(/(import\s+.+?\s+from\s+['"])(.+?)\.mjs(['"])/g, (match, before, importPath, after) => {
|
|
71
89
|
const platFile = `${importPath}.${targetPlat}.mjs`;
|
|
72
90
|
const platformFullPath = path.resolve(currentDir, platFile);
|
|
@@ -185,8 +203,11 @@ const targets = [
|
|
|
185
203
|
const stubPath = path.join(QUICKJS_DIR, 'repl_stub.c');
|
|
186
204
|
writeFileSync(stubPath, `const unsigned char qjsc_repl[] = {0}; const unsigned int qjsc_repl_size = 0;`);
|
|
187
205
|
|
|
206
|
+
// Feature optimization flags for qjsc
|
|
207
|
+
const qjscFlags = IS_OPTIMIZED ? '-fno-eval -fno-regexp -fno-proxy -fno-map -fno-typedarray -fno-promise' : '';
|
|
208
|
+
|
|
188
209
|
targets.forEach(t => {
|
|
189
|
-
console.log(`\n--- Compiling for: ${t.id}
|
|
210
|
+
console.log(`\n--- Compiling for: ${t.id} ---`);
|
|
190
211
|
|
|
191
212
|
// --- PLATFORM SPECIFIC BUILD RESOLUTION ---
|
|
192
213
|
const PLATFORM_BUILD_DIR = path.join(USER_CWD, 'build', t.id);
|
|
@@ -200,7 +221,10 @@ targets.forEach(t => {
|
|
|
200
221
|
|
|
201
222
|
const TARGET_INPUT_ABS = path.join(PLATFORM_BUILD_DIR, path.basename(INPUT_FILE_RELATIVE));
|
|
202
223
|
|
|
203
|
-
|
|
224
|
+
// Dynamic Optimization Flags
|
|
225
|
+
let optFlags = IS_OPTIMIZED && 'darwin' !== t.plat ? '-O3 -flto' : '-O2';
|
|
226
|
+
|
|
227
|
+
const cmdBase = `${ZIG_PATH} cc -target ${t.id} -I${QUICKJS_DIR} ${optFlags} ${t.cflags} -Wno-ignored-attributes -DCONFIG_VERSION=\\"${VERSION}\\" ${t.libs} -s`;
|
|
204
228
|
|
|
205
229
|
try {
|
|
206
230
|
execSync(`${cmdBase} -o "${path.join(BIN_DIR, t.qjs)}" ${baseSources} ${stubPath} "${path.join(QUICKJS_DIR, 'qjs.c')}"`);
|
|
@@ -209,11 +233,11 @@ targets.forEach(t => {
|
|
|
209
233
|
|
|
210
234
|
const tempC = path.join(BIN_DIR, `${t.id}_app.c`);
|
|
211
235
|
|
|
212
|
-
// Use host qjsc to compile the platform-
|
|
213
|
-
execSync(`"${hostQjscPath}" -e -o "${tempC}" "${TARGET_INPUT_ABS}"`, { cwd: USER_CWD });
|
|
236
|
+
// Use host qjsc to compile the platform-resolved source
|
|
237
|
+
execSync(`"${hostQjscPath}" ${qjscFlags} -e -o "${tempC}" "${TARGET_INPUT_ABS}"`, { cwd: USER_CWD });
|
|
214
238
|
|
|
215
239
|
execSync(`${cmdBase} -o "${path.join(DIST_DIR, t.app)}" "${tempC}" ${baseSources} -I${QUICKJS_DIR}`);
|
|
216
|
-
console.log(`✅ Binary built: ${t.app}`);
|
|
240
|
+
console.log(`✅ Binary built${IS_OPTIMIZED ? ' and optimized' : ''}: ${t.app}`);
|
|
217
241
|
} catch (e) {
|
|
218
242
|
console.error(`❌ Compilation failed for ${t.id}`);
|
|
219
243
|
console.error(e.stderr?.toString() || e.message);
|
|
@@ -242,4 +266,5 @@ binFiles.forEach(file => {
|
|
|
242
266
|
});
|
|
243
267
|
if (existsSync(stubPath)) unlinkSync(stubPath);
|
|
244
268
|
|
|
245
|
-
console.log(
|
|
269
|
+
console.log(`🚀 Build process complete. (Optimization: ${IS_OPTIMIZED ? 'ON' : 'OFF'})`);
|
|
270
|
+
console.log("Platform sources kept in build/ subfolders.");
|
package/package.json
CHANGED