Deploy express api with serverless-webpack. Sequelize import error - express

I try do deploy me project to AWS Lambda with serverless-webpack. But i got error on import model to sequelize.
Here is error log from AWS:
module initialization error: ReferenceError
at t.default (/var/task/app.js:1:8411)
at Sequelize.import(/var/task/node_modules/sequelize/lib/sequelize.js:398:32)
My serverless.yml file:
service: backend-aquatru
plugins:
- serverless-webpack
- serverless-offline
- serverless-dotenv-plugin
custom:
webpackIncludeModules:
forceInclude:
- pg
- pg-hstore
webpackConfig: 'webpack.config.js'
includeModules: true
packager: 'npm'
provider:
name: aws
runtime: nodejs8.10
stage: dev
region: us-west-1
functions:
app:
handler: app.handler
events:
- http: 'ANY /'
- http: 'ANY {proxy+}'
webpack.config.js
const path = require('path')
const Dotenv = require('dotenv-webpack')
module.exports = {
entry: './app.js',
target: 'node',
externals: [nodeExternals()],
output: {
libraryTarget: 'commonjs',
path: path.resolve(__dirname, '.webpack'),
filename: 'app.js', // this should match the first part of function handler in serverless.yml
},
plugins: [
new Dotenv(),
],
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
include: __dirname,
loaders: ['babel-loader'],
},
],
},
}
And my sequelize import model:
import {sequelize as dbConfig} from '../config/vars'
import Sequelize from 'sequelize';
const db = {
Sequelize,
sequelize: new Sequelize(dbConfig.makeUri(), {
operatorsAliases: Sequelize.Op,
dialect: dbConfig.dialect
}),
};
// require each model from every endpoint with sequelize
db.User = db.sequelize.import('User', require('../api/models/user.model'));
// run associations from every model here
Object.keys(db).forEach((modelName) => {
if ('associate' in db[modelName]) {
db[modelName].associate(db);
}
});
export const User = db.User;
export default db;
I saw serverless-webpack issue with import model files with require, and modify my code that way. But it doesn't help. Here is link to discussion. [enter link description here][issue]

Related

Outlook addin JS- NPM run build missing JS files

I am working on creating an Outlook addin project following the below tutorial:-
https://learn.microsoft.com/en-us/office/dev/add-ins/quickstarts/outlook-quickstart?tabs=yeomangenerator
During development i added some extra JavaScript files(like helper.js, settings.js) which contains some common and helper functions which are work fine while running locally,
Now when i run "npm run build" command for generating a published version of the project to be deployed on server these files are missing and thus published project is not working due to missing functions.
Below is my project.
project structure
missing helper and setting folder
below is my webpack.config.js boiler plate code
module.exports = async (env, options) => {
const dev = options.mode === "development";
const buildType = dev ? "dev" : "prod";
const config = {
devtool: "source-map",
entry: {
polyfill: ["core-js/stable", "regenerator-runtime/runtime"],
taskpane: "./src/taskpane/taskpane.js",
commands: "./src/commands/commands.js",
landing: "./src/landing/landing.js"
},
resolve: {
extensions: [".html", ".js"]
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader",
options: {
presets: ["#babel/preset-env"]
}
}
},
{
test: /\.html$/,
exclude: /node_modules/,
use: "html-loader"
},
{
test: /\.(png|jpg|jpeg|gif)$/,
loader: "file-loader",
options: {
name: '[path][name].[ext]',
}
}
]
},
plugins: [
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
filename: "taskpane.html",
template: "./src/taskpane/taskpane.html",
chunks: ["polyfill", "taskpane"]
}),
new CopyWebpackPlugin({
patterns: [
{
to: "taskpane.css",
from: "./src/taskpane/taskpane.css"
},
{
to: "[name]." + buildType + ".[ext]",
from: "manifest*.xml",
transform(content) {
if (dev) {
return content;
} else {
return content.toString().replace(new RegExp(urlDev, "g"), urlProd);
}
}
}
]}),
new HtmlWebpackPlugin({
filename: "commands.html",
template: "./src/commands/commands.html",
chunks: ["polyfill", "commands"]
}),
new HtmlWebpackPlugin({
filename: "landing.html",
template: "./src/landing/landing.html",
chunks: ["polyfill", "dialog"]
})
],
devServer: {
headers: {
"Access-Control-Allow-Origin": "*"
},
https: (options.https !== undefined) ? options.https : await devCerts.getHttpsServerOptions(),
port: process.env.npm_package_config_dev_server_port || 3000
}
};
return config;
};
Could you please help
Finally found the solution, We need to include the custom/helper js files by
marking the functions as export & making them require on the main files that needs &
then use the functions exported and
once we run "npm run build" function is available as the part of main file which made it required
below is the example of the same
//custom or helper file in a subfodler
sample.js
export function sampleFunc() {
//some codeenter code here
}
taskpane.js // main file where we need to use
const samJs = require("./../helpers/sample"); // without extesion
//Call the function
var data = samJs.sampleFunc

