-
-
Notifications
You must be signed in to change notification settings - Fork 198
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
Refactor plugin configuration #99
Conversation
Extract encore built in plugin configuration logic into plugin utils. First step toward allowing to be able to configure plugins through options. From now own only public API with proper options is needed for most cases.
I'll check this out tonight! Excited about this! |
Ok, just checked this out! Breaking things into smaller pieces is a win :). To be honest, I'm struggling on a few of the details about "how best" to do this... but since it's internal stuff, we shouldn't sweat it too much.
What do you mean by this? About the individual plugins files, naming the method // clean.js
module.exports = function(plugins, webpackConfig, paths, cleanUpOptions = {}) {
let config = Object.assign({}, cleanUpOptions, {
root: webpackConfig.outputPath,
verbose: false,
});
plugins.push(new CleanWebpackPlugin(paths, config));
};
if (this.webpackConfig.cleanupOutput) {
cleanPluginUtil(plugins, this.webpackConfig, ['**/*']);
} Actually, we could go a step further, and include the logic of whether or not a plugin should be enabled, inside of that file: // clean.js
module.exports = function(plugins, webpackConfig, paths, cleanUpOptions = {}) {
if (!this.webpackConfig.cleanupOutput) {
return;
}
let config = // ...
// rest of file
}; It still doesn't feel perfect, but maybe good enough for the next step :). |
lib/plugins/dev-server.js
Outdated
@@ -0,0 +1,28 @@ | |||
/* |
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 isn't really a dev-server
plugin... it's a "AssetOutputDisplayPlugin", which happens to be disabled when the dev-server is used.
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.
oops !! my bad. I'll update that.
lib/plugins/dev-server.js
Outdated
getPlugins(webpackConfig) { | ||
const outputPath = pathUtil.getRelativeOutputPath(webpackConfig); | ||
const friendlyErrorsPlugin = FriendlyErrorsPlugin.getPlugins(); | ||
return [new AssetOutputDisplayPlugin(outputPath, friendlyErrorsPlugin[0])]; |
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 is clever, but a problem :). Because FriendlyErrorsPlugin.getPlugins()
actually instantiates a new FriendlyErrorsWebpackPlugin
internally, when FriendlyErrorsPlugin.getPlugins()
is called by config-generator
, it will receive one instance. When it's called here, it will receive a different instance. I "got away: with doing stuff like this with the loaders, because those return static config objects, not new instances of objects. In practice, this might not be a problem, but we can do better :).
The only idea I can think of right now, is to change plugins
in config-generator
to a hash - i.e. create keys for each plugin - e.g.
// old
plugins.push(new FriendlyErrorsPlugin());
// now
plugins.push('friendly_errors_plugin', new FriendlyErrorsPlugin());
then we could use that internal key to find other plugins. At the bottom of buildPluginsConfig()
in config-generator
, we would still return an actual array (not a hash/object). I don't love this magic, invented friendly_errors_plugin
machine name... but it would work, and would still be an internal implementation detail, at least for now (i.e. not exposed to users in any way).
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 see your point. Is this issue present in general for all plugins or it is just this particular case with the FriendlyErrorsWebpackPlugin
?
Regarding hashed solution:
... this magic, invented
friendly_errors_plugin
machine name...
I don't like it either. This case looks to me like a good scenario for a singleton. I did some research about the topic on the nodejs
land. I did found some resources:
What do you think if we try to implement one of those solutions for that FriendlyErrorsPlugin
?
I think this is the best way we can guaranty the single instance we need.
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 case looks to me like a good scenario for a singleton
Yes.... but no :). We allow you to generate multiple webpack configs. And to be strict about it, each separate webpack config should have its own instances of plugins.
So, yes, we need to make sure that we don't create multiple FriendlyErrorsWebpackPlugin
while generating one webpack config... but do need to create distinct instances, each time we ConfigGenerator.getWebpackConfig()
. If you can take a shot at that, perfect :).
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.
To apply a solution fitting all cases known so far, I take into account:
- This is a problem applied only for
FriendlyErrorsWebpackPlugin
? - We.... do need to create distinct instances, each time we ConfigGenerator.getWebpackConfig()
- We need to make sure that we don't create multiple FriendlyErrorsWebpackPlugin while generating one webpack config
From what we have talked I think the best solution is to not refactor this plugin at all :), we leave it as it was originally. That way we met all requirements.
Still, I am sorry to go over this but I would like to know what I am missing :)
FriendlyErrorsWebpackPlugin
is configured currently without any options coming from user, we set up same config options, so every time we will be creating same object values. Different instances (memory references etc..) but behavior i believe is the same.
Having the previous in mind. In which way a singleton will be different to the original code when we call Encore.reset()
to generate a new configuration?
thanks in advance for taking the time.
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.
In which way a singleton will be different to the original code when we call Encore.reset() to generate a new configuration?
Honestly, in practice, it probably makes not difference for FriendlyErrorsWebpackPlugin
. In fact, it's not clear to me what the proper behavior is for this plugin specifically when it comes to multi webpack config setups - there's an option question about it: geowarin/friendly-errors-webpack-plugin#56.
Could we just pass in the FriendlyErrorsPlugin instance as a dependency - i.e. add a friendlyErrorsWebpackPlugin
argument to this plugin and pass the instance in from config-generator
? It would work and no complexity or magic.
To answer your first comment Regarding:
I did mean that with this approach (broken into smaller pieces). Any future plugin ( For:
I like this idea far more than current one, actually I was trying to get some result similar to an interface implementation, as long as all plugins integration follow same pattern i don't see any problem. To your suggestion though I would only change one thing, function signature:
I think we don't need the plugin array any more because
we could push to What do you think? |
I understand!
This sounds good... but so far, when we call Do we agree on enough to get this to a good spot? I feel pretty comfortable - it's internal stuff anyways, which we can continue to iterate on. I don't want to delay this PR too much more :). Thanks! |
Make module export factory method modifying the plugis array to build.
I feel also comfortable with the result. Thanks for the clarifications, did helped a lot. |
Very nice! Thank you David! |
This PR was squashed before being merged into the master branch (closes #101). Discussion ---------- Forked typescript type checking This PR fixes: #63 it should be possible to merge also with #99 directly. Open points: Regarding point .1 in #2 > If this plugin is added. we need to check dependency is added using loader-features.js. This module name is getting name from loaders, we are not adding a loader here but a plugin. Maybe some more general module is needed for checking features? After implementing this I realize that as soon as you require a module which doesn't exist node throws an error, we don't even go through error catch from encore. So possible solutions I see for this pending point are: 1. We don't refactor `loader-features.js` file and we still will get a loud error when trying to use some plugin not installed. From error is clear whats need to be done. 2. We refactor `loader-features.js` to be named more general and we include plugins dependencies also there as intended initially. But this way we need to check for missing packages earlier in `WebpackConfig.js` like I am doing now in this PR. I like either solutions the same, I would like to get feedback on what do you guys think about it? thanks in advance. Commits ------- 7a7e399 Forked typescript type checking
Extract encore built in plugin configuration logic into plugin utils.
First step toward allowing to be able to configure plugins through options and have more modular integration for plugins inside encore. From now on only public API with proper options is needed,
for most cases.
This changes are internals and tries to improve plugin architecture inside encore. Please take a look on it and feedback are welcome :). So far I see improvements for several issues:
thanks in advance.