Related
I have a node application that compiles typescript files to a dist folder and then serves these files as lambda resolvers via aws cdk. Here is an example of my setup:
The code
register.ts
import ValidateUserFields from '../utils/forms';
exports.main = async function (event: any, context: any) {
return {
statusCode: 200,
};
}
register-lambda-config.ts
import { Construct } from 'constructs';
import * as apigateway from 'aws-cdk-lib/aws-apigateway';
import * as lambda from 'aws-cdk-lib/aws-lambda';
import * as s3 from 'aws-cdk-lib/aws-s3';
export class FrontendService extends Construct {
constructor(scope: Construct, id: string) {
super(scope, id);
const api = new apigateway.RestApi(this, 'frontend-api', {
restApiName: 'Frontend Service',
description: 'This service serves the frontend.',
});
const functionName = 'register';
const handler = new lambda.Function(this, functionName, {
functionName,
runtime: lambda.Runtime.NODEJS_14_X,
code: lambda.Code.fromAsset('dist/src/lambda'),
handler: 'register.main',
});
const registerIntegration = new apigateway.LambdaIntegration(handler, {
requestTemplates: { 'application/json': '{ "statusCode": "200" }' },
});
const registerResource = api.root.addResource('register');
registerResource.addMethod('POST', registerIntegration);
}
}
tsconfig.json
{
"compilerOptions": {
"target": "ES2018",
"module": "commonjs",
"moduleResolution": "node",
"lib": ["es2018"],
"declaration": true,
"strict": true,
"noImplicitAny": false,
"strictNullChecks": true,
"noImplicitThis": true,
"alwaysStrict": true,
"esModuleInterop": true,
"noUnusedLocals": false,
"noUnusedParameters": false,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": false,
"inlineSourceMap": true,
"inlineSources": true,
"experimentalDecorators": true,
"strictPropertyInitialization": false,
"outDir": "dist",
"typeRoots": ["./node_modules/#types"]
},
"exclude": ["node_modules", "cdk.out", "./dist/**/*"]
}
And finally here is the script part of my package.json file:
"scripts": {
"build": "tsc",
"watch": "tsc -w",
"cdk": "cdk",
"bootstrap": "cdk bootstrap",
"deploy": "cdk deploy && rimraf cdk.out",
"destroy": "cdk destroy",
"run-same-local-fe-api": "sam local start-api -p 4000 -t ./template.yaml",
"dev": "npm run build && npm run synth && concurrently --kill-others \"npm run watch\" \"npm run run-same-local-fe-api\"",
"synth": "cdk synth --no-staging > template.yaml"
},
The problem
When I run npm run dev it compiles my typescript files to the dist folder in the same structure as what I have in my src folder (where all my typescript files live). I however run into the following error if I have any imports in my register.ts file:
{"errorType":"Runtime.ImportModuleError","errorMessage":"Error: Cannot
find module '../utils/forms'\nRequire stack:\n-
/var/task/register.js\n- /var/runtime/UserFunction.js\n-
/var/runtime/index.js","stack":["Runtime.ImportModuleError: Error:
Cannot find module '../utils/forms'","Require stack:","-
/var/task/register.js","- /var/runtime/UserFunction.js","-
/var/runtime/index.js"," at _loadUserApp
(/var/runtime/UserFunction.js:202:13)"," at
Object.module.exports.load (/var/runtime/UserFunction.js:242:17)","
at Object. (/var/runtime/index.js:43:30)"," at
Module._compile (internal/modules/cjs/loader.js:1085:14)"," at
Object.Module._extensions..js
(internal/modules/cjs/loader.js:1114:10)"," at Module.load
(internal/modules/cjs/loader.js:950:32)"," at Function.Module._load
(internal/modules/cjs/loader.js:790:12)"," at
Function.executeUserEntryPoint [as runMain]
(internal/modules/run_main.js:75:12)"," at
internal/main/run_main_module.js:17:47"]}
This happens for imports from relative local files (like '../utils/forms' as shown in the code above) but also for imports from node_modules. When I look into the compiled register.js file in the dist folder I see that it has made an attempt to parse the import:
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const forms_1 = __importDefault(require("../utils/forms"));
const bucketName = process.env.BUCKET;
exports.main = async function (event, context) { ...
however it shows the error message above. I have tried using require instead of import but it was the same result...
Any help would be greatly appreciate! Thanks
Stated that this is really hard to answer without a minimal reproducible example; I would at least suggest to avoid any require and exports, and to use only import / export statements and following in tsconfig.json.
{
"compilerOptions": {
"module": "esnext"
}
}
Well.. I do understand that you want your main function to look something like this:
// final result written in javascript
exports.main = async function (event, context) {
return {
statusCode: 200,
};
}
But... using module.exports in Typescript is not the way to achieve that. Instead, Typescript using export directive (no s at the end of it) to define which parts of your code should be export. It's then up to your tsconfig.json file to determine which syntax will be used in order to represent this export (this is actually a part of Typescript engine)
So... a script written like this in Typescript
export async function main(event: any, context: any) {
return {
statusCode: 200,
};
}
Will be parse in Typescript as follow (I've used module: commonjs to achieve below result)
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.main = void 0;
async function main(event, context) {
return {
statusCode: 200,
};
}
exports.main = main;
//# sourceMappingURL=test.js.map
Please note how the resulted js file correctly use modile.exports and main as you intended
In short: when using Typescript, please use the language directives and let the engine to do the rest for you. This way - a single source of code can be deployed for different environment without requireing changing your app logic. Neat!
I am working on a nodejs app and I want to configure my path in tsconfig.json but I am having issues with the path configuration I keep getting an error Error: Cannot find module '#environment'. what could be the issue?
tsconfig
{
"compilerOptions": {
"resolveJsonModule" : true,
"target": "es6",
"module": "commonjs" ,
"lib": [
"dom",
"es6"
],
"outDir": "build",
"rootDir": "src",
"removeComments": true ,
"strict": true,
"noImplicitAny": true,
"baseUrl": "./",
"paths": {
"#lime/*": ["src/*"],
"#environment": ["src/config/environment.ts"],
},
"esModuleInterop": true
}
}
Project tree:
src - config - environment.ts
...
- index.js
package.json
tsconfig.json
...
environment.ts
import * as dotenv from 'dotenv';
dotenv.config();
interface Environment {
port: number | string,
baseUrl: string,
databaseUri: string,
}
export const environment: Environment = {
port: process.env.PORT!,
baseUrl: process.env.BASE_URL!,
databaseUri: process.env.DATABASE_URI!
}
in index.ts i imported environment.ts as import { environment } from '#environment'; please what could be wrong?
If you are trying to execute this directly with node or ts-node, you should be aware that tsconfig paths are not resolved by default by node. If you are using tsc for the build (and not webpack or similar to generate a bundle), you can add to your dependencies tsconfig-paths like this:
npm install --save tsconfig-paths
And then execute the code with:
node -r tsconfig-paths/register dist/index.js
If you are using TS code directly with ts-node, you can use:
ts-node -r tsconfig-paths/register src/index.ts
In production is suggested instead to bundle the source with webpack for example, and use a plugin like tsconfig-paths-webpack-plugin) to resolve paths while bundling.
I may not sure, i check the documentation. Seems like paths should be dir. please try this combination.
{
"baseUrl": "./",
"paths": {
"#lime/*": ["src/*"],
"#environment": ["src/config/"],
},
"esModuleInterop": true
}
}
and import like:
import { environment } from '#environment/environment'
tsconfig.json
// prettier-ignore
{
"extends": "#tsconfig/react-native/tsconfig.json", /* Recommended React Native TSConfig base */
"compilerOptions": {
/* Visit https://aka.ms/tsconfig.json to read more about this file */
/* Completeness */
"skipLibCheck": true, /* Skip type checking all .d.ts files. */
/* Path */
"baseUrl": "./src",
"paths": {
"#/*": ["./*"],
"#assets/*": ["assets/*"],
"#components/*": ["components/*"],
"#hooks/*": ["hooks/*"],
"#lib/*": ["lib/*"],
"#ui/*": ["ui/*"],
}
},
"exclude": [
"node_modules",
"babel.config.js",
"metro.config.js",
"jest.config.js"
]
}
babel.config.js
module.exports = {
presets: ['module:metro-react-native-babel-preset'],
plugins: [
[
'module-resolver',
{
root: ['./src'],
extensions: [
'.ios.ts',
'.android.ts',
'.ts',
'.ios.tsx',
'.android.tsx',
'.tsx',
'.jsx',
'.js',
'.json',
],
alias: {
'#': './src',
'#assets': './src/assets',
'#components': './src/components',
'#hooks': './src/hooks',
'#lib': './src/lib',
'#ui': './src/ui',
},
},
],
],
};
In my app, i need to use the require keyword to import something. But i can't. It shows the error below:
ERROR in src/app/components/test1/test1.component.ts:3:24 - error TS2591: Cannot find name 'require'. Do you need
to install type definitions for node? Try `npm i #types/node` and then add `node` to the types field in your tsconfig.
3 const {Pool, Client} = require('pg');
test1.component.ts
import { Component, OnInit } from '#angular/core';
const {Pool, Client} = require('pg');
const connectionString = 'postgressql;://postgres:1#localhost:3000/test1';
const client = new Client({connectionString});
client.connect();
client.query('select * from posts',
(err, res) => {console.log(err, res);
client.end();
});
#Component({
selector: 'app-test1',
templateUrl: './test1.component.html',
styleUrls: ['./test1.component.css']
})
export class Test1Component implements OnInit {
constructor() { }
ngOnInit(): void {
}
}
tsconfig.json
{
"compileOnSave": false,
"compilerOptions": {
"baseUrl": "./",
"outDir": "./dist/out-tsc",
"sourceMap": true,
"declaration": false,
"downlevelIteration": true,
"experimentalDecorators": true,
"module": "esnext",
"moduleResolution": "node",
"importHelpers": true,
"target": "es2015",
"lib": [
"es2018",
"dom"
],
"types": [ "node" ],
"typeRoots": [ "../node_modules/#types" ]
},
"angularCompilerOptions": {
"fullTemplateTypeCheck": true,
"strictInjectionParameters": true
}
}
Please point out what went wrong
[ A note that, for this part of error
Try npm i #types/node and then add node to the types field in your
tsconfig.
i did npm install #types/node --save
and then added lines to tsconfig.json but error stays same ]
Regardless if you can even use postgresql in the browser (which you can't). To import a package like that, you have to install the types and then you can use the import statement:
npm i -D #types/pg
import { Pool, Client } from 'pg';
Let me just say it again though, the package pg is just for a node.js environment, not for a browser:
Non-blocking PostgreSQL client for Node.js
I have a problem on set webpack alias path using create-react-app and craco, already googling it but can't solve the problem.
I got an error Module not found: Can't resolve '#app/App' in 'C:\ReactSandbox\my-project\src everytime i run application using command yarn start
Steps to reproduce:
create-react-app my-project
cd my-project
yarn add #craco/craco
cat > craco.config.js (see configuration below)
replace react-scripts to craco on 'script' section on package.json (craco start, craco build, etc)
edit file src/index.js (replace line 4, see code below)
yarn start
craco.config.js
const path = require("path");
module.exports = {
webpack: {
resolve: {
alias: {
"#app": path.resolve(__dirname, "src/"),
}
}
}
};
src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from '#app/App'; //replace './App' into '#app/App'
import * as serviceWorker from './serviceWorker';
ReactDOM.render(<App />, document.getElementById('root'));
serviceWorker.unregister();
Current result
Module not found: Can't resolve '#app/App' in 'C:\ReactSandbox\my-project\src
Expected
I'm avoiding call relative path hell, instead of import module like ../../../../FilterComment.js, it would be clean to write #app/FilterComment.js
resolve for carco:
u need install craco-alias, then will write in
craco.config.js
const CracoAlias = require('craco-alias')
module.exports = {
plugins: [
{
plugin: CracoAlias,
options: {
source: 'tsconfig',
baseUrl: '.',
tsConfigPath: './tsconfig.path.json',
},
},
],
}
tsconfig.path.json
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"#/*": ["src/*"],
"#svg/*": ["src/assets/svg/*"],
"#img/*": ["src/assets/images/*"],
"#icons/*": ["src/assets/icons/*"],
"#shared/*": ["src/shared/*"],
"#components/*": ["src/components/*"],
"#hooks/*": ["src/hooks/*"],
"#constants/*": ["src/constants/*"],
"#layout/*": ["src/layout/*"],
"#services/*": ["src/services/*"]
}
}
}
tsconfig.json
{
"extends": "./tsconfig.path.json",
"compilerOptions": {
"target": "es5",
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"allowJs": true,
"checkJs": false,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"declaration": false,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx",
"noFallthroughCasesInSwitch": true,
"removeComments": true
},
"include": [
"src",
"src/configs",
"react-app-env.d.ts"
]
}
First - tell to IDE about aliases in tsconfig.json:
create separate file tsconfig.paths.json and add aliases:
{
"compilerOptions": {
"baseUrl": "./src",
"paths": {
"#utils/*": ["utils/*"]
}
}
}
Add created tsconfig.paths.json to main tsconfig.json
{
"extends": "./tsconfig.paths.json",
... other staff ...
}
Second - tell to webpack about aliases:
Add aliases to config-overrides.js
const {
override,
addWebpackAlias
} = require('customize-cra');
const path = require("path");
module.exports = override(
addWebpackAlias({
"#utils": path.resolve(__dirname, "./src/utils"),
}),
);
my craco.config.js look likes below, it works:
const path = require('path');
module.exports = {
// ...
webpack: {
alias: {
'#': path.join(path.resolve(__dirname, './src')),
}
}
}
Just keep your file craco.config.js just like this, and you need to add 1 more file with named jsconfig.json
it's content:
{
"compilerOptions": {
"module": "commonjs",
"target": "es2016",
"jsx": "preserve",
"checkJs": true,
"baseUrl": "./src/",
"paths": {
"#app/*": ["./*"]
}
},
"exclude": ["node_modules", "**/node_modules/*"]
}
then you can import from the absolute path like #app/FilterComment.js
It also worked for VSCode (editor now understand where #app point to).
But if you want VSCode to do the import automatically, then you should add more config for it to force it always do the import from absolute path.
file .vscode/settings.json
content:
{
"javascript.preferences.importModuleSpecifier": "non-relative"
}
An example (which I'm using) without using dependency:
//craco.config.js
const path = require('path')
const tsconfig = require('./tsconfig.base.json')
const removeAsterisk = path => path.replace('/*', '')
const aliasProps = Object.entries(tsconfig.compilerOptions.paths).map(([key, value]) => {
const newKey = removeAsterisk(key)
let newValue = removeAsterisk(value[0])
newValue = path.resolve(__dirname, newValue)
return [newKey, newValue]
})
const alias = Object.fromEntries(aliasProps)
module.exports = {
webpack: {
alias,
},
}
//tsconfig.base.json
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"~/*": ["./src/*"],
//...
}
}
}
// tsconfig.json
{
"extends": "./tsconfig.base.json",
"compilerOptions": {/*...*/}
}
Use react-app-alias:
Install craco and react-app-alias and create craco config:
// craco.config.js
const {CracoAliasPlugin} = require('react-app-alias')
module.exports = {
plugins: [
{
plugin: CracoAliasPlugin,
options: {}
}
]
}
Replace react-scripts with craco in package.json.
Create typescript config and alias in separated config like this:
// tsconfig.paths.json
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"example/*": ["example/src/*"],
"#app/*": ["app/src/*"]
}
}
}
// tsconfig.json
{
"extends": "./tsconfig.paths.json",
// ...
}
Now you can do import like this:
import App from '#app/App'
Maybe the OP had a different version of React / Webpack (I'm using today's current versions), but putting the alias object directly inside the webpack object (without nesting it in the resolve object) did the trick for me:
const path = require("path");
module.exports = {
webpack: {
alias: {
"#app": path.resolve(__dirname, "src"),
}
}
};
I am using craco-alias plugin for automatic aliases generation for Webpack and Jest.
(I am just an intern but that's how senior developers in my company are using absolute imports in react)
Install
yarn add #craco/craco
yarn add craco-alias
craco.config.js
const CracoAlias = require('craco-alias');
module.exports = {
plugins: [
{
plugin: CracoAlias,
options: {
source: 'tsconfig',
baseUrl: './src',
tsConfigPath: './tsconfig.paths.json', // or wherever you have defined your paths
},
},
],
};
And make sure that you scripts in package.json look like the following
"scripts": {
"start": "craco start",
"build": "craco build",
"test": "craco test",
"eject": "craco eject",
...
},
Then It'll work as specified in tsconfig.json.
FYI I have,
"react-scripts": "4.0.3"
"#craco/craco": "^6.3.0"
"craco-alias": "^3.0.1"
I am using typescript with the following build instructions.
"build:types": "tsc --emitDeclarationOnly",
"build:js": "babel src --out-dir lib --extensions \".ts,.tsx\" --source-maps inline",
"start": "npm run build:types && npm run build:js && node ./lib/bin/www.js"
One of my .ts files imports mongoose. When running npm start I get the following error. in the .d.ts file
\lib\models\v1\collection1.model.d.ts:1
(function (exports, require, module, __filename, __dirname) { import mongoose from 'mongoose';
^^^^^^^^
SyntaxError: Unexpected identifier
note "#types/mongoose" and "mongoose" are dependence already.
the content of collection1.model.d.ts is as follows. which is generated by tsc --emitDeclarationOnly
import mongoose from 'mongoose';
declare const _default: mongoose.Model<mongoose.Document, {}>;
export default _default;
tsconfig.json
{
"compilerOptions": {
"target": "es2015",
"module": "commonjs",
"declaration": true,
"outDir": "./lib",
"strict": false,
"allowSyntheticDefaultImports": true,
"esModuleInterop": true,
},
"include": ["src"]
}
.babelrc
{
"presets": [
"#babel/env",
"#babel/typescript"
],
"plugins": [
"#babel/proposal-class-properties",
"#babel/proposal-object-rest-spread",
"#babel/transform-runtime"
]
}
So the problem is I should have not used babel and instead simply use tsc to generate all the code. Thank you to all that helped