Earlier today I tweeted:
I want to use node modules in my existing requirejs browser app. What’s the right path?
This was really understating the problem I'm trying to solve. I need a way to share modules across various JS (browser) applications. Some of these applications are RequireJS apps, and changing them away from that is probably not on the table. Others are newer applications where we have a choice when it comes to the build system -- common choices of late seem to be browserify and webpack.
I want to be able to maintain a set of modules separate from these projects that can be used by these projects. The requirements, then, are:
- Modules must be usable by a CommonJS-based module/build system, such as Browserify or Webpack.
- Modules must be usable by an AMD-based module/build system, such as RequireJS.
- Modules must be installable, update-able, and version-able; that is, the modules should be not need to be modified in any way by the host application.
- Modules must be able to share dependences; that is, if two modules require the same version of lodash, then an application that requires them should not end up with two lodashes in its build.
- We can make modifications to the RequireJS apps short of completely changing the module/build system.
- Modules should work just fine for Node apps, too, where appropriate.
Assuming you control the authoring of these shared modules, use a UMD wrapping in the module source to allow cross use between CJS and AMD.
The next piece is choosing a package manager. For your last point, that likely means publishing to npm. If choosing npm to consume the modules in the front end app, then be wary of nested dependencies, which could lead to your "duplicate code" issue. Hope that
npm dedupe
does something for you. Your mileage may vary.When using npm, then the main issue, if the modules are in UMD wrappers in source form, is configuring the requirejs loader to know how to resolve the IDs.
The requirejs loader's nodeIdCompat option might also be useful, but I would encourage just not referencing dependencies by using ".js" in the file names, it muddies the difference between module IDs and paths. The nodeIdCompat can help though if you do not control some of the dependency strings in the modules you are consuming.