An open API service indexing awesome lists of open source software.

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.

Awesome Lists containing this project

README

          


FJS Logo

# πŸš€ FJS - Flutter JavaScript Engine

High-performance JavaScript runtime for Flutter ⚑
Built with Rust and powered by QuickJS πŸ¦€

[![pub package](https://img.shields.io/pub/v/fjs.svg)](https://pub.dev/packages/fjs)
[![GitHub stars](https://img.shields.io/github/stars/fluttercandies/fjs.svg?style=flat&logo=github&colorB=deeppink&label=stars)](https://github.com/fluttercandies/fjs)
[![License](https://img.shheels.io/badge/license-MIT-blue.svg)](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.