Importing a file local to an npm module - node.js

I have a node module named redux-loop that I'm using, and I would like to modify one of its functions slightly.
It's not a very complicated file, so I've made a copy of it in my react-native app and made my changes. The original code requires a few exports from files inside the module, eg:
var { loop, isLoop, getEffect, getModel } = require('./loop');
var { batch, none } = require('./effects');
The problem is that my copy of this file cannot seem to get direct access to those files, so I can't import those symbols.
I've tried various combinations of things, such as:
var { loop, isLoop, getEffect, getModel } = require('redux-loop/loop');
var { batch, none } = require('redux-loop/effects');
…which conceptually would mean to me to require the loop.js file inside the redux-loop module, but apparently module loading doesn't work that way.
What's the best way for me to import theses symbols into this file?

If I understand your question and you're open to reapplying your changes to the source of the package, you could use npm edit <pkg> and modify the package directly. When your changes are done the package will be rebuilt with your modifications.

Related

How to build multiple npm packages for sharing?

I'm trying to create a mono repository to host multiple small packages that I plan to deploy on npm. I use Rollup for the bundling part.
After many hours watching what others do, searching on the internet and experimenting, I've reached a point where I'm stuck and little push in the right direction would be very much appreciated.
I've created a minimalist demo project that I've hosted on GitHub so it's easy to experiment with. You can find it here:
https://github.com/Stnaire/my-lib
In the repository you'll find 3 packages in the packages directory:
config: contains a SharedConfiguration service
container: a wrapper around Inversify to have a statically accessible container with helper methods
storage: a package containing a StorageService (normally for writing in the local storage, cookies, etc) and a VarHolder helper which is just a memory storage.
In each package there is a package.json (defining the npm package parameters) and a tsconfig.json for the build.
What I'm trying to do is the have a npm package for each of the packages, each allowing for the following types of usages:
With a bundler in a TypeScript environment
import { SharedConfiguration } from '#my-lib/config';
// or ideally:
import { SharedConfiguration } from '#my-lib/config/shared-configuration';
// this way only this dependency is included, not the whole `config` pacakge
With a bundler in a JavaScript environment
var SharedConfiguration = require('#my-lib/config');
// Or like above, ideally:
var SharedConfiguration = require('#my-lib/config/shared-configuration');
By including the output JS file in the browser
<script src="my-lib-config.umd.js"></script>
<script>
MyLibConfig.SharedConfiguration.get(...);
</script>
What I tried
I've created two branches in the demo repository, corresponding to two strategies.
First strategy: create aliases (branch detailed-modules-resolution)
In the tsconfig.json, I do:
{
"paths": {
"#my-lib/config/*": ["packages/config/src/*"],
"#my-lib/container/*": ["packages/container/src/*"],
"#my-lib/storage/*": ["packages/storage/src/*"]
}
}
This way I can import precisely what I need:
import { SharedConfiguration } from '#my-lib/config/shared-configuration';
And because the aliases also correspond to the folder structure in node_modules, it should work for the end user with a bundler as well.
But this way I get warnings when building as UMD:
No name was provided for external module '#my-lib/config/shared-configuration' in output.globals – guessing 'sharedConfiguration'
No name was provided for external module '#my-lib/container/container' in output.globals – guessing 'container'
Creating a global alias for each import is out of question, thus the second strategy.
Second strategy: centralize all public exports (branch centralized-imports)
So the idea is simply to export everthing the package wants to expose to other packages in the index.ts:
// packages/config/index.ts
export * from './shared-configuration';
Then in the build script, I do this:
// scripts/build/builds.js
/**
* Define the mapping of externals.
*/
export const Globals = {
'inversify': 'Inversify'
};
for (const build of Object.keys(Builds)) {
Globals[`#my-lib/${Builds[build].package}`] = Builds[build].moduleName;
}
Wihch creates the following object:
{
'inversify': 'Inversify',
'#my-lib/config': 'MyLibConfig',
'#my-lib/container': 'MyLibContainer',
'#my-lib/storage': 'MyLibStorage',
}
This way umd builds are working.
But there is two main drawbacks:
You have very little control on what you import. You import a whole package or nothing. And if the package depends on other packages you can quickly import thousands of lines for a little service.
This creates circular dependencies, as in my example project.
SharedConfiguration uses VarHolder which is in the #my-lib/storage. But this package also contain a StorageService which uses SharedConfiguration, creating a circular dependency
because all the imports are based on the index.ts: #my-lib/config => #my-lib/storage => #my-lib/config.
I thought about using one strategy or the other depending if I build in umd or not, but it feels wrong.
It must be simplier way to handle all of this.
Thank you very much for reading all this.

Is it possible to import a function in a modules subfolder

I'm trying to access the decode() method in the jsQR module.
I found an example that called decode() directly but that was from an HTML file, not nodejs.
In visual code I see this...
I know that the default export is defined in index.d.ts but is there anyway of importing the other classes/functions on the rest of the dist folder?
I've tried to import using require("jsqr/decoder") and require("jsqr/decoder/decode") to no avail.
EDIT
To be clear, I don't want jsQR, the default export. That deals with images. I'm trying to explicitly call the decode() method in the pic which accepts a BitMatrix
There are no limitations in what you can require from node_modules. So, with your case it should look like:
TypeScript\ESM Modules:
import { decode } from 'jsqr/dist/decoder/decoder';
CommonJS:
const { decode } = require('jsqr/dist/decoder/decoder');
UPD: If you take a look into dist folder for jsqr package, you can find that there are only d.ts files. Which means that you can not import it from there.
But, you can find an actual export of the module here:
Which means that you should able to import it from jsqr:
const { decode } = require('jsqr');

