Self-published NPM package not importing anything when added - node.js

I published a very simple NPM package with the following:
module.exports = { foo: "baz" };
When webpacked, it looks like the line below, and this file is referenced as the main property in package.json.
(()=>{var r={579:r=>{r.exports={foo:"baz"}}},o={};!function t(e){if(o[e])return o[e].exports;var p=o[e]={exports:{}};return r[e](p,p.exports,t),p.exports}(579)})();
Now, in a separate project when I install the package and try to import it, I get nothing:
const obj = require('mypackage')
console.log(obj)
// => {}
import obj from 'mypackage'
console.log(obj)
// => {}
What is missing here? How do I get this exported object to come through to the installed NPM package?

Rather than messing with webpack config, my solution was indeed to use Microbundle as suggested by Derek in the comments.
It worked immediately, so the "answer" is that there was something wrong with the webpack config, though I don't know what it was.

Related

How to deal with node modules in the browser?

My title is a bit vague, here is what I'm trying to do:
I have a typescript npm package
I want it to be useable on both node and browser.
I'm building it using a simple tsc command (no bundling), in order to get proper typings
My module has 1 entry point, an index.ts file, which exposes (re-exports) everything.
Some functions in this module are meant to be used on node-only, so there are node imports in some files, like:
import { fileURLToPath } from 'url'
import { readFile } from 'fs/promises'
import { resolve } from 'path'
// ...
I would like to find a way to:
Not trip-up bundlers with this
Not force users of this package to add "hacks" to their bundler config, like mentioned here: Node cannot find module "fs" when using webpack
Throw sensible Errors in case they are trying to use node-only features
Use proper typings inside my module, utilizing #types/node in my code
My main problem is, that no matter what, I have to import or require the node-only modules, which breaks requirement 1 (trips up bundlers, or forces the user to add some polyfill).
The only way I found that's working, is what isomorphic packages use, which is to have 2 different entry points, and mark it in my package.json like so:
{
// The entry point for node modules
"main": "lib/index.node.js",
// The entry point for bundlers
"browser": "lib/index.browser.js",
// Common typings
"typings": "lib/index.browser.d.ts"
}
This is however very impractical, and forces me to do a lots of repetition, as I don't have 2 different versions of the package, just some code that should throw in the browser when used.
Is there a way to make something like this work?
// create safe-fs.ts locally and use it instead of the real "fs" module
import * as fs from 'fs'
function createModuleProxy(moduleName: string): any {
return new Proxy(
{},
{
get(target, property) {
return () => {
throw new Error(`Function "${String(property)}" from module "${moduleName}" should only be used on node.js`)
}
},
},
)
}
const isNode = typeof window === undefined && typeof process === 'object'
const safeFs: typeof fs = isNode ? fs : createModuleProxy('fs')
export default safeFs
As it stands, this trips up bundlers, as I'm still importing fs.

Importing from lower level of node package

I have a node package (lets call it my-package) that currently looks like the following
src/
index.js
generators/
generate-stuff.js
index.js looks like the following
module.exports={
"some": {
"json": "objects",
...
},
"other": {
"json": "things",
...
}
};
Now I can import this file very easily in other packages by doing the following
const myPackage = require('my-package');
And myPackage will have the contents of that JSON you see above
However what I really want to import is a function that exists in generate-stuff.js (The structure of this package is inherited and I cannot easily change it)
That file looks like the following
module.exports = { functionIWantToExport(input1, input2){
return {
// do stuff with said inputs
};
}
}
However when I do something like
const functionIWant = require('my-package/generators/generate-stuff');
I get the following failure.
Cannot find module 'my-package/generators/generate-stuff'
Is there any way I can pull out the function I need from this package?
I can see in my node_modules that the module.exports is on the file I need
So was able to figure out the source of my problem. And it has do with the main in package.json
In my package.json there is the following
"main": "src/index.js"
So that's why just doing require('my-package'); works. But if I want to use the relative path it's still from above the src folder, so what I really need is
const functionIWant = require('my-package/src/generators/generate-stuff');
Doing this resolved my issue

Nodejs - Create modules from string with the npm package 'module'

