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

Draft: Fix 12509: Match webpack/babel - evaluate dirname/filename at runtime when doing a build #14917

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

EliLichtblau
Copy link

@EliLichtblau EliLichtblau commented Oct 30, 2024

What does this PR do?

Fixes #12509
Fixes #13921
Fixes #4216

This PR tries to correctly evaluate __dirname and __filename whenever possible.

Rather than almost always inlining them to the current source path. This PR changes the behavior to only do that on "run" not build since it doesn't match the behavior of webpack or babel and was bugged in the above issue.

Webpack:
target browser: inline __dirname
target esm: convert to esm compat

In webpack you can control the values or preserve them but this is the default.

Babel:
always preserve no matter the module target

How did you verify your code works?

I wrote test cases

  • [ X ] I checked the lifetime of memory allocated to verify it's (1) freed and (2) only freed when it should be
  • [ X ] I included a test for the new code, or an existing test covers it
  • [ X ] I wrote TypeScript/JavaScript tests and they pass locally (bun-debug test test-file-name.test)

@paperdave
Copy link
Member

updated the pr description to link to more issues it would close. see also #2865

Copy link
Member

@paperdave paperdave left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice! thanks for working on this.

in addition to this, can you add tests for when --format=cjs is used?

@@ -0,0 +1,53 @@
import { describe, expect, it, beforeAll } from "bun:test";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

instead of manually testing, can you move these to using the itBundled function. you can use onAfterBundle to use expect on the output code.

stdin: Bun.file("/dev/null"),
});
const text = out.stdout.toString()
expect(text.includes("__dirname =")).toBe(true)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should attempt to ensure that the value assigned to __dirname is the correct value.

} else if (p.options.output_format == options.Format.esm) {
if (uses_dirname or uses_filename) {
const count = @as(usize, @intFromBool(uses_dirname)) + @as(usize, @intFromBool(uses_filename));
var declared_symbols = DeclaredSymbol.List.initCapacity(p.allocator, count) catch unreachable;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tiny nit, can all newly added catch unreachable on memory allocation failures be rewritten to catch bun.outOfMemory()

@@ -3507,7 +3508,7 @@ pub const Parser = struct {
// var __dirname = "foo/bar"
// var __filename = "foo/bar/baz.js"
//
if (p.options.bundle or !p.options.features.commonjs_at_runtime) {
if (p.options.target == Target.browser or !p.options.transform_only) {
Copy link
Member

@paperdave paperdave Oct 30, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is target being passed for this? was the original version of this incorrect? i think the main issue is lowering __dirname to a string when bundling.

edit: oh, i didnt realize there was more string emitting code (i saw it deleted). i still find this code extremely odd because it emits absolute paths from the builder, which surely dont have any use in a browser.

Copy link
Author

@EliLichtblau EliLichtblau Oct 30, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe I should look more closely to when commonjs_at_runtime is true. To exactly match current tooling it seemed best to do this only when target was browser. Also I think in node later I use .dirname while in bun it was set to use "dir".

So I think the cases are

  • Bun run ... - always inline
  • Bun build --target="node" -> import.meta.dirname / path.basename(pathToFileURL(import.meta.url))
  • Bun build --target="bun" -> import.meta.dir
  • Bun build --target="browser" -> souce_path
  • Bun build format=cjs -> do nothing

@paperdave paperdave marked this pull request as draft October 30, 2024 23:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
2 participants