Newly made NPM package is found, but deeper import references are all unfound - node.js

This is my first go publishing an NPM package and I feel like a newb. My basic imports aren't working, both within the module itself and when trying to reference specific files within the package from outside. The whole npm publish -> npm install part works as expected.
The file structure is a ./lib directory, with a ./lib/data-types directory. The main files with the objects getting exported live in the lib, and some other "helper" files live in the data-types.
- index.js, etc
- /lib
-- connection.js
-- session.js
-- /data-types
--- point.js, etc
I have an index.js file that's just a passthrough for some other objects:
import Connection from "./lib/connection.js"
import Session from "./lib/session.js"
export default {
Connection,
Session,
}
And I've defined the main export and the data-types in package.json:
{
"name": "ef-vue-crust",
"type": "module",
"main": "index.js",
"exports": {
"." : "./index.js",
"./data-types/": "./lib/data-type/*.js"
},
...
}
The basic import from my application seems to work, i.e. import {Connection} from 'ef-vue-crust', except for the aforementioned inner disconnect. index.js is unable to find the following files:
import Connection from "./lib/connection.js"
import Session from "./lib/session.js"
Module not found: Error: Can't resolve './lib/session.js' in 'C:\Projects\my-app\node_modules\ef-vue-crust'
Directly importing a file from the ./lib/data-type/ directory has the same issue in my application:
import Point from '#ef-vue-crust/data-types/point.js';
Does anyone see the disconnect?

Part 1: changed export default {} to export {} in index.js.
Part 2: looks like I was missing an * in the exports:
{
"name": "ef-vue-crust",
"type": "module",
"main": "index.js",
"exports": {
"." : "./index.js",
"./data-types/*": "./lib/data-type/*.js"
},
...
}
And finally: I had some strings flat out not matching in the imports, which became obvious once the above was fixed.
So I suppose the answer is "attention to detail"

Related

How to get snowpack to look inside a package for subpath

I am building a snowpack app right now, and I would like to import socket.io client in the frontend (For intellisense and offline dev testing). However, socket.io only exports the backend materials when using import ... from 'socket.io'.
Normally, I use
import { io } from 'socket.io/client-dist/socket.io.js';
Which gets all the correct files and exports, however, when building with snowpack I get this error:
Package exports for 'C:\dev\JS\Node+Browser\foo\node_modules\socket.io' do not define a './client-dist/socket.io.js' subpath
Which fails the build, stopping everything.
Right now, my snowpack.config is really bare bones:
module.exports = {
buildOptions: {
out: 'dist/client'
},
mount: {
"src/client": "/"
}
}
All of the rest of my modules run fine, because they are all imported with only import ... from 'module-name. I understand what the error is saying, but I cant find anything online or thing of anything to solve it. Does anyone know how to fix this?
NOTE: This is a "hacky" fix that I think is messy and can not be used for larger projects.
I patched this by editing the package.json of the socket.io package (In node_modules) to use a temporary export alias that was exactly the same as the real directory path:
node_modules/socket.io/package.json
"exports": {
".": [
{
"require": "./dist/index.js",
"import": "./wrapper.mjs"
},
"./src/index.js"
],
"./client-dist/socket.io": "./client-dist/socket.io.js",
"path-to-other-modules": "same-path"
},

Package.json with multiple entrypoints

I have a library which was used as follows
import { Foo } from '#me/core';
const foo = new Foo();
The package.json of that library looks like
"name": "#me/core",
"version": "1.0.0",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"license": "MIT",
...
With dist/index.js its entrypoint. Now, however, I would provide an import for NodeJs projects only and one for web projects. Ideally I would have something like this for NodeJs
import { Foo } from '#me/core/nodejs';
and if you're working on a web-project you could do
import { Foo } from '#me/core/web';
My understanding is that both #me/core/nodejs and #me/core/web will be different NPM packages this way, which is not what I want. I want it to be in 1 npm package.
I tried to changed the library's index.ts file, from
export * from './foo';
into
import * as nodejs from './nodejs';
import * as web from './web';
export { web, nodejs };
This actually works, but I have to use it now (in a NODEJS project) as follows
import { nodejs } from '#me/core';
const foo = new nodejs.Foo();
Is there maybe a way to import this such that I don't need the nodejs everytime?
As you can see I'm not so sure what I should do here so any help would be appreciated!
UPDATE: Based on the suggestions by #Klaycon I see the following error:
As you're using ECMAScript modules, please refer to node.js docs on package entry points:
In a package’s package.json file, two fields can define entry points for a package: "main" and "exports". The "main" field is supported in all versions of Node.js, but its capabilities are limited: it only defines the main entry point of the package.
The "exports" field provides an alternative to "main" where the package main entry point can be defined while also encapsulating the package, preventing any other entry points besides those defined in "exports". This encapsulation allows module authors to define a public interface for their package.
So, in your package.json, you could define exports like this:
"main": "dist/index.js",
"exports": {
".": "./dist/index.js",
"./nodejs": "./dist/nodejs",
"./web": "./dist/web",
}
The accepted answer, using the exports field, is one way to do it, but not the only way -- and as you've found, isn't currently supported by Typescript.
Look at the #angular/material package, which works similarly to what you have in mind. In #angular/material/package.json, you've got a module field that points to an empty JS file, and a typings field that points to an empty .d.ts file. But you've also got #angular/material/button/package.json which points (indirectly) to the implementation of MatButton (and a bunch of other stuff). When you import {MatButton} from "#angular/material/button", it resolves this package file, looks at its module and typings fields, and uses those to resolve the runtime code and exported types, respectively.
You could do the same thing: #me/core/package.json would have module and typings fields that point to empty files; #me/core/node/package.json would point to code for your Node-specific Foo class, and #me/core/web/package.json would point to code for your browser version of Foo.
Try to add the following code to the tsconfig.json:
{
"compilerOptions": {
"moduleResolution": "NodeNext"
}
}
And then you can import the module like this:
import { Foo } from '#me/core/nodejs';
If you Don't Want to Touch the tsconfig.json you can use the following for the import:
import { Foo } from '#me/core/dist/nodejs';
References
Package entry points
Support for NodeJS 12.7+ package exports
A Proposal For Module Resolution

