I have a Node server and multiple controllers that perform DB operations and helpers (For e-mail, for example) within that directory.
I'd like to use source from that directory within my functions. Assuming the following directory structure:
src/
server/
/app/controllers/email_helper.js
fns/
send-confirm/
What's the best way to use email_helper within the send-confirm function?
I've tried:
Symbolically linking the 'server' directory
Adding a local repo to send-confirm/package.json
Neither of the above work.
In principle, your Cloud Functions can use any other Node.js module, the same way any standard Node.js server would. However, since Cloud Functions needs to build your module in the cloud, it needs to be able to locate those dependency modules from the cloud. This is where the issue lies.
Cloud Functions can load modules from any one of these places:
Any public npm repository.
Any web-visible URL.
Anywhere in the functions/ directory that firebase init generates for you, and which gets uploaded on firebase deploy.
In your case, from the perspective of functions/package.json, the ../server/ directory doesn't fall under any of those categories, and so Cloud Functions can't use your module. Unfortunately, firebase deploy doesn't follow symlinks, which is why that solution doesn't work.
I see two possible immediate fixes:
Move your server/ directory to be under functions/. I realize this isn't the prettiest directory layout, but it's the easiest fix while hacking. In functions/package.json you can then have a local dependency on ./server.
Expose your code behind a URL somewhere. For example, you could package up a .tar and put that on Google Drive, or on Firebase Cloud Storage. Alternatively, you can use a public git repository.
In the future, I'd love it if firebase deploy followed symlinks. I've filed a feature request for that in Firebase's internal bug tracker.
Related
Hi everyone,
I use vercel to deploy my project. One of my NextJS project dependencies, located inside node_modules, reads and writes files in its own folder. When I import this dependency, I get the following error:
"errorType":"Runtime.UnhandledPromiseRejection","errorMessage":"Error: EROFS: read-only file system, chmod '/var/task/node_modules/MY_DEPENDENCY/src/FILE'"
Is there a solution?
Check out following thread - https://github.com/vercel/community/discussions/314?sort=new
If you need to store something temporarily, you may try to use /tmp directory.
Limit 512 MB + no guaranty - https://github.com/vercel/vercel/discussions/5320
You did not mention what the project dependency does, however its generally an anti-pattern to use serverless functions to write files as there is no guarantee of existence on the next invocation
Potential directional Solves
It might be better for you depending on the type of file written (assets or flat files ) to a bucket like S3 OR to a database - There are multiple ways to accomplish writing of shared state between functions.
I've created a javascript script that will get information from this api. I'm trying to set this up inside of a google cloud function. I understand how you "require" or "import" a reference normally inside of a google cloud function, and even that you can make reference to a local file. When i downloaded the api.js from the source and try to reference it, i get "bomgarState is undefined" where bomgarState is the reference that i need. I understand that it is looking for a json when an api is being defined but i need to use the api.js. I know that this code can work,when you run this in collaboration with an html that sources said api, i have no problems. I have tried many different solutions such as "require(./api.js)", getting from url, and much more but am unsure if this is something that is supported at this point.
TLDR: can't make reference or source a javascript api inside of google cloud functions, had been sourcing using html, now that we moved to google cloud functions can't figure out how to make reference.
For you to import dependencies and libraries to your Cloud Functions, there are some available options that you can take with JavaScript, but only while using Node.js - without Node it's not possible.
For example, as the documentation Specifying dependencies in Node.js indicates:
A function is allowed to use external Node.js modules as well as local data. Dependencies in Node.js are managed with npm and expressed in a metadata file called package.json.
So, you can use with Node.js the npm to import your dependencies to your Cloud Functions.
Other options are indicated in the following posts from the Community - that I would recommend you to take a look at it - one, for example, would be using the 'gcloud' command to deploy your function. This way, it would upload and deploy with all files from your directory.
Google Cloud Functions include private library
How do I structure Cloud Functions for Firebase to deploy multiple functions from multiple files?
I hope these articles help you, since they indicate the only available options, unfortunately, to upload dependencies on your Cloud Functions.
I'm creating an API for multiple customers. The core endpoints like /users are used by every customer but some endpoints rely on individual customization. So it might be that User A wants a special endpoint /groups and no other customer will have that feature. Just as a sidenote, each customer would also use his own database schema because of those extra features.
I personally use NestJs (Express under the hood). So the app.module currently registers all my core modules (with their own endpoints etc.)
import { Module } from '#nestjs/common';
import { UsersModule } from './users/users.module'; // core module
#Module({
imports: [UsersModule]
})
export class AppModule {}
I think this problem is not related to NestJs so how would you handle that in theory?
I basically need an infrastructure that is able to provide a basic system. There are no core endpoints anymore because each extension is unique and multiple /users implementations could be possible. When developing a new feature the core application should not be touched. Extensions should integrate themselves or should get integrated on startup. The core system ships with no endpoints but will be extended from those external files.
Some ideas come to my mind
First approach:
Each extension represents a new repository. Define a path to a custom external folder holding all that extension projects. This custom directory would contain a folder groups with a groups.module
import { Module } from '#nestjs/common';
import { GroupsController } from './groups.controller';
#Module({
controllers: [GroupsController],
})
export class GroupsModule {}
My API could loop through that directory and try to import each module file.
pros:
The custom code is kept away from the core repository
cons:
NestJs uses Typescript so I have to compile the code first. How would I manage the API build and the builds from the custom apps? (Plug and play system)
The custom extensions are very loose because they just contain some typescript files. Due to the fact they don't have access to the node_modules directory of the API, my editor will show me errors because it can't resolve external package dependencies.
Some extensions might fetch data from another extension. Maybe the groups service needs to access the users service. Things might get tricky here.
Second approach:
Keep each extension inside a subfolder of the src folder of the API. But add this subfolder to the .gitignore file. Now you can keep your extensions inside the API.
pros:
Your editor is able to resolve the dependencies
Before deploying your code you can run the build command and will have a single distribution
You can access other services easily (/groups needs to find a user by id)
cons:
When developing you have to copy your repository files inside that subfolder. After changing something you have to copy these files back and override your repository files with the updated ones.
Third approach:
Inside an external custom folder, all extensions are fully fledged standalone APIs. Your main API would just provide the authentication stuff and could act as a proxy to redirect the incoming requests to the target API.
pros:
New extensions can be developed and tested easily
cons:
Deployment will be tricky. You will have a main API and n extension APIs starting their own process and listening to a port.
The proxy system could be tricky. If the client requests /users the proxy needs to know which extension API listens for that endpoint, calls that API and forwards that response back to the client.
To protect the extension APIs (authentication is handled by the main API) the proxy needs to share a secret with those APIs. So the extension API will only pass incoming requests if that matching secret is provided from the proxy.
Fourth approach:
Microservices might help. I took a guide from here https://docs.nestjs.com/microservices/basics
I could have a microservice for the user management, group management etc. and consume those services by creating a small api / gateway / proxy that calls those microservices.
pros:
New extensions can be developed and tested easily
Separated concerns
cons:
Deployment will be tricky. You will have a main API and n microservices starting their own process and listening to a port.
It seems that I would have to create a new gateway api for each customer if I want to have it customizable. So instead of extending an application I would have to create a customized comsuming API each time. That wouldn't solve the problem.
To protect the extension APIs (authentication is handled by the main API) the proxy needs to share a secret with those APIs. So the extension API will only pass incoming requests if that matching secret is provided from the proxy.
There are several approaches to this. What you need to do is figure out what workflow is best suited for your team, organization, and clients.
If this was up to me, I would consider using one repository per module, and use a package manager like NPM with private or organization scoped packages to handle the configuration. Then set up build release pipelines that push to the package repo on new builds.
This way all you need is the main file, and a package manifest file per custom installation. You can independently develop and deploy new versions, and you can load new versions when you need to on the client-side.
For added smoothness, you could use a configuration file to map modules to routes and write a generic route generator script to do most of the bootstrapping.
Since a package can be anything, cross dependencies within the packages will work without much hassle. You just need to be disciplined when it comes to change and version management.
Read more about private packages here:
Private Packages NPM
Now Private NPM registries cost money, but if that is an issue there are several other options as well. Please review this article for some alternatives - both free and paid.
Ways to have your private npm registry
Now if you want to roll your own manager, you could write a simple service locator, that takes in a configuration file containing the necessary information to pull the code from the repo, load it up, and then provide some sort of method to retrieve an instance to it.
I have written a simple reference implementation for such a system:
The framework: locomotion service locator
An example plugin checking for palindromes: locomotion plugin example
An application using the framework to locate plugins: locomotion app example
You can play around with this by getting it from npm using npm install -s locomotion you will need to specify a plugins.json file with the following schema:
{
"path": "relative path where plugins should be stored",
"plugins": [
{
"module":"name of service",
"dir":"location within plugin folder",
"source":"link to git repository"
}
]
}
example:
{
"path": "./plugins",
"plugins": [
{
"module": "palindrome",
"dir": "locomotion-plugin-example",
"source": "https://github.com/drcircuit/locomotion-plugin-example.git"
}
]
}
load it like this:
const loco = require("locomotion");
It then returns a promise that will resolve the service locator object, which has the locator method to get a hold of your services:
loco.then((svc) => {
let pal = svc.locate("palindrome"); //get the palindrome service
if (pal) {
console.log("Is: no X in Nixon! a palindrome? ", (pal.isPalindrome("no X in Nixon!")) ? "Yes" : "no"); // test if it works :)
}
}).catch((err) => {
console.error(err);
});
Please note that this is just a reference implementation, and is not robust enough for serious application. However, the pattern is still valid and shows the gist of writing this kind of framework.
Now, this would need to be extended with support for plugin configuration, initializations, error checking, maybe add support for dependency injection and so on.
I would go for external packages option.
You can structure your app to have a packages folder. I would have UMD compiled builds of external packages in that folder so that your compiled typescript won't have any issues with the packages. All packages should have an index.js file on each package's root folder.
And your app can run a loop through the packages folder using fs and require all the packages index.js into your app.
Then again dependency installation is something you have to take care of. I think a configuration file on each package could solve that too. You can have a custom npm script on main app to install all the package dependencies before starting the application.
This way, you can just add new packages to your app by copy pasting the package into the packages folder and rebooting the app. Your compiled typescript files won't be touched and you don't have to use private npm for your own packages.
I am new to React and was learning how to hide API keys gotten from GitHub API and from other APIs. I found out that it is possible to hide keys in .env files and get access to those keys by using REACT_APP and ensure that .env file is added into .gitignore file in order not to be submitted to a server. `The question is Is it considered best practice the way of hiding keys I described above. Secondly, is .env file added to a server even if we add .env file into .gitignore file.
If you are going to be passing the contents of the environment data file to React, which is client-side code, then it isn't likely to be very useful for keeping things secret.
Mostly this will be useful for keeping your various environments separate (e.g. so you don't accidentally use the URL for your test API server in the production deployment of your app).
If you were using this for server-side code, then it would be useful to keep your secrets secret and not publishing them in a git repository (that you might want to allow other people access to).
Whether or not the environment data file would be deployed to your server would depend on your deployment process. If your deployment process consisted of nothing more than checking out your git repository to the live server, then no, it wouldn't be deployed.
I have a Javascript library that I wrote for a client. This is written in typescript using webpack and "compiles" into javascript. I want to give the client access to the distribution files but not the whole source. Ideally they can install from the command line to make installing updates easy.
The library provides some javascript functions. The client would install the script in one location on their server. They could then include the javascripts in their web surveys as they need it.
+project
+dist
-main.js
-vendor.js
-index.html
-README.md
-LICENSE.md
+src
-index.js
-index.html
...
My initial thoughts are to give them access to a private git repository that contains only the distribution files. So my project would be a git repository, only I would have access to this repo. I would then copy the contents of the dist directory to a release directory. The release directory would be another git repo I could supply to the client.
I'm not sure this is the best approach.
It was suggested that GitHub releases may be an option - but I don't use GitHub, I use GitLab and would like to continue to do so.
npm also doesn't seem like a good choice. It installs files into the node_modules directory and creates a package.json file. That's going to be confusing to my client and isn't "clean".
It sounds like a second git repository as submodule could work for you. On your side it would receive the built files, and on the clients side they could consume them.
I'd suggest making use of tags to indicate significant versions in the submodule
By using a separate repository there is no risk of leaking the original files.
Alternatively you could package the files as a zip, and upload somewhere like S3 as part of your ci process, and write a script to give the client that can automatically download the distribution files - but this seems more complex than just using a package manager like npm.