Serverless framework lambda function access denied to S3

Anyone have any ideas why I'm getting "Access Denied" when trying to put object into S3 inside a lambda function? I have the serverless AWS user with AdministorAccess and allow access to s3 resource inside serverless.yml:
iamRoleStatements:
- Effect: Allow
Action:
- s3:PutObject
Resource: "arn:aws:s3:::*"
Edit - here are the files
serverless.yml
service: testtest
app: testtest
org: workx
provider:
name: aws
runtime: nodejs12.x
iamRoleStatements:
- Effect: Allow
Action:
- s3:PutObject
Resource: "arn:aws:s3:::*/*"
functions:
hello:
handler: handler.hello
events:
- http:
path: users/create
method: get
handler.js
'use strict';
const AWS = require('aws-sdk');
// get reference to S3 client
const S3 = new AWS.S3();
// Uload the content to s3 and allow download
async function uploadToS3(content) {
console.log('going to upload to s3!');
const Bucket = 'mtest-exports';
const key = 'testtest.csv';
try {
const destparams = {
Bucket,
Key: key,
Body: content,
ContentType: "text/csv",
};
console.log('going to put object', destparams);
const putResult = await S3.putObject(destparams).promise();
return putResult;
} catch (error) {
console.log(error);
throw error;
}
}
module.exports.hello = async event => {
const result = await uploadToS3('hello world');
return {
statusCode: 200,
body: JSON.stringify(result),
};
};
I was using TypeScript plugin - #serverless/typescript. I used it to create Lambda function that will resize images that are uploaded to S3 + do some kind of content moderation.
Here is the content of serverless.ts file:
import type { AWS } from '#serverless/typescript';
import resizeImageLambda from '#functions/resizeImageLambda';
const serverlessConfiguration: AWS = {
service: 'myservice-image-resize',
frameworkVersion: '3',
plugins: ['serverless-esbuild'],
provider: {
name: 'aws',
stage: 'dev',
region: 'us-east-1',
profile: 'myProjectProfile', // reference to your local AWS profile created by serverless config command
// architecture: 'arm64', // to support Lambda w/ graviton
iam: {
role: {
statements: [
{
Effect: 'Allow',
Action: [
's3:GetObject',
's3:PutObject',
's3:PutObjectAcl',
's3:ListBucket',
'rekognition:DetectModerationLabels'
],
Resource: [
'arn:aws:s3:::myBucket/*',
'arn:aws:s3:::myBucket',
'arn:aws:s3:::/*',
'*'
]
},
{
Effect: 'Allow',
Action: [
's3:ListBucket',
'rekognition:DetectModerationLabels'
],
Resource: ['arn:aws:s3:::myBucket']
}
]
}
},
// architecture: 'arm64',
runtime: 'nodejs16.x',
environment: {
AWS_NODEJS_CONNECTION_REUSE_ENABLED: '1',
NODE_OPTIONS: '--enable-source-maps --stack-trace-limit=1000',
SOURCE_BUCKET_NAME:
'${self:custom.myEnvironment.SOURCE_BUCKET_NAME.${self:custom.myStage}}',
DESTINATION_BUCKET_NAME:
'${self:custom.myEnvironment.DESTINATION_BUCKET_NAME.${self:custom.myStage}}'
}
},
// import the function via paths
functions: { resizeImageLambda },
package: { individually: true },
custom: {
esbuild: {
bundle: true,
minify: false,
sourcemap: true,
exclude: ['aws-sdk'],
target: 'node16',
define: { 'require.resolve': undefined },
platform: 'node',
concurrency: 10,
external: ['sharp'],
packagerOptions: {
scripts:
'rm -rf node_modules/sharp && SHARP_IGNORE_GLOBAL_LIBVIPS=1 npm install --arch=x64 --platform=linux --libc=glibc sharp'
}
},
myEnvironment: {
SOURCE_BUCKET_NAME: {
dev: 'myBucket',
prod: 'myBucket-prod'
},
DESTINATION_BUCKET_NAME: {
dev: 'myBucket',
prod: 'myBucketProd'
}
},
myStage: '${opt:stage, self:provider.stage}'
}
};
module.exports = serverlessConfiguration;
resizeImageLambda.ts
/* eslint-disable no-template-curly-in-string */
// import { Config } from './config';
export const handlerPath = (context: string) =>
`${context.split(process.cwd())[1].substring(1).replace(/\\/g, '/')}`;
export default {
handler: `${handlerPath(__dirname)}/handler.main`,
events: [
{
s3: {
bucket: '${self:custom.myEnvironment.SOURCE_BUCKET_NAME.${self:custom.myStage}}',
event: 's3:ObjectCreated:*',
existing: true,
forceDeploy: true // for existing buckets
}
}
],
timeout: 15 * 60, // 15 min
memorySize: 2048
};
I remember there were few issues when I wanted to connect it to existing buckets (created outside serverless framework) such as IAM policy was not re-created / updated properly (see forceDeploy end existing parameters in function.events[0].s3 properties in resizeLambda.ts file)
Turns out I was an idiot and have the custom config in the wrong place and ruin the serverless.yml file!

