I have an Express API already in production using Firebase Cloud Functions but I need to add custom domain to it. I followed these instructions to create a custom domain for Cloud Functions using Firebase Hosting and end up with the following firebase.json
{
"functions": {
"predeploy": [
"npm --prefix \"$RESOURCE_DIR\" run lint",
"npm --prefix \"$RESOURCE_DIR\" run build"
],
"source": "functions"
},
"firestore": {
"rules": "firestore.rules",
"indexes": "firestore.indexes.json"
},
"emulators": {
"functions": {
"port": 5001
},
"firestore": {
"port": 8080
},
"ui": {
"enabled": false
}
},
"hosting": [{
"site": "devbp",
"target:":"devbp",
"public": "public",
"rewrites": [
{
"source": "/api/**",
"function": "api"
}
]
}]
}
index.ts
import { functions } from './utils/exports-converter';
import App from './web-api/configs/app';
export * from './functions';
export * from './backup/schedules';
export * from './firestore-triggers/credits/credits-triggers'
export * from './schedules/transactions/aggregations-schedules';
export const api = functions.runWith({
memory: '1GB',
timeoutSeconds: 300
}).https.onRequest(App.express);
exports-converter.ts
import * as express from "express";
import * as functions from "firebase-functions";
import * as admin from "firebase-admin";
export { express, functions, admin };
app.ts
import * as cors from "cors";
import * as bodyParser from "body-parser";
import Routes from "./routes";
import { express } from "../../utils/exports-converter";
class App {
public express: express.Application;
constructor() {
this.express = express();
this.init();
this.mountRoutes();
}
private init() {
const corsOptions = { origin: true };
this.express.use(cors(corsOptions));
this.express.use(bodyParser.raw());
this.express.use(bodyParser.json());
this.express.use(bodyParser.urlencoded({ extended: true }));
}
private mountRoutes() {
Routes.mount(this.express);
}
}
The problem is that the endpoints inside the api are not reachable, e.g. GET devbp.web.app/api/user?id=123 which returns Cannot GET /api/user. This response indicates that Express is handling the requests (if not, the Hosting would throw a 404 page) but not as expected.
I believe that I'm missing something in my firebase.json because the same api, as said above, is currently in production.
Any thoughts on it?
According to the documentation (here as well) hosting syntax is:
"hosting": {
...
}
while in the presented firebase.json you have [{ ... }].
Try to remove square brackets.
I am not sure, if I am following the logic, however I don't see any new App anywhere in the code. If I understand correctly if you do not create new App object you will not run it's constructor so express app will not be created.
2nd thing I think :) is that, again according to my understanding, there should be Express get() method called when GET request is called by http GET requst.
I found this tutorial it's not cloud function, however the logic is similar. New instance App is created and get method invoked.
Related
I'm building a Nuxt-electron-prisma app and I kinda stuck here. when I use prisma normally as guided every thing is fine on dev but on build i get this error :
A javascript error occurred in the main process
Uncaught exception:
Error: can not find module : '.prisma/client'
I tried changing prisma provider output to ../resources/prisma/client
generator client {
provider = "prisma-client-js"
output = "../resources/prisma/client"
}
and in main.js of electron
const { PrismaClient } = require('../resources/prisma/client');
const prisma = new PrismaClient()
but I get error Cannot find module '_http_common' at webpackMissingModules in both dev and build ! which by others opinion is caused when using prisma on client-side but I only use it on background.js (main.js of the my boilerplate)
I'm using Nuxtron boilerplate for Nuxt-electron which is using yml file for electron-builder config file and in it I also added prisma to files property:
appId: com.example.app
productName: nuxt-electron-prisma
copyright: Copyright © 2021
nsis:
oneClick: false
perMachine: true
allowToChangeInstallationDirectory: true
directories:
output: dist
buildResources: resources
files:
- "resources/prisma/database.db"
- "node_modules/.prisma/**"
- "node_modules/#prisma/client/**"
- from: .
filter:
- package.json
- app
publish: null
and still get errors
in my win-unpacked/resources I have this only: win-unpacked\resources\app.asar.unpacked\node_modules\#prisma\engines
and of course my package.json
{
"private": true,
"name": "nuxt-electron-prisma",
"productName": "nuxt-electron-prisma",
"description": "",
"version": "1.0.0",
"author": "",
"main": "app/background.js",
"scripts": {
"dev": "nuxtron",
"build": "nuxtron build"
},
"dependencies": {
"electron-serve": "^1.0.0",
"electron-store": "^6.0.1",
"#prisma/client": "^3.0.2"
},
"devDependencies": {
"#mdi/font": "^6.1.95",
"#nuxtjs/axios": "^5.13.6",
"#nuxtjs/device": "^2.1.0",
"#nuxtjs/dotenv": "^1.4.1",
"#nuxtjs/vuetify": "1.12.1",
"core-js": "^3.15.1",
"electron": "^10.1.5",
"electron-builder": "^22.9.1",
"glob": "^7.1.7",
"noty": "^3.2.0-beta",
"nuxt": "^2.15.7",
"nuxtron": "^0.3.1",
"sass": "1.32.13",
"swiper": "^5.4.5",
"prisma": "^3.0.2",
"vue-awesome-swiper": "^4.1.1"
}
}
The solution provided by Mojtaba Barari works but it results in #prisma packages being present in both resources/app/node_modules and resources/node_modules.
There is a better way how to do it:
{
"build": {
"extraResources": [
{
"from": "node_modules/.prisma/client/",
"to": "app/node_modules/.prisma/client/"
}
],
}
}
In this case, the Prisma client files will be copied directly to resources/app/node_modules where other #prisma packages are already present and so you will save ~ 10 MB compared to the other solution.
EDIT:
My previous solution doesn't work if an application is packaged into an asar archive. You need to use files field instead:
{
"build": {
"files": [
{
"from": "node_modules/.prisma/client/",
"to": "node_modules/.prisma/client/"
}
],
}
}
This is a universal solution which works even if you don't use an asar archive.
Ok, I finally solved it!!
first of all no need to change client generator output direction!
//schema.prisma
datasource db {
provider = "sqlite"
url = "file:../resources/database.db"
}
generator client {
provider = "prisma-client-js"
// output = "../resources/prisma/client" !! no need for this!
}
then in electron-builder config add ./prisma , #prisma and database
// my config file was a .yml
extraResources:
- "resources/database.db"
- "node_modules/.prisma/**/*"
- "node_modules/#prisma/client/**/*"
// or in js
extraResources:[
"resources/database.db"
"node_modules/.prisma/**/*"
"node_modules/#prisma/client/**/*"
]
this solved `Error: cannot find module : '.prisma/client'
but this alone won't read DB in built exe file!
so in main.js where importing #prisma/client should change DB reading directory:
import { join } from 'path';
const isProd = process.env.NODE_ENV === 'production';
import { PrismaClient } from '#prisma/client';
const prisma = new PrismaClient({
datasources: {
db: {
url: `file:${isProd ? join(process.resourcesPath, 'resources/database.db') : join(__dirname, '../resources/database.db')}`,
},
},
})
with these configs I could fetch data from my sqlite DB
we are using nuxt 2.14.12 and #nuxtjs/router 1.5.0
we are trying to use runtime config to make some HTTP request client side.
here is our router.js
export async function createRouter(ssrContext, createDefaultRouter) {
[...]
try {
const res = await axios.get(`${config.public.apiBaseUrl}/myslug`)
} catch (e) { }
[...]
}
here is the config file
[...]
const apiBaseUrl = `${process.env.NUXT_ENV_MY_API_URL || 'http://my-dev-domain.com'}`
[...]
export default {
apiBaseUrl,
},
private: {
apiBaseUrl,
},
[...]
here is our nuxt.config.js
export default {
[...]
publicRuntimeConfig: config.public,
privateRuntimeConfig: config.private,
[...]
buildModules: [
['#nuxtjs/router', { keepDefaultRouter: true }],
],
[...]
router: {
linkActiveClass: 'current-menu-item'
},
[...]
}
we use nuxt build in our CI and later at runtime we use nuxt start
at runtime, despite on server side the env variable NUXT_ENV_MY_API_URL is correctly set, on the client site the variable looks hardcoded (I think webpack replace it) and we get the value present on build time (http://my-dev-domain.com)
is there a way to use the runtime config on the client side?
thank you
Development using nodejs for running (--experimental-modules)
Current visual studio code intelligence import as below
import config from "./config";
but required as below
import config from "./config.js";
Without .js getting error as below
internal/modules/esm/resolve.js:61
let url = moduleWrapResolve(specifier, parentURL);
^
Error: Cannot find module C:\Uday\Projects\practice-server\config imported from C:\Uday\Projects\practice-server\index.js
at Loader.defaultResolve [as _resolve] (internal/modules/esm/resolve.js:61:13)
at Loader.resolve (internal/modules/esm/loader.js:85:40)
at Loader.getModuleJob (internal/modules/esm/loader.js:191:28)
at ModuleWrap.<anonymous> (internal/modules/esm/module_job.js:42:40)
at link (internal/modules/esm/module_job.js:41:36) {
code: 'ERR_MODULE_NOT_FOUND'
}
So i need visual studio code intelligence for importing with extension??
//index.js
import express from "express";
import config from "./config.js";
const api_app = express();
const api_port = config.api_port
api_app.listen(api_port, () => {
console.log(`Practice Server started on ${api_port}`);
});
//package.json
{
"name": "practice-server",
"type": "module",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"express": "^4.17.1"
}
}
//config.js
let config = function () { };
config.api_port = 6000;
export default config;
In the global settings (or the project settings), add the following configuration:
// Preferred path ending for auto imports.
// - auto: Use project settings to select a default.
// - minimal: Shorten `./component/index.js` to `./component`.
// - index: Shorten `./component/index.js` to `./component/index`
// - js: Do not shorten path endings; include the `.js` extension.
"javascript.preferences.importModuleSpecifierEnding": "js",
Note that at the moment this only works for auto imports (i.e via intellisense when referencing an export of another file and VSCode imports it automatically). It does not work with with autosuggest when typing the import statement manually.
I always used my config.js like this this. May be it can help you.
const config = require('./config');
//Now access value from config
const sys_dbconfig = config_data['sys_database'];
const user = configdata['system_admin_name'];
Here is my config.js
var config = {
"sys_database": {
"user": 'postgres',
"host": 'localhost',
"database": 'postgres',
"password": 'postgres',
"port": "5432"
},
"system_admin_name": "system",
"url":"http://xxx.xx.x.xxx:3000/wscalc1?wsdl"
}
module.exports = config;
I'm trying to use Nuxt JS's 2.9.2 generate object to generate dynamic pages as static files using my .env file to pull a URL, I'm having difficuility in getting it to properly link up:
nuxt.config.js
require('dotenv').config();
import pkg from './package'
import axios from 'axios'
export default {
mode: 'universal',
env: {
blog_api: process.env.BLOG_API || "http://localhost:3000/articles/blogs.json"
},
/*
** Build directory
*/
generate: {
dir: 'dist-next',
routes: function () {
return axios.get(`${process.env.blog_api}`)
.then((res) => {
return res.data.blogs.map((blog) => {
return '/posts/view/' + blog.title
})
})
}
}
}
The above code, more specifically ${process.env.blog_api}, can't seem to resolve the routes, despite it working perfectly if I replace it with my own local domain.
.env
BLOG_API="http://my-local-domain.clone/articles/blogs.json"
EDIT:
Updated code with my config, http://my-local-domain.clone/articles/blogs.json is inside of static/articles
You should use dotenv module:
https://www.npmjs.com/package/dotenv
More Info about configuration with NUXT you have here:
https://samuelcoe.com/blog/nuxt-dotenv/
You probably want to set your env property in nuxt.config.js, for example:
module.exports = {
env: {
BLOG_API: process.env.BLOG_API_URL,
},
In your component, you can now use them :
makeAsyncCall({
to: process.env.BLOG_API,
})
I'm creating a angular app that talks to a node backend express application and using a config file to set env variables in my node app I can access my config file like this:
index.js
var port = config.get("server:port");
var server = app.listen(port, function() {});
My config file looks like this:
app.config.js
module.exports =
{
"server":{
"host":"localhost",
"port":3000
},
"mongodb": "",
"redis": {
"loadBalancerInstance": {
"host": "server",
"port": {
"default": "6379"
}
}
},
"elastic": {
"server": "server",
"port": "9200",
"user":"foo",
"password":"bar"
},
"log": {
"level": "info",
"filename": "",
"console": true,
"logio": {
"port": "28777",
"node_name": "this-server-name",
"host": "server"
}
}
};
I have statically defined the route/port to a backend
datafactory.js
angular.module('dashboard.factories')
.factory('DataFactory', function($http, $q, FormatFactory) {
var backend = function(apiEndPoint, clientKey) {
clientKey = clientKey || "";
var deferred = $q.defer();
$http.get("http://localhost:3000/<-(pull this from config file)" + apiEndPoint + "/" + clientKey)
My question is how can I access app.config.js within angular and dynamically set host/port within my angular service
I suppose if you're stuck on using the same configuration file that your node server uses, you'll have to make the .js file available to a GET request from your app, which you'll then have to parse out the string into JSON.
Edit:
You're going to have to have two configuration files, one available to your node server, and one for your angular app. Now, if you want the source to be one file, you could build that into your build process - if you use something like gulp or grunt, this would be reasonably easy. It could take the singular config file and build two files - the node server config file, and an angular module (I would suggest a constant or value) that you could inject into your data services.
If you're serving the config file at localhost:3000/config, you can do this:
angular.module('dashboard.factories')
.factory('DataFactory', function($http, $q, FormatFactory) {
$http.get('localhost:3000/config')
.success(function(config) {
$http.get(config.server.host + ":" + config.server.port)
// whatever you want here
});
});