I want to load a custom module using the npm package 'module', to be able to require it like any other local folder that exports something.
I cannot find any documentation on the use of the package https://www.npmjs.com/package/module
I tried to use it without any documentation on it, but i simply cannot as i dont understand how you use it.
let myFunction = module.wrap(`module.exports = () => console.log("hej")`);```
Honestly, I've never read documentation about this but I've been using Node.js for years so I'll explain how I import modules. Given a project that has the files app.js and mod1.js and the subfolder utils with the file mod2.js, you could do something like this:
prj/mod1.js
module.exports = {
test: "testing"
}
prj/utils/mod2.js
module.exports = () => {
console.log("testing");
}
prj/app.js
var mod1 = require("mod1"),
mod2 = require("utils/mod2");
console.log(mod1.test);
mod2();
I think you are trying to create a module of your own to be able to use it at multiple places within your project ( correct me if I am wrong).
SO you can do that like :
In utils/custom.js
module.exports = {
logThis: "Hi"
}
OR
var a={
logThis:function (){
console.log('HI')
}
module.exports=a;
And then in the file where you want to access this :
In app.js
let custom=require('./utils/custom.js')

RequireJS Dependancies Fail Randomly: "Module has not been loaded yet for context", Puzzling

I've run into a problem with RequireJS that pops up randomly in different areas over and over, after a long period (about a year) of working fine.
I declare my requireJS file like this:
define(['TestController'], function (TestController)
{
return {
oneFunction: function(callback)
{
//When I try to use "TestController" here, I get the
//"Error: Module name "TestController" has not been
//loaded yet for context" error...
TestController.test(); //ERROR
//I had been using the above for years, without changes,
//and it worked great. then out of the blue started not
// working. Ok, let's try something else:
if(typeof TestController == "undefined")
{
var TestController = require('TestController'); //ERROR
}
//The above method worked for a few months, then broke AGAIN
// out of the blue, with the same error. My last resort is one
// that always works, however it makes my code have about 20+
//layers of callbacks:
require(['TestController'], function(TestController){
TestController.test();
//WORKS, but what's the point of declaring it as a
//requirement at the top if it doesn't work and I have to
//wrap my code every time? :(
});
},
anotherFunction: function()
{
console.log("hello");
}
}
});
I am getting the "Error: Module name "TestController" has not been loaded yet for context" error over and over until I re-declare the dependency... My question is, what's the point of declaring 'TestController' at the top as a dependency if I have to keep re-declaring it as if I never listed it? What am I doing wrong here?
I declare 'TestController' in other files and it works great, but every once and a while, ONE of the declarations will fail...and it's always a different file (there are about 200-300)... I never know which one, and the only way to fix it is to re-declare it and wrap it.
Anyone see anything I'm doing wrong that could be causing this? I keep updating RequireJS to see if it fixes it and it doesn't :/
Version
RequireJS 2.1.22
jquery-1.12.1
node 4.2.6
As #Louis pointed out, it was circular dependencies that was causing the problem.
Circular Dependency Solution #1: 'exports'
Here's the solution straight from RequireJS's documentation:
If you define a circular dependency ("a" needs "b" and "b" needs "a"), then in this case when "b"'s module function is called, it will get an undefined value for "a". "b" can fetch "a" later after modules have been defined by using the require() method (be sure to specify require as a dependency so the right context is used to look up "a"):
//Inside b.js:
define(["require", "a"],
function(require, a) {
//"a" in this case will be null if "a" also asked for "b",
//a circular dependency.
return function(title) {
return require("a").doSomething();
}
}
);
If you are familiar with CommonJS modules, you could instead use exports to create an empty object for the module that is available immediately for reference by other modules.
//Inside b.js:
define(function(require, exports, module) {
//If "a" has used exports, then we have a real
//object reference here. However, we cannot use
//any of "a"'s properties until after "b" returns a value.
var a = require("a");
exports.foo = function () {
return a.bar();
};
});
Circular Dependency Solution #2: Visualize with madge
I came accross this npm module that will create a dependency graph for you : https://github.com/pahen/madge
I've decided to analyze my code with madge and remove the circular dependencies.
Here is how I used the tool:
cd <Client-Code-Location>
madge --image dep.png .
This gave me an image of the dependencies, however there were no circular dependencies found. So I decided to try another way:
cd <Client-Code-Location>
madge --image dep.png --format amd .
This way I was able to see where I had the circular dependency. :)

Importing Node modules in TypeScript

How can I import Node modules which reside in the node_modules folder in TypeScript?
I get an error message (The name ''async'' does not exist in the current scope) when I try to compile the following piece of TypeScript code:
// Converted from: var async = require('async');
import async = module('async');
You need to create a definition file and include this:
module "async" {}
then add a reference to this definition file in your TypeScript code
///<reference path='definition-file.d.ts' />
import async = module('async');
The standard "import blah = require('x')" semantics in typescript flat out don't work with node modules.
The easiest way to work around this is to define and interface and use require explicitly, rather than import:
// You can put this in an external blah.d file if you like;
// remember, interfaces do not emit any code when compiled.
interface qOrm {
blah:any;
}
declare var require:any;
var qOrm:qOrm = require("../node_modules/q-orm/lib/q-orm");
var x = qOrm.blah;
npm install --save-dev #types/async
npm install --save async
And the syntax:
import * as async from "async"

Resources