Is it possible to ensure iisnode respects NODE_PATH in Azure? - node.js

It is not uncommon to want to be able to have non-relative imports, for example, for configuration, etc...
In the world of running a node executable on your own (development env, any cloud provider... things like that) you can simply set an env var and have it respected by the node runtime.
Imagine a project structure like so:
dist
|--foo
|--bar
|--baz
app.js
|--config
in app.js with NODE_PATH=dist, I can simply require('config') and have what I need.
Within Azure App Services, it appears to ignore NODE_PATH from Application Settings. Is something missing or is this not possible?

In Azure App Services, you can set the NODE_PATH environment variable in the Azure portal with the following steps.
1, Create the D:\home\site\my_node_modules\config directory and put the index.js file in where. In this case, I just export the "name" variable.
// D:\home\site\my_node_modules\config\index.js
var name = "foobar";
// export it
exports.name = name;
2, Navigate to your App Service in the Azure portal, click on Application settings in the SETTING menu and then set the NODE_PATH variable as below:
3, In the app.js file, you can simply require('config') like this:
var http = require('http')
var config = require('config')
http.createServer(function (req, res) {
res.end(config.name)
}).listen(process.env.PORT || 3000)
4, At last, it works fine.

Related

Site is deployed on Azure, but I cannot get access index.html

I am trying to build and release front-end app based on quasar on Azure Portal.
Building is OK.
Releasing is OK, but when I go to the apps link I see standard welcome screen:
I checked deployed code via SSH it is there, but it is located on "/home/site/wwwroot/index.html"
How do I point to the correct folder with my app? Thank you!
Firstly there is an official doc about this: how to set the default document in a Node.js app.
It uses express to solve it, Create index.js there with the following code, then restart your app then it will work.
var express = require('express');
var server = express();
var options = {
index: 'index.html'
};
server.use('/', express.static('/home/site/wwwroot', options));
server.listen(process.env.PORT);
Except this, there is another way to solve it, use pm2 since that is already part of the stack. Add the below startup command for the app:
pm2 serve /home/site/wwwroot --no-daemon
After restart the app, it will pick the index pages from the wwwroot.

When is process.env set to NODE_ENV?

