Now Reading
Roll your personal JavaScript runtime, pt. 3

Roll your personal JavaScript runtime, pt. 3

2023-05-04 13:28:50

This publish is a continuation of
Roll your own JavaScript runtime and
Roll your own JavaScript runtime, pt. 2.

We have been delighted by the optimistic response to this sequence on rolling your personal
customized JavaScript runtime. One space that
some expressed interest in is
tips on how to use snapshots to get quicker startup occasions. Snapshots can present improved
efficiency at a (sometimes) negligible improve in filesize.

On this weblog publish, we’ll construct on the
first and
second part by making a snapshot
of runtime.js in a construct script, then loading that snapshot in predominant.rs to
pace up begin time for our customized runtime.

Screenshot of the video walkthrough from Andy and Leo

Watch the video demo or
view source code here.

Getting setup

For those who adopted the first and
second blog post, your challenge
ought to have three recordsdata:

  • instance.ts: the JavaScript file we intend to execute with the customized runtime
  • src/predominant.rs: the asynchronous Rust perform that creates an occasion of
    JsRuntime,
    which is chargeable for JavaScript execution
  • src/runtime.js: the runtime interface that defines and supplies the API that
    will interop with the JsRuntime from predominant.rs

Let’s write a construct.rs file that can create a snapshot of the customized runtime,
runjs.

Making a snapshot in construct.rs

Earlier than create a construct.rs file, let’s first add deno_core as a construct
dependency in Cargo.toml:

[package]
title = "runjs"
model = "0.1.0"
version = "2021"

# See extra keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
deno_ast = { model = "0.22.0", options = ["transpiling"] }
deno_core = "0.174.0"
reqwest = "0.11.14"
tokio = { model = "1.25.0", options = ["full"] }

+ [build-dependencies]
+ deno_core = "0.174.0"

Subsequent, let’s create a construct.rs file within the root of your challenge. On this file,
we’ll must do the next steps:

  • Create a small extension of src/runtime.js
  • Construct a file path to the snapshot
  • Create the snapshot

Placing the above steps into code, your construct.rs script ought to seem like:

use std::env;
use std::path::PathBuf;
use deno_core::{Extension, include_js_files};

fn predominant() {
  
  let runjs_extension = Extensions::builder("runjs")
    .esm(include_js_files!(
      "src/runtime.js",
    ))
    .construct();

  
  let o = PathBuf::from(env::var_os("OUT_DIR").unwrap());
  let snapshot_path = o.be a part of("RUNJS_SNAPSHOT.bin");

  
  deno_core::snapshot_util::create_snapshot(deno_core::snapshot_util::CreateSnapshotOptions {
    cargo_manifest_dir: env!("CARGO_MANIFEST_DIR"),
    snapshot_path: snapshot_path,
    startup_snapshot: None,
    extensions: vec!(runjs_extension),
    compression_cb, None,
    Snapshot_module_load_cb: None,
  })
}

The principle perform is create_snapshot, which accepts a number of choices. Let’s go
over them within the subsequent part.

Diving into CreateSnapshotOptions

The create_snapshot perform is a pleasant abstraction layer that makes use of an choices
struct to find out how the snapshot is created. Let’s go over the totally different
fields which can be obtainable in CreateSnapshotOptions.

pub struct CreateSnapshotOptions {
  pub cargo_manifest_dir: &'static str,
  pub snapshot_path: PathBuf,
  pub startup_snapshot: Possibility<Snapshot>,
  pub extensions: Vec<Extensions>,
  pub compression_cb: Possibility<Field<CompressionCb>>,
  pub snapshot_module_load_cb: Possibility<ExtModuleLoaderCb>,
}
  • cargo_manifest_dir: the listing by which Cargo will likely be compiling
    every part into. This could at all times be the CARGO_MANIFEST_DIR setting
    variable.
  • snapshot_path: the trail the place we write the snapshot to.
  • startup_snapshot: you may cross in a snapshot, if you wish to construct a
    snapshot from one other snapshot.
  • extensions: any extensions that you just want to add on high of the snapshot
  • compression_cb: you may set which compression methodology to make use of to additional
    cut back the filesize.
  • snapshot_module_load_cb: you may cross a module loader that can rework
    recordsdata included within the snapshot. For instance, you may transpile TypeScript to
    JavaScript.

On this instance, we solely use:

  • snapshot_path: we outline the snapshot path by resolving OUT_DIR and
    RUNJS_SNAPSHOT.bin.
  • extensions: we cross the runjs_extension, which is constructed from
    src/runtime.js.

Loading the snapshot in predominant.rs

Presently, the predominant.rs file’s run_js perform masses the runjs_extension.
We’ll modify this perform to as a substitute load the snapshot we created in
construct.rs:

- use deno_core::include_js_files;
+ use deno_core::Snapshot;

// Different stuff…

+ static RUNTIME_SNAPSHOT: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/RUNJS_SNAPSHOT.bin"));

async fn run_js(file_path: &str) -> End result<(), AnyError> {
    let main_module = deno_core::resolve_path(file_path)?;
    let runjs_extension = Extension::builder("runjs")
-         .esm(include_js_files!(
-             "runtime.js",
-         ))
        .ops(vec![
            op_read_file::decl(),
            op_write_file::decl(),
            op_remove_file::decl(),
            op_fetch::decl(),
            op_set_timeout::decl(),
        ])
        .construct();
    let mut js_runtime = deno_core::JsRuntime::new(deno_core::RuntimeOptions {
        module_loader: Some(Rc::new(TsModuleLoader)),
+      startup_snapshot: Some(Snapshot::Static(RUNTIME_SNAPSHOT)),
        extensions: vec![runjs_extension],
        ..Default::default()
    });

    let mod_id = js_runtime.load_main_module(&main_module, None).await?;
    let consequence = js_runtime.mod_evaluate(mod_id);
    js_runtime.run_event_loop(false).await?;
    consequence.await?
}

We’ll take away the .esm() perform, since that was moved to construct.rs script.
Then, we’ll add a line to load the snapshot.

Lastly, to load the snapshot, we’ll add startup_snapshot in RuntimeOptions
that factors to the RUNTIME_SNAPSHOT, which is outlined above run_js as a
static slice of bytes of the snapshot we created in construct.rs.

And that is it! Let’s attempt working with:

cargo run -- instance.ts

It ought to work!

What’s subsequent?

Snapshotting is a wonderful software to assist enhance startup speeds for a customized
runtime. That is an very simple instance, however we hope that it sheds some
mild into how Deno makes use of snapshots to optimize efficiency.

By this sequence, we have proven tips on how to construct your personal customized JavaScript
runtime, add APIs like fetch, and now pace up startup occasions by way of snapshotting.
We love listening to from you so if there’s something you need us to cowl, please let
us know on Twitter,
YouTube, or
Discord.

Do not miss any updates — observe us on
Twitter.



Source Link

What's Your Reaction?
Excited
0
Happy
0
In Love
0
Not Sure
0
Silly
0
View Comments (0)

Leave a Reply

Your email address will not be published.

2022 Blinking Robots.
WordPress by Doejo

Scroll To Top