NodeJs Lambda Layers and webpack (without serverless) - node.js

I've got a lambda function which is connecting to some layers. It's built using nodejs/typescript and I'm trying to get it built using webpack.
My problem is that I can't seem to figure out how to package the app using webpack with my layer module imports.
For example, I have a reference like this in my application:
import { ProductEntity, IProduct, productEntityManager } from "/opt/nodejs/orm";
If I try to run webpack normally, i'll get a Module not found error saying it can't find "/opt/nodejs/orm".
So I've added in the ignore plugin as below:
"use strict";
const path = require("path");
const webpack = require('webpack')
const ignore = new webpack.IgnorePlugin({resourceRegExp:/^(\/opt\/nodejs\/search|\/opt\/nodejs\/orm|\/opt\/nodejs\/put-event)$/})
module.exports = {
devtool: "source-map",
entry: "./src/handler.ts",
mode: "production",
target: "node",
plugins: [ignore],
node: {
__dirname: true,
},
output: {
filename: "index.js",
libraryTarget: "commonjs2",
path: path.resolve(__dirname, ".build"),
},
module: {
rules: [
{
test: /\.(graphql|gql)$/,
loader: "graphql-tag/loader",
exclude: /node_modules/,
},
{
test: /\.(tsx?)$/,
loader: "ts-loader",
exclude: [
[
path.resolve(__dirname, "node_modules"),
path.resolve(__dirname, ".serverless"),
path.resolve(__dirname, ".webpack")
],
],
options: {
transpileOnly: false,
experimentalWatchApi: true,
},
},
],
},
resolve: {
extensions: [".ts", ".tsx", ".js"],
},
};
And now I get the same error, but it's just baked in to my packaged js file.
I get something like this appear in that bundled js file:
...
var e=new Error("Cannot find module '/opt/nodejs/orm'")
...
So my question is... How do I build my lambda function using webpack and get it to not try and resolve or import the lambda layer modules?
I can see a lot of examples using serverless but I'm not using it (and not planning to because I'm using terraform).

Related

How do I ignore a an import in webpack?

I have a webpack file that looks like the one below, and I have a line in my handler.ts which looks like this:
import { PayoutEntity, IPayout, payoutEntityManager } from "/opt/nodejs/orm";
However I get the following error as the module/path for "/opt/nodejs/orm" doesn't exist locally:
Module not found: Error: Can't resolve '/opt/nodejs/orm'
The webpack build is for a lambda and the files for "/opt/nodejs/orm" are in a lambda layer that will only be accessable from the application once it's deployed to aws.
So in fact I would like webpack to ignore completely /opt/nodejs/orm and not even try to pack it.
I've tried using the ignore plugin with const ignore = new webpack.IgnorePlugin({resourceRegExp:/^(\/opt\/nodejs\/search|\/opt\/nodejs\/orm|\/opt\/nodejs\/put-event)$/}) but this just results in baking the "module not found" error into the bundled output file.
"use strict";
const path = require("path");
module.exports = {
devtool: "source-map",
entry: "./src/handler.ts",
mode: "production",
target: "node",
externals: [nodeExternals()],
node: {
__dirname: true,
},
output: {
filename: "index.js",
libraryTarget: "commonjs2",
path: path.resolve(__dirname, ".build"),
},
module: {
rules: [
{
test: /\.(graphql|gql)$/,
loader: "graphql-tag/loader",
exclude: /node_modules/,
},
{
test: /\.(tsx?)$/,
loader: "ts-loader",
exclude: [
[
path.resolve(__dirname, "node_modules"),
path.resolve(__dirname, ".serverless"),
path.resolve(__dirname, ".webpack")
],
],
options: {
transpileOnly: false,
experimentalWatchApi: true,
},
},
],
},
resolve: {
extensions: [".ts", ".tsx", ".js"],
},
};

Import path is different when service is deployed to AWS lambda using serverless framework

