0

I am attempting to find a good way to use local modules in npm, or a way of structuring a large application so it can be bundled off into modules which may or may not be in a separate repository.

Each local module has it's own package.json and dependencies which are installed.

My requirements are that the modules are written in ES6 and only compiled as part of the main project being built (so I don't have lots of dependencies being indiependently built constantly).

Project structure

/root
  /main-module 
    ... main js files <- entry point
    webpack.config.js
    package.json
  /module-1
    ... module 1 js files
    package.json
  /module-2
    ... module 2 js files
    package.json
  /module-3
    ... module 3 js files
    package.json

I'm currently investigating using local modules via specifying a local file in my package.json like so:

...
"dependencies": {
  "lodash": "^4.17.10",
  "module-1": "../module-1",
  "module-2": "../module-2",
  "module-3": "../module-3",
  "normalize.css": "^8.0.0"
}
...

You can see the whole project here: https://github.com/SamStonehouse/webpack-local-modules-test

I'm using webpack with the babel-loader which doesn't need any extra setup in order to use this form and even watches the module file for changes and rebuilds when they're complete which is amazing.

Issue: once this has built lodash is included in the built bundle 4 times over, one for each module which requires it, even though they all require the same version and all the sources are compiled at the same time.

  • I've tried using the splitChunkPlugin but to no avail
  • I've tried setting lodash as a devDependency in the local modules (this was something I didn't want to do but it didn't work anyway)

Does anyone have a solution for this?

Or an alternative way of bundling local modules in a similar fashion

Sam
  • 2,771
  • 2
  • 28
  • 41

1 Answers1

0

Change each of the modules to have lodash as a peer dependency instead of a direct dependency. So in the package.json file, change this:

  "dependencies": {
    "lodash": "^4.17.5"
  }

To:

  "peerDependencies": {
    "lodash": "^4.17.5"
  }
Cymen
  • 14,079
  • 4
  • 52
  • 72
  • Would this stop the module working locally? For example, for running tests as part of the module it would still need to reference lodash as it's own dependency, rather than a peer dependency? – Sam May 03 '18 at 21:20
  • I linked to an nodejs blog post with more details. It should be fine. You might have to install the peer dependency manually (ie if using npm > v2). See the bottom of the blog post in the UPDATE part: https://nodejs.org/en/blog/npm/peer-dependencies/ – Cymen May 03 '18 at 21:21
  • It seems to not work, I've changed them to peer dependencies. Upon first trying it still bundled lodash 4 times. After removing all node_modules folders and running npm install again no node_modules are installed (which may be what I want). I get the following error: Module not found: Error: Can't resolve 'lodash' in 'C:\code\local-module-test\module-1'. It seems it's still trying to load them as dependencies – Sam May 03 '18 at 21:26
  • In the parent project, you'll need to install peer dependencies. When you do an npm install in the parent, do you not get a warning? – Cymen May 03 '18 at 21:27
  • I do, but Ideally I don't want that, because I'm not guarentteed to be using the modules required by the other local modules in my main repo, it just so happens that I am in the example. – Sam May 03 '18 at 21:29
  • Oh, but you do want that. You most definitely do. You want separate modules that you are going to package and publish via say npm or some internal thing to be loose on their peer dependencies and the main project should satisfy those peer dependencies. The end of that nodejs.org blog post goes into more detail on those the version requirements for peer dependencies should be as loose as possible. It should be clear why you would want that! – Cymen May 03 '18 at 21:31
  • What you want to go look at is how to publish an npm module. It might have something to do with those modules not being built. I'm not sure. Hopefully, someone will come along and give the answer that solves it. But you should fully understand peer dependencies and why the consumer of the module should satisfy the dependency rather than the module. – Cymen May 03 '18 at 21:32
  • But the modules are also their own separate entities, which may have entry points of their own. Therefore peer dependencies won't work. Edit: I do understand the purpose of peer dependencies and why they would be the right solution in a very similar problem – Sam May 03 '18 at 21:33
  • Oh, I reread your post. Yeah, this is just not how modules work. A local module is easy -- it's just a file and you export it and then you import it. The root of what you want is something like maybe page splitting? Not sure... But I think you'll need to go up a bit in what you're trying to accomplish to get a good answer. – Cymen May 03 '18 at 21:35
  • My goal is to allow easy transition from local module inside a project to external module hosted by npm. Once a module is mature enough to be it's own entity then it will be put on npm and the main package.json requirement will be changed from "module-1": "../module-1", to "module-1: "^0.0.1", for example. – Sam May 03 '18 at 21:41
  • @Sam Right, so take a look at how other people do npm modules. Say you're making a react datepicker. You wouldn't want to include react as a dependency in your datepicker because it would balloon up the size and force all the consumers to use a specific version. Instead, you set a loose as possible peer dependency to react. I would try looking at a few existing modules to see how it's done. Also, most publish an ES5 build of the module as node_modules usually isn't compiled or is excluded from webpack. But now there are ways to do both ES5 and ES6. It gets confusing. – Cymen May 04 '18 at 00:40