TypeScript, Serverless and Webpack complications - node.js

I am trying to use typescript with serverless applications and I ran in some issues like the serverless-typescript package had its last update a year ago. I also tryed to use it with serverless webback but i am running in some issues regarding the use of ORMS because webpack cannot load the modals properly (it can when i import the files but not a runtime). Does someone have any advice of how to devolop serverless applications with typescript or should I keep using just javascript?

Basically it doesn't matter either it is serverless application or not. What matters is your webpack config. Try using serverless-webpack plugin with proper webpack config for typescript compilation
serverless.yml webpack part example:
plugins:
- serverless-webpack
custom:
webpack:
webpackConfig: ./webpack.config.js
webpack.config.js example:
const path = require('path')
const slsw = require('serverless-webpack')
module.exports = {
mode: 'development',
devtool: 'source-map',
entry: slsw.lib.entries,
target: 'node',
resolve: {
extensions: ['.mjs', '.ts', '.js', '.json', '.tsx']
},
output: {
libraryTarget: 'commonjs2',
path: path.join(__dirname, '.webpack'),
filename: '[name].js'
},
module: {
rules: [
{
oneOf: [
{
test: /\.(ts|js)$/,
exclude: [/node_modules/],
loader: 'ts-loader',
options: {
transpileOnly: true
}
}
]
}
]
}
}
You can adapt it to your needs, I've just shared a little piece of my config

Related

NodeJs Lambda Layers and webpack (without serverless)

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).

NodeJS+Webpack+Docker project on WSL throwing errors with native 'fs' library

I have a NodeJS project that I'm building with Webpack and running inside a Docker container. This was being developed in a Linux environment, but I decided to try to move it to WSL (Windows subsystem for Linux) because that would make things easier for the dev team. Getting it to run on WSL has been difficult though.
Currently the project builds with no problems, and Docker also seems to be running smoothly. However, when I open the project on a browser, nothing loads. On the console is the following error message:
Uncaught TypeError: Cannot read property 'native' of undefined
at Object../node_modules/fs-extra/lib/fs/index.js (index.js:107)
at __webpack_require__ (bootstrap:19)
at Object../node_modules/fs-extra/lib/index.js (index.js:6)
at __webpack_require__ (bootstrap:19)
at Object.<anonymous> (RollingFileWriteStream.js:2)
at Object../node_modules/streamroller/lib/RollingFileWriteStream.js (RollingFileWriteStream.js:265)
at __webpack_require__ (bootstrap:19)
at Object../node_modules/streamroller/lib/index.js (index.js:2)
at __webpack_require__ (bootstrap:19)
at Object.<anonymous> (file.js:3)
When I check index.js:107, I see the following lines:
// fs.realpath.native only available in Node v9.2+
if (typeof fs.realpath.native === 'function') {
exports.realpath.native = u(fs.realpath.native)
}
However, all node versions I have running are 10+. My base image is node:12 (more specifically, version 12.13.0). Nodejs and npm versions on WSL are:
me#computer:.../addin$ nodejs --version
v12.11.1
me#computer:.../addin$ npm --version
6.12.0
And NodeJS on windows is:
PS H:\> node --version
v10.15.3
I'm not sure if this is relevant, but here are my webpack config files:
webpack.server.config.js:
const path = require('path')
const webpack = require('webpack')
const nodeExternals = require('webpack-node-externals')
module.exports = {
entry: {
server: './src/server/server.js',
},
output: {
path: path.join(__dirname, 'dist'),
publicPath: '/',
filename: '[name].js'
},
target: 'node',
node: {
// Need this when working with express, otherwise the build fails
__dirname: false, // if you don't put this is, __dirname
__filename: false, // and __filename return blank or /
fs: 'empty'
},
externals: [nodeExternals()], // Need this to avoid error when working with Express
module: {
rules: [
{
// Transpiles ES6-8 into ES5
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader"
}
}
]
}
}
webpack.config.js:
const path = require("path")
const webpack = require('webpack')
const HtmlWebPackPlugin = require("html-webpack-plugin")
module.exports = {
entry: {
main: './src/js/index.tsx'
},
output: {
path: path.join(__dirname, 'dist'),
publicPath: '/',
filename: '[name].js'
},
target: 'web',
devtool: 'source-map',
resolve: {
extensions: ['.ts', '.tsx', '.html', '.js']
},
module: {
rules: [
{
test: /\.tsx?$/,
exclude: /node_modules/,
use: 'ts-loader'
},
{
test: /\.js$/,
exclude: /node_modules/,
loader: "babel-loader",
},
{
// Loads the javacript into html template provided.
// Entry point is set below in HtmlWebPackPlugin in Plugins
test: /\.html$/,
use: [
{
loader: "html-loader",
//options: { minimize: true }
}
]
},
{
test: /\.css$/,
use: [ 'style-loader', 'css-loader' ]
},
{
test: /\.(png|svg|jpg|gif)$/,
use: ['file-loader']
}
]
},
plugins: [
new HtmlWebPackPlugin({
template: "./src/html/index.html",
filename: "./index.html",
excludeChunks: [ 'server' ]
})
]
}
And the build command is:
rm -rf dist && webpack --mode development --display-error-details --config webpack.server.config.js && webpack --mode development
I'm out of ideas on how to fix this. I have tried removing and reinstalling nodejs, deleting all docker images, etc. Any suggestions would be much appreciated.
Fixed by installing this npm package, importing it on server.js, and monkey-wrenching:
var rp = require('fs.realpath')
rp.monkeypatch()
Unfortunately fixing it didn' give me any more insight on what's wrong with WSL and node, but at least it works.
EDIT:
Since this question seems to be relevant to some, I have since discovered that the real problem is that I was trying to use fs in a class that was bundled with target: 'web' (the second config file I posted). This is another part of the code, and it didn't occur to me that this could be the problem.
The webpack.config.js I posted originally is for an expressJS server, while this other part of the code was for the frontend of the application.
From what I understand, target: 'web' tells Webpack not to bundle and NodeJS functions because this code will be run in a browser. target: 'node' is appropriate for code that will run in a node environment (i.e. an expressJS server, that will run on the backend)
I hope this helps people who are running into this problem.
Do you have jquery in your package.json? I remember getting that error with Create-React-App when I forget to add the jquery cdn to index.html

