Nestjs: import modules undefined, but methods and functions from modules can be imported - node.js

I am using Nestjs with WebStorm & TS 4.2.3^latest.
The problem that I am facing is a bit strange. For example, some modules, like axios can be installed, imported, and used as usual. But some modules, especially Nodejs Core, like fs or path, can't be imported as modules. BUT their methods can be imported and used just fine!
//ERROR: Module undefined on run:dev, but no error in IDE
import path from 'path';
import fs from 'fs';
//Working fine
import { join } from 'path';
import { readFileSync } from 'path';
I am sure, they have correct TS types, even installed manually. For example:
import axios from 'axios';
import path from 'path'; //path is undefined
import { join } from 'path'; // working fine
import { Injectable } from '#nestjs/common';
#Injectable()
export class AppService {
async test(input: string): Promise<void> {
await axios.get() // working fine
await path.join() // Cannot read property 'join' of undefined
//BUT await join() // Works fine!
}
}
I have only one tsconfig.json which is generated by Nest Cli. I am starting my apps via npm start:dev -name and IDE don't show any errors in code, until I ran code.
tsconfig.json module part, just to be sure: "module": "commonjs", package.json doesn't have module part at all.

IDE in this case, misdirect me a bit. Almost forgot, that I am dealing with TS now. Some modules seem to have no default exports, so:
You should import as with them: import * as fs from 'fs';
Or, another option is enabling: "esModuleInterop": true, in your tsconfig.json

Related

Cannot use import after adding Typescript

