Skip to content

feat(@parcel/transformer-js): Rewrite __dirname/__filename to be relative to asset.filePath#7727

Merged
mischnic merged 50 commits into
parcel-bundler:v2from
LekoArts:dirname-relative-path
Apr 11, 2022
Merged

feat(@parcel/transformer-js): Rewrite __dirname/__filename to be relative to asset.filePath#7727
mischnic merged 50 commits into
parcel-bundler:v2from
LekoArts:dirname-relative-path

Conversation

@LekoArts

@LekoArts LekoArts commented Feb 17, 2022

Copy link
Copy Markdown
Contributor

↪️ Pull Request

This adds a way of accomplishing #7611 - this functionality will be enabled by default in node environment.

Fixes #7611

💻 Examples

See linked issue, but TL;DR is:

Some code in e.g. <root>/index.ts has a ${__dirname}/data string in it.
When it'll be compiled to e.g. <root>/dist the path should be changed to:

const path = require("path")
const dirname = path.resolve(__dirname, "..")
return `${dirname}/data`

🚨 Test instructions

I've added a test to the integration tests, it has to have the node env (so e.g. engines: node key).

✔️ PR Todo

  • Added/updated unit tests for this change
  • Filled out test instructions (In case there aren't any unit tests)
  • Included links to related issues/PRs

@height

height Bot commented Feb 17, 2022

Copy link
Copy Markdown

Link Height tasks by mentioning a task ID in the pull request title or commit messages, or description and comments with the keyword link (e.g. "Link T-123").

💡Tip: You can also use "Close T-X" to automatically close a task when the pull request is merged.

Comment thread packages/core/core/src/resolveOptions.js Outdated
Comment thread packages/transformers/js/src/JSTransformer.js Outdated
Comment thread packages/transformers/js/src/JSTransformer.js Outdated
@LekoArts LekoArts changed the title feat(@parcel/transformer-js): Rewrite __dirname to be relative to projectRoot feat(@parcel/transformer-js): Rewrite __dirname/__filename to be relative to projectRoot Feb 17, 2022

@mischnic mischnic left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Looks good overall!

IMO relativeContext doesn't really convey that this is about __dirname and __filename 🤷‍♂️


There's a similar existing test here:

it('should insert global variables when needed', async function () {

So duplicate that and add a package.json with that new config option, then you can delete the example you've committed.


Regarding the path import: this is similar to how an import for buffer is added for the Buffer global, that is done here:

@LekoArts

Copy link
Copy Markdown
Contributor Author

Ok, so I pushed some more changes to the Rust code and I have two problems now:

  1. Actually the generated relative path is incorrect
  2. I'm not seeing my changes in the tests

Let me explain.


When we have a source file at <root>/index.ts and we compile to <root>/dist/index.js we would expect that the relative path to the projectRoot is "..".
But it isn't.

Here is the relevant line: https://github.com/LekoArts/parcel/blob/eca555e83e8ba3ac7ad0eded8dd9c0723a21713e/packages/transformers/js/core/src/global_replacer.rs#L144

dirname here is the path of the <root>/index.ts file, which is identical with projectRoot. So the relative path created will be "" and not "..".

How can I get the distDir here to construct a correct relative path?


I'm not seeing my Rust code changes in the tests. I think I've added the test and the new option correctly, but when I print out the js (currently commented out) I'm not seeing the changes I did when I still had the example project in packages/examples.

@LekoArts

Copy link
Copy Markdown
Contributor Author

Let me know @mischnic if my above questions/comments make sense and you can help me? Appreciate it a lot! Thanks

@mischnic

Copy link
Copy Markdown
Member

How can I get the distDir here to construct a correct relative path?

The transformer doesn't know the final path of the bundle that the asset will be put into. This is only known after bundling/packaging (https://parceljs.org/plugin-system/overview/), so you have to do the path.relative(root, bundle.filePath) computation and insertion in a packager (so @parcel/packager-js).


I don't know why the changes wouldn't show up in the tests (apart from forgetting to recompile the Rust code), so I guess it has to be that your change doesn't modify the behaviour somehow.

@LekoArts

Copy link
Copy Markdown
Contributor Author

Ok, thanks for that information. I'll look into the tests, I probably made an error somewhere.

I'm trying to wrap my head around how to go about this then. Do I need to keep the changes I made to the transformer so far and add some "identifier" so that later the packager can modify/replace things, or do I completely remove the Rust logic and make all my changes in the packager? From my understand I'd need both, so that in the transformer I actually replace the call and then the packager can change the import path?

@mischnic

Copy link
Copy Markdown
Member

Exactly. The logic to determine whether __dirname wasn't declared as a local variable definitely needs to happen in the transformer.

Then in the packager, one possibility would be replacing that placeholder literally or (though somewhat sketchy) do the same as $parcel$global and just assume that this variable is unused by the user and emit it in the transformer, and then prepend a variable declaration in the packager. Though in this case you probably need one variable per asset

return Ident::new("$parcel$global".into(), node.span);

@LekoArts

Copy link
Copy Markdown
Contributor Author

Ok, I was sick 🤧 for a bit, I'll start working on this again now

@LekoArts

Copy link
Copy Markdown
Contributor Author

Ok, so I got it working in my example (currently still committed in this PR) in how I expect it:

Bildschirmfoto 2022-03-18 um 12 54 01

But I'll remove the example and add tests.

The API and naming etc. is pretty gross and I'm also still using same placeholder everywhere, not per asset.

So it works, but still lot to do.

@mischnic

@LekoArts LekoArts marked this pull request as ready for review March 22, 2022 15:50
@LekoArts

LekoArts commented Apr 7, 2022

Copy link
Copy Markdown
Contributor Author

Thanks! Will look into it and add a test

@LekoArts

LekoArts commented Apr 7, 2022

Copy link
Copy Markdown
Contributor Author

Good catch @mischnic 👍

The issue was that I've used pathdiff::diff_paths for __filename where I didn't need to use it. It just worked in the past but it seems with /folder-name/index.js it doesn't give back index.js but /folder-name/index.js.

Comment thread packages/transformers/js/core/src/lib.rs Outdated
Comment thread packages/packagers/js/src/ScopeHoistingPackager.js Outdated

@mischnic mischnic left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Looks good to me!

@LekoArts

LekoArts commented Apr 8, 2022

Copy link
Copy Markdown
Contributor Author

Awesome 🎉 I'll let you re-run the CI, otherwise with my commit trigger I'd invalidate your review

),
);
wrapped = wrapped.replace('$parcel$dirnameReplace', relPath);
wrapped = wrapped.replace('$parcel$filenameReplace', relPath);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Is there a reason we have two different variables that get replaced with the same path? Were these meant to be different, or do we only need one of them?


*self.has_node_replacements = true;
}
"__dirname" => {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Some of this could probably be combined with the above but ok for now

@devongovett devongovett left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Looks good overall! Thanks again!

@LekoArts

LekoArts commented Apr 8, 2022

Copy link
Copy Markdown
Contributor Author

I will optimize this (i.e. address the two new review comments) in a follow-up PR -- I'd like to get this into a nightly release so that we can try it out at Gatsby :)

@LekoArts

Copy link
Copy Markdown
Contributor Author

I think you'll need to re-run a bunch of times for the flaky tests 😅

@LekoArts

LekoArts commented Apr 11, 2022

Copy link
Copy Markdown
Contributor Author

With #7931 merged I guess I need to change some ast::Lit::Str occurrences. I'll do this in a bit

@mischnic

Copy link
Copy Markdown
Member

Sorry, I forgot that merging it would break this PR 😬

@mischnic

mischnic commented Apr 11, 2022

Copy link
Copy Markdown
Member

Looks like it compiles, the only breaking change from the swc update was related to :ast:Number. And these changes from ast::Str{} to .into() are just using a shorter syntax and are equivalent. So we can clean that up later.

@mischnic mischnic merged commit be0929a into parcel-bundler:v2 Apr 11, 2022
@LekoArts

Copy link
Copy Markdown
Contributor Author

Awesome. I'll do that in the follow-up PR. Thanks for merging and help on the PR <3

@LekoArts LekoArts deleted the dirname-relative-path branch April 11, 2022 15:23
@LekoArts

Copy link
Copy Markdown
Contributor Author

The nightly release that would include this failed here: https://github.com/parcel-bundler/parcel/actions/runs/2151865409

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

Successfully merging this pull request may close these issues.

Rewrite __dirname/__filename to be relative from asset.filePath

3 participants