How to use multiple compiled ts files in a node module?

Currently I am trying to use TypeScript to create JavaScript-Files which are then required in a index.js file. I am using VS 2015 Update 3 with node.js tools 1.2 RC. Sadly it is not working like I thought it would.
To begin with here is my initial idea:
I have a node module (to be precise, it is a deployd module http://docs.deployd.com/docs/using-modules/). This module is handling payment providers like paypal or stripe. Now I want to use TypeScript to write interfaces, classes and use types to make it easier to add new payment providers. The old .js files should still be there and used. I want to migrate step by step and use the self-written and compiled .js files together. So I thought I can create .ts files, write my code, save, let VS compile to js and require the compiled js file in another js file. Okay, that is my idea... Now the problem
I have a PaymentProvider.ts file which looks like this
import IPaymentProvider = require("./IPaymentProvider.ts"); // Interface, can't be realized in JavaScript, just TypeScript
export abstract class PaymentProvider implements IPaymentProvider.IPaymentProvider
{
providerName: string;
productInternalId: number;
constructor(providerName : string)
{
this.providerName = providerName;
}
//... some methods
};
The other file is PaypalPaymentProvider.ts
import PaymentProvider = require("./PaymentProvider.ts");
export class PaypalPaymentProvider extends PaymentProvider.PaymentProvider
{
constructor()
{
super("paypal");
}
// more methods
}
VS 2015 doesn't show any errors. The js and .js.map files are generated. Now I thought I could require the files and that's it. I tried to use the PaypalPaymentProvider.js like this const PaypalPaymentProvider = require("./lib/payment-provider/PaypalPaymentProvider.js"); (yes, it is located there) but it's not working. When starting the index.js via node I get the following error:
...\Path\PaymentProvider.ts:1 (function (exports, require, module, __filename, __dirname) { import IPaymentProvider = require("./IPaymentProvider.ts"); Unexpected token import....
I find it strange that this is the error, because JavaScript doesnt't have Interfaces. The compiled IPaymentProvider.js is empty.
Also I thought that TypeScript is mainly for development and the compiled JavaScript for production. So why it is requiring a ts-file? I thought imports in typescript will be converted to require of the compiled js-file?
Do I need to require all compiled js files and not only the one I currently try to use? (I don't think so...)
To be honest, I think the main problem is that I am new to TypeScript and make something wrong from the very beginning.
Any help/advice? Thanks!
I have the solution... Thanks to Paelo's links I was able to see that I need to omit the file ending! So the really simple solution was to write
import IPaymentProvider = require("./IPaymentProvider");
instead of
import IPaymentProvider = require("./IPaymentProvider.ts");
When I changed that in every ts file it worked perfectly!

Requiring the same local node module from two directories results in two copies

I have a module (server.js) in the root of my project structure. It includes a module in a directory called lib:
var mongo = require('./lib/MongoUtils');
Another module in the lib directory also needs the 'MongoUtils' module, so it does:
var mongo = require('./MongoUtils');
The problem is I end up with two copies of the object (which is bad as it has some system resources like DB connections, etc.).
I've read the Node.js caching caveats documentation (http://nodejs.org/api/modules.html#modules_module_caching_caveats) and so it seems the problem is that I'm referring to the same module with two different paths and thus Node.js gives me two copies. Is this understanding correct?
How can I work around this? I didn't want to just dump my modules in node_modules since that's managed by npm via my package.json (and .gitignore-d). I thought about putting my local modules in the package.json (assuming that's possible), but then I'd need to be running 'npm install' whenever I make a change.
If this can't be done cleanly, I'll simply load the module in one place and pass it around, but that doesn't sound scalable if this occurs with lots of my modules.
I solved it. It turns out I typoed the capitalization of one of my modules. Node.js happily loaded the module and it worked fine, the only side effect was that I got the module loaded twice.
Here's an example. Note the capital B in the require statement in lib1.js.
main.js:
var lib1 = require('./lib/lib1')
, lib2 = require('./lib/lib2');
lib/lib1.js:
var lib2 = require('./liB2');
lib/lib2.js:
function MyClass() {
console.log('Constructor called');
}
module.exports = new MyClass();
If you run "node main.js" you'll get the following output:
Constructor called
Constructor called
If you fix the capital B in lib1.js and run it again, you'll see:
Constructor called

Nodejs importing multiple classes with modules.export from multiple source files

I have a directory with multiple js source files that is imported on client side webpage. I am also needing to import all of those sources files into server side node js app.
I have used the following approach so far
if( 'undefined' != typeof global ) {
module.exports = global.Class= Class;
}
The code is appended to the end of the source file
However I need to avoid editing the source files. Is there a good approach of how to import all of the classes contained the source folders? Instead of just running through the source files and having a modules.exports for each class? Also is there a way to give a directory to the require() call and have it import all the contained source files?
By exporting the objects into the global namespace you are kind of going against best standards in Javascript. The point in the module.exports is so that you can use requireJS to import the object that you need, rather than have every object available to you. So I'm afraid the answer is no, the require call only accepts single module references (due to the return value of the function assigning the object to a variable).
The 'good' approach would be to include a single file on the client that holds your main cilent code that references the modules/objects it needs to continue working. The source files will then be included as and when they are needed.
If you could modify the client side files, you could use this pattern: http://caolanmcmahon.com/posts/writing_for_node_and_the_browser/
file: tool.js
(function(exports) {
exports.Hello = function(name) {
console.log('Hello %s', name);
}
})(exports || window);
file index.js
require('./tool').Hello('username');

Resources