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

Resolve loaders directly from Encore instead of using their names #739

Merged
merged 1 commit into from
May 6, 2020

Conversation

Lyrkan
Copy link
Collaborator

@Lyrkan Lyrkan commented Apr 24, 2020

This issue fixes #727 by replacing the use of loader names in rules (for instance 'file-loader') by their resolved path (require.resolve('file-loader')).

The problem with using their name is that we are assuming that the loader's package will be present at the top-level of node_modules.

If for some reason that's not the case and npm/Yarn decides to put it in, let's say node_modules/@symfony/webpack-encore/node_modules, the compilation will fail when Webpack tries to require it.

Another reason to do that is to ensure that Webpack uses the right version of a loader. We had some issues before 0.29 because we expected an old version of file-loader when some other packages included a newer one that was then used by Webpack because it got hoisted to the top-level node_modules.

This change should in my opinion be considered a BC break for people that were:

  • adding a different version of a loader we embed into their package.json: that one won't be used anymore
  • requiring a package that also included one of our embedded loaders: depending on which one was hoisted it could result in a different behavior
  • manipulating the generated config and filtering loaders based on their names: the comparison won't be the same anymore (see the tests I had to change)

I also modified dev dependencies loaders for more consistency but it doesn't really matter for those.

@Lyrkan Lyrkan requested a review from weaverryan April 24, 2020 22:24
@@ -302,7 +302,7 @@ class ConfigGenerator {

rules.push(applyRuleConfigurationCallback('images', {
test: /\.(png|jpg|jpeg|gif|ico|svg|webp)$/,
loader: loaderName,
loader: require.resolve(loaderName),
Copy link
Member

Choose a reason for hiding this comment

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

This is a nit-pick, but I'm asking in case it's important. loaderName here may be file-loader or url-loader. file-loader is required by Encore, but url-loader is something that the user must have installed. What affect does require.resolve() have on a package that we know the user must have installed?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

That's already what we do to check if those kind of packages are installed:

function isPackageInstalled(packageConfig) {
try {
require.resolve(packageConfig.name);
return true;
} catch (e) {
return false;
}
}

@weaverryan
Copy link
Member

Also, for the Encore 1.0 release (with Webpack 5), I have been wondering if we should consider to stop the practice of requiring things on behalf of our users. We would still, of course, require things we use directly - e.g. semver - but not things that user "should" (in a pure webpack.config.js with Webpack setup) have installed - e.g. webpack itself, css-loader, babel-loader. The original motivation was to help keep the user's package.json "sane", which I still think is nice. However, with the recipe system, it's still very easy to ship a working package.json to the user. And even without that, we would leverage the features.js system to notify the user of what they need to install. On the downside, this would give users more freedom to choose what versions of packages they want. That's a "downside" because Encore would need to be able to handle more versions of possible dependencies, or at least communicate intelligently when we think you might be using a version we don't support. We already do that - we would just need to make sure it was very solid.

I'd love any thoughts you have on that - the goal would be to create less problems (as sometimes requiring these dependencies like we are causes issues) not more ;)

@stof
Copy link
Member

stof commented May 6, 2020

Will this help with yarn's PnP mode too ?

@stof
Copy link
Member

stof commented May 6, 2020

@weaverryan with your proposal, a nice effect could also be to reduce the dependency footprint of Encore. For instance, I'm only bundling JS with encore, not CSS, so I don't need all the css-loader or optimize-css-assets-webpack-plugin stuff.

@weaverryan
Copy link
Member

Thank you @Lyrkan!

@weaverryan weaverryan merged commit 950d5dd into symfony:master May 6, 2020
@Lyrkan
Copy link
Collaborator Author

Lyrkan commented May 6, 2020

@weaverryan I mean we could, it's probably only a matter of moving them to peer dependencies and adding the features checks in bin/encore, but I don't know if it will be well perceived by users having to:

  • add a lot of new dependencies to their package.json before being able to run Encore for the first time (not everybody uses the flex recipe). Maybe that could be fixed by addingn a --install-missing-dependencies option that automatically run yarn/npm when executing Encore (similar to what Webpack does for webpack-cli).
  • being asked to update those dependencies when they update Encore (that was already the case for optional features but it would be way more likely to happen then)

Also one annoying point is that the current "enforce_version" message is sometimes hidden because it appears after the build summary, which means that users could miss a required update that would have been done transparently in the current version.


@stof The issue with doing that is that we can't know before running Webpack if the user need those loaders/plugins (which is the case for other package checks since we do them when building the webpack config).

That could probably be handled by looking at the errors thrown by Webpack but it means that someone initializing a project that uses CSS will have to:

  • add Encore using Yarn/npm
  • run Encore a first time to get a list of mandatory dependencies (webpack, webpack-cli, ...)
  • use Yarn/npm again to retrieve them
  • run Encore again and encounter another error with another list of dependencies
  • use Yarn/npm again for them

I feel that it will annoy people more than downloading something that has a slightly bigger footprint.

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.

Can't resolve 'file-loader'
3 participants