https://github.com/fluttercandies/fjs
A high-performance JavaScript runtime for Flutter applications, built with Rust and powered by QuickJS.
https://github.com/fluttercandies/fjs
flutter flutter-js js-engine js-runtime quickjs rust
Last synced: about 1 month ago
JSON representation
A high-performance JavaScript runtime for Flutter applications, built with Rust and powered by QuickJS.
- Host: GitHub
- URL: https://github.com/fluttercandies/fjs
- Owner: fluttercandies
- License: mit
- Created: 2025-02-14T08:40:29.000Z (about 1 year ago)
- Default Branch: main
- Last Pushed: 2026-01-21T07:57:11.000Z (about 1 month ago)
- Last Synced: 2026-01-21T18:58:33.688Z (about 1 month ago)
- Topics: flutter, flutter-js, js-engine, js-runtime, quickjs, rust
- Language: Dart
- Homepage: https://pub.dev/packages/fjs
- Size: 3.15 MB
- Stars: 61
- Watchers: 1
- Forks: 6
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
README
# π FJS - Flutter JavaScript Engine
High-performance JavaScript runtime for Flutter β‘
Built with Rust and powered by QuickJS π¦
[](https://pub.dev/packages/fjs)
[](https://github.com/fluttercandies/fjs)
[](https://github.com/fluttercandies/fjs/blob/main/LICENSE)
*[π δΈζζζ‘£](README_zh.md)*
## β¨ Why FJS?
- **High Performance** - Rust-powered, optimized for mobile platforms
- **ES6 Modules** - Full support for import/export syntax
- **Async/Await** - Native async JavaScript execution
- **Type Safe** - Strongly typed Dart API with sealed classes
- **Bridge Communication** - Bidirectional Dart-JS communication
- **Cross Platform** - Android, iOS, Linux, macOS, Windows
- **Memory Safe** - Built-in GC with configurable limits
## π― Real-world Usage
**[Mikan Flutter](https://github.com/iota9star/mikan_flutter)** - A Flutter client for [Mikan Project](https://mikanani.me), an anime subscription and management platform. FJS powers its core JavaScript execution engine.
## π¦ Installation
```yaml
dependencies:
fjs: any
```
## π Quick Start
```dart
import 'package:fjs/fjs.dart';
void main() async {
await LibFjs.init();
// Create runtime with builtin modules
final runtime = await JsAsyncRuntime.withOptions(
builtin: JsBuiltinOptions(
console: true,
fetch: true,
timers: true,
),
);
// Create context
final context = await JsAsyncContext.from(runtime);
// Create engine
final engine = JsEngine(context);
await engine.init(bridge: (jsValue) {
return JsResult.ok(JsValue.string('Hello from Dart'));
});
// Execute JavaScript
final result = await engine.eval(JsCode.code('''
console.log('Hello from FJS!');
1 + 2
'''));
print(result.value); // 3
await engine.dispose();
}
```
## π¦ ES6 Modules
```dart
// Declare modules
await engine.declareNewModule(
module: JsModule.code(module: 'math', code: '''
export const add = (a, b) => a + b;
export const multiply = (a, b) => a * b;
'''),
);
// Use modules
await engine.eval(source: JsCode.code('''
import { add, multiply } from 'math';
console.log(add(2, 3)); // 5
console.log(multiply(4, 5)); // 20
'''));
```
## π Bridge Communication
```dart
await engine.init(bridge: (jsValue) async {
final data = jsValue.value;
if (data is Map && data['action'] == 'fetchUser') {
final user = await fetchUser(data['id']);
return JsResult.ok(JsValue.from(user));
}
return JsResult.ok(JsValue.none());
});
// In JavaScript
await engine.eval(source: JsCode.code('''
const user = await fjs.bridge_call({ action: 'fetchUser', id: 123 });
console.log(user);
'''));
```
## π§ Memory Management
```dart
// Set limits
await runtime.setMemoryLimit(50 * 1024 * 1024); // 50MB
await runtime.setGcThreshold(10 * 1024 * 1024); // 10MB
// Monitor usage
final usage = await runtime.memoryUsage();
print(usage.summary());
// Force GC
await runtime.runGc();
```
## π Core API
### JsEngine
```dart
class JsEngine {
factory JsEngine({required JsAsyncContext context});
Future init({required FutureOr Function(JsValue) bridge});
Future initWithoutBridge();
Future eval({required JsCode source, JsEvalOptions? options});
Future call({required String module, required String method, List? params});
Future declareNewModule({required JsModule module});
Future declareNewModules({required List modules});
Future clearNewModules();
Future isModuleDeclared({required String moduleName});
Future> getDeclaredModules();
Future evaluateModule({required JsModule module});
Future dispose();
bool get running;
bool get disposed;
JsAsyncContext get context;
}
```
### JsValue
```dart
sealed class JsValue {
const factory JsValue.none();
const factory JsValue.bool(bool value);
const factory JsValue.integer(PlatformInt64 value);
const factory JsValue.float(double value);
const factory JsValue.string(String value);
const factory JsValue.array(List value);
const factory JsValue.object(Map value);
static JsValue from(Object? any);
dynamic get value;
}
```
### JsCode & JsModule
```dart
sealed class JsCode {
const factory JsCode.code(String value); // Inline code
const factory JsCode.path(String value); // File path
const factory JsCode.bytes(Uint8List value); // Raw bytes
}
sealed class JsModule {
static JsModule code({required String module, required String code});
static JsModule path({required String module, required String path});
static JsModule bytes({required String module, required List bytes});
}
```
### JsResult
```dart
sealed class JsResult {
const factory JsResult.ok(JsValue value);
const factory JsResult.err(JsError error);
bool get isOk;
bool get isErr;
JsValue get ok;
JsError get err;
}
```
## π§© Built-in Modules
| Module | Description |
|--------|-------------|
| `console` | Console logging (`console.log`, `console.error`, etc.) |
| `timers` | Timer functions (`setTimeout`, `setInterval`, `setImmediate`) |
| `buffer` | Buffer utilities for binary data |
| `util` | Utility functions |
| `json` | JSON parsing and serialization |
| `fetch` | HTTP client (Fetch API) |
| `url` | URL parsing and formatting |
| `crypto` | Cryptographic functions (hash, HMAC, random bytes) |
| `events` | EventEmitter implementation |
| `streamWeb` | Web Streams API |
| `navigator` | Navigator information (web-compatible) |
| `exceptions` | Error handling utilities |
| `fs` | File system operations (Node.js-compatible) |
| `path` | Path manipulation (POSIX/Windows) |
| `process` | Process information and environment |
| `os` | Operating system utilities |
| `net` | Network TCP/UDP sockets |
| `dns` | DNS resolution |
| `childProcess` | Child process spawning |
| `workerThreads` | Worker thread support |
| `asyncHooks` | Async lifecycle tracking |
| `perfHooks` | Performance measurement APIs |
| `perfHooks` | Performance measurement APIs |
| `tty` | Terminal utilities |
| `stringDecoder` | String decoding from buffers |
| `zlib` | Compression/decompression (gzip, deflate) |
| `assert` | Assertion testing |
| `abort` | AbortController support |
### Quick Presets
```dart
// Essential: console, timers, buffer, util, json
JsBuiltinOptions.essential()
// Web: console, timers, fetch, url, crypto, streamWeb, navigator, exceptions, json
JsBuiltinOptions.web()
// Node.js: Most modules except OS-specific ones
JsBuiltinOptions.node()
// All modules
JsBuiltinOptions.all()
// Custom selection
JsBuiltinOptions(
console: true,
fetch: true,
timers: true,
// ... other options
)
```
## β οΈ Error Handling
```dart
try {
final result = await engine.eval(source: JsCode.code('invalid.code()'));
} on JsError catch (e) {
print('Error: ${e.code()} - ${e}');
}
```
## β‘ Performance Tips
1. **Reuse Engines** - Create once, use many times
2. **Set Memory Limits** - Configure appropriate limits
3. **Use Bytes** - Prefer `JsCode.bytes()` for binary data
4. **Batch Operations** - Group related operations
## π License
MIT License - see [LICENSE](LICENSE) file.