Webpack using wrong node_modules folder

I have a vue client project that uses a vue library project (the vue library project is also using some 3rd party packages like vue-material).
They are linked via the client project's Package.json like this "lib": "file:../lib" and I am importing components in the client project using import Comp from "lib/src/components/Comp";
The problem is that when I build the client project using Webpack, the files in my library use lib/node_modules/vue instead of node_modules/vue which causes double vue instancing.
Anyone has any idea why when I am using webpack build from the client folder, it looks for vue package in my library folder? and is there a way to get around that?
My webpack.config
"use strict";
const path = require("path");
const utils = require("./utils");
const config = require("../config");
const vueLoaderConfig = require("./vue-loader.conf");
function resolve(dir) {
return path.join(__dirname, "..", dir);
}
module.exports = {
entry: {
app: ["babel-polyfill", "./src/main.js"]
},
output: {
path: config.build.assetsRoot,
filename: "[name].js",
publicPath: process.env.NODE_ENV === "production" ? config.build.assetsPublicPath : config.dev.assetsPublicPath
},
resolve: {
extensions: [".js", ".vue", ".json"],
alias: {
vue$: "vue/dist/vue.esm.js",
"#": resolve("src"),
src: resolve("src"),
assets: resolve("src/assets"),
components: resolve("src/components"),
utilities: resolve("src/utilities"),
directives: resolve("src/directives"),
plugins: resolve("src/plugins"),
data: resolve("src/data"),
"vuex-store": resolve("src/store"),
"lib": resolve("node_modules/lib")
}
},
module: {
rules: [
{
test: /\.(js|vue)$/,
loader: "eslint-loader",
enforce: "pre",
include: [resolve("src")],
options: {
formatter: require("eslint-friendly-formatter")
}
},
{
test: /\.vue$/,
loader: "vue-loader",
options: vueLoaderConfig
},
{
test: /\.js$/,
loader: "babel-loader",
include: [resolve("src"), resolve("../lib/src")]
},
{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
loader: "url-loader",
options: {
limit: 10000,
name: utils.assetsPath("img/[name].[hash:7].[ext]")
}
},
{
test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
loader: "url-loader",
options: {
limit: 10000,
name: utils.assetsPath("media/[name].[hash:7].[ext]")
}
},
{
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
loader: "base64-font-loader",
options: {
limit: 10000,
name: utils.assetsPath("fonts/[name].[hash:7].[ext]")
}
},
{
test: /\.ico$/,
loader: "file-loader?name=[name].[ext]"
}
]
}
};
My client's main entry
// The Vue build version to load with the `import` command
// (runtime-only or standalone) has been set in webpack.base.conf with an alias.
// Core Imports
import Vue from 'vue'
import App from './App'
// Plugins
import { ComponentsPlugin } from "lib/src/components";
/* eslint-disable no-new */
new Vue({
el: '#app',
router,
store,
template: '<App/>',
components: { App }
})
As I ran out of solutions to this problem I decided to debug webpack's compiler.
It seems webpack uses a library called 'enhanced-resolve' (We actually send parameters to that library in our webpack's resolve:{} section). And using the resolve.alias property we can redirect any require to any folder we want.
So to redirect any require("vue") to my own vue.esm.js, all I need is to add an entry like this (I originally had that line but it was pointing to a relative path rather than an absolute path):
resolve: {
alias: {
vue$: resolve("node_modules/vue/dist/vue.esm.js"),
}
}
Note the $ at the end of the library name, It signals enhanced-resolve that the package only has 1 module so any require whos name is "vue" or a sub-directory of "vue" should be parsed using the alias.
Enhanced-Resolve - ResolverFactory.js
if(/\$$/.test(alias)) {
onlyModule = true;
....
}
Enhanced-Resolve - AliasPlugin.js
// InnerRequest is the path (vue/dist/vue.esm.js)
// name is the alias name without the $ (vue)
if(innerRequest === name || (!onlyModule && startsWith(innerRequest, name + "/"))) {
continue resolving....
}

Different variable value in Vue.js + Webpack in dev server vs build

I'm working on a Vue.js project which is running Webpack in local development & builds static files for deployment.
There is a variable apiDomain which needs to change from:
http://localhost.api/ - in local development
to
https://api.example.com/ - in the static build files
I've been trying to get my head around environmental variables but I'm not sure how they work in Webpack vs Vue.js.
What is the correct way to setup a Vue.js variable so it's different between local development & the static build files?
You can adapt this idea for your needs:
import axios from "axios";
const env = process.env.NODE_ENV || "development";
console.log(`we are on [${env}] environment`);
const addr = {
production: "https://rosetta-beer-store.io",
development: "http://127.0.0.1:3000",
};
const api = axios.create({
headers: {"x-api-key": "my-api-key", "x-secret-key": ""},
baseURL: addr[env],
});
export const beerservice = {
list: params => api.get("/beer/list", {params}),
find: id => api.get(`/beer/${id}`),
};
export const mediaservice = {
url: id => (id ? `${addr[env]}/media/${id}` : `${addr[env]}/icon.svg`),
};
By using the process.env.NODE_ENV (available on development and build time) you can not only to set the correct profile for the app services endpoints but also manage any tweak you need on your build scripts:
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const CleanWebpackPlugin = require("clean-webpack-plugin");
const webpack = require("webpack");
module.exports = {
mode: process.env.NODE_ENV || "development",
module: {
rules: [
{
test: /\.css$/,
use: ["style-loader", "css-loader"]
},
{
test: /\.html$/,
loader: "html-loader"
},
{
test: /\.(png|svg|jpg|gif|woff|woff2|eot|ttf|otf)$/,
use: ["file-loader"]
},
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: ["babel-loader"]
}
]
},
resolve: {
extensions: ["*", ".js", ".jsx"]
},
entry: "./src/main.jsx",
output: {
filename: "build.js",
path: path.resolve(__dirname, "dist")
},
devtool:
process.env.NODE_ENV == "development" ? "inline-source-map" : undefined,
devServer: {
contentBase: "./dist",
hot: true
},
plugins: [
new CleanWebpackPlugin(["dist"]),
new HtmlWebpackPlugin({
template: "./index.html"
}),
new webpack.HotModuleReplacementPlugin()
]
};
You can see more examples on this github project, but the general idea is to take advantage of node at the build time

