Lambda function with additional dependencies - javascript

I'm starting a CDK lambda project which gets the source code like this:
code: lambda.Code.fromAsset("resources"),
handler: "synthetic_test.main",
There's a single javascript file synthetic_test.js in that folder.
This seems to work but I can't figure out how to make it so that I could do:
const axios = require("axios");
in that file.
For some reason it seems to be able to import:
const AWS = require("aws-sdk");
but nothing else.
I did yarn add axios which added it to the package.json of my CDK project. But that does not really seem to help the lambda a lot.

The AWS Lambda runtime environment includes native language libraries and the relevant language-specific AWS SDK.
It does not contain arbitrary third-party packages. You need to either package those dependencies with your code or create a Lambda Layer that includes the dependencies and configure your Lambda function to use the Lambda Layer.
To package CDK app dependencies, see #aws-cdk/aws-lambda-nodejs and here.

I went with packaging dependencies with my code
My cdk went to
// 👇 define PUT account function
const putAccountLambda = new lambda.Function(this, "put-account-lambda", {
runtime: lambda.Runtime.NODEJS_14_X,
handler: "main.handler",
code: lambda.Code.fromAsset(path.join(__dirname, "/../src/put-account/dist")),
environment: {
REGION,
ADMINS_TABLE,
ADMINS_TABLE_PARTITION_KEY,
HASH_ALG,
}
})
With dist being the folder with a packed main.js file. And this file has a handler entrypoint. I had to update the package.json of these lambdas with packed dependencies.
{
"name": "put-account",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"build": "webpack --mode=production --env env=prod",
"build:dev": "webpack --mode=development --env env=dev"
},
"author": "",
"license": "ISC",
"devDependencies": {
"webpack": "^5.66.0",
"webpack-cli": "^4.9.1",
"webpack-merge": "^5.8.0"
},
"dependencies": {
"aws-sdk": "^2.1058.0",
"crypto": "^1.0.1",
"uuid": "^8.3.2"
}
}
And I updated the package.json of my cdk project to these scripts.
"build": "tsc && npm run build:webpack",
"build:webpack": "for file in ./src/*; do (cd $file && npm i && npm run build) & done",
"build:beta": "tsc && npm run build:webpack:beta",
"build:webpack:beta": "for file in ./src/*; do (cd $file && npm i && npm run build:dev) & done",
Notice that my file structure is as follows:
./
bin
lib
src
package.json
With src holding the source code for my project's lambdas.
I am not sure if you are familiar with webpack, but I have divided my webpack configuration in common, dev, prod.
A dev webpack configuration is specially useful for debugging because otherwise you lose line numbers among other useful information when something goes wrong on runtime.

Related

How to properly expose subpaths in package.json using the ”exports” key?

I’ve released a NPM package which is a plugin for a framework where only the main entry of my package.json is needed for usage in the framework and its environment. I also want to be able to use a subpath of the plugin in order for users to be able to use the plugin outside of this framework as well, which will require that the main entry point is never initialized as there are framework specific dependencies used there which I don't want to initialize when using this plugin outside of the framework.
My project structure looks like this:
.
├── index.js
├── submodule.js
└── package.json
Source code for the sake of this example looks like this:
// index.js
export default function () {
return "foo";
}
// submodule.js
export default function () {
return "bar";
}
// package.json
{
"name": "my-package",
"version": "1.0.0",
"description": "",
"main": "index.js",
"type": "module",
"exports": {
".": "./index.js",
"./submodule": "./submodule.js"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "MIT"
}
According to Node.js documentation on this matter, this setup should allow me to use my package like this:
import myPackage from ’my-package’
import mySubModule from ’my-package/submodule’
In order to be able to test my package locally I run npm link in the project root of my npm package and then in another project i run npm link my-package. Now that I try to run the project (using parcel-bundler) that imports my-package and my-package/submodule like in the example above I get the following exception:
Cannot resolve dependency 'my-package/submodule'
I'm using NVM with Node v.12.18.4 and NPM v.7.15.0. I have also tried with Node v.14.17.0 but the issue persists. What am I missing?
It seems that the project setup is correct and that the problem lies in the parcel-bundler which does not support package.json#exports yet. There's currently an open issue on this matter.

Webpack: prebuild lifecycle hook for libraries

I'm the author of a library and I need a script to be run each time before webpack bundles my library into the user's app code.
My library's package.json would be something like this:
{
"name": "some-js-library",
"version": "0.1.0",
"scripts": {
"prebuild": "./path/to/my-libs-prebuild-script.js"
}
}
The user's package.json could be anything, for example:
{
"scripts": {
"//": "or however the user uses webpack",
"build": "webpack"
},
"dependencies": {
"some-js-library": "^0.1.0"
}
}
I don't have any control over my users' package.json, so I'm left to wonder if it's possible to have my-libs-prebuild-script.js executed every time before webpack starts building?
Ideally this would be a standard that every bundler agrees on, but a webpack only solution would be fine.
Thanks!

How can I incorporate JS libraries into my NPM build script?

My current site is build with html+css (scss) and using a NPM build script (see below). I now want to add a few JS libraries to my website (for example: lozad).
So far I've downloaded the dependencies for it. As I'm not familiar with JS, I don't understand the other steps I need to take. I tried following the documentation but it's not working so far.
I now assume that this is because my current NPM build script doesn't track JS, so any JS wouldn't be shown on my devserver. So maybe it did work, but just not in test?
Can anyone point me in the direction of what I need to do to make it working, and/or how to update my NPM script?
"scripts": {
"watch:sass": "node-sass sass/main.scss css/style.css -w",
"devserver": "live-server --browser=firefox",
"start": "npm-run-all --parallel devserver watch:sass",
"compile:sass": "node-sass sass/main.scss css/style.comp.css",
"concat:css": "concat -o css/style.concat.css css/icon-font.css css/style.comp.css",
"prefix:css": "postcss --use autoprefixer -b 'last 10 versions' css/style.concat.css -o css/style.prefix.css",
"compress:css": "node-sass css/style.prefix.css css/style.css --output-style compressed",
"build:css": "npm-run-all compile:sass concat:css prefix:css compress:css"
},
"devDependencies": {
"autoprefixer": "^9.6.0",
"concat": "^1.0.3",
"node-sass": "^4.12.0",
"npm-run-all": "^4.1.5",
"postcss-cli": "^6.1.2",
"webpack": "^4.35.3",
"webpack-cli": "^3.3.6"
},
"dependencies": {
"aos": "^2.3.4",
"lozad": "^1.9.0",
}
}
You just need to give the relative path to the dependency and run the script like so:
"scripts": {
...
"lozad": "npm run ./node_modules/lozad/index.js --argument"
}
Note that this is only assumed data. The real path and file are probably called something else (Just look into the node:modules folder for lozad).
According to this article, you can also omit the path and the npm rum when there is a .bin folder for that dependency, but I have not tested that.
Edit
In case you meant on how to use the library locally.
You have to add the package to your dependencies (Like you did) and then call
npm install
in your project directory. It will install all your dependencies specified in package.json.
You can omit the manual "add dependency to file" step by simply calling:
npm install --save lozad
After that you can use it in your project like so:
// using ES6 modules
import lozad from 'lozad'
// using CommonJS modules
var lozad = require('lozad')
If you don't know which one to use, just try them - your IDE will tell you if something is wrong.
When you imported the library, you can use it like described at the Usage Description.

