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

Babel config invalidation #3261

Merged
merged 57 commits into from
Aug 30, 2019
Merged

Babel config invalidation #3261

merged 57 commits into from
Aug 30, 2019

Conversation

padmaia
Copy link
Contributor

@padmaia padmaia commented Jul 24, 2019

↪️ Pull Request

This PR updates @parcel/transformer-babel to use the new config invalidation pattern. It also uses @babel/core to resolve babel configs, so babel.config.js is now supported. There are certain newly supported scenarios that are non optimal (such as having a babel.config.js file in the first place) in which case a warning will be administered. One more notable change is that it is now using core-js over the deprecated @babel/polyfill.

✔️ PR Todo

  • Implement config.shouldInvalidateOnStartup() now that graphs are being cached
  • Figure out how to surface performance warnings (can we deduplicate?)
  • Integration tests
  • Add a README that describes how the plugin works and steps to take to optimize for caching
  • Separate Config into public and internal classes

Copy link
Member

@devongovett devongovett left a comment

Choose a reason for hiding this comment

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

Looking good! I left a few inline comments and questions. Would like to nail down the public API a bit more. Happy to discuss in person/on a call if that's easier.

packages/core/core/src/RequestGraph.js Outdated Show resolved Hide resolved
packages/core/core/src/public/Config.js Outdated Show resolved Hide resolved
packages/core/core/src/public/Config.js Outdated Show resolved Hide resolved
packages/core/core/src/public/Config.js Outdated Show resolved Hide resolved
packages/core/integration-tests/test/babel.js Show resolved Hide resolved
setResolvedPath(filePath: FilePath): void;
// $FlowFixMe could be anything
setResult(result: any): void; // TODO: fix
setResultHash(resultHash: string): void;
Copy link
Member

Choose a reason for hiding this comment

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

Did you consider an API where you the result directly from the plugin, instead of mutating the passed object? We could also automatically compute the hash from the result in core, unless there's a case where leaving that to the plugin is required.

loadConfig({config}) {
  return {
    filePath: '...', // instead of setResolvedPath
    config: {...}    // instead of setResult
  };
}

I'm ok with either, just wanted to ensure we considered it.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, that's something I've discussed with @wbinnssmith a bit. One reason I was leaning this way is that it is more consistent with how we pass Asset to the other methods. It also alleviates some work with methods like getConfig that both help with resolving/parsing config and also adding whichever file was resolve to included files.

We could also automatically compute the hash from the result in core, unless there's a case where leaving that to the plugin is required.

Yeah, my thinking was it would be nice to be flexible because it's possible a resolved config might contain more information than is relevant for invalidation. One example where we're actually using it right now is the parcel config. For invalidation of a pipeline transformation, we only care about one pipeline, not the entire config. We could accomplish the same thing in other ways for Parcel, but it seemed like it might be useful for plugins. For instance, plugins might be using information from package.json, but they only care a single field. (That reminds me the babel transformer should probably invalidate if the source field changes)

Copy link
Member

Choose a reason for hiding this comment

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

With transformers we kinda actually support both: there is that TransformerResult type which has fields like code and map that you can return instead of mutating the asset. We found this to be challenging to deal with when eg adding dependencies, and passing assets into util functions, and mutation was easier there. The difference here is that Assets start out fully hydrated (they have input code etc.), whereas config starts out as an empty object. It just felt a little strange. I'm not totally against what's here, just curious what it would look like another way.

I think your usecase with hashes is a good one to allow control to plugins, but I think we should make it optional. i.e. if no hash is set by the plugin, we could set one automatically based on the result. Perhaps the shouldReload setting could also set the hash to something random?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I haven't had the time to explore this yet. Is this a blocker for the PR or could we follow up on it?

packages/core/core/src/Transformation.js Outdated Show resolved Hide resolved
@@ -250,13 +251,19 @@ export default class Transformation {
moduleName,
parcelConfig.resolvedPath
);
Copy link
Member

