Jest moduleNameMapper and NPM package exports - node.js

I am developing fullstack NPM packages with multiple entrypoints (namely client, server and sometimes tests), using the exports property of package.json.
I also use a small hack to make TS work with exports until it's officially supported (see this Stack Overflow post, this hackish solution and this ticket).
The package.json ends up looking like this:
{
"name": "#vulcanjs/graphql",
"version": "0.4.7",
"main": "./dist/index.js",
"files": [
"dist/"
],
"exports": {
".": "./dist/index.js",
"./server": "./dist/server/index.js",
"./testing": "./dist/testing.js"
},
"types": "./dist/index.d.ts",
"typesVersions": {
"*": {
"server": [
"./dist/server/index.d.ts"
],
"testing": [
"./dist/testing.d.ts"
]
}
},
"description": "Vulcan graphQL schema generator",
...
You can then import using either #vulcanjs/graphql for shared code, and #vulcanjs/graphql/server for Node.js-only code.
It works perfect in my Next.js app. However, it seems to break Jest moduleNameMapper.
First, I had this:
moduleNameMapper: {
"#vulcanjs/(.*)": [
"<rootDir>/node_modules/#vulcanjs/$1",
],
},
The error is:
Configuration error:
Could not locate module #vulcanjs/graphql/server mapped as:
[
"/code/vulcan-next/node_modules/#vulcanjs/graphql/server",
].
The problem is that it tries to find a package named #vulcanjs/graphql/server: yet "server" is not a different package, it's an entrypoint of #vulcanjs/graphql.
I've also tried this:
moduleNameMapper: {
"#vulcanjs/(.*)/(.*)": [
"<rootDir>/node_modules/#vulcanjs/$1",
],
},
With this config, #vulcanjs/graphql/server is mapped to #vulcanjs/graphql. The problem is that now, server code is not found. I've checked and the problem is that this solution totally removes the /server: so #vulcanjs/graphql/server points to the main entrypoints instead of the server entrypoint.
Finally I did try to remove the moduleNameMapper, but then #vulcanjs/graphql/server package is not found by Jest. Note that I need the mapper for a use case I did not demonstrate here, so getting rid of it is possible but not the best solution.
The bug can be reproduced by installing the framework: https://github.com/VulcanJS/vulcan-next. You can clone, yarn install, unskip the test in src/models/tests/sampleModel.server.test.ts and run yarn run test:unit sampleModel. It will show the error.
Any idea how I could fix this?

Related

Jasmine on Node.js fails with ERR_UNSUPPORTED_DIR_IMPORT

I'm writing an Express v4.18.2 app on Node.js 18.12.1 on Windows. I'm testing a controller with Jasmine 4.5.0. When I run jasmine spec, it fails with an error message about resolving ES modules:
Error [ERR_UNSUPPORTED_DIR_IMPORT]: Directory import
'...\SimpleServiceJasmine\spec' is not supported resolving ES modules
imported from
...\SimpleServiceJasmine\node_modules\jasmine\lib\loader.js
...
code: 'ERR_UNSUPPORTED_DIR_IMPORT',
url: 'file:///D:/.../SimpleServiceJasmine/spec'
I use require, not import, everywhere in the code being tested or the spec.
Note that jasmine runs fine if I specify the spec file explicitly, even with wildcards, as long as the wildcard path resolves to a single file:
jasmine spec/service/contact-api.spec.js # ok
jasmine spec/*/c* # ok
I tried downgrading jasmine to 3.0.0 and 2.0.1 but got the same error. The behavior is the same on Windows 11 and Windows Server 2019.
Any suggestions for how can I run all the specs in this project?
Here's my package.json:
{
"name": "simpleservice",
"version": "1.0.0",
"description": "A simple CRUD API for contacts",
"main": "service/contact-api.js",
"scripts": {
"test": "jasmine spec/service/contact-api.spec.js",
"start": "node src/service/contact-api.js"
},
"author": "Puzzled Dev",
"license": "ISC",
"dependencies": {
"express": "^4.18.2"
},
"devDependencies": {
"jasmine": "^4.5.0"
}
}
Here's the spec/support/jasmine.json:
{
"spec_dir": "spec",
"spec_files": [
"**/*[sS]pec.?(m)js"
],
"helpers": [
"helpers/**/*.?(m)js"
],
"env": {
"stopSpecOnExpectationFailure": false,
"random": true
}
}
Jasmine uses glob for pattern matching, which means whenever you pass spec as a pattern, glob finds this particular directory and then returns it to jasmine. Unfortunately, path validation in jasmine does not seem in a very smart way, it continues executing with the given path, and then it throws an error by Node.js.
It is equivalent to this:
import spec from './spec'
You can take a look at the jasmine-runner code, and the line in which contributor put a comment:
The ES module spec requires import paths to be valid URLs. As of v14,
Node enforces this on Windows but not on other OSes. On OS X, import
paths that are URLs must not contain parent directory references.
So, once you have defined spec_files in jasmine.json, there is no need to give an extra pattern to execute all tests.
jasmine will execute all tests with the help of spec_dir, and spec_files fields in jasmine.json. All you need to do is just simply run jasmine or npx jasmine.

How to fix NestJS deployment error to the Vercel?

this is the now.json
{
"version": 2,
"name": "nestjs-now",
"builds": [
{
"src": "dist/main.js",
"use": "#now/node"
}
],
"routes": [
{
"src": "/(.*)",
"dest": "dist/main.js"
}
]
}
I'm not sure what's the reason and how to fix.
I just followed the vercel tutorial to deploy my nestjs backend project, but don't works.
It inclues GraphQL APIs and Rest APIs together as well as socket.io server.
Why it doesn't work?
Serverless Functions on Vercel (at the moment) do not accept a build step for the code of the function. For that reason, any backend framework that needs a "build step" to generate a server, will not work.
What Vercel is best for?
Frontend deployments and Serverless Functions as helpers. Full-blown APIs should be deployed elsewhere. You can check the following resources:
https://vercel.com/guides
https://vercel.com/import
https://vercel.com/docs/runtimes#official-runtimes
What are my options?
I recommend that you use Heroku or Digital Ocean as alternatives.
Update 2021-11-11
Now you can deploy any framework with SSR, API routes, and Edge Functions (soon) to Vercel. Just make sure you are following the File System API specification.
You can read the introduction section for more information. Remember that Vercel is a platform optimized for frontend deployments.
the problem is that VERCEL looks for the DIST folder as soon as it starts the BUILD process
What you can do is remove the DIST folder from the .gitignore this way it will resolve the 404
after that, whenever you make a new deploy it is necessary to force deploy without cache to compile your dist againe
In your production dashboard you will find this buttom with
vercel function logs
and inside you can find what is breaking your app
but, in my opinion, the first mistake that are crashing is about your VERCEL.JSON file:
When you are building a serveless app in nestjs, you will not renderize by dist/ or output/, you gotta render from your src/, so your vercel.json must be like this:
{
"version": 2,
"builds": [
{
"src": "src/main.ts",
"use": "#vercel/node"
}
],
"routes": [
{
"src": "/(.*)",
"dest": "src/main.ts",
"methods": ["GET", "POST", "PUT", "PATCH", "DELETE"]
}
]
}
And you must do set it with the documentation help
calling your API like it needs.
This following resolution doesn't works with NESTJS/SWAGGER because it is not sending SwaggerUIBundle to browser as in this image, but a solution to the same issue can be founded here with only swagger in C# (and if is your case, you can try to adapt it to nestjs/swagger)
I oppened this to find some solution
I have successfully deploy nestjs to vercel and I used the following starter project: https://github.com/nestjs/javascript-starter
1)- first, you need to install #babel/cli and #babel/core both at the same time, otherwise npx will install out-of-dated babel 6.x. which will cause issues later when building the project using babel, and thats according to babel own docs
2)- remove #babel/core from package.json
3)- remove #babel/cli if exists from package.json
4)- remove package-lock.json
5)- remove node_modules
6)- run the command npm i
7)- run the command npm i --save-dev #babel/core #babel/cli
8)- build/transpile the project using the command npx babel src --out-dir build
9)- add vercel.json to your project like with following
{
"version": 2,
"builds": [
{
"src": "build/main.js",
"use": "#vercel/node"
}
],
"routes": [
{
"src": "/(.*)",
"dest": "build/main.js",
"methods": [ "GET", "POST", "PUT", "PATCH", "DELETE" ]
}
]
}
10)- now push this to github, then deploy to vercel

Why does ESLint throw an error while using export/import statement on Node.js 12.13.0?

I have a project built on Node.js, DynamoDB and other AWS services, deployed on Serverless architecture. I also have the ESLint package installed.
I am getting the following error:
ESLint: Import and export declarations are not supported yet on Node 8.0.0. (node/no-unsupported-features)
Following are the details of my project:
Node version: 12.13.0
NPM version: 6.12.0
Serverless version: 1.40.0
ESLint: 6.8.0
I have double verified by node version of my project and my local. Both are the same (12.13.0).
I am able to use async/await but whenever I try using import/export, it gives me the error.
Following is my .eslintrc file :
{
"extends" : [
"eslint:recommended",
"plugin:node/recommended"
],
"plugins": [
"promise",
"node"
],
"env" : {
"browser" : false,
"node": true,
"es6": true
},
"parserOptions": {
"ecmaVersion": 9,
"sourceType": "module",
"impliedStrict": false
},
"globals" : {
},
"rules": {
"no-console": 0,
"no-unused-vars": ["error", { "vars": "all", "args": "none", "ignoreRestSiblings": false }],
"node/no-unpublished-require": [
"error",
{
"allowModules": [
"aws-sdk"
]
}
],
"node/no-unsupported-features": ["error", {
"version": 8,
"ignores": []
}]
}
}
`
Node.js by default uses Common.js style for import/export.
In the new versions of Node.js you can use different extensions or the --experimental-modules option in the command line.
*.mjs you use ES6 import/export
*.js or *.cjs you use commonjs
If you consider that ECMAScript modules import/export are still experimental, I would say that ESLint is quite correct.
You might want to override EsLint rules in order to make it work with that.
Firstly consider that the rule you mentioned is obsolete so you might want to use the new ones => https://github.com/mysticatea/eslint-plugin-node/blob/master/docs/rules/no-unsupported-features.md
Because those rules are obsolete I would suggest you to take a look at your eslint and its external rulesets version (if you use them) and try again.
In any case...
Check/create the .eslintrc.json file in the root of your project and override the project rules you might want to change.
Just stumpled upon a similiar error.
In my case i solved it by adding the engines definition to package.json
"engines": {
"node": ">=12.13.0"
}
I am not sure if this solves you problem but a quite similar issue can be found here.

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"

How to add Tether in Aurelia-CLI to use with Bootstrap 4

I am trying to add Bootstrap 4 to Aurelia. I can only get the CSS to work but the bootstrap.js requires Tether and I can't get it included, since I keep getting this error in the console:
Bootstrap tooltips require Tether
I tried something along this
"jquery",
"Tether",
{
"name": "tether",
"path": "../node_modules/tether/dist",
"main": "js/tether.min",
"exports": "Tether",
"resources": [
"css/tether.css"
]
},
{
"name": "bootstrap",
"path": "../node_modules/bootstrap/dist",
"main": "js/bootstrap.min",
"deps": ["tether", "jquery"],
"exports": "$",
"resources": [
"css/bootstrap.css"
]
},
It does bundle, but it's still complaining about the missing Tether.
I read on another stack answer that I have to makeTetheravailable globally which could be done viarequirejs.config.js` with this
define(['lib/tether.min'], function(tether) {
window.Tether = tether;
});
but there's no such config with Aurelia.
After some more time spent on this, I believe that I came up with something working. I don't see anymore errors and I am now able to use Bootstrap tooltip, so I will assume this is the working solution.
All the changes were made inside the aurelia.json configuration file, as the following:
"prepend": [
"node_modules/bluebird/js/browser/bluebird.core.js",
"node_modules/tether/dist/js/tether.min.js",
"scripts/require.js"
],
"dependencies": [
...
"aurelia-templating-binding",
"jquery",
"tether",
{
"name": "bootstrap",
"path": "../node_modules/bootstrap/dist",
"main": "js/bootstrap.min",
"deps": ["jquery", "tether"],
"exports": "$",
"resources": [
"css/bootstrap.css"
]
},
...
So basically, I just had to add it to the prepend to get it working. Also note that adding tether inside the deps[] array has no effect (probably because Tether is now global with the prepend), but I like to see it there as a reminder that it's a dependencies anyway.
EDIT
As mentioned by #Paul-Sebastian, it's probably better to remove tether from showing up in the deps of Bootstrap to remove possibility of double inclusion. Basically this is the updated code:
"tether",
{
"name": "bootstrap",
"path": "../node_modules/bootstrap/dist",
"main": "js/bootstrap.min",
"deps": ["jquery"],
"exports": "$",
"resources": [
"css/bootstrap.css"
]
},
EDIT #2
There is now also an append section that just got added to Aurelia-CLI to help with Legacy Library with Plugins. The section reads as the following:
A Very Stubborn Legacy Library With Plugins
Some legacy libraries may support plugins which you also want included in your bundle. In some cases these plugins depend on a
global object defined by the main library, so it is important that the
plugins exist later in the bundle than the main library scripts. These
plugins can go in the append section, which works exactly the same
as the prepend section but the scripts are appended to the end of
the bundle, after all other items. Like the prepend section all items
are relative to the project folder, not the src.

Resources