package.json - how to determine what parts of the module are installed

I have a project structure like this:
__tests__
example
src
.bablerc
.eslintignore
.eslintrd
.gitignore
package.json
package-lock.json
README.md
and package.json parameters like:
{
"name": "",
"version": "0.0.1",
"description": "",
"main": "src/index.js",
"scripts": {
"test": "jest"
},
"files": [
"src/"
],
"repository": {
"type": "git",
"url": "url"
},
"jest": {
},
"devDependencies": {
},
"peerDependencies": {
}
}
When I npm install this modules I only get src folder with an empty index.js file. The goal was to only have the user install all of the src folder and not the example part since that is an example app. I thought that "files": ["src/"], would solve this. However it's not doing what I would expect. I don't see anything that is in the src folder. It's empty!
npm docs say:
The optional files field is an array of file patterns that describes
the entries to be included when your package is installed as a
dependency. File patterns follow a similar syntax to .gitignore, but
reversed: including a file, directory, or glob pattern (*, **/, and
such) will make it so that file is included in the tarball when it’s
packed. Omitting the field will make it default to [""], which means
it will include all file
How do I allow the user to install all of the src folder and ignore the example folder?
I'm on npm 5.6.0 and node v9.11.2
Almost there! Files entry behave like in a line a .gitignore. That works:
"files": ["src"]
For testing purposes, you can run npm pack --dry-run to check in the pack reports what files would be included when running npm install on the package you're developing.

Create vendor.js bundle with pure npm script

I am trying out the modern approach to build javascript applications without Grunt or Gulp. I am creating my build utilities by just using the scripts key word in package.json.
It works great, but I ran into a challenge. Is there a good way to create separate vendor.js and app.js bundles without making every dependency explicit in the browserify command (or alternatively passing a list of deps to the browserify command)?
Something better than:
"dependencies": {
"react": "latest",
"react-dom": "latest",
"redux": "latest",
"d3": "latest"
},
"devDependencies": {
"browserify": "latest"
},
"scripts": {
"vendor": "browserify -r react -r react-dom -r redux -r d3 > vendor.js",
"app": "browserify -x react -x react-dom -x redux -x d3 ./app/main.js > app.js"
}
Preferable, I would recycle the information stored in the dependencies keyword. Obviously, I do not want bundle devDependencies or dependencies not used in my code (even though the latter can be prevented by good maintenance of the requirements).
Yes, it is possible. Whether the solution is very elegant, I'll leave up to you to decide. Basically it boils down to something like the following (incomplete, browserify not yet called) snippet:
"scripts": {
"init": "npm ls -json --depth 0 | jq .dependencies | jq keys[]",
"vendor": "npm run --silent init | sed 's/\\(.*\\)/-r \\1/g' | xargs"
},
The init script is used to extract the dependencies. The vendor script calls this script, and converts it to the input parameters for browserify.
Note 1: I'm using jq to extract information from the dependencies tree.
Note 2: construction of the argument list can also be done in the init script. You will have to provide an environment variable to distinguish between the -r or -x options.

Categories

Resources