Using node subpath exports in Nuxt

I have a local repo(called repo-components) with some vue components and a package.json where I want to implement subpath exports, like so:
{
"name": "repo-components",
"version": "1.0.0",
"description": "Local repo",
"exports": {
"./components/": "./src/components/"
},
}
I want to then use that repo inside a Nuxt project(let's call it nuxt-project) as a dependency, and then use subpath exports like so inside nuxt-project:
import MyButton from 'repo-components/components/MyButton.vue'
However, when I try to do that import inside nuxt-project, it's not recognizing the subpath export I defined and simply tries to go directly to that path I defined(which doesn't exist). But if I try to do import MyButton from 'repo-components/src/components/MyButton.vue' then that works.
And if I try to use repo-components inside a simple node project and use require instead of import, then the exports field works perfectly, so clearly I'm missing some sort of configuration inside the Nuxt project.
Any help?

Trying to share code from Hyperapp with Bit.dev

I'm trying to share my code from my front (hyperapp) to my admin (hyperapp to) to make "preview" button.
The setup of these projects was made by an other dev, so i had to learn hyperapp workflow on the job, i'm not expert.
From what i know he was inspired by Facebook React conf.
All my usefull code is in src/ folder, and there is many dependencies so i have to export all (api, constants, utils, etc..).
Here is my bit configuration (that work, it export code correctly):
"bit": {
"env": {
"compiler": "bit.envs/compilers/react#1.0.2"
},
"packageManager": "yarn",
"packageManagerArgs": [
"--production",
"--no-optional"
],
"packageManagerProcessOptions": {
"shell": true
},
"resolveModules": {
"modulesDirectories": [
"src"
]
},
"dist": {
"entry": "src",
"target": "dist"
}
}
So, the code is "correctly" exported to bit.dev, but, when i import it from my admin with
"#bit/adrienbelair.betterise-web.modules": "^0.3.0",
i get the following error after running yarn:
yarn install
ls: Command failed.
Exit code: 1
Command: node .bit.postinstall.js
...
Error: ENOTDIR: not a directory, mkdir 'node_modules/utils/HOA'
Yes, if i look into node_module, utils is a file, and not a directory
All these are auto-generated, i dont understand what am i doing wrong?
Second thing, probably from this above error, when i try to import a component (even if there is an error, vendor are downloaded and at their place), i get:
import { Advice } from '#bit/adrienbelair.betterise-web.modules/dist/modules';
./node_modules/#bit/adrienbelair.betterise-web.api/controlleur.js
Module not found: Can't resolve 'api' in '/Users/prinzivalle/Web/betterise/admin-front/node_modules/#bit/adrienbelair.betterise-web.api'
From this line (if i look into node_module, where the error is thrown):
import { User, Cardline } from 'api';
I know, its a very specific case, mine, but i dont find any forum or explicit tutorial. Only some little component export with not a lot of dependencies.
I made my code with a little knowledge of Hyperapp/React and without thinking about sharing it one day..
Thank for reading.

Import Phaser in Aurelia

I want to use Phaser in an aurelia CLI application using typescript,
npm install runs properly, and I have already modified aurelia.json as follows
...
{
"name": "phaser",
"path": "../node_modules/phaser/build",
"main": "phaser"
},
....
When I try to use phaser in a ts file, it says phaser is undefined. And in fact, looking cli onsole, doesn't seem to be tracking phaser. If I change dependency name to something like "phaserjs", it starts tracing it, but of course I cannot use it because the import requires another name.
import {autoinject} from 'aurelia-framework';
import * as phaser from "phaser";
#autoinject
export class Login {
attached():void{
console.log("this print undefined", Phaser);
}
}
I have tried using import * as phaser from "phaser", import {Game} from "phaser" and nothing seems to work.
However, looking at vendor-bundle.js, phaser.js lines are found. So I do not know why I cannot use it
Any help will be great.
For someone with same issue later:
Phaser 2x was not designed to be modular,. To be able to use it you need to exports a couple of dependencies it requires.
First, use phaser-ce (Community-edition), it has support for webpack.
Second, export its dependencies:
In aurelia using requirejs, modify aurelia.json vendor dependencies.
{
"name": "pixi",
"path": "../node_modules/phaser-ce/build/custom",
"main": "pixi",
"exports": ["PIXI"]
},
{
"name": "p2",
"path": "../node_modules/phaser-ce/build/custom",
"main": "p2",
"exports": ["p2"]
},
{
"name": "phaser-ce",
"path": "../node_modules/phaser-ce/build/custom",
"main": "phaser-split",
"exports": ["Phaser"]
},
Now you can use phaser without problems
import * as Phaser from "phaser-ce";
Phaser-CE also includes typescripts definitions inside its module folder "typings"

Resources