I had to add this code to my project that has Express as a back end and React as a front end in order to deploy to Heroku (along with some other adjustments like the heroku-postbuild field). I am new to Express/Node and read process.env is the Node environment, but what does it mean to just check if it exists/is set to true? I see people use it to set process.env.NODE_ENV to development or production but am not familiar with this usage.
if (process.env.NODE_ENV) {
app.use(express.static('client/build'));
const path = require('path');
app.get('*', (req, res) => {
res.sendFile(path.resolve(__dirname, 'client', 'build', 'index.html'));
});
}
if condition is there to check if NODE_ENV has been set or not (e.g., "" will evaluate to false).
* inside app.get() is a wildcard that matches any route a user could type in a browser for this server (i.e., http://localhost/*).
So what it does is that if the NODE_ENV is set to something (not necessarily dev or production environment), then for any route (or any web page on the site) requested, you are going to send the client/build/index.html file back - basically render an index (main) page of the website.
This environment variable (i.e., NODE_ENV) is defined, well, as an environment variable in some computer (e.g., VM somewhere on the cloud like Heroku). On a cloud, it would probably have "production" set as a value. On your laptop, it may not have anything as you are just testing it out, playing with it, etc. But production environment is quite important because this is where users of your app can see and use your app.
According to Express.js docs, "Setting NODE_ENV to “production” makes Express cache view templates; cache CSS files generated from CSS extensions; and generate less verbose error messages." Ref: https://expressjs.com/en/advanced/best-practice-performance.html
My guess is that it sends this index.html file while on Heroku, and does something else (depending on defined routes) when it is not.
This link may also help: https://dev.to/flippedcoding/difference-between-development-stage-and-production-d0p
P.S. Natalie noted that Heroku sets Node.js applications to use NODE_ENV=production by default since 2015. Ref: https://devcenter.heroku.com/changelog-items/688

Node.js express: access application config from required modules

I've got a large Node.js Express API to build, so I want to make sure my solution architecture is stable and scalable.
The routes are defined each in its own separate file and stored in /routes folder. There's an index.js file as well, where all of the child routes are registered to the master router.
There's an application configuration file /config/app.js:
module.exports = {
development: {
configVar: 123
},
test: {
configVar: 456
},
production: {
configVar: 789
},
}
The config object is loaded in the main application index.js file:
const path = require("path");
const env = process.env.NODE_ENV || "development";
const config = require(path.join(__dirname, 'config', 'app.js'))[env];
Now that I have the config object, I'd like to pass it down to whatever consumer. For Express app it's mostly the routes. Loading the config repeatedly in each module would be kind of redundant. So I have set up my main routes module (/routes/index.js) as follows:
const express = require('express');
const router = express.Router();
module.exports = {
init: function(config) {
router.use('/test', require('./test').init(config));
return router;
}
}
And the /test route (/routes/test.js):
const express = require('express');
const router = express.Router();
module.exports = {
init: function(config) {
router.post("/", function(req, res) {
res.send('hello world');
});
return router;
}
}
I also like that with this structure I can mock the config object when testing the routes. My question is, if this can be considered a good pattern for Express application, or perhaps there is some convention to follow.
There are many ways to skin a cat and many more ways to setup an express project.
The one thing that jumps out at me as a good thing to change is your configuration method. Your approach makes total sense, but there's a module called config which works in much the same way you've illustrated but you won't need to list every option for every environment.
Using this module you can have a default.json file which contains all of your base configurations. You can then override it with a file which matches the name of your environment such as development or test without having to do it by hand.
More importantly, it will also let you map from your applications configurations to Environment Variables. You very rarely want to store your applications configuration values in the codebase itself, especially when we're talking API keys and secrets. The last thing you want to do is commit API keys / secrets into version control. The config module linked above will allow you to define environment variable mappings which means you can feed them in via the systems environment variables instead.
I should note finally that there are many modules which act in a similar way to config and they all function slightly differently. You might also want to consider nconf which is also a brilliant module.

where to store api keys in express node for Heroku

I am finishing up a node express App where I have an API key for Sendgrid and Stripe but I am not sure how to store these in my app that will be deployed on Heroku (also a few other variable I would like to store similarly like db password and what not). I saw online many people were using process.env so after some looking I tried using dotenv npm and even with some problems with the structure of the app after trying to use the dotenv for my sendgrid key I got an error every time.
My question is can somebody supply some detailed instructions or a way to securely store API keys in my node express app that I will be deploying to Heroku?
P.S. I followed a tutorial to implement Passport.js for Oauth2 through facebook, google and linkedIn so users can easily log in to the application. The app secrets, id and callbacks are retrieved from a json file in a folder call config in my application. Is this information secure at least in its placement and retrieval in the application? Should I do something similar for my sendgrip and stripe api keys? (picture below)
You can set up your folder directory like this:
config.js
var config = {};
//development
var env = process.env.NODE_ENV || 'development';
if(env === 'development'){
config = require('./env/development');
}else if (env === 'test'){
config = require('./env/test');
} else if(env === 'production'){
config = require('./env/production');
}
module.exports = config;
development.js
var envFile = __dirname + '/env.json';
var jsonfile = require('jsonfile');
var envVars = jsonfile.readFileSync(envFile);
module.exports = {
value: envVars["VALUE"]
};
production.js
module.exports = {
value: process.env.VALUE
};
test.js
module.exports = {
value: 'Some value'
};
The basic idea here is that each developer can configure their own keys in their own env.json file. For production, you can store these in a secure file somewhere and load them into the environment however you want prior to running your application. Using heroku, it makes it easy to configure these environment variables and stores them for you. Check it out here
You can also ommit any details you may not need like development or test stuff.
Edit: An example
Try this from the command line first to get an idea of what is happening. In this example I am using linux. If you are using anything else just research how to set the environment variables in the command line you are using.
app.js
var config = require('./config/config');
//get value from config
var value = config.value;
Set environment variables from bash command line
$: VALUE="my value"
$: NODE_ENV="production"
$: export VALUE
$: export NODE_ENV
Run the application
$: node app.js
or if you are using npm scripts
$: npm start
When you run the application node will automatically load process.env with every environment varaible defined within the command line shell. Now, if you are using heroku you can follow the link I posted earlier in this answer and you don't have to set them. Just define them in heroku interface and it will load them for you.

NPM - path to root of the application

I am developing a NPM package, which needs to require a module from the application root. Think of it as the package requiring a properties module, which is placed in the application root by the user.
How do I get the path to root of the application?
UPDATE:
To summarize what I am trying to do, express allows you to do something like this:
app.use(express.router(myNPMModule.router));
The router function will get app as the parameter. The idea is to allow the users to specify the routes in a separate file, and they just need to follow certain conventions like putting their controllers in /controllers folder, and my module will be able to dynamically parse the path, and then invoke the correct method in the correct module. I have already got it working, but just realized that if I package it in NPM, I no longer have access to the path of the app, so I can't invoke a controller module's method dynamically.
Make the user call a function that sets the variables:
myModule.setProps(json)
OR
myModule = new MyModule(json)
Then the user can require their root config and init your module with it.
Update In response to edited question:
Express allows you to define routes like this:
var routes = require('./routes')
app.get('/info', routes.info);
//Routes Module
exports.info = function(req, res) {
res.render('info', {title: 'Express'})
};
I believe this is exactly what you are trying to do. Is it not?
Update 2:
You can find the directory the currently executing script is in using __dirname
console.log(__dirname);
I have same question.
And I can only find this environment variable help:
process.env.PWD
It would always point to the root of your application path where it running.
Try this.
var path = require('path');
console.log(path.dirname(module.parent.filename));

Resources