denoland / deno_ast

Source text parsing, lexing, and AST related functionality for Deno
https://crates.io/crates/deno_ast
MIT License
156 stars 46 forks source link

feat: enhance dynamic import with template argument #266

Open Mutefish0 opened 2 months ago

Mutefish0 commented 2 months ago

We now support dynamic imports with template arguments:

import("./a/${test}/.mod.ts")

This will include all files matching ./a/**/mod.ts.

The problem:

Many libraries that use Deno FFI require multiple files compiled for specific platforms. For example:

Library entry:

In our project:

// main.ts
import xxx from "jsr:@scope/mylib"
...

Then use deno compile:

deno compile --unstable-ffi  --include ... main.ts

Currently, we have to manually --include all the files regardless of the actual platform it will run on:

deno compile --unstable-ffi  --include https://jsr.io/@scope/mylib/0.0.1/ffi/aarch64-apple-darwin/ffi.ts --include https://jsr.io/@scope/mylib/0.0.1/ffi/x86_64-unknown-linux-gnu/ffi.ts main.ts

Another option is to statically import all the FFI files, as shown here:

截屏2024-08-06 下午6 37 22

it will be more complicated to maintain the library, and also will incrase the compiled bundle size.

Proposal

Analyze the expressions in the template argument in specific cases if they are known at compile time:

import(`./${Deno.build.target}/mod.ts`)

We can replace ${Deno.build.target} with correct target

import("./aarch64-apple-darwin/mod.ts")

which then become statically analyzable.

Proof of concept

I have created a patch and some tests for deno_graph which rely on this PR.

  run_test(
    "
  await import(`./${Deno.build.target}.ts`);
  ",
    vec![
      ("file:///dev/x86_64-unknown-linux-gnu.ts", ""),
      ("file:///dev/aarch64-unknown-linux-gnu.ts", ""),
      ("file:///dev/x86_64-pc-windows-msvc.ts", ""),
      ("file:///dev/x86_64-apple-darwin.ts", ""),
      ("file:///dev/aarch64-apple-darwin.ts", ""),
      ("https://dev/aarch64-apple-darwin.ts", ""),
    ],
    if cfg!(all(
      target_arch = "x86_64",
      target_os = "macos",
      target_vendor = "apple"
    )) {
      vec!["file:///dev/x86_64-apple-darwin.ts"]
    } else if cfg!(all(
      target_arch = "aarch64",
      target_os = "macos",
      target_vendor = "apple"
    )) {
      vec!["file:///dev/aarch64-apple-darwin.ts"]
    } else if cfg!(all(
      target_arch = "x86_64",
      target_os = "linux",
      target_env = "gnu"
    )) {
      vec!["file:///dev/x86_64-unknown-linux-gnu.ts"]
    } else if cfg!(all(
      target_arch = "aarch64",
      target_os = "linux",
      target_env = "gnu"
    )) {
      vec!["file:///dev/aarch64-unknown-linux-gnu.ts"]
    } else if cfg!(all(
      target_arch = "x86_64",
      target_vendor = "pc",
      target_os = "windows",
      target_env = "msvc"
    )) {
      vec!["file:///dev/x86_64-pc-windows-msvc.ts"]
    } else {
      vec![]
    },
  )
  .await;

run_test(
    "
  await import(`https://dev/${Deno.build.target}.ts`);
  ",
    vec![
      ("https://dev/x86_64-unknown-linux-gnu.ts", ""),
      ("https://dev/aarch64-unknown-linux-gnu.ts", ""),
      ("https://dev/x86_64-pc-windows-msvc.ts", ""),
      ("https://dev/x86_64-apple-darwin.ts", ""),
      ("https://dev/aarch64-apple-darwin.ts", ""),
    ],
    if cfg!(all(
      target_arch = "x86_64",
      target_os = "macos",
      target_vendor = "apple"
    )) {
      vec!["https://dev/x86_64-apple-darwin.ts"]
    } else if cfg!(all(
      target_arch = "aarch64",
      target_os = "macos",
      target_vendor = "apple"
    )) {
      vec!["https://dev/aarch64-apple-darwin.ts"]
    } else if cfg!(all(
      target_arch = "x86_64",
      target_os = "linux",
      target_env = "gnu"
    )) {
      vec!["https://dev/x86_64-unknown-linux-gnu.ts"]
    } else if cfg!(all(
      target_arch = "aarch64",
      target_os = "linux",
      target_env = "gnu"
    )) {
      vec!["https://dev/aarch64-unknown-linux-gnu.ts"]
    } else if cfg!(all(
      target_arch = "x86_64",
      target_vendor = "pc",
      target_os = "windows",
      target_env = "msvc"
    )) {
      vec!["https://dev/x86_64-pc-windows-msvc.ts"]
    } else {
      vec![]
    },
  )
  .await;

Related Issues

https://github.com/denoland/deno/issues/24871

Works fine with my local patch:

DENORT_BIN=./target/debug/denort ./target/debug/deno compile --unstable-ffi -o ./main main.ts 
CLAassistant commented 2 months ago

CLA assistant check
All committers have signed the CLA.