Webpack bundling custom Utilities separately from App code

I would like to bundle up my TypeScript ReactJs project using webpack. As my project is rather large, I want to bundle the utils separately from the main App code, so I can keep them separate.
I have the following folder structure;
Scripts
- App
- Components
- ComponentOne.tsx
- App.tsx
- Utilities
- Interfaces
- IHelperInterface.ts
- Interfaces.ts
ComponentOne imports IHelperInterface with a an import statement import { IHelperInterface } from '../../Utilities/Interfaces/IHelperInterface';
Along with my custom Utils, I am also using npm for various packages.
So my current webpack config looks like this;
var webpack = require('webpack'),
pkg = require('./package.json');
module.exports = {
entry: {
app: './scripts/app/app',
vendor: Object.keys(pkg.dependencies)
},
output: {
filename: '[name].bundle.js',
path: __dirname + '/wwwroot/js/app'
},
plugins: [
new webpack.optimize.CommonsChunkPlugin({ name: 'vendor', filename: 'vendor.bundle.js' })
],
// Enable sourcemaps for debugging webpack's output.
devtool: 'source-map',
resolve: {
// Add '.ts' and '.tsx' as resolvable extensions.
extensions: ['.ts', '.tsx', '.js', '.json']
},
module: {
rules: [
// All files with a '.ts' or '.tsx' extension will be handled by 'awesome-typescript-loader'.
{ test: /\.tsx?$/, loader: 'awesome-typescript-loader' },
// All output '.js' files will have any sourcemaps re-processed by 'source-map-loader'.
{ enforce: 'pre', test: /\.js$/, loader: 'source-map-loader' }
]
}
};
My vendor files (npm packages) are being bundled together, and currently the rest is then bundled into 1 file. How can I modify the config to bundle my Utils?
I tried adding a 2nd entry point;
entry: {
app: './scripts/app/app',
utils: './scripts/interfaces',
vendor: Object.keys(pkg.dependencies)
},
In the hope that this would work, however it created utils.bundle.js file, but the app.bundle.js file still had all the code in it.

Webpack 2: can't resolve node.js native modules

After bundling I have following errors:
Module not found: Error: Can't resolve 'crypto' in //filePath
It can't resolve five modules: crypto, fs, path, vm and constants - from any file which requires them
I thought it could be because of nvm which I use, but I switched to system nodejs via nvm use system command and webpack still throws these errors.
I also thought it could be target property, so I changed it to node, but it didn't help too (anyway I need electron-renderer, not node).
Important note: I've just migrated from webpack 1. It all works well before I migrated. But these are the only errors I have. Moreover, webpack seems to work fine, it even watches files when I pass --watch option.
Here is my webpack.config.js:
const config = {
target: 'electron-renderer',
context: __dirname,
entry: { app: './app.js', vendor: [/*vendors*/]},
cache: true,
devtool: 'source-map',
watch: false
resolve: {
extensions: ['.js', '.json', '.jsx'],
modules: ["node_modules"]
},
module: {
rules: [
{test: /\.html/, loader: 'html-loader'},
{
test: /\.less$/,
use: ExtractTextPlugin.extract({
fallback: "style-loader",
use: ["css-loader?sourceMap", "less-loader?sourceMap"]
})
},
{
test: /\.css/,
use: ExtractTextPlugin.extract({
fallback: "style-loader",
use: "css-loader?sourceMap"
})
},
{test: /\.(jpg|png|gif|jpeg|svg|otf|ttf|eot|woff)$/, loader: 'url-loader?limit=10000'}
]
},
plugins: [
new ExtractTextPlugin('styles.[contenthash].css'),
new webpack.optimize.CommonsChunkPlugin({
names: ['commons', 'vendor', 'manifest'],
minChuncks: Infinity
}),
new HtmlWebpackPlugin({
template: './index.html',
filename: 'index.html',
hash: false,
inject: 'head',
cashe: true,
showErrors: true
})
],
output: {
publicPath: './',
path: path.join(__dirname, 'dist'),
filename: '[name].[chunkhash].js',
chunkFilename: '[name].[chunkhash].js'
}
};
module.exports = config;
The problem was in worker-loader, which is not in my webpack.config.js (I used it directly when importing file). See this issue for details (not fixed yet).

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