So I'm trying to implement typescript to an existing project.
However, I came to a stop, where I get an error of: SyntaxError: Cannot use import statement outside a module
Here, is my helper class, which is omitted. However, you can see that I am using an import, rather than require
index.ts
// const axios = require('axios');
// const {includes, findIndex} = require('lodash');
// const fs = require('fs');
import { includes, findIndex } from "lodash";
import fs from 'fs';
type storeType = {
[key: string]: string | boolean
}
class CMS {
_store;
constructor(store: storeType) {
this._store = store;
<omitted code>
export default CMS;
}
Than, I import index.ts file to server.js file:
const { CMS, getCookie, checkLang, getLangByDomain, handleRoutes } = require('./src/utils/cms/index.ts');
Unfortunately, when I start the server, I get an error of: SyntaxError: Cannot use import statement outside a module
I am using a default tsconfig.json which has been generated after creating file and running dev environment.
Edit your tsconfig.json and change "module": "esnext" to "module": "commonjs".
This is ES type modules:
import { includes, findIndex } from "lodash";
import fs from 'fs';
But this is commonJs type:
const { CMS, getCookie, checkLang, getLangByDomain, handleRoutes } =
require('./src/utils/cms/index.ts');
I think that's the problem. You should use one type of modules.
Try to rewrite this const { CMS, getCookie, checkLang, getLangByDomain, handleRoutes } = require('./src/utils/cms/index.ts'); to this import { CMS, getCookie, checkLang, getLangByDomain, handleRoutes } from './src/utils/cms/index.ts'
Or opposite rewrite ES to commonJs, but don't forget to change type in tsconfig
You cannot explicitly import typescript files into Javascript files. Instead, you need to use the compiled typescript files(i.e. Javascript files in outDir folder).
So assume you compiled your typescript files into Javascript, then it would be converted to outDir/index.js. After that, you could directly import it into server.js
const { CMS, getCookie, checkLang, getLangByDomain, handleRoutes } =
require('./path/to/index.js'); // You cannot require a ts file.
If the typescript files and Javascript files are part of the same project, then you need to transpile the js files alongside the ts as well. In order to achieve this, you need to set allowJs to true in tsconfig.
{
"compilerOptions": {
...
"allowJs": true,
}
}
Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files.

Prerendering causes a SyntaxError: Cannot use import statement outside a module

I'm trying to execute prerender.ts as seen here to prerender my Angular code, but when I try and execute it using ts-node prerender.ts, I get the error:
import 'zone.js/dist/zone-node';
^^^^^^
SyntaxError: Cannot use import statement outside a module
at Module._compile (internal/modules/cjs/loader.js:892:18)
What is the proper way to execute this from NodeJS? Here is what prerender.ts looks like:
import 'zone.js/dist/zone-node';
import * as path from 'path';
import * as fs from 'fs';
import { enableProdMode } from '#angular/core';
import { renderModuleFactory } from '#angular/platform-server';
import { AppPrerenderModuleNgFactory } from './dist-prerender/main.bundle';
const distFolder = './dist';
const index = fs
.readFileSync(path.resolve(__dirname, `${distFolder}/index.html`), 'utf8')
.toString();
// we could automate this based on the app.routes.ts file but
// to keep it simple let's just create an array with the routes we want
// to prerender
const paths = [
'/about',
'/brews',
'/consultancy'];
enableProdMode();
// for every route render the html and save it in the correct folder
paths.forEach(p => renderToHtml(p, distFolder + p));
// don't forget to overwrite the index.html as well
renderToHtml('/index.html', distFolder);
function renderToHtml(url: string, folderPath: string): void {
// Render the module with the correct url just
// as the server would do
renderModuleFactory(AppPrerenderModuleNgFactory, {
url,
document: index
}).then(html => {
// create the route directory
if (url !== '/index.html') {
fs.mkdirSync(folderPath);
}
fs.writeFile(folderPath + '/index.html', html, (err => {
if (err) {
throw err;
}
console.log(`success`);
});
});
}
Update: I found that if I used tsc to transpile prerender.ts to JavaScript first and then executed that with node, I could get past this error. However, I started getting an error which I think is indicative of this code not running within the context of ngZone. So the code is still not right.
As stated here:
Current node.js stable releases do not support ES modules. Additionally, ts-node does not have the required hooks into node.js to support ES modules. You will need to set "module": "commonjs" in your tsconfig.json for your code to work.
Thus, pass below compiler option:
ts-node --compiler-options '{"module": "commonjs"}' prerender.ts
Of course, you can just include "module": "commonjs" in your (root) tsconfig.json file under "compilerOptions". This way you only have to execute:
ts-node prerender.ts

export/import javascript class like module node into electron with webpack

In context of basic electon-vue app, I want to create my own javascript class and use it into main process or renderer or into vue component.
I created JS Class but I never find a good way for exporting my class.
All possibility of writing import/export module find in the web finished by same error : Undefined exports
"use strict"
import fs from 'fs'
import typeorm from 'typeorm'
import Public from './../entity/Public'
class ConnectionManager
{
constructor(){}
getConnection(type, name, options) {
}
}
module.exports = ConnectionManager
But it seeams that others js file work perfectly like the vue-router js for routing into vue.js app :
import Vue from 'vue'
import Router from 'vue-router'
Vue.use(Router)
export default new Router({
routes: [
{
path: '/',
name: 'home',
component: require('#/components/Home').default
}
]
})
I package my code with Webpack and libraryTarget Output is : commonjs2
I seems that use babel-loader with webpack
node version : 10.13.0
electron : 3.0.10
Babel : 6
EDIT :
I try this syntax class js file :
"use strict"
import * as fs from 'fs'
import * as typeorm from 'typeorm'
import {Public} from './../entity/Public'
export default class ConnectionManager
{
constructor(){}
getConnection(type, name, options) {
}
}
with this import syntax :
import ConnectionManager from './../service/connectionManager'
But I have this error when I execute code into electron :
Uncaught TypeError:
_service_connectionManager__WEBPACK_IMPORTED_MODULE_8__.default.getConnection
is not a function
I console logged this service class "ConnectionManager" and I have this result (so it really exist) :
ƒ ConnectionManager() {
babel_runtime_helpers_classCallCheck__WEBPACK_IMPORTED_MODULE_0___default()(this, ConnectionManager);
}
It seems that the final js module webpack contain the ConnectionManager class
It seems that you mix commonjs modules with ES modules by the wrong way.
There are a lot of modules (include node built-in) which have no default export. To import such a module you need to use * as moduleAlias or { exportedField } in your import statement. Try to rewrite your code by this way:
import * as fs from 'fs'
import * as typeorm from 'typeorm'
import { Public } from '../entity/Public'
export default class ConnectionManager
{
constructor(){}
getConnection(type, name, options) {
}
}
Because this class is exported as a default value, you can use the following construction to import it as a default field, where ConnectionManager is an alias for the current scope:
import ConnectionManager from '../service/connectionManager'

Why doesn't 'fs' work when imported as an ES6 module?

Why do I get errors like these when I try to use the new Node.js support for ES6 modules (e.g. with node --experimental-modules script.mjs)?
// script.mjs
import * as fs from 'fs';
// TypeError: fs.readFile is not a function
fs.readFile('data.csv', 'utf8', (err, data) => {
if (!err) {
console.log(data);
}
});
// TypeError: fs.readdirSync is not a function
fs.readdirSync('.').forEach(fileName => {
console.log(fileName);
});
You must use import fs from 'fs', not import * as fs from 'fs'.
This is because (at least from the point of view of mjs files) the 'fs' module exports only one thing, which is called default. So if you write import * as fs from 'fs', fs.default.readFile exists but fs.readFile does not. Perhaps the same is true of all Node.js (CommonJS) modules.
Confusingly, in TypeScript modules (with #types/node and ES5 output), import fs from 'fs' produces error
error TS1192: Module '"fs"' has no default export
so in TypeScript you must write import * as fs from 'fs'; by default. It appears this can be changed to match the way mjs files work using the new "esModuleInterop": true option in tsconfig.json.
We can simply import like this it in our code
import * as fs from 'fs';
and it is perfectly working for me, give it a try

How to export and use multiple custom modules in the same library with React Native

So I have a React Native custom library that I made that has 2 modules made, moduleA and moduleB. How do I export them so that I can call both of the modules in my project?
Before when I had only one module it would work perfectly like this:
//Index.js file of my library
import { NativeModules } from 'react-native';
const { moduleA } = NativeModules;
export default moduleA;
and then in my React native project I could call it like this
//Home.js file of my project
import moduleA from 'custom_library';
moduleA.method(); //Works fine
But now that I have two modules, I'm not sure how to change the modules and the import such that both can be used. Is it even possible? The end goal that I want to be able to do is
//Home.js file of my project
import { moduleA, moduleB } from 'custom_library';
moduleA.method();
moduleB.method();
Sorry for the basic question, but I'm getting frustrated that nothing I've tried is really working.
Just use the export keyword. You will find more detailed examples here.
index.js of custom_library
import { NativeModules } from 'react-native';
const { moduleA, moduleB } = NativeModules;
export { moduleA, moduleB };
home.js
import { moduleA, moduleB } from 'custom_library';
moduleA.method();
moduleB.method();

Resources