Choose a reason for hiding this comment

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

So, if I understand correctly, all config for all plugins is loaded in the main thread. Then it's sent back to the transformer thread, and rehydrated. But, if it needs to be reloaded, it is immediately reloaded again on the transformer thread. So we end up needing to load it twice in that case?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, for babel that will happen if you are using a babel.config.js file and you have something like:

module.exports = {plugins: [require('babel-plugin-whatever')]}

because at that point all we have is a function which can not be rehydrated. And unfortunately, we don't know if the user is using this type of configuration until we try to load it. Not ideal obviously, but I thought it would be better to just support it and surface a warning that this type of configuration has performance impacts. I was thinking it would also be a good idea to document how to optimize for caching in a README for this package. I'll add that as a TODO.

Copy link
Member

Choose a reason for hiding this comment

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

Do configs need to be loaded on the main thread at all? I guess to check the graph? What if we just didn't store anything in the graph at all for configs that are uncacheable?

Copy link
Contributor Author

@padmaia padmaia Aug 9, 2019

Choose a reason for hiding this comment

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

We probably need some placeholder so we can at least invalidate on startup. Might not have to store an entire Config class though. Is this something we can follow up on?

packages/core/types/index.js Outdated Show resolved Hide resolved
packages/core/types/index.js Show resolved Hide resolved
Copy link
Contributor

@wbinnssmith wbinnssmith left a comment

Choose a reason for hiding this comment

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

Really excited about this 😃

I agree with @devongovett that we should have a stricter public interface for Config that calls through to internals.

packages/core/core/src/Transformation.js Show resolved Hide resolved
packages/core/core/src/public/Config.js Outdated Show resolved Hide resolved
packages/transformers/babel/src/typescript.js Show resolved Hide resolved
packages/core/workers/src/types.js Outdated Show resolved Hide resolved
packages/core/core/src/public/Config.js Outdated Show resolved Hide resolved
@padmaia
Copy link
Contributor Author

padmaia commented Aug 6, 2019

@devongovett I've separated Config into a public and internal class. Going to resolve conversations related that so it's easier for me to tell what's still left to do, but let me know what you think.

@padmaia padmaia force-pushed the babel-transformer-config branch 2 times, most recently from 6e89660 to 9b1f338 Compare August 9, 2019 03:19
@wbinnssmith wbinnssmith force-pushed the babel-transformer-config branch 3 times, most recently from cf7099f to b1b673b Compare August 9, 2019 22:39
[
'@parcel/babel-preset-env',
{
useBuiltIns: 'entry',
Copy link
Member

Choose a reason for hiding this comment

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

How do we feel about changing this to useBuiltIns: 'usage'? That would let babel automatically add only the polyfills needed from babel-polyfill instead of requiring the user to import 'babel-polyfill' in their app. See #1762.

@wbinnssmith wbinnssmith force-pushed the babel-transformer-config branch from 5dc9e01 to dff6e29 Compare August 28, 2019 22:56
@wbinnssmith wbinnssmith force-pushed the babel-transformer-config branch from 09ee1fe to d83d8dc Compare August 28, 2019 23:05
@wbinnssmith wbinnssmith force-pushed the babel-transformer-config branch from 90a9b6c to f4b8a36 Compare August 29, 2019 19:49
@wbinnssmith wbinnssmith force-pushed the babel-transformer-config branch from 4962eef to 4256be5 Compare August 29, 2019 21:46
@wbinnssmith wbinnssmith force-pushed the babel-transformer-config branch from 4256be5 to 6776ccb Compare August 29, 2019 21:54
@wbinnssmith wbinnssmith self-requested a review August 30, 2019 21:20
@padmaia padmaia merged commit 95da953 into v2 Aug 30, 2019
@wbinnssmith wbinnssmith deleted the babel-transformer-config branch September 23, 2019 17:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants