Node.js Dependencies as Singletons - node.js

I am trying to create my own npm package my-package that relies on a dependency dependency-a and is used in some project cool-project that relies on both my-package and dependency-a.
cool-project
- dependency-a
- my-package
- dependency-a
dependency-a:
export const someVar = 0;
my-package:
import depA from 'dependency-a'
const someFun = () => {
depA.someVar = 1;
}
cool-project:
import depA from 'dependency-a';
import myPackage from 'my-package';
myPackage.someFun();
console.log(depA.someVar); // expected (desired) 1, actual 0
The above would work if myPackage was a module apart of cool-project, however since I want my-package to be a standalone npm module, when I try to link it in cool-project it seems to be relying on a separate version of dependency-a.
Is there a way to create an npm module that can modify a singleton of a third party library, and share that across two modules relying on it automagically. I am using babel/webpack to build my-package so if there is a way to do it through that, then that works for me too!
Side note: I know that I could do something like return depA from my-package--this is not workable for what I need to do. I'm trying to use a version of this example to create a connection middleware for a database.

Add dependency-a as a peer dependency in my-package's package.json file,
"peerDependencies": {
"dependency-a": "1.x"
}
Now, when installing my-package, dependency-a won't be installed automatically if there is another dependency-a (with same version you declared) installed in cool-project.

Related

Meteor as dependency in npm module? Error: Cannot find module 'meteor/mongo'

I have 2 meteor projects which share models. I'd like to consolidate the model schemas into an NPM private module.
My module contains this code:
import { Mongo } from 'meteor/mongo';
import { packageSchema } from './schema';
export const Packages = new Mongo.Collection('packages');
Packages.attachSchema(packageSchema);
export default Packages;
When I install this NPM module in my parent meteor project and start the server, I get the following error on the first line of this file:
Error: Cannot find module 'meteor/mongo'
What is the correct way to install/reference meteor in an NPM module? (It cannot be added as a standard NPM dependency.)
I was not able to find a way to include meteor in my NPM module. Instead, I put the code in an Atmosphere package and used the git subtree methods to include it in both projects. (This avoided known issues with submodules and symlinks.)

How do I use pouchdb with typescript?

I am trying to use pouchdb with Typescript. I cannot link to the pouchdb module.
import { PouchDB } from "pouchdb"
reports that it cannot find module pouchdb, even though it is in node_modules.
I also cannot find the appropriate typings for pouchdb.
I'm doing this in Ionic, so I may be missing a step on getting the types file loaded properly.
Make sure your types are installed with:
npm install --save-dev #types/pouchdb
At the top of your data service import pouch like so:
import * as PouchDB from 'pouchdb';
* edit *
I don't have all the facts, but this is my current understanding.
Typings is no longer needed in Typescript >2.0
I believe typescript now works automatically with types files installed from DefinitelyTyped.
DefinitelyTyped is an official central repository that is kept current like npm.
And even if I'm dead wrong about all this, DefinitelyTyped is still better than typings and has a much bigger community.
Cause i just had this Problem, For Angular 2 + Typescript the correct way to use PouchDB (using angular-cli) is to:
ng new SOMENAME
npm install --save pouchdb
npm install --save-dev #types/pouchdb
In your app.component import PouchDB from 'pouchdb';
In your App Component Class public db: any; and to init this.db = new PouchDB('test'); // , {storage:'persistent'} not working in typescript without updating typings
see https://github.com/nolanlawson/pouchdb-find/issues/201.
If you have problems installing the packages on windows with an EPERM Error use (f.e.) npm install --save pouchdb --no-optional to disable the warning. The installation should still be ok. For more info see https://github.com/npm/npm/issues/17671
I had the same problem trying to import into Angular 6.
Your imports seem fine:
import PouchDB from 'pouchdb';
import PouchFind from 'pouchdb-find';
PouchDB.plugin(PouchFind);
What you may be missing is you need to add this to your polyfills.ts file:
(window as any).global = window;
(window as any).process = {};
(window as any).process.nextTick = setTimeout;
import PouchDB from 'pouchdb';
export abstract class PouchDBDatabase {
private _database: PouchDB.Database<Sheet>;
constructor(protected DATABASE_URL: string) {
this._database = new PouchDB(this.DATABASE_URL);
}
}
And you're good to go with typescript + pouchDB :)
I managed to get the module recognised by using
declare function require(a)
var PouchDB = require("pouchdb")
I have given up type checking, but at least I can make progress.

What is the correct way of adding a dependency to react in your package.json for a react component

