webpack: Duplicate module loaded multiple times

Hi,

Let’s say I have a project with a dependency tree like (all dependencies being declared as “dependencies” in package.json)

  • Main application
    • angular
    • Sub-module 1
      • angular
    • Sub-module 2
      • angular

When bundling my app, I will end-up with angular being included 2 times in my webpage. I know I can use webpack.optimize.DedupePlugin() to prevent the file being included multiple times but it will still be called two times at runtime, resulting in a warning “tried to load angular more than once”.

I feel this is the same for every sub-dependencies shared by my app dependencies, every sub-module will have its own version of angular and even though they use the exact same version, it will be loaded multiple times.

Is this tied to the philosophy of not having a flat dependency tree or am I doing something wrong ? One solution I have found is to move all the dependencies of my sub-modules as peerDependencies and add them as dependencies to my “Main application” but I feel like this is a very bad solution.

Any insights on this ?

Thanks.

About this issue

  • Original URL
  • State: closed
  • Created 8 years ago
  • Reactions: 47
  • Comments: 24 (1 by maintainers)

Commits related to this issue

Most upvoted comments

You probably do want angular to be a peerDependency, since it is a framework within which your code runs. That’s how I’ve modeled it in an angular component library we use internally at my company.

You can then ensure that only one instance of angular is loaded from your main module by adding an alias for angular to your webpack config:

// webpack.config.js
import path from 'path';
// ...

export default {
  resolve: {
    alias: {
      'angular': path.resolve(path.join(__dirname, 'node_modules', 'angular'))
     },
     //...
  },
  // ...
}

For reference, another possible way to handle this is to add angular to externals and load it onto the page separately through a <script> tag or a separate bundle. This solution is useful if you’re building your submodules independently as UMD libraries.

Is there any solution for this problem? I’m having the same problem.

+1

peerDependency works well in the case of Angular, because it’s also a dependency of my main package. But I also have some dependencies shared by my sub-modules that aren’t dependencies of my main application and I find it quite ugly to “move up” all the dependencies of my modules just because I have no other way to share them properly. Ex:

  • Main application
    • Sub-module 1
      • angular-infinite-scroll
    • Sub-module 2
      • angular-infinite-scroll

Here with Webpack, angular-infinite-scroll will be executed two times in my bundle, even with the Dedupe plugin (it will just prevent the source from being duplicated but it’s still called multiple times). I don’t think this is a good pattern to move angular-infinite-scroll (or any other fancy dependency needed by only one or two sub-modules) to my main application since it doesn’t need it at all. And setting it as a peer dependency of my sub-modules means anyone that will want to use them will be obliged to depend on these modules.

I thought npm dedupe could be the solution to my problem but since I’m working with npm link-ed modules I’m still stucked… https://github.com/npm/npm/issues/7742

Anyone else faced this problem before ? 😃

+1

The same module should be loaded only once…

I’m using Webpack 4.x. In my case, I had the same modules loaded multiple times, esp. React and lodash, which caused me a lot of troubles.

For some reason, I had several named entries in Webpack config, and some of them must be added to the same page. They do point to the same React in bundled in a cacheGroup, but it’s loaded multiple times.

Eventually, I’ve solved this by adding optimization.runtimeChunk: 'single', which creates an extra runtime.js.

Back to my issue, I realize that there’re multiple Webpack runtimes (webpackJsonp handling logics) in different named entries, each of them will try to install the modules in cacheGroups but they don’t communicate with each others, which leads to duplicated loadings. By merging the runtimes into the single one, it will always know which modules have been installed and which not, so that duplicated loadings can be avoided.

Hope my discovery helps.

I had a similar problem importing a lib from other project. When i did ‘import XXX from xxx’ in my project, my xxx reference was different than xxx reference in lib because webpack import twice the same file but assign it different IDs.

May be this plugin can help you.

https://bitbucket.org/snippets/joaquinfq/KB9Ag

Add it to webpack plugins instead of DedupePlugin:

    plugins : [
        new (require('dedupe-by-ref-plugin/DedupeByRefPlugin'))()
    ],

I have the same problem. A close-like setup is presented in this repo, I created to illustrate the problem.

https://github.com/ru-web-designer/lerna-webpack-typescript

The story below is a simplification of what really happend in my real repo. Ehem…

There is a monorepo with two private local packages, boopler and woopler.

boopler is depending on woopler, both of them have import * as $ from "jquery". boopler binds DOMReady event with it, woopler makes some DOM manipulations. Their deps are perfectly symlinked with Lerna.

Finally, there is index.ts in the root of the repo, which have import "boopler". It is an entry point for Webpack bundle.

The thing is in that both boopler and woopler packages has same jquery dependency version. However, it’s included twice in the output main.js file. And this is sad. I know, that is how resolving works but still. This is sad.

You can check it out by browse main.js file, outputted by Webpack.

Possible workarounds listed here, i am up to test them, but still they’re looks clumsy.