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

Provide option to avoid tree walking during transpilation #133

Open
jordanbtucker opened this issue Aug 28, 2023 · 6 comments
Open

Provide option to avoid tree walking during transpilation #133

jordanbtucker opened this issue Aug 28, 2023 · 6 comments

Comments

@jordanbtucker
Copy link

I have a use case where I do not want deno_emit to walk the import tree when transpiling. When I tell it to transpile index.ts I only want it to give me the JS for index.ts, but not the JS for everything index.ts imports recursively.

My use case is that I don't want to have to specify which files are "roots" or "entry points" for transpiling. I want to say "transpile all TS files in this directory" so I can output them to another folder as modules rather than bundles.

Currently, I have three workarounds.

  1. Walk the directory, call transpile for each TS file, pick out the current file from the returned map. This has the unfortunate side-effect of performing many redundant transpilations.
  2. Create a main map, walk the directory, if the current file already exists in the main map, skip it, otherwise call transpile on the current TS file and add its results to the main map. This is more efficient, but it still walks the entire import tree.
  3. Walk the directory, call transpile for each TS file, provide a load function that returns { kind: "module", specifier, content } for imports that match the current entry and { kind: "external", specifier } for those that don't, which seems to exclude it from the map. This is complicated and requires implementing something that could be built in, but it does prevent walking the entire import tree, so it's the most efficient.
@yacinehmito
Copy link
Contributor

This is complicated and requires implementing something that could be built in, but it does prevent walking the entire import tree, so it's the most efficient.

This seems to cover your use case very well. Is there a compelling reason to make this behaviour built-in?

Can you explain your use-case a bit more? Maybe this is something that we can expect other people to need, but it is hard to tell until we know the why behind the use case.

@jordanbtucker
Copy link
Author

There are two use cases here.

  1. Creating a JS library for browsers using Deno's tooling and ecosystem. While it may be standard to have one mod.ts file that re-exports everything, that isn't the only way to do things. In fact, I think that's bad practice for browser modules because it forces the browser to fetch all dependencies even if they're not needed for the current task. I'd rather just give deno_emit one directory and have it transpile all files inside it.
  2. Creating a full-stack Deno web app. The browser scripts need to be transpiled from TS to JS, however I don't want to worry about which scripts are going to be entry points. Again, I just want to give deno_emit a directory and transpile all the files in it.

I suppose this could also apply to any project that has multiple entry points that rely on common code. For example, foo.ts ultimately relies on common.ts, and bar.ts ultimately relies on common.ts too. Both foo.ts and bar.ts are entry points, but since they both rely on common.ts, common.ts will get transpiled twice.

The behavior I'm proposing also mirrors tools like tsc and babel, which are transpilers, rather than webpack and esbuild, which are bundlers. In other words, it makes sense for deno_emit's bundle to accept entry points and walk the tree, but it doesn't make sense to me to have transpile walk the tree.

@benStre
Copy link
Contributor

benStre commented Oct 4, 2023

We also faced this issue in our project and implemented a transpileIsolated function in our fork of deno_emit, which provides this exact functionality.

As an alternative, we also created a standalone TS transpiler based on deno_ast/deno_graph, that takes TS module code as an input and returns the transpiled JS code.

@jordanbtucker
Copy link
Author

I just wanted to follow up on this to see if this is something that sounds worthwhile to implement. I also want to emphasize that this behavior would mirror other transpilers like TypeScript's tsc and Babel.js.

@jordanbtucker
Copy link
Author

jordanbtucker commented Jun 15, 2024

Chiming in again to say that I've been investigating Bun as an alternative since its Transpiler does not walk the tree.

Bun has Bun.build for bundling, which walks the tree, and Bun.Transpiler, which is a pure transpiler with the ability to replace and manipulate imports and exports.

@yacinehmito
Copy link
Contributor

What are the limitations of the third workaround you proposed? It seems like it only takes a few lines of code. Is there something I am not seeing?

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

3 participants