Why are my js files being loaded as `index.html` instead of the actual js files created by webpack?

I'm creating a simple build from webpack, using typescript, jade, and stylus. When the final index.html file is spit out, however, it seems to think the js files are just the index.html file and not the actual js files bundled up by webpack and dynamically inserted at the bottom of the html body.
My project directory structure looks like this:
- dist (compiled/transpiled files)
- server
- dependencies
- index.js
- app.js
- app.[hash].js
- polyfills.[hash].js
- node_modules
- src
- server
- dependencies
- index.ts
- app.ts
- client (ng2 ts files)
- index.jade
This is my webpack build:
'use strict';
const webpack = require('webpack');
const path = require('path');
const HTMLWebpackPlugin = require('html-webpack-plugin');
const WebpackShellPlugin = require('webpack-shell-plugin');
const rootDir = __dirname;
/**
* Resolve paths so that we don't have to use relative paths when importing dependencies.
* Very helpful when scaling an application and changing the location of a file that my require another file
* in the same directory as the one it used to be in
*/
const pathResolves = [path.resolve(rootDir, 'src'), path.resolve(rootDir, 'node_modules')];
console.log('path', path.resolve(rootDir, 'src/server'));
module.exports = {
entry: {
'app': path.resolve(rootDir, 'src/client/main.ts'),
'polyfills': [
'core-js/es6',
'core-js/es7/reflect',
'zone.js/dist/zone'
]
},
output: {
path: path.resolve(rootDir, 'dist'),
filename: '[name].[hash].js'
},
module: {
rules: [
{
test: /\.component.ts$/,
use: [
{
loader: 'angular2-template-loader'
},
{
loader: 'ts-loader',
options: {
configFileName: path.resolve(rootDir, 'tsconfig.client.json')
}
}],
include: [path.resolve(rootDir, 'src/client')]
},
{
test: /\.ts$/,
use: [
{
loader: 'ts-loader',
options: {
configFileName: path.resolve(rootDir, 'tsconfig.client.json')
}
}
],
exclude: /\.component.ts$/
},
{
test: /\.jade$/,
use: ['pug-ng-html-loader']
},
{
test: /\.styl$/,
use: [
{ loader: 'raw-loader' },
{ loader: 'stylus-loader' }
]
}
]
},
resolve: {
extensions: ['.js', '.ts', '.jade', '.styl'],
modules: pathResolves
},
plugins: [
new webpack.optimize.CommonsChunkPlugin({
name: 'polyfills'
}),
new HTMLWebpackPlugin({
template: path.resolve(rootDir, 'dist/index.html')
}),
/**
* Define any environment variables for client
*/
new webpack.DefinePlugin({
APP_ENV: JSON.stringify(process.env.APP_ENVIRONMENT || 'development')
}),
/**
* This plugin is required because webpack 2.0 has some issues compiling angular 2.
* The angular CLI team implemented this quick regexp fix to get around compilation errors
*/
new webpack.ContextReplacementPlugin(
/angular(\\|\/)core(\\|\/)(esm(\\|\/)src|src)(\\|\/)linker/,
'./'
)
]
};
And finally, this is the src/server/app.ts file that serves up index.html:
import * as express from 'express';
import * as fs from 'fs';
import * as morgan from 'morgan';
import {
Config
}
from './dependencies/config';
export
function app(Container) {
const app = express();
const config: Config = Container.get(Config);
if (config.log.dev) {
app.use(morgan('combined'));
}
app.get('/', (req: express.Request, res: express.Response) => {
const indexPath: string = `dist/index.html`;
const encodeType: string = `utf-8`;
const html = fs.readFile(indexPath, encodeType, (err: Error, result: string) => {
if (err) {
return res.status(500).json(err);
}
return res.send(result);
});
});
return app;
}
The browser console shows the following 404 error messages (they're red in the browser console) when i go to localhost:3000:
GET http://localhost:3000/polyfills.9dcbd04127bb957ccf5e.js
GET http://localhost:3000/app.9dcbd04127bb957ccf5e.js
I know it's supposed to be getting the js files from dist/[file].[hash].js, but can't seem to make it work with webpack. Also, I should note that I set NODE_PATH to ./ in my gulp nodemon config. Any ideas why this isn't working?
Figured it out on my own. Forgot to add app.use(express.static('dist')) middleware to the app.ts file.