How to build expanding include_str!("__index.js") expanded to literal r#"<index.js raw text>"# in main.rs?

How to expand something like this, Rust source code referencing a file is src directory, in src/main.rs source code

let js_code = include_str!("__index.js");

into this

// Actual source code raw text of `__index.js`
let js_code = r#"
function getMessage() {
  const headerBuffer = std.in.read(4);
  // ...

before/using/during cargo build?

What do you mean? include_str!() does include the file.

    let js_code = include_str!("index.js");
    context.eval(Source::from_bytes(js_code.as_bytes()))?;

This is crude, but works

mod.js

// Write JavaScript source into Rust main.rs as r#"JS_SOURCE"#
import { readFileSync, writeFileSync } from "node:fs";
const MAIN_RS = "./src/main.rs";
const JS_SOURCE = "./src/nm_boa.js";
const rustRawStringLiteralRegExp = /r#".*"#/;
const jsStringToRustRawStringLiteral = (str) => `r#"${str}"#`;
const jsSourceToEmbedInMainRs = readFileSync(JS_SOURCE, "utf8");
const mainRs = readFileSync(MAIN_RS, "utf8");
const modifiedMainRs = mainRs.replace(
  rustRawStringLiteralRegExp,
  jsStringToRustRawStringLiteral(jsSourceToEmbedInMainRs),
);
writeFileSync(MAIN_RS, modifiedMainRs);

mod_reset.js

// Reset Rust main.rs to r#""#, remove JavaScript source
import { readFileSync, writeFileSync } from "node:fs";
const MAIN_RS = "./src/main.rs";
const rustRawStringLiteralRegExp = /r#"([\s\S]*?)"#/g;
const jsStringToRustRawStringLiteral = (str) => `r#"${str}"#`;
const mainRs = readFileSync(MAIN_RS, "utf8");
const modifiedMainRs = mainRs.replace(
  rustRawStringLiteralRegExp,
  `r#""#`,
);
writeFileSync(MAIN_RS, modifiedMainRs);

I was thinking there might be a way to dynamically write the referenced raw string literal into the compiled binary.

Ideally such that the placeholder template remains the same, unmodified.

The idea is that the compiled JavaScript/WASM interpreter does not have to search a filesystem for a file to interpret at runtime. The target compiled binary does one task, and that's it, execute the embedded JavaScript/TypeScript/WASM/whatever. main.rs includes some kind of template instructing the compiler to expand the file reference in src to a Rust raw string literal before compilation.

What is it that you think include_str!() does? How is that different from what you're asking for? I've tried to read your posts about three times now, and I can't tell what the difference is.

I guess the difference is we don't necessarily have to have a file on disk at all. We can pass the data to be compiled as stdin to mod.js.

What is "mod.js" in the context of rust compiling code? The closest I can think of is you want something like:

// run the provided code at build time, read the output to a string, 
// and include it as static data in the compiled binary 
let source = include_exec_stdout!("node mod.js");

where mod.js itself returns some JS code (presumably different to the source of mod.js itself) for the Rust binary to execute.

But that doesn't work for the example of "it could read from stdin" because stdin in this case is whatever the implementation of include_exec_stdout!() does, and there's not anything interesting it could provide, at least in that form (certainly you can't read the stdin to the top level cargo build)

Part of the confusion here is probably because there's too many levels of "build" and "run" happening in your examples so far. To help clarify things, please try to describe a simple, but complete example flow that you would like to work, from the original command line you run to create a binary, to the result of executing it. For example, with the original code you provided here:

let js_code = include_str!("index.js");
context.eval(Source::from_bytes(js_code.as_bytes()))?;

When you run cargo build:

  • the include_str!() macro will read the file src/index.js
  • the contents are included literally in the compiled binary as a string

When you run the compiled binary later:

  • the included string is parsed and evaluated by context eval

Try to make sure each process that runs is included.

Would you like to call a JS bundler/builder/tool to generate JS code during building your Rust binary and include the generated JS code into the resulting Rust binary?

There is build.rs for those tasks: Build Scripts - The Cargo Book