Reusing my own JavaScript modules without using relative paths - javascript

I am new to JavaScript development and could do with some advice regarding how best to work with multiple modules of my own creation.
Module1
--src
----a.js
----b.js
Module2
--src
----c.js
----d.js
Module3
--src
----e.js
----f.js
Module4
--src
----g.js
----h.js
Now each module is a collection of js files that use module.exports to export functions that they need to.
In this example Module1 and Module2 are library module. Module2 depends on Module1. Both of these modules are platform agnostic and can be ran inside a browser or nodejs.
Module3 is a project module which depends on both Module2 and Module1. It is designed for a browser and uses browserify to combine them all into a bundle.
Module4 is another project module which also depends on Module2 and Module1. This is designed to run under nodejs.
Each module has its own git repo.
Now the problem I am having is to do with relative paths inside the require. For example c.js currently does require("../../Module1/src/a.js"); Similarly h.js does require("../../Module2/src/c.js");
This causes foldering structure to be an absolute pain and each project has to be cloned from git in the correct setup.
The following is what I am trying to achieve.
To do away with relative paths so I simply do require ("ModuleX/src/foo.js"); This needs to work with both browserify and nodejs.
To clone a project module from git and have it get all of its dependent modules (perhaps git submodules?). Not caring about folder structure as this should be solved using the point mentioned above.
Once a project and it's dependent modules have been cloned to be able to edit each of these modules, make changes and push them to their individual git repo.
I imagine what I am trying to do is pretty standard. Creating my own modules and reusing them in different projects. Am I trying to go about solving it in the standard way? I've read that there are different ways to achieve this using NODE_PATH which is supported by both node and browserify but both discourage it. Browserify supports a paths option but doesn't work for node. Also read about putting the modules inside node_modules but not sure how that would help with relative paths.
Any advice would be greatly appreciated
Thanks

What you probably want to do is commit your reusable code to git (here GitHub) and then npm install <git remote url>:. An example would be npm install git+https://isaacs#github.com/npm/npm.git. On the other hand your repo needs a package.json and a index.js holding your code or pointing to it. Alternatively you could define the location of your main file in the package.json via main:"" key.
The dependencies between those projects would be defined in the respective package.jsons. Upon install npm does it's magic to avoid circular dependencies, caching etc.
Once you've done all that you would be able to just var x = require("ModuleX") to get ModuleX/src/foo.js if you so wish to.
Alternatively use npms private modules.

Related

Allowing deep imports from npm packages without a build directory (like lib/dist) in the path

The standard approach when packaging code for npm is to place transpiled or bundled code in a separate lib, dist or build directory and to set the package.main property (and module/browser) to point to the built files, which makes the existence of the build directory transparent when doing bare imports (without a path). However, if deep imports are needed (importing specific modules not referenced in package.json properties), it means that the build directory needs to be included in the path like so: require('package/lib/some-module'), which looks bad.
Are there any examples of an approach that would at the same time:
Support deep imports without the build directory in the path
Support npm-link and tools like Lerna
Still place the built files in a separate directory for tidiness
Every approach I've tried or seen fails to fit one of the criteria; for example, copying package.json into the build directory (lib/dist) allows publishing or linking the package from the build directory, but tools like Lerna don't support this approach since they expect the package.json to be in the root of the package instead of the build directory, so only points 1 and 3 are met.
Placing sources in the root of the package and the transpiled or built files next to the sources allows deep imports and is also supported by Lerna, but it doesn't meed the 3rd criteria (tidiness).
Having import maps would solve this issue, but I'm not sure if any tool supports import maps yet.
The question is: is there some approach that I've missed that could meet all three listed points?

Mixing browserify and webpack externals

