How to include functions of JavaScript files in the Node.js server? - javascript

I have a typescript file in which some functions have been added.
The following shows the actual address of the typescript file :
../myproject/src/util/validation/user-validation
All the functions are exported from the file. For instance,
export function validateSignUpData(userDetail:UserDetail):Array<String>{
let errorMessages = new Array<String>();
/* Some Code */
Now I am trying to use the exported function in Node server, though it throws an error which I do not comprehend.
Error: Cannot find module '../myproject/src/util/validation/user-validation'
This is how I tried to get the functions inside my Node server file:
app.post('/users',(req,res)=>{
let validator = require('../myproject/src/util/validation/user-validation');
let errorMessages = validator.validateSignUpData(req.body);
I googled require function, and it seemed that my code must work properly. Some forums suggests that typescript must be installed to resolve the issue, though I have already installed typescript!
I will be glad, if you help me!
Thank you.

The export keyword is used for ES6 modules (Related article also covering node.js). This is a new language feature that was shipped in 2015.
It uses export function name() {...} to export a function and import {name} from './path/to/file'; to import it somewhere else.
Node uses the CommonJs syntax (which is still largely popular).
The idea behind it is that any module (i.e. js-file) can export an object like this: module.exports = {key: "value"}. This object can then be imported using require('./path/to/file').
You can use es6 modules in node like this: How can I use an es6 import in node?.

There are 2 methods of modules in node js, es6 modules and requrejs
require is used together with module.exports
add this to your module
module.exports.validateSignUpData=validateSignUpData
and then the require function will export it.
The other way is to use es6 modules but it doesn't work under all circumstances
https://nodejs.org/docs/latest-v13.x/api/esm.html#esm_enabling

Related

Import JSON file in NodeJs using es6

Hi i'm currently learning nodejs and I try to import a json file like this :
'use strict'
import data from 'users.json'
console.log(data)
Each time I get this error "Cannot find package 'users.json'"
But if I read the file with fs it worked so can you explain me how to do please
try :
import data from './users'
which is the es6 method of doing things or if you want an older syntax method you can try
const data = require('./users')
Okay so the explanation just is this, those fullstops and forward slash are used to indicate relative paths to the file the import is being called from, which means somethings you'd see something like for example ../file/help. The ./ means go up one directory ../ means go up two directories and so on. The name after the slash just tells your program the folder to go in to look for the file to import from so ./folder means go up one directory and enter into the folder directory and so on.
Almost forgot to mention, you should not import from a json file or a text file or any other file that does not have a .js extention(of which you do not actually have to specify) unless absolutely neccessary. To deal with files in node you have to use the fs library.
const fs =require('fs')
....
fs.readFile('./users.json','utf-8',(err,jsonString)=>{
const data = JSON.parse(jsonString);
//whatever other code you may fanacy
}
take a look at the fs module for a list of awesome features you can use to play with files
While the selected answer is correct, here's an explanation that I hope might add some clarity:
import MyModule from 'some-module'
is ES6 import syntax, as opposed to the older CommonJS syntax, which uses require.
CommonJS's require can be used to import files generally; ES6's import statement is more specific, and is generally used for importing js files which meet the criteria for being a module (having an export statement), or specific assets such as CSS sheets. Unlike require, it won't generally work for reading in files that are not modules.
You can't mix CommonJS require and ES6 import in the same file (at least not easily), so if you're using ES6 import and wish to read a file, do so with fs.readFileSync or a similar method. If the file is a json string, you'll need to parse it with JSON.parse().
If you want to use ES6 (NOT CommonJS) module system but want to use the Node.js version which is less than V18 (supports direct json import) then use the below approach.
import { createRequire } from "module";
const require = createRequire(import.meta.url); // construct the require method
const data = require("users.json"); // Now you can use require method in ES6
console.log(data)

Multiple TypeScripts Files Configuration

Here comes silly and simple question:
I am new to this whole webpack tools.
I have been trying to build a simple web-app using typescript and webpack. In the old days, I created typescript and compile them without bundling them.
With webpack, I already installed necessary loaders, typescript, and jQuery.
The problem is, I have 3 typescript files:
main.ts -> imports all assets (images, css) and other typescripts
functions.ts -> consist all of my custom functions/modules
ui-controller.ts
in functions.ts I always created namespaces such as:
module Functions{
export module StringTools{
export function IsEmpty(): boolean{
//some code
}
}
}
in the browser, I knew that the snippet code above will be called, but it is not recognized in the main.ts (in the run time) even thou I already import it.
This is how I import it in main.ts:
import '.src/functions'
Any suggestion how I can resolve this?
Typescript module keyword is confusing, and in version 1.5 it was indeed changed to namespace to better reflect it's meaning. Look here.
Namespaces are also called internal modules. They are meant to be used when your files are evaluated at the global scope. You can use typescript playground to see how namespaces are transpiled. The point is - namespaces are not modules.
Webpack however, does not evaluate files in the global scope, it evaluates them inside a function in order to provide real module behavior.
So what does make your typescript file into a module? the keywords export and import (but not inside a namespace like in your example).
Typescript will see those keywords, and will transpile them into commonjs\AMD\es6 require or define statements, according to your configuration in tsconfig.json. Now you have "real" modules. Then it's Webpack's job to do something (lots of info about that online) with those modules so that they will work in the browser where you don't have modules, but that part is not related to typescript.
TL;DR -
So how would you do this in Webpack?
/* functions.ts */
export function IsEmpty(): boolean{
//some code
}
and
/* main.ts */
import {isEmpty} from './functions';
if you want better code organisation as suggested by your use of module StringTools, just split into different files. You can read more about es6 import syntax for more info.
The first part of this answer is that your main module (which has been replaced with the namespace keyword) is not exported... so there are no exported members for your functions file.
export namespace Functions { //...
Part two of the answer is that if you are using modules, you don't need to use namespaces as the module is enclosed within its own scope.
Working version of the file as you designed it, I'd say drop the wrapping namespace:
functions.ts
export namespace StringTools{
export function IsEmpty(): boolean{
//some code
}
}

Is it possible to generate JS from TypeScript surrounded by require() instead of define()?

I already understood how to load modules (tip: you should always start with ./ when referencing files relatively, even on the same folder), and created an application that is totally written using TypeScript.
The current issue I'm facing is: how to USE modules I wrote? Right now I'm employing a main.js file similar to:
require(['my/typescript/module'], function(module) {
//my application boostrapping code goes here
});
But by doing it this way I lose various advantages from TypeScript:
I'm unable to use ES6-style imports (c'mon, import {Module} from
'./my/typescript/module' looks way cleaner to me)
I can't get the type system from TypeScript, as I'm writing JavaScript directly
The project build don't break if I add some wrong import reference
(The worse part IMO) I can't get the autocomplete feature from the modules (again, I'm inside a JavaScript file)
So, I wonder if there are any possibility to combine ES6 imports and TypeScript, generating a require()-enclosed JS file instead of a define() one.
To use ES6-style import, I think you should export the module first
export default class SomeRamdomClass {
hello(name: string) {
return `hello ${name}`;
}
}
import importedRamdomClass from "./SomeRamdomClass";
let greeting = new importedRamdomClass();
console.log(greeting.hello('Jon'));
more information can be found on TypeScriptLang

How Does Babel Know To Treat A Module As A Module

I have gone through 2ality article on Modules, however, I am confused, how does the system know to treat a module as a module?
import React from "react";
import { hello } from "./hello.js";
var Ctrl = React.createClass ({
render : function () {
return (
<div .... random data
></div>
);
}
});
export default Ctrl;
To me, a module is just a file with global code written in it. We reference the module via its filename.
However, I wonder how does this all gel together when we build the production build.
How does the system know that this is a module & not just global varaibles being declared?
Is it the import / export commands that actually make it say: 'aha, this is a module!'
Excuse the newbie question.
Is it the import / export commands that actually make it say: 'aha, this is a module!'
Yes!
More precisely, the import keyword instructs the JavaScript engine (or transpiler) to load an external file as a module.
if by system you mean the browser, it doesn't know, you normally use another tool that implements the idea of modules for you, and it transforms (puts in code) that act as a module system for you that the browser understands.
some tools like do this is require in node, browserify, webpack
that*, not like

Migrating node code base to TypeScript: global scope?

I'm trying to migrate large node codebase to TypeScript. To make things easier, I just want to start by renaming .js files to .ts files, fix any semantic issues, without much refactoring, and then gradually improve the code base.
Let's consider the following example:
logger.js:
exports = function(string) {
console.log(string);
}
moduleA.js:
var logger = require('./logger')
exports.someAction = function() {
logger.log('i'm in module a')
}
moduleB.js:
//var logger = require('./logger')
exports.someOtherAction = function() {
logger.log('i'm in module B')
}
moduleC.js:
var moduleA = require('./moduleA');
var moduleB = require('./moduleB');
exports.run = function(string) {
moduleA.someAction();
moduleB.someOtherAction(); //exception here - logger not defined
}
So if i execute moduleB.someOtherAction() i'll get an exception, because logger is not defined in scope in moduleB.js.
But typescript compiles just fine, because logger is declared in moduleA, and this is because (if i understand correctly) typescript treats all of those files as a single compilation unit.
So is there anyway to avoid this without much refactoring?
Update
I've created a sample project which can be found here
If i run typescript compiler, i get no errors, though logger is commented out in moduleB.ts:
g#w (master) ~/projects/ts-demo: gulp generate
[10:39:46] Using gulpfile ~/projects/ts-demo/gulpfile.js
[10:39:46] Starting 'generate'...
[10:39:46] Starting 'clean'...
[10:39:46] Finished 'clean' after 11 ms
[10:39:46] Starting '<anonymous>'...
[10:39:47] Finished '<anonymous>' after 1.4 s
[10:39:47] Finished 'generate' after 1.41 s
g#w (master) ~/projects/ts-demo:
Update 2
Ok, so this is expected behaviour as stated in TypeScript deep dive book:
If you now create a new file bar.ts in the same project, you will be allowed by the TypeScript type system to use the variable foo from foo.ts as if it was available globally
Louy is right. Every file (when compiling for node with CommonJS) is created like its own module. Just like the normal case in node.
So to get this to work you could do something like this:
logger.ts
export default (str: string) => console.log(str);
moduleA.ts
import logger from './logger';
export var someAction = () => {
logger("i'm in module a");
}
moduleB.ts
import logger from './logger';
export var someOtherAction = () => {
logger("i'm in module B");
}
moduleC.ts
import { someAction } from './moduleA';
import { someOtherAction } from './moduleB';
someAction();
someOtherAction();
I also used a tsconfig.json:
{
"compilerOptions": {
"module": "commonjs",
"noImplicitAny": true
},
"files": [
"logger.ts",
"moduleA.ts",
"moduleB.ts",
"moduleC.ts"
]
}
Compiling this (just type tsc in the folder containing the tsconfig.json) results in one .js file per .ts file. It should compile and run just fine. The main thing you need to take from this is that each file is its own self contained module when compiling for node/CommonJS.
EDIT Due to edits in question:
Ok after looking at your code again there is a couple of reasons that this compiles but fail to run properly:
If you send a group of files to the compiler all references in all of those files, and all of the variables in the global scope will be available in all .ts files sent to the compiler. This is confusing and sometimes regrettable, but at the moment it is how things work. This in your case results in that the require function defined in the global scope in node.d.ts is available in all .ts files, not only in moduleC.ts; if the reference is removed from moduleC.ts you will get an error in logger.ts because the require function is not defined for example. It also results in var logger = .. defined in logger.ts will be seen as available in the other .ts files. Typescript assumes that it will be available at run time.. not ideal when compiling for node, but not a problem when you are writing actual typescript not trying to compile pure javascript. In fact, because it is pure javascript the compiler does not recognise it as a node module, and treats it as a generic javascript file.
When compiling with commonjs each file is compiled on its own by the typescript compiler. If any references or imports are found those will be followed and used to type and verify the code of course, but the compilation is still done on a per file basis (var something = require('./whatever'); is not an import, it is interpreted by the compiler as a variable being assigned by a function taking a string as an argument.)
So thats why it compiles, lets go on to why its not working then.
Each file outputted by the compiler in commonjs mode is its own "node-module". If you want to have access to one module from within another in node (this has nothing to do with typescript really, it is just how node works) you will need to require that file. in moduleB.ts (and in moduleB.js for that matter) there is no indication to node to say what logger is. So you simply need to require logger.
In the example you are referring to in your second update of the question commonjs is not being used, and further more it is in connection with typescripts internal modules - not node modules which is a completely different thing.
So the simple answer is, that if you want to use one file from within a another in node you have to require it. Simply uncommenting the commented reference in moduleB.ts should get everything up and running.
In the current state of your code the typescript compiler is not helping you much, because it can't really. The code is close to pure javascript, to get decent help from the compiler you will need to start converting it to typescript. The first step might be to replace var asdf = require("") with import asdf = require("");, this will make it possible for the compiler to check the references and help you a lot in return.
I realise this is a wordy answer, but you managed to create yourself a confusing and difficult to explain behaviour.
There's something called internal/external modules in typescript.
Internal modules can declare stuff that can be referenced everywhere in the project. Think about typings/lib files, you should be able to reference things like Error and String everywhere in your project.
External modules on the other hand have to be imported to be referenced. This is what you want to do.
The difference between internal and external modules is that external ones use import and export.
Internal ones use declare module/namespace/var.
Just add "compilerOptions": {"module": "commonjs"} to your tsconfig.json file to enable external modules.

Categories

Resources