I have made a few simple reusable react components and wanted to know the correct way to include a dependency to react in my package.json for publishing with npm.
I am currently doing this:
Assuming my component will use the most recent version of react and I have tested and it works with that version. e.g. 0.13.3
"peerDependencies": {
"react": "^0.13.3"
},
For reusable components:
Put a react dependency in both peerDependencies and devDependencies.
Never put a react dependency in dependencies.
peerDependencies specifies which version(s) of React your reusable component supports/requires. When using npm 2 this also adds React to the list of modules to be installed, but this is no longer the case with npm 3.
devDependencies ensures React will be installed when you run npm install while developing your component, or when running tests on Travis or similar.
Putting react in dependencies will cause multiple versions of React to be installed if somebody uses your component but has a different version of React in their own package.json - having multiple versions of React not only bloats the build, but also causes errors when different versions try to interact.
The selected answer is definitely the prescribed approach here however I've started favoring the use of inversion of control as opposed to relying on npm peer dependencies for my libraries dependencies and its served me well.
Libraries are easier if you build them functional. It seems to be easier to maintain libraries that export a single function which takes in an object with all of their heavy dependencies and export an object containing each of your libraries typical exports.
Library 'injected'
lib/index.js
export default ({ React }) => {
const InjectedComponent = props => (
<p style={{color: props.color}}>This component has no React npm dependencies.</p>
)
/** other stuff */
return { InjectedComponent }
}
Consuming App
app.js
import React from 'react'
import { render } from 'react-dom'
/** Import the default export factory from our library */
import createInjectedComponent from 'injected'
/** Call the factory, passing its dependencies (guaranteed to match what we're bundling) and get back our component */
const { InjectedComponent } = createInjectedComponent({ React })
render(<InjectedComponent color="blue" />, document.getElementById('root'))
If your component only works with a given version of react or some other dependency, you can write some assertions around the version for the React parameter that is passed in. Overall, building libraries in this fashion should be less prone to new build issues appearing anytime version of React is published and will more importantly ensure that you are not causing your library consumers to bundle multiple versions of React and other heavy libraries. This pattern works well with npm link (I generally have 16+ libraries running from npm link simultaneous and experienced issues when I didn't use this pattern).
In your main app I would recommend always splitting out react, react dom and any react lib components you use into a vendor bundle (webpack) and mark it as external in your main bundle so that you do not unintentionally bundle two versions.
You can have react in either peerDependencies or in dependencies. The difference being that with a peerDependencies, react is only installed once for the package using your package. If you put it in dependencies, react will be installed twice, one time for the package using your package, and once time for your package.
React itself seems to favor peerDependencies for some reason. You obviously don't want two separate versions of react in your Javascript bundle (which happens by default if you use dependencies), but that is easy to fix with npm dedupe.
So there's no correct way to do it, both peerDependencies and dependencies work. Using dependencies is more in line with the node/NPM way, but using peerDependencies is friendlier to users of your package that doesn't know about npm dedupe and why it's needed.

Can I access locally-installed packages from a globally-installed package?

I don't know if I've worded the question properly, so I apologize if it isn't clear from the title what I mean.
Say I have an NPM package which installs an executable. Presumably I want users to install this package with the -g flag so that they can run it whenever.
In this case, when I call require() from within the executable, it will look for packages installed globally.
But suppose this package provides generic functionality for Node projects. I might want to know which packages the current project has installed locally. Should I just assume:
path.join(process.cwd(), 'node_modules')
Or is there a more "correct" way to set the NODE_PATH in this case? (Or rather than set NODE_PATH, should I just require(absolute_path_to_file)?)
require will not only lookup the package inside $(CWD)\node_modules but also inside all node_modules of parent, grandparent, etc. So you can use resolve on npm to solve this problem
FILE: your_global_command.js
// npm install resolve
var resolve = require('resolve').sync;
// Lookup for local module at current working dir
function require_cwd(name) {
var absolute_path = resolve(name, { basedir: process.cwd() });
return require(absolute_path);
}
// Load local express
// this will throw an error when express is not found as local module
var express = require_cwd('express');
I also create a package to require a package at current-working-dir (instead of __dirname of module):
https://npmjs.org/package/require-cwd

Determine NPM modules used from a running node.js application

Other than grabbing the package.json file at the project root is there a way to determine the list of dependencies of a running node.js application? Does node keep this meta information available as some var in the global namespace?
If you are just looking for the currently installed npm packages in the application directory, then you can install the npm package (npm install -g npm) and programatically invoke ls to list the installed packages and the dependency trees.
Obviously, this has no bearing on whether the installed packages are actually require'd in the application or not.
Usage is not that well documented but this should get you started.
var npm = require('npm');
npm.load(function(err, npm) {
npm.commands.ls([], true, function(err, data, lite) {
console.log(data); //or lite for simplified output
});
});
e.g.:
{ dependencies:
{ npm: { version: '1.1.18', dependencies: [Object] },
request: { version: '2.9.202' } } }
Otherwise, I believe the only other option is to introspect the module module to get information pertaining to the currently loaded/cached module paths. However this definitely does not look to have been developed as a public API. I'm not sure if there are any alternatives so would be keen to hear if there are e.g.
var req = require('request'); // require some module for demo purposes
var m = require('module');
// properties of m contain current loaded module info, e.g. m._cache
I believe you could use require-analyzer, which sort of works according to Isaacs(could miss some). You could hear this in Nodeup's first podcast from 11:55.
Or you could try James node-detective which probably will find your dependencies better(but not by running code), but because of Javascript dynamic nature(12:46).
detective
Find all calls to require() no matter how crazily nested using a
proper walk of the AST.
P.S: to expose those package.json variables to node.js you could use node-pkginfo

Resources