Giter Site home page Giter Site logo

lyming1994 / flutter_qjs Goto Github PK

View Code? Open in Web Editor NEW

This project forked from ekibun/flutter_qjs

0.0 0.0 0.0 6.28 MB

A quickjs engine for flutter.

Home Page: https://pub.dev/packages/flutter_qjs

License: MIT License

Dart 15.19% CMake 4.40% C++ 7.45% C 1.65% Kotlin 0.17% Ruby 1.41% Swift 0.56% Objective-C 0.16% Shell 0.09% JavaScript 0.04% CSS 2.28% HTML 66.60%

flutter_qjs's Introduction

flutter_qjs

Pub Test

English | δΈ­ζ–‡

This plugin is a simple js engine for flutter using the quickjs project with dart:ffi. Plugin currently supports all the platforms except web!

Getting Started

Basic usage

Firstly, create a FlutterQjs object, then call dispatch to establish event loop:

final engine = FlutterQjs(
  stackSize: 1024 * 1024, // change stack size here.
);
engine.dispatch();

Use evaluate method to run js script, it runs synchronously, you can use await to resolve Promise:

try {
  print(engine.evaluate(code ?? ''));
} catch (e) {
  print(e.toString());
}

Method close can destroy quickjs runtime that can be recreated again if you call evaluate. Parameter port should be close to stop dispatch loop when you do not need it. Reference leak exception will be thrown since v0.3.3

try {
  engine.port.close(); // stop dispatch loop
  engine.close();      // close engine
} on JSError catch(e) { 
  print(e);            // catch reference leak exception
}
engine = null;

Data conversion between dart and js are implemented as follow:

dart js
Bool boolean
Int number
Double number
String string
Uint8List ArrayBuffer
List Array
Map Object
Function(arg1, arg2, ..., {thisVal})
JSInvokable.invoke([arg1, arg2, ...], thisVal)
function.call(thisVal, arg1, arg2, ...)
Future Promise
JSError Error
Object DartObject

Use Modules

ES6 module with import function is supported and can be managed in dart with moduleHandler:

final engine = FlutterQjs(
  moduleHandler: (String module) {
    if(module == "hello")
      return "export default (name) => `hello \${name}!`;";
    throw Exception("Module Not found");
  },
);

then in JavaScript, import function is used to get modules:

import("hello").then(({default: greet}) => greet("world"));

notice: Module handler should be called only once for each module name. To reset the module cache, call FlutterQjs.close then evaluate again.

To use async function in module handler, try run on isolate thread

Run on Isolate Thread

Create a IsolateQjs object, pass handlers to resolving modules. Async function such as rootBundle.loadString can be used now to get modules:

final engine = IsolateQjs(
  moduleHandler: (String module) async {
    return await rootBundle.loadString(
        "js/" + module.replaceFirst(new RegExp(r".js$"), "") + ".js");
  },
);
// not need engine.dispatch();

Same as run on main thread, use evaluate to run js script. In isolate, everything returns asynchronously, use await to get the result:

try {
  print(await engine.evaluate(code ?? ''));
} catch (e) {
  print(e.toString());
}

Method close can destroy isolate thread that will be recreated again if you call evaluate.

Use Dart Function (Breaking change in v0.3.0)

Js script returning function will be converted to JSInvokable. It does not extend Function, use invoke method to invoke it:

(func as JSInvokable).invoke([arg1, arg2], thisVal);

notice: evaluation returning JSInvokable may cause reference leak. You should manually call free to release JS reference.

(obj as JSRef).free();
// or JSRef.freeRecursive(obj);

Arguments passed into JSInvokable will be freed automatically. Use dup to keep the reference.

(obj as JSRef).dup();
// or JSRef.dupRecursive(obj);

Since v0.3.0, you can pass a function to JSInvokable arguments, and channel function is no longer included by default. You can use js function to set dart object globally. For example, use Dio to implement http in qjs:

final setToGlobalObject = await engine.evaluate("(key, val) => { this[key] = val; }");
await setToGlobalObject.invoke(["http", (String url) {
  return Dio().get(url).then((response) => response.data);
}]);
setToGlobalObject.free();

In isolate, top level function passed in JSInvokable will be invoked in isolate thread. Use IsolateFunction to pass a instant function:

await setToGlobalObject.invoke([
  "http",
  IsolateFunction((String url) {
    return Dio().get(url).then((response) => response.data);
  }),
]);

flutter_qjs's People

Contributors

ekibun avatar huage2580 avatar mabdc avatar narumi147 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.