we are in the process of uplifting parts of a huge code base. We are bringing in a module which has been built with webpack. In order to avoid code duplication we have used webpacks externals option.
When we start to integrate our module into the main codebase which is currently using browserify, we have an issue where a shared dependency is included twice and causes issues.
Is there are a way to have webpack use the packaged version of the dependency? So in the final browserified bundle we just have the dependency included once?
It seems to me like this may not be possible, if so I will push for moving the rest of our codebase onto webpack (it is underway already).
The only solution I have come up with so far is to have the webpack module also export the shared dependency, and then have the main app use that export, but this is not ideal.
I have ensured that the dependency in both node_modules folders are at the same version and I still get 2 instances.
I need to be able to tell Browserify to only resolve my apps node_modules, or tell it to resolve from top to bottom, i.e. look in the top level node_modules first, is this possible?
I have tried setting the NODE_PATH option when using the cli to no affect.
** update **
So the issue is that when Browserify hits the require() statement in the webpack bundle it resolves from the local node_modules folder, so we end up with 2 instances of the dependency. I can fix this by using a relative path in either the apps require() or webpacks external option and ensuring they use the same file.
So it seems the issue was caused by the fact that I had symlinked (with npm link), the module as I was working on this also. It seems that when Browserify resolves the require in the symlinked module it resolves to its own node_modules, and we end up with 2 copies.
When I install the module normally it all works fine, so this is OK as other consumers of the module should have no issues. It is annoying that it behaves this way, but I just need to ensure that I point at the same dependency in my main app when developing alongside the module.
So my require statement in the main app (while symlinking) looks something like this:
require('./node_modules/my-module/node_modules/shared-dependency/index.js');
I can require as normal when not symlinking.

Including node modules in HTML

I'm struggling to get my head around how npm manages dependencies - in terms of how they are actually referenced in HTML.
Say I have a specific version of a plugin installed, which includes a version number in its path or file name - if npm is configured to update to a new minor release - the files referenced via script tags will no longer be present.
I've also read that exposing node_modules path is incorrect and should be avoided.
How then should these files be referenced so that they are loaded and so version updates do not break a site?
The idea is that you use these modules in your code. Let's say you have a main.js file which has your application, then you import modules using import $ from 'jquery'; (this could depend on your configuration, you could also use 'require'). Then use a tool like browserify which is going resolve all your dependencies for you and package it into a nice file which can then be loaded into your browser.
This is only one setup out of many so this could vary, for example if you use webpack this will be different but the idea is the same, you import what you need into your main.js.
npm uses package.json file as reference to build dependency map. And installs all dependencies in node_modules folder. When you publish an update to your module, you also publish a new version of package.json file which will include modifications to dependencies.
So short answer is - package.json file... I hope you can figure things out from this.

Change NPM entry point without an index.js

I recently published a private module to NPM which has some common code we use across a few of our services.
The code is written in ES6 and so we need to transpile it using babel before publishing to NPM. I've got a prepublish script which transpiles src in to lib.
There's no index.js file in this module since it's just some common code.
The problem I'm having is that when I install the module from NPM, using require('#ourorg/ourmodule/somecode') doesn't work (module can't be found). I instead have to use require('#ourorg/ourmodule/lib/somecode').
I've tried changing the main field in package.json to many variations of lib, but it doesn't seem to work unless I include an index.js file, in which case require('#ourorg/ourmodule') returns whatever is exported there. One workaround I can see would be to export all the common code in an index.js file, but this isn't maintainable at all.
The main field in package.json follows the same rules as normal Node imports - either it should point at a single file in particular, or it can point at a directory that has an index.js in it.
As far as I know, there is no way to make importing your package simply be an alias for a directory. If there was, what would require("#ourorg/ourmodule") return?
If it's absolutely driving you crazy having to type lib every time you import something, maybe you could add a step to your build process that autogenerates an index.js that re-exports everything at the root?

Use local version of node.js package

I'm digging into a node package that uses a CLI, and am trying to extend it by adding some functionality. I've cloned the repo from github, but I've also installed it via npm.
How can I use my local version, instead of the one that's been installed via npm?
Thanks!
When you install a package using npm, it just puts it into the node_modules folder in the folder where you ran it (or if you pass -g, into a global node_modules folder).
require() uses a particular search order to find modules. To get a specific version of a module to load you can take two paths:
Specify a relative path to the module: require("./path/to/myfork/of/module")
Delete the version of the module installed by npm into mode_modules and put your fork of it in there
Make sure that your fork of that module is in a "closer" node_modules folder. Node searches the node_modules in same folder as the file calling require() and then works its way up the folder hierarchy to find a module.
For more information, take a look at http://nodejs.org/docs/v0.4.11/api/modules.html

Categories