Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Is it possible to implement a selective evaluator that can cross module boundaries? #4

Open
wtlin1228 opened this issue Oct 31, 2024 · 0 comments
Assignees

Comments

@wtlin1228
Copy link
Owner

Cross-Module Selective Evaluator

In some cases, we will want to selectively evaluate some expressions in one module, but those expressions are depending on other modules. So, we need to either bundle all files into one or evaluate recursively.

Use the following example, How to evaluate the result if it is a constant expression?

// main.js
import { a1, a2 } from "./a";
import { b1, b2 } from "./b";
import { c1, c2 } from './c';

const a1b1 = a1 + b1;
const a2b2 = a2 + b2;

export const result = a1b1 + a2b2;

// a.js
export const a1 = "a1";
export const a2 = "a2";
export const a3 = "a3";

// b.js
export const b1 = "b1";
export const b2 = "b2";
export const b3 = "b3";

// c.js
export const c1 = "c1";
export const c2 = "c2";
export const c3 = "c3";

Approach 1 - Bundler + Compressor

Use bundler like Rollup and set the entry as main.js, we can get:

const a1 = "a1";
const a2 = "a2";

const b1 = "b1";
const b2 = "b2";

const a1b1 = a1 + b1;
const a2b2 = a2 + b2;

const result = a1b1 + a2b2;

export { result };

Then, use compressor like Terser we can get:

const a="a1b1a2b2";export{a as result};

With bundler and compressor, we can evaluate the result to "a1b1a2b2". So, to achieve selective evaluation:

  1. create a new module
  2. copy our target and its dependencies into the module
  3. export the target
  4. run bundler
  5. run minifier

Approach 2 - Bundler + SWC's Evaluator

SWC actually implemented its own minifiler with the help of terser's maintainer (swc-project/swc#1302). And there is a Evaluator we can leverage on.

  1. run bundler to bring all the dependencies into one file
  2. parse the file with SWC
  3. evaluate the expression with Evaluator::eval

Approach 3 - SWC's Evaluator + Recursive eval()

Paste our original example here again for easier reference.

// main.js
import { a1, a2 } from "./a";
import { b1, b2 } from "./b";
import { c1, c2 } from './c';

const a1b1 = a1 + b1;
const a2b2 = a2 + b2;

export const result = a1b1 + a2b2;

// a.js
export const a1 = "a1";
export const a2 = "a2";
export const a3 = "a3";

// b.js
export const b1 = "b1";
export const b2 = "b2";
export const b3 = "b3";

// c.js
export const c1 = "c1";
export const c2 = "c2";
export const c3 = "c3";

Here is the recursive evaluation. This way we can evaluate result if all the paths are evaluated successfully.

To evaluate `result`, evaluate `a1b1` and `a2b2`
    -> To evaluate `a1b1`, evaluate `a1` and `b1`
        -> Evaluate `a1`
        -> Evaluate `b1`
    -> To evaluate `a2b2`, evaluate `a2` and `b2`
        -> Evaluate `a2`
        -> Evaluate `b2`

wyw-in-js also approaches this way, they create a new Entry and process only the imported ones. By the way, they use Babel to first try to do evaluation statically then use node:vm for more eagerly evaluation.

Approach 4 - Bundler + SourceMap + SWC's Evaluator

Bundle the whole project so we have one large file. Then we can parse it with SWC and selectively evaluate what we care. Finally, we need to map things back to our original path with SourceMap.

This approach only need to bundle once, but parse one very large file into AST could lead to memory overflow. And our process could become very slow.

Approach 5 - ...

@wtlin1228 wtlin1228 self-assigned this Oct 31, 2024
@wtlin1228 wtlin1228 moved this to Todo in Leo's Work Oct 31, 2024
@wtlin1228 wtlin1228 moved this from Todo to Pending in Leo's Work Jan 9, 2025
@wtlin1228 wtlin1228 removed this from Leo's Work Jan 13, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant