I'm relatively new to node.js and am attempting to utilize a javascript library without any success.
The library itself is psn-api.
To set up for usage I have:
Installed node.js locally
Created my project folder
Ran npm init and successfully created package.json
Ran npm install i -s psn-api which has successfully installed psn-api to my project folder in node-modules and updated the dependencies in package.json.
I've copied the sample code from the psn-api github (see below) and saved as index.ts file in my project folder.
I run npx tsc --init which generates my tsconfig.json file
I run npx tsc index.ts which compiles into index.js
I run node index.js
Sample code (index.ts):
import * as fs from "fs";
import type { Trophy } from "psn-api";
import {
exchangeCodeForAccessToken,
exchangeNpssoForCode,
getTitleTrophies,
getUserTitles,
getUserTrophiesEarnedForTitle,
makeUniversalSearch,
TrophyRarity
} from "psn-api";
async function main() {
// 1. Authenticate and become authorized with PSN.
// See the Authenticating Manually docs for how to get your NPSSO.
const npsso = "xxxxxxxx";
const accessCode = await exchangeNpssoForCode(npsso);
const authorization = await exchangeCodeForAccessToken(accessCode);
// 2. Get the user's `accountId` from the username.
const allAccountsSearchResults = await makeUniversalSearch(
authorization,
"xelnia",
"SocialAllAccounts"
);
const targetAccountId =
allAccountsSearchResults.domainResponses[0].results[0].socialMetadata
.accountId;
// 3. Get the user's list of titles (games).
const { trophyTitles } = await getUserTitles(authorization, targetAccountId);
const games: any[] = [];
for (const title of trophyTitles) {
// 4. Get the list of trophies for each of the user's titles.
const { trophies: titleTrophies } = await getTitleTrophies(
authorization,
title.npCommunicationId,
"all",
{
npServiceName:
title.trophyTitlePlatform !== "PS5" ? "trophy" : undefined
}
);
// 5. Get the list of _earned_ trophies for each of the user's titles.
const { trophies: earnedTrophies } = await getUserTrophiesEarnedForTitle(
authorization,
targetAccountId,
title.npCommunicationId,
"all",
{
npServiceName:
title.trophyTitlePlatform !== "PS5" ? "trophy" : undefined
}
);
// 6. Merge the two trophy lists.
const mergedTrophies = mergeTrophyLists(titleTrophies, earnedTrophies);
games.push({
gameName: title.trophyTitleName,
platform: title.trophyTitlePlatform,
trophyTypeCounts: title.definedTrophies,
earnedCounts: title.earnedTrophies,
trophyList: mergedTrophies
});
}
// 7. Write to a JSON file.
fs.writeFileSync("./games.json", JSON.stringify(games));
}
const mergeTrophyLists = (
titleTrophies: Trophy[],
earnedTrophies: Trophy[]
) => {
const mergedTrophies: any[] = [];
for (const earnedTrophy of earnedTrophies) {
const foundTitleTrophy = titleTrophies.find(
(t) => t.trophyId === earnedTrophy.trophyId
);
mergedTrophies.push(
normalizeTrophy({ ...earnedTrophy, ...foundTitleTrophy })
);
}
return mergedTrophies;
};
const normalizeTrophy = (trophy: Trophy) => {
return {
isEarned: trophy.earned ?? false,
earnedOn: trophy.earned ? trophy.earnedDateTime : "unearned",
type: trophy.trophyType,
rarity: rarityMap[trophy.trophyRare ?? 0],
earnedRate: Number(trophy.trophyEarnedRate),
trophyName: trophy.trophyName,
groupId: trophy.trophyGroupId
};
};
const rarityMap: Record<TrophyRarity, string> = {
[TrophyRarity.VeryRare]: "Very Rare",
[TrophyRarity.UltraRare]: "Ultra Rare",
[TrophyRarity.Rare]: "Rare",
[TrophyRarity.Common]: "Common"
};
I've run around in circles with possible fixes such as adding "type":"module" to the package.json, trying to import or otherwise define psn-api in my js file but I keep hitting error after error. I'm sure there's some fundamental misunderstanding I have. I'd really appreciate if someone could outline the direct steps I need to take to get the sample script running in the cmd line.
My package.json as it stands:
{
"name": "psnapitest",
"version": "1.0.0",
"description": "",
"main": "index3.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"#types/node": "^18.6.2",
"psn-api": "^2.7.0"
},
"type": "module",
"devDependencies": {
"#tsconfig/node16": "^1.0.3",
"typescript": "^4.7.4"
}
}
My tsconfig.json as it stands (after advice in comments):
{
"compilerOptions": {
"target": "es2016",
"module": "es6",
"moduleResolution": "node",
"allowSyntheticDefaultImports": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": true
}
}
Current error when running compiled js:
Now compiles with no issues.
I run node index.js and get the following error
exports.__esModule = true;
^
ReferenceError: exports is not defined in ES module scope
I tried this locally and no error
when using node library you need to set "moduleResolution": "node" on your tsconfig.json
index.ts
import fs from 'fs'
package.json
{
"name": "psn-api-test",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "tsc index.ts",
"start": "node index.js"
},
"type": "module",
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"psn-api": "^2.7.0"
},
"devDependencies": {
"#types/node": "^18.6.2",
"typescript": "^4.7.4"
}
}
tsconfig.json
{
"compilerOptions": {
"target": "es2016",
"module": "es6",
"moduleResolution": "node",
"allowSyntheticDefaultImports": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"strict": true
}
}
Try instead of using import, use require:
const fs = require('fs')
const psn = require('psn-api')
type { Trophy } = psn
const { exchangeCodeForAccessToken } = psn
const { exchangeNpssoForCode } = psn
const { getTitleTrophies } = psn
const { getUserTitles } = psn
const { getUserTrophiesEarnedForTitle } = psn
const { makeUniversalSearch } = psn
const { TrophyRarity } = psn
Also, instead of compiling it to node.js, try using this library:
https://www.npmjs.com/package/ts-node
Its basicly node.js but for typescript
Related
I'm working on a nextjs project with wagmi hooks. Nextjs threw Can't resolve 'module' error (see error message below). Note this is after I surpressed the initial 'cannot resolve fs module' and 'child_process module' error by adding fallback statement in my next.config.js file.
I'm using wagmi hooks to read and send transactions to deployed smart contracts. I wonder if this threw the chain of the error messages. Any help would be appreciated. Thank you!
Error message:
./node_modules/eslint-config-next/index.js:42:0 Module not found: Can't resolve 'module'
Reference code in /eslint-config-next/index.js:42:0
const mod = require('module')
const resolveFilename = mod._resolveFilename
mod._resolveFilename = function (request, parent, isMain, options) {
const hookResolved = hookPropertyMap.get(request)
if (hookResolved) {
request = hookResolved
}
return resolveFilename.call(mod, request, parent, isMain, options)
}
My next.config.js:
const nextConfig = {
reactStrictMode: true,
/**below is added to suppress initial fs module not found and child_process module not found error*/
webpack: (config, { isServer }) => {
if (!isServer) {
config.resolve.fallback.fs = false;
config.resolve.fallback.tls = false;
config.resolve.fallback.net = false;
config.resolve.fallback.child_process = false;
}
return config;
},
future: {
webpack5: true,
},
fallback: {
fs: false,
tls: false,
net: false,
child_process: false,
},
};
module.exports = nextConfig;
My package.json:
{
"name": "slot_next",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint"
},
"dependencies": {
"#next/font": "13.1.2",
"#nodelib/fs.scandir": "^2.1.5",
"#rainbow-me/rainbowkit": "^0.8.1",
"eslint": "8.31.0",
"eslint-config-next": "13.1.2",
"ethers": "^5.7.2",
"next": "13.1.2",
"react": "18.2.0",
"react-dom": "18.2.0",
"wagmi": "^0.9.6"
},
"devDependencies": {
"autoprefixer": "^10.4.13",
"postcss": "^8.4.21",
"tailwindcss": "^3.2.4"
}
}
I also trie to run npm cache clear --force and npm install but it didn't help
While writing jest tests, I needed to use memfs as a mock for the Nodejs native file system module, so I used jest's manual mocks, but I'm getting this error:
> rimraf tests/{coverage,public} && jest
PASS tests/x.test.ts (19.926 s)
FAIL tests/mix.test.ts
● Test suite failed to run
TypeError: Object prototype may only be an Object or null: undefined
at Function.setPrototypeOf (<anonymous>)
at node_modules/graceful-fs/polyfills.js:139:39
at patch (node_modules/graceful-fs/polyfills.js:141:5)
at patch (node_modules/graceful-fs/graceful-fs.js:104:3)
at Object.<anonymous> (node_modules/graceful-fs/graceful-fs.js:96:18)
at Object.<anonymous> (node_modules/fs-extra/lib/fs/index.js:5:12)
PASS tests/options.test.ts (35.412 s)
Test Suites: 1 failed, 2 passed, 3 total
Tests: 6 passed, 6 total
Snapshots: 0 total
Time: 36.834 s
Ran all test suites.
Here are the files for a minimal reproduction of the error:
// src/index.ts
// this is just a minimal reproduction
import "laravel-mix";
import fs from "fs";
export default function getContent(path: string) {
return fs.readFileSync(path, "utf-8");
}
// tests/index.test.ts
import path from "path";
import fs from "fs";
import memfs from "memfs";
import getContent from "../src";
// Use memfs instead of native fs module.
jest.mock("fs");
jest.mock("fs/promises");
beforeAll(() => {
memfs.fs.mkdirSync(path.resolve(), {recursive: true});
});
// this is for demonstration only.
test("should mock fs", () => {
expect(fs).toBe(memfs.fs);
});
test("returns content from memfs", () => {
memfs.fs.writeFileSync("test.txt", "test text");
const result = getContent("test.txt");
expect(result).toBe("test text");
});
// more tests
// jest.config.js
module.exports = {
collectCoverageFrom: ["src/*.ts"],
coverageDirectory: "tests/coverage",
preset: "ts-jest",
testEnvironment: "node",
testMatch: ["<rootDir>/tests/**/*.test.ts"],
};
// tsconfig.json
{
"compilerOptions": {
"downlevelIteration": true,
"declaration": true,
"declarationDir": "dist",
"strict": true,
"esModuleInterop": true,
"resolveJsonModule": true,
"moduleResolution": "node",
"sourceMap": true,
"noImplicitReturns": true,
"noImplicitOverride": true,
"importHelpers": true
}
}
// package.json
{
"name": "jest-mock-error-reproduction",
"version": "1.0.0",
"description": "",
"main": "src/index.ts",
"scripts": {
"test": "jest"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"#types/jest": "^27.0.1",
"#types/node": "^16.7.8",
"#types/serve-static": "^1.13.10",
"jest": "^27.1.0",
"laravel-mix": "^6.0.29",
"memfs": "^3.2.4",
"ts-jest": "^27.0.5",
"typescript": "~4.2.0"
}
}
And the manual mock files:
// __mocks__/fs.ts
import {fs} from "memfs";
export default fs;
// __mocks__/fs/promises.ts
import {fs} from "memfs";
export default fs.promises;
Note that when I remove :
jest.mock("fs");
jest.mock("fs/promises");
from tests/index.test.ts, tests fail as expected.
I tried debugging the source code that produces the error, and I couldn't find the problem.
I also tried to use import * as memfs from "memfs" syntax in the __mock__ files, because from other answers it seems like that solves the problem, but the error persists.
Any help would be appreciated.
I was able to narrow the source of the problem down to a dependency.
It seems like memfs is not compatible with graceful-fs which is a dependency of fs-extra which in turn is a dependency of a library I'm using in my own code (laravel-mix). So here's a very minimal reproduction of the error now:
// tests/index.test.ts
import fs from "fs";
import memfs from "memfs";
import "graceful-fs"; // comment this and the test should pass.
jest.mock("fs");
jest.mock("fs/promises");
test("should mock fs", () => {
expect(fs).toBe(memfs.fs);
});
To solve my issue, I changed the virtual file system library in use. I switched from memfs to mock-fs.
First, I installed mock-fs and #types/mock-fs:
npm i -D mock-fs #types/mock-fs
And then I used it in tests/index.test.ts:
// tests/index.test.ts
import path from "path";
import fs from "fs";
import mock_fs from "mock-fs";
import getContent from "../src";
beforeEach(() => {
mock_fs();
});
afterEach(() => {
mock_fs.restore();
});
test("returns content from mocked fs", () => {
fs.writeFileSync("test.txt", "test text");
const result = getContent("test.txt");
expect(result).toBe("test text");
});
// more tests
I am trying to create a web game using webGL, TypeScript and node.
I have a file structure that currently looks like this
> node_modules
> src
engine.ts
webgl.ts
index.ts
index.html
package.json
engine.ts looks like this:
namespace EngineSpace {
export class Engine {
// ....
}
}
and webgl.js:
namespace EngineSpace {
export class WebGLUtil {
// ....
}
}
and index.js
window.onload = function() {
let engine = new EngineSpace.Engine();
engine.start();
}
However when I run npm start, I get that src/index.ts:5:22 - error TS2304: Cannot find name 'EngineSpace'..
I am not sure why it cannot resolve this namespace. Given that I am trying to create a game, how should I have this set up / what would be best practices?
below is the package.json: file
{
"name": "typescript-engine",
"version": "1.0.0",
"description": "",
"main": "app.js",
"scripts": {
"start": "npm run build:live",
"build": "tsc -p .",
"build:live": "nodemon --watch 'src/**/*.ts' --exec 'ts-node' src/index.ts"
},
"repository": {
"type": "git",
"url": ""
},
"keywords": [],
"author": "",
"license": "ISC",
"bugs": {
"url": ""
},
"homepage": "",
"devDependencies": {
"#types/node": "^12.11.1",
"nodemon": "^1.19.4",
"ts-node": "^8.4.1",
"typescript": "^3.6.4"
}
}
here is the tsconfig:
{
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"lib": ["es6","dom"],
"outDir": "lib",
"rootDir": "src",
"strict": false,
"esModuleInterop": true,
"resolveJsonModule": true
}
}
If you want to use namespace in nodejs side you need to export it also to use it in another module. Becuase namespace will be converted like this
engine.ts
namespace EngineSpace {
export class Engine {
public start() {
console.log('hello');
}
}
}
enigne.js
var EngineSpace;
(function (EngineSpace) {
class Engine {
start() {
console.log('hello');
}
}
EngineSpace.Engine = Engine;
})(EngineSpace || (EngineSpace = {}));
And if you want to use some property of another module in nodejs you need to export it and need to require it in another module.
Refer this for nodejs namespace
For the browser setup with typescript please refer this
Hope it helps you
I would like to turn on warning as errors policy on entire solution. It easy to turn on C# project, but I ma strugling with NodeJS (JavaScript and TypeScript).
I got web project in Visual Studio solution.
My aim is following:
See all warnings from JavaScript, Typescript as errors in Visual Studio - in build output and in Error Window as well.
Have the same output in Visual Studio and in MS Build or any other CI.
With current solution I can achieve it only partly
Warnings as errors works only for JavaScript and not TypeScript.
Error formating recognize by Visual Studio works only with TypeScript and not JavaScript.
watch mode shows warning from Javascript not from typescript.
package.json:
{
....
"scripts": {
"start:localhost": "cross-env REACT_APP_API_URL=http://localhost:5000/restapi REACT_APP_SIGNALR_URL=http://localhost:5000/hub REACT_APP_USE_MOCKS=true react-app-rewired start",
"build": "react-app-rewired build",
"lint": "eslint .",
"analyze": "source-map-explorer build/static/js/main.*",
...
},
}
tsconfig.js:
{
"compileOnSave": false,
"compilerOptions": {
"outDir": "./tscompiled",
"moduleResolution": "node",
"allowJs": true,
"jsx": "react",
"allowSyntheticDefaultImports": true,
"target": "es6",
"lib": [ "es7", "dom" ]
},
"include": [
"./src/**/*.ts",
"./src/**/*.vue",
"./src/**/*.tsx",
"./typings/**/*"
],
"exclude": [
"./node_modules"
]
}
config-overrides.js
/* eslint-disable */
const path = require('path');
const fs = require('fs');
const rewireBabelLoader = require('react-app-rewire-babel-loader');
const rewireTypescript = require('react-app-rewire-typescript');
var ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
const WarningsToErrorsPlugin = require('warnings-to-errors-webpack-plugin');
const appDirectory = fs.realpathSync(process.cwd());
const resolveApp = relativePath => path.resolve(appDirectory, relativePath);
function visualStudioErrorFormatter(error) {
//https://blogs.msdn.microsoft.com/msbuild/2006/11/02/msbuild-visual-studio-aware-error-messages-and-message-formats/
//http://www.gnu.org/prep/standards/standards.html#Errors
return (
//Object.keys(error) -> type, code, severity, content, file, line, character
error.file + '(' + error.line + ',' + error.character + ') : ' + error.severity + ' ' + error.code + ':' + error.content
);
}
module.exports = function override(config, env) {
// config = rewireReactHotLoader(config, env);
config = rewireTypescript(config, env);
config = rewireBabelLoader.include(
config,
resolveApp('node_modules/#MyProject/mykit-react/'),
);
var typescriptChecker = new ForkTsCheckerWebpackPlugin();
var warningsToErrorsPlugin = new WarningsToErrorsPlugin();
typescriptChecker.workersNumber = 2;
typescriptChecker.errorFormatter = visualStudioErrorFormatter;
typescriptChecker.formatter = visualStudioErrorFormatter;
config.plugins.push(warningsToErrorsPlugin);
config.plugins.push(typescriptChecker);
config.context = __dirname;
config.entry = './src/index.tsx';
config.module = {
...config.module,
rules: [
...config.module.rules,
{
test: /\.tsx?$/,
loader: 'ts-loader',
options: {
// disable type checker - we will use it in fork plugin
transpileOnly: true,
}
}
],
};
return config;
};
I have seen other questions about this but it is not the same.
Windows 7 x64
Node 6.6.0
electron 1.4.1
npm 3.19.8
My problem is that if I run npm start which calls electron . defined in my package.json the app runs fine. However if I just try to run electron . then I get the above error "Cannot find module app"
I think it must be path related but I can't figure it out. npm start is running the same command, I am running both commands in the root folder where main.js is located. I have also tried explicitly calling electron main.js with the same error.
Another note: when I run a debug session using Phpstorm it runs successfully. The debug configuration, Node interpreter = electron.cmd and Javascript File = main.js
package.json as requested
{
"name": "demoelectronaureliamongodb",
"title": "Demo Electron ES6, Aurelia MongoDB",
"version": "1.0.0",
"description": "Thick client demo app showing Electron, ES6, Aurelia, and MongoDB working together.",
"main": "main.js",
"scripts": {
"start": "electron .",
"build-mac": "electron-packager . 'DemoElectronAureliaMongoDB' --platform=darwin --arch=x64 --version=0.35.1 --overwrite --out ./build/mac",
"build-win": "electron-packager . 'DemoElectronAureliaMongoDB' --platform=win32 --arch=ia32 --version=0.35.1 --overwrite --out ./build/win"
},
"author": "",
"homepage": "http://karlshifflett.wordpress.com",
"license": "MIT",
"keywords": [
"electron",
"aurelia",
"es6",
"mongodb"
],
"repository": {
"type": "git",
"url": "https://github.com/Oceanware/demoelectronaureliamongodb.git"
},
"devDependencies": {
"electron-packager": "^5.1.1",
"electron-prebuilt": "^0.35.1"
},
"jspm": {
"directories": {
"baseURL": "src"
},
"dependencies": {
"aurelia-bootstrapper": "npm:aurelia-bootstrapper#^1.0.0-beta.1",
"aurelia-framework": "npm:aurelia-framework#^1.0.0-beta.1.0.2",
"font-awesome": "npm:font-awesome#^4.4.0"
},
"devDependencies": {
"babel": "npm:babel-core#^5.8.24",
"babel-runtime": "npm:babel-runtime#^5.8.24",
"core-js": "npm:core-js#^1.1.4"
}
}
}
main.js
(function () {
/**
* Main Electron process
*/
'use strict';
const electron = require('electron')
// Module to control application life.
const app = electron.app
// Module to create native browser window.
const BrowserWindow = electron.BrowserWindow
// var app = require('app');
// var BrowserWindow = require('browser-window');
var applicationMenu = require('./browser/application-menu');
var mainWindow = null;
app.on('ready', function () {
global.aureliaRoot = __dirname + '/src/';
applicationMenu.setup();
mainWindow = new BrowserWindow({
width: 900,
height: 700,
"min-width": 400,
"min-height": 300,
center: true,
resizable: true
});
mainWindow.loadUrl('file://' + __dirname + '/src/index.html');
});
})();
I did the below change to fix the issue:
const {app,BrowserWindow} =require('electron')
app.on('ready',function(){
var mainWindow= new BrowserWindow({
height:600,
width:600
})
})