When I deploy a serverless function to AWS I get "Cannot find module '../knexfile'". That import path works when im working using serverless-offline. However, when I deploy to AWS all the packages get included at the root level so the import path is not correct. When I change it to 'knexfile' instead of '../knexfile' it works when deployed but not when ran locally. What can I do for the path to be what it needs to be automatically?
I would like for the path to get automatically resolved when deployed to AWS or tested locally.
I used the serverless-webpack npm package to solve the problem. This ended up being my webpack.config.js file:
const path = require('path')
const slsw = require('serverless-webpack')
const nodeExternals = require('webpack-node-externals')
module.exports = {
entry: slsw.lib.entries,
target: 'node',
mode: slsw.lib.webpack.isLocal ? 'development': 'production',
optimization: {
// We no not want to minimize our code.
minimize: false
},
performance: {
// Turn off size warnings for entry points
hints: false
},
devtool: 'nosources-source-map',
externals: [nodeExternals(),
{
'sqlite3': 'sqlite3',
'mariasql': 'mariasql',
'mssql': 'mssql',
'mysql': 'mysql',
'mysql2': 'mysql2',
'mssql/package.json': 'mssql/package.json',
'mssql/lib/base': 'mssql/lib/base',
'oracle': 'oracle',
'strong-oracle': 'strong-oracle',
'oracledb': 'oracledb',
'pg-native': 'pg-native',
'pg-query-stream': 'pg-query-stream',
'tedious': 'tedious'
}],
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: [
{
loader: 'babel-loader'
}
],
}
]
},
output: {
libraryTarget: 'commonjs2',
path: path.join(__dirname, '.webpack'),
filename: '[name].js',
sourceMapFilename: '[file].map'
}
}

TypeError: <X> is not a function when using imported function after webpack

When I push my module to npm, then import it into another application, I get TypeError: <myModule> is not a function.
Is my issue actually with webpack or with the way I am declaring / using my imported function when it is bundled via webpack? or the way I am using babel-loader?
DETAILS:
When myModule's package.json has "main":"src/index.js" which is the pre-webpacked version, it works. When I change it to "main":"dist/index.js" I get the issue.
I'm trying to use it like this:
import { myModule } from '#myNPM/myModuleInNPM'
...
async function someFunction(stuff) {
const scooby = await myModule(stuff)
...
}
my webpack config:
var path = require('path')
const nodeExternals = require('webpack-node-externals')
module.exports = {
entry: './src/index.js',
target: 'node',
mode: 'production',
optimization: {
// We do not want to minimize our code.
minimize: false
},
performance: {
// Turn off size warnings for entry points
hints: false
},
devtool: 'nosources-source-map',
externals: [nodeExternals()],
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: [
{
loader: 'babel-loader'
}
]
}
]
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'index.js'
}
}
I found my answer... I needed to specify my libraryTarget in my webpack config. I am now using libraryTarget: 'commonjs' an it works beautifully

React not loading from babel.rc file

I am receiving a "module parse failed" error when trying to load my react app with Babel6 Stage-1. We initially ran browserify but I am now trying to port us completely to Babel6.
babel.rc file
{
"presets": ["stage-1", "react"],
"env": {
"development": {
"presets": ["react-hmre"]
}
}}
webpack config
var path = require('path');
var webpack = require('webpack');
module.exports = {
devtool: 'cheap-module-eval-source-map',
entry: [
'eventsource-polyfill', // necessary for hot reloading with IE
'webpack-hot-middleware/client',
'./src/index'
],
output: {
path: path.join(__dirname, 'dist'),
filename: 'bundle.js',
publicPath: '/static/'
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new webpack.NoErrorsPlugin()
],
module: {
loaders: [{
test: /\.jsx?/,
loaders: ['babel'],
include: path.join(__dirname, 'src'),
},
{
test: /\.css$/,
exclude: /node_modules/,
loader: 'style!css'
}]
}
};
I have tried reading the documentation on Babel6 and it seems like I need to include react in my presets along with Stage-1.
I have done both and npm installed:
babel preset stage 1, babel preset react, and babel preset react hmre
Any ideas on how I can get react loading again?
Fixed by adding es2015 to the babel.rc file

Sass loader not working in webpack

