I am building a simple Hello World function for AWS Lambda/APIGateway and want to incorporate ESLint and Typescript functionality. Normally when I am using Typescript and ESlint, I need the eslint-plugin-import
package and need to specify the extensions in my .eslintrc
file like so:
"settings": {
"import/resolver": {
"node": {
"extensions": [".js", ".jsx", ".ts", ".tsx"]
}
}
}
However, with this monorepo, I am still getting the Unable to resolve path to module 'aws-lambda'
error even after those are setup. Here is my repo setup:
apis/
users/
dist/ <-- My complied JS code
node_modules/
src/
functions/ <-- My Typescript Lambda functions
test/ <-- My Jest tests
.eslintrc <-- My ESLint config
package.json
template.yaml <-- My SAM template
tsconfig.json <-- My Typescript config
webpack.config.js <-- My WebPack config
Here is my .eslintrc
config:
{
"root": true,
"env": {
"es2020": true,
"mongo": true,
"node": true,
"jest": true
},
"parser": "@typescript-eslint/parser",
"extends": [
"airbnb",
"plugin:@typescript-eslint/recommended",
"plugin:prettier/recommended" // This will display prettier errors as ESLint errors. Make sure this is always the last configuration.
],
"ignorePatterns": ["dist/", "coverage/", "test/"],
"parserOptions": {
"ecmaVersion": 2018,
"sourceType": "module",
"ecmaFeatures": {
"impliedStrict": true
}
},
"rules": {
"import/extensions": [
"error",
"ignorePackages",
{
"js": "never",
"jsx": "never",
"ts": "never",
"tsx": "never"
}
],
"max-len": [
"error",
{
"code": 100,
"ignoreComments": true,
"ignoreStrings": true,
"ignoreTemplateLiterals": true
}
],
"quotes": ["error", "single", { "allowTemplateLiterals": true }],
"no-unused-vars": "off",
"@typescript-eslint/no-unused-vars": [
"error",
{
"vars": "all",
"args": "none"
}
]
},
"settings": {
"import/resolver": {
"node": {
"extensions": [".js", ".jsx", ".ts", ".tsx"]
}
}
}
}
Here is my tsconfig.json:
{
"compilerOptions": {
"module": "commonjs",
"esModuleInterop": true,
"target": "esnext",
"noImplicitAny": true,
"moduleResolution": "node",
"sourceMap": true,
"outDir": "dist"
},
"include": ["src/**/*"],
"exclude": ["**/*.test.*"]
}
and finally my webpack config:
/* eslint-disable */
const path = require('path');
const { readFileSync } = require('fs');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
const { yamlParse } = require('yaml-cfn');
/* eslint-enable */
const conf = {
prodMode: process.env.NODE_ENV === 'production',
templatePath: './template.yaml',
};
const cfn = yamlParse(readFileSync(conf.templatePath));
const entries = Object.values(cfn.Resources)
// Find nodejs functions
.filter((resource) => resource.Type === 'AWS::Serverless::Function')
.filter(
(resource) =>
(resource.Properties.Runtime && resource.Properties.Runtime.startsWith('nodejs')) ||
(!resource.Properties.Runtime && cfn.Globals.Function.Runtime)
)
.map((resource) => ({
// Isolate handler src filename
handlerFile: resource.Properties.Handler.split('.')[0],
// Build handler dst path
CodeUriDir: resource.Properties.CodeUri.split('/').splice(1).join('/'),
}))
.reduce(
(resources, resource) =>
Object.assign(
resources,
// Generate {outputPath: inputPath} object
{ [`${resource.CodeUriDir}/${resource.handlerFile}`]: `./src/${resource.CodeUriDir}.ts` }
),
{}
);
module.exports = {
entry: entries,
target: 'node',
mode: conf.prodMode ? 'production' : 'development',
module: {
rules: [
{
test: /\.tsx?$/,
use: 'ts-loader',
},
],
},
resolve: {
extensions: ['.tsx', '.ts', '.js'],
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].js',
libraryTarget: 'commonjs2',
},
devtool: 'source-map',
plugins: conf.prodMode
? [
new UglifyJsPlugin({
parallel: true,
extractComments: true,
sourceMap: true,
}),
]
: [],
};