How can I package symbolic link in node_modules with `serverless? - aws-lambda

I am using serverless to package nodejs application. I am using yarn workspace in my project.
- common
- projectA
- projectB
the projectA and projectB are using common module which is managed by yarn workspace. It creates a link inside node_modules/common -> ../common. But when I package the application with sls deploy, it doesn't inlude the link node_modules/common. How can I make it package symbolic link?

You should start using code bundler.
What is code bundler?
What code bundler does:
It scans your AWS Lambda code structure through all of the files, starting from handler file.
It goes through all of the imports to create a tree of dependencies.
Then it inlines all of those dependencies into single "fat" file.
After that you are free to deploy your application, which has only single file.
As you can see, it's a perfect match for AWS Lambda and your use case.
All of the dependencies from common package will be included in the output file.
Also code bundlers have other cool features, like removing all of the unneeded files, that are defined in libraries that you use, but you are not using them directly. Due to this output package size of your Lambda will be a lot smaller, which will decrease cold starts.
How to achieve that using Serveless Framework
The easiest way is to start with serverless-webpack plugin, which includes Webpack (one of the most popular code bundlers) and some most common configurations for it.
After adding this plugin, simply configure it in serverless.yml:
custom:
webpack:
webpackConfig: 'webpack.config.js' # you can remove it, it's the same as default
packager: 'yarn'
Now you need to configure Webpack using webpack.config.js file. There are a lot of possibilities to configure it and the example below is the most basic one:
const path = require('path');
const slsw = require('serverless-webpack');
module.exports = {
entry: slsw.lib.entries,
target: 'node',
mode: slsw.lib.webpack.isLocal ? 'development' : 'production',
stats: 'minimal',
devtool: 'nosources-source-map',
externals: [{'aws-sdk': 'commonjs aws-sdk'}],
resolve: {
extensions: ['.js', '.json'],
},
output: {
libraryTarget: 'commonjs2',
path: path.join(__dirname, '.webpack'),
filename: '[name].js',
sourceMapFilename: '[file].map',
},
};
Now when you call sls package in projectA or projectB, then after unzipping ./.serverless/functionName.zip, you will find just single "fat" file, that will include all of the required dependencies.
During sls deploy phase, this file will be deployed as Lambda handler.
Correctly defining dependencies
Make sure, that common package is listed as dependency of projectA and projectB:
// common/package.json
{
"name": "#your-project/common",
"version": "1.0.0",
"license": "ISC",
}
// projectA/package.json
{
"name": "#your-project/packageA",
"version": "1.0.0",
"license": "ISC",
"dependencies": {
"#your-project/common": "1.0.0"
}
}
Thanks to this, you will be able to reference commons in pakcageA imports via:
import exampleHelper from '#your-project/common/src/exampleHelper';
Project using this approach can be found on my Github here:
https://github.com/PatrykMilewski/serverless-series

Related

Cache transformed node modules with vite/esbuild

vite build uses esbuild to transform both the package dependencies (node modules) as well as the app source code into the target JavaScript specification, i.e. es2015.
I observe that vite/esbuild re-transform the entire sources in ./node_modules every time vite build is run.
How can this build stack be used to keep and reuse the previously transformed files, at least for the entire ./node_modules folder (given dependencies didn't change of course) so that subsequent vite build command invocations run significantly faster?
One way to improve the performance of subsequent Vite build command invocations is by using a caching mechanism. You can use a caching tool such as cache-loader or hard-source-webpack-plugin to cache the transpilation results of the node modules.
This will allow Vite to reuse the previously transpiled files for the node modules, as long as the dependencies haven't changed.
This can greatly speed up the build process.
You can also try to configure esbuild to only transpile the changed files instead of the entire codebase using the -w or --watch option when running the esbuild command. This option tells esbuild to watch the input files and only transpile the files that have been modified.
In Vite, you can configure the esbuild plugin to use the --watch option by adding the following to your vite.config.js file:
const esbuildConfig = {
watch: true,
};
module.exports = {
esbuild: esbuildConfig,
};
Examples :
cache-loader:
Install the package:
npm install cache-loader --save-dev
In your vite.config.js file, configure the cache-loader to be used for transpiling the node modules by adding it as a rule in the build object:
module.exports = {
build: {
...
css: {
...
},
js: {
...
loaderOptions: {
cache: true,
cacheDirectory: 'node_modules/.cache'
}
},
...
}
}
Run your build command ( vite build )
hard-source-webpack-plugin:
install the package:
npm install hard-source-webpack-plugin --save-dev
In your vite.config.js file, import the plugin and add it to the build.plugins array:
const HardSourceWebpackPlugin = require('hard-source-webpack-plugin');
module.exports = {
build: {
...
plugins: [
new HardSourceWebpackPlugin()
],
...
}
}
Run your build command (vite build)
These examples, as you asked in your comment, are for Vite versions 2.5.8 and 3.x. However, in order to use them with Vite 3.x you need to update the build config to match the new format.
Please don't hesitate to write a comment if you still have a problem or questions!

Share code between two repos that require different versions of node

I have a monorepo with this dependency tree:
/root
package.json
/packages
/api <--- requires node v16.x because of a critical dependency
package.json
/ui <--- requires node v14.x because Vercel does not yet support v16.x
package.json
/shared <--- shared code between both /ui and /api
package.json
I'm unable to deploy the /ui package on Vercel because it complains of about the dependency under /api that requires v16.
Is there a way to configure yarn workspaces such the offending dependency can be ignored when building /ui, or is my only option to eject from yarn workspaces and find some other way to share the /shared code?
Another way of asking the question:
I have repo A which must run on node 16, and repo B which must run on node 14. How can I share code between the two repos? Yarn workspaces isn't working for me because it forces all packages to conform to a single node version.
I ended up ejecting /ui from yarn workspaces, and continuing to share code by just importing the files from outside of the package's root directory.
I had a lot of file includes that utilized the following convention because of yarn workspaces:
import { someFunc } from '#project/shared/someFile'
Quite elegantly, I was able to continue sharing code without having to change that syntax at all - by simply updating jsconfig.json to simulate yarn workspaces:
{
"compilerOptions": {
"module": "commonjs",
"baseUrl": ".",
"paths": {
"#project/shared/*": ["../shared/*"]
}
}
}

Reuse package.json version within file

I have a project which uses dependency having having version same as that of the project. So I would like to change the version only in one place and write something like below this in my package.json
{
"name": "my-child-app",
"version": "1.2.3",
"description": "My Application",
"dependencies": {
"my-parent-app": %npm_package_version%
}
}
Basically the child app is always supposed to have version in sync with the parent app. So any approach where I will have to change only one line (instead of two in usual scenario) when I have to upgrade to a newer parent-app would suffice.
Note: I am using frontend-maven-plugin to build the project as child-app is a module of Java Project. parent-app is also built in a same way but they are not in the same code repository so file referencing cannot be used.

Cannot find module after creating and adding plugin in Nativescript

Using the latest version of Nativescript I've created a plugin as per the documentation and after running tns plugin add ../nativescript-keychain I get the message Successfully installed plugin nativescript-keychain.
I can also see that it's been added to the node_modules directory of my app but require("nativescript-keychain") doesn't work as I get the error Cannot find module 'nativescript-keychain'
My plugin package.json looks like
{
"name": "nativescript-keychain",
"version": "0.0.1",
"nativescript": {
"platforms": {
"ios": "2.2.1"
}
}
}
There are several reasons why this might occur; it would be helpful if you provided a repo to see all the code.
package.json doesn't have a link to the source, typically you have a main: "somefile" key.
Did you do tns run ios --emulator after you installed the plugin, you have to rebuild the app before it will take effect, plugins can't be synced via livesync...
Is the code TypeScript or JavaScript, if it is TypeScript it needs to be transpiled to JS before you can add it to your demo application. TNS will NOT compile any TS code in the plugins. Plugins have to ship with the final JS code.
You need typings for TS to use the auto-complete and not throw warnings about what methods are available.

gulp, wiredep and custom sass file

So I made a library that I can bower install using a direct link. I can use this library from another internal application by adding the library name in the dependency of the bower.json file. When other internal application does a bower update, the changes I made on the library will be applied to their application. This part is working very well.
Now, I'd like the other software devs to have freedom to change the styles. They can create css file directly and that will work. However, it's a hackish route. I can provide them the same settings file that I use.
So i tried putting that file in the main section of the bower.json but wiredep is processing it. I put it in exclude and the error is gone when I run gulp.
"main": [
"dist/stylesheet.css",
"src/_settings.scss"
],
this is the code that prevented it from being parsed by wiredep
wiredep: {
directory: 'bower_components',
exclude: ['css/foundation.css','src/_settings.scss']
}
Am I right that I'll have to create a new gulp task and put 'src/_settings.scss' as gulp.src like this
gulp.task('sasstask2', function () {
return gulp.src('src/_settings.scss')
.pipe($.sass())
.pipe(gulp.dest('src/css'));
});
I also like the generate css to be injected to index.html but not sure how to do it? Will wiredep automatically inject it to index.html?

Resources