I am trying to get *.scss files to be supported in my webpack configuration but I keep getting the following error when I run the webpack build command:
ERROR in ./~/css-loader!./~/sass-loader!./app/styles.scss
Module build failed: TypeError: Cannot read property 'sections' of null
at new SourceMapConsumer (/Users/sean/Development/playground/webpack.sass.test/node_modules/css-loader/node_modules/postcss/node_modules/source-map/lib/source-map/source-map-consumer.js:23:21)
at PreviousMap.consumer (/Users/sean/Development/playground/webpack.sass.test/node_modules/css-loader/node_modules/postcss/lib/previous-map.js:37:34)
at new Input (/Users/sean/Development/playground/webpack.sass.test/node_modules/css-loader/node_modules/postcss/lib/input.js:42:28)
at parse (/Users/sean/Development/playground/webpack.sass.test/node_modules/css-loader/node_modules/postcss/lib/parse.js:17:17)
at new LazyResult (/Users/sean/Development/playground/webpack.sass.test/node_modules/css-loader/node_modules/postcss/lib/lazy-result.js:54:47)
at Processor.process (/Users/sean/Development/playground/webpack.sass.test/node_modules/css-loader/node_modules/postcss/lib/processor.js:30:16)
at processCss (/Users/sean/Development/playground/webpack.sass.test/node_modules/css-loader/lib/processCss.js:168:24)
at Object.module.exports (/Users/sean/Development/playground/webpack.sass.test/node_modules/css-loader/lib/loader.js:21:15)
# ./app/styles.scss 4:14-117
I can't for the life of me figure out why. It's a very basic setup.
I have created a dropbox share with the bare minimum illustrating this:
https://www.dropbox.com/s/quobq29ngr38mhx/webpack.sass.test.zip?dl=0
Unzip this then run:
npm install
webpack
Here is my webpack.config.js file:
var path = require('path')
var webpack = require('webpack')
module.exports = {
devtool: 'eval',
entry: [
'./app'
],
output: {
path: path.join(__dirname, 'dist'),
filename: 'index.js',
publicPath: '/dist/'
},
plugins: [
new webpack.NoErrorsPlugin()
],
resolve: {
extensions: ['', '.js']
},
module: {
loaders: [{
test: /\.scss$/,
loader: 'style-loader!css-loader!sass-loader'
}]
}
}
And the index.js entry file:
require('./styles.scss');
alert('foo bar baz');
And the styles.scss file:
body {
background-color: #000;
}
It appears to follow the recommendations of the sass-loader documentation site, but I can't get it to run.
:(
Information about my environment:
node - 0.12.4
npm - 2.10.1
os - OS X Yosemite
I have managed to get another workaround working that doesn't involve editing the css-loader libraries within my npm_modules directory (as per the answer by #chriserik).
If you add '?sourceMap' to the sass loader the css loader seems to handle the output.
Here is my updated configuration:
var path = require('path')
var webpack = require('webpack')
module.exports = {
devtool: 'eval',
entry: [
'./app'
],
output: {
path: path.join(__dirname, 'dist'),
filename: 'index.js',
publicPath: '/dist/'
},
plugins: [
new webpack.NoErrorsPlugin()
],
resolve: {
extensions: ['', '.js']
},
module: {
loaders: [{
test: /\.scss$/,
loader: 'style!css!sass?sourceMap'
}]
}
}
P.S. I even expanded this test to include a compass-mixins include, and this worked too.
After having the same issue, I found this: https://github.com/webpack/css-loader/issues/84
Apparently, the solution for now is to manually modify lines 17-19 of /node_modules/css-loader/lib/loader.js with
if(map && typeof map !== "string") {
map = JSON.stringify(map);
}
This fixed the problem for me.
The problem is solved by setting source-map option to true (as seen in other answers).
But in case you find messy passing options in the query string there is an alternative;
for configuring the sass loader you can create a sassLoader property in the webpack config object:
module.exports = {
devtool: 'eval',
entry: [
'./app'
],
output: {
path: path.join(__dirname, 'dist'),
filename: 'index.js',
publicPath: '/dist/'
},
plugins: [
new webpack.NoErrorsPlugin()
],
resolve: {
extensions: ['', '.js']
},
module: {
loaders: [{
test: /\.scss$/,
loader: 'style!css!sass'
// loader: ExtractPlugin.extract('style', 'css!sass'),
}]
},
sassLoader: {
sourceMap: true
},
}

Resources