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
Allow plugins to indicate dependencies on random files #11741
Conversation
This pull request is automatically built and testable in CodeSandbox. To see build info of the built libraries, click here or the icon next to each commit SHA. Latest deployment of this branch, based on commit 8dfab48:
|
Build successful! You can test your changes in the REPL here: https://babeljs.io/repl/build/24831/ |
Good catch, I believe |
@JLHwung, another question! I notice that the code for determining whether to recompile a file is different in file.js and dir.js. Specifically, file.js has a check that dir.js does not have. (dir.js does not call Context: As I'm performing the integration of @babel/cli's watch mode with the external dependency tracking, I'm consolidating some of the code in dir.js and file.js in utils.js. Edit: It seems like there is a bug in file.js because the check Another question is: What does "file.js" do to handle the scenario where multiple files are changed in rapid succession? It seems like |
I think it should also be applied for
Can you address them in a separate PR? So we can fast track them in patch release.
Correct, if a folder is specified in
It could happen, though we have used |
@JLHwung -- the PR is ready for review now!
|
@JLHwung any updates on this? I do think this would be helpful for plugin/macro authors. At the same time, I understand that the Babel core team is busy, so if right now's not a good time, I can check back later 😃 |
@sosukesuzuki anywhere we can improve on this to get this out? |
@goatandsheep I'm not a maintainer, just the PR author, but it seems good to add some tests to verify this new feature works. I would do it myself if I had the time. |
Any news when this will hit prod? @JLHwung @vedantroy @goatandsheep @nicolo-ribaudo |
@vedantroy @MauriceArikoglu Sorry I completely forgot this PR. I will rebase on the latest main and it should be ready for review. |
It's not sufficient to know the file paths of all external dependencies. Babel needs to know which source files correspond to which external dependencies and vice-versa.
Video-Doc-Id[b0]: babel/babel/1
8dfab48
to
32cf26a
Compare
@JLHwung thank you! Can I be of any help in the review process? |
return await callback(null); | ||
} else { | ||
for (const dependent of externalFileDeps.get(filePath)) { | ||
await callback(dependent); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can be improved by Promise.all
: the external deps can be compiled in parallel.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@JLHwung can it actually? what if a dependency depends on another dependency?
If thats not possible, you are right. It should be changed to Promise.all @vedantroy
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this should be changed to Promise.all
(the API doesn't support a chain of deps), alas I don't have tons of bandwidth to do this right now so if @JLHwung wants to change it, that'd be great.
🚀 🚀 🚀 Thanks to @JLHwung and @vedantroy! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I downloaded this locally to play a bit with it, and there are a few changes that we need to do:
api.addExternalDependency
should only take a single parameter: the dependency path. It should already know the path of the current file.- the
dependencies
andexternalDependencies
set contain the same data, they are just inverted; I don't understand why we need both of them.
What should happen when the dependencies of a file change? Assume we have this plugin, which replaces the INLINE_ME
variable with the file contents.
function inlineFilePlugin(api, { inlineFile }) {
const { types: t } = api;
api.addExternalDependency(inlineFile, "./demo.js");
return {
visitor: {
Identifier(path) {
if (path.node.name === "INLINE_ME") {
path.replaceWith(t.stringLiteral(readFileSync(inlineFile, "utf8")));
}
},
},
};
}
the user might be running it like this:
babel.transformFileSync("./demo.js", {
plugins: [[inlineFilePlugin, { inlineFile: "./file1.txt" }]],
});
The user has a watcher that uses babel.getExternalDependencies()
to re-trigger their compiler step. Whenever file1.txt
changes, it re-compiles demo.js
.
At some point the config changes to { inlineFile: "./file2.txt" }
: when file1.txt
changes, it should not re-compile demo.js
anymore because it's not a dependency anymore.
I was going to propose fixing this by re-setting demo.js
's dependencies whenever it's compiled, but then I realized that the user might want to compile both with { inlineFile: "./file1.txt" }
and { inlineFile: "./file2.txt" }
for different build targets that run in "parallel".
The solution to all of this is to not store dependencies in a shared global, but to return them in a Set
in the result of babel.transform*
: Babel integrations are then free that set however they want, avoiding:
- global state that leaks across unrelated build pipelines
- "phantom" dependencies that should not be marked as dependencies anymore.
I can do these changes if you want; I also want to add tests.
I opened an alternative PR: #14065 |
I took a shot at fixing #8497.
The fix seems surprisingly simple, so I might be missing something obvious.(was missing something obvious)This PR adds a
addExternalDependency
function to Babel's plugin API. Plugins can call this function with 2 values:Calling
addExternalDependency
establishes a 2 way-mapping. Specifically, @babel/core exports 2 methods:getExternalDependencies
- This method returns a map of external dependency names to their dependent filesgetDependencies
- This method returns a map of source file names to the non-source files (external dependencies) that depend on them.This PR integrates the above information with @babel/cli's --watch flag. Whenever a file is compiled in watch mode, @babel/cli will check the above information and watch any new external dependencies.
This is a draft PR because there's a few things missing:
tests (I'm not sure how to test this, given that it's not a normal code transformation)This PR could work in conjunction with a PR to babel-loader. Specifically, babel-loader could use
getExternalDependencies
to call webpack'saddDependency
.