I am trying to build a small framework using flatiron. I want to use nconf to load in all my configuration files so theyre available anywhere in my app. in my root directory I have my app.js, which i want to pull in the config data from config/bootstrap.js.
config/config/js
module.exports =
{ 'app' :
{ "host" : "localhost"
, "port" : process.env.port || 3000
}
}
bootstrap.js:
var nconf = require('nconf')
// database config
, dsource = require('./datasource')
// general or user config
, config = require('./config')
// allow overrides
nconf.overrides({
'always': 'be this value'
});
// add env vars and args
nconf.env().argv();
// load in configs from the config files
var defaults = {}
// so we can iterate over each config file
, confs = [dsource, config]
// for every config file
confs.forEach(function(conf)
{
// get each key
for (var key in conf)
{
// and add it to the defaults object
defaults[key] = conf[key]
}
})
// save the defaults object
nconf.defaults(defaults)
// logging this here works and properly shows the port setting
console.log('app port : ' + nconf.get('app:port'))
module.exports = nconf
so when console logging from in the file. everything seems to load fine. But when I try to export it, and require it from app.js as conf.get('app:port') it doesnt work.
app.js (just a vanilla app.js from 'flatiron create app')
var flatiron = require('flatiron')
, app = flatiron.app
, path = require('path')
, conf = require('./config/bootstrap')
app.config.file({ file: path.join(__dirname, 'config', 'config.json') });
app.use(flatiron.plugins.http);
app.router.get('/', function () {
this.res.json({ 'hello': 'world' })
});
// this doesnt work, conf
app.start(conf.get('app:port'));
So how can I get this to work properly so config is available anywhere in my app. ideally i would like to be able to have the config available from anywhere from something like app.config
Is this the best way to use nconf? I cant seem to find many examples. all the ones i see are just pulling config info from inside the actual nconfig example file. not from outside the file anywhere as app.config
Or am i not using it properly? Is there a better way to do it. Ideally i want to use this bootstrap file to load in all my configs, as well as resources/views (RVP style app) so its all loaded up.
This is the general idea i have for a layout, for an idea
|-- conf/
| |-- bootstrap.js
| |-- config.js
|-- resources
| |-- creature.js
|-- views/
|-- presenters/
|-- app.js
|-- package.json
Your config is available from everywhere you have access to app like this:
app.config.get('google-maps-api-key')
if you loaded it like this:
app.config.file({ file: path.join(__dirname, 'config', 'config.json') })
This is the right way to load a JSON config:
nconf.use('file', {
file: process.cwd() + '/config.ini'
, format: nconf.formats.json
});
Related
-- plugins
---- myplugin1
------ core
---- myplugin2
------ core
If this is my directory structure, is there any way for me to import all core folders from plugins without knowing the name myplugin1 etc?
require('/plugins/./core')
I know how to require from parent folders... but there seem to be nothing about child folders?
Node-Cheat available here, run node app followed by npm i glob.
Possible try:
const glob = require('glob');
const path = require('path');
glob.sync('./plugins/**/core/*.js').forEach(( file ) => {
require(path.resolve( file ) );
});
Expected output:
myplugin1 core loading
myplugin2 core loading
You can use require-dir to achieve this.
These will be the steps
npm install require-file-directory
var requireDir = require('require-dir');
var dir = requireDir('pathToyourCoreDirectory');
And inside the above handler function you can require all of the modules
I am trying to access some environment variables using process.env that were loaded by dotenv.
My folder structure :
.env
src
-- - server.js
My server.js configuration :
(...)
import auth from './middleware/auth'
import dotenv from 'dotenv'
dotenv.load({
path: '../',
silent: process.env.NODE_ENV === 'production'
})
auth()
// Instantiate app
const app = express();
The file where I try to access process.env variable :
(...)
module.exports = function() {
console.log("env", process.env.MONGODB_URI)
var options = {};
options.jwtFromRequest = ExtractJwt.fromAuthHeader()
options.secretOrKey = process.env.JWT_SECRET
Which logs env, undefined, and then crashes with
TypeError: JwtStrategy requires a secret or key
Even if I move .env into src (same directory as server) and remove path in config, it fails.
It appears that when you specify the path, you need to make it full:
require('dotenv').config({path: __dirname + '/../.env'});
.env being your file
Try this; this should work.
import {} from 'dotenv/config'
import somethingElse from 'somethingElse'
...
[the rest of your code]
This works because of how ES6 modules imports modules.
If you want to dig into more.
Please refer this. https://hacks.mozilla.org/2015/08/es6-in-depth-modules/
As a summary :
When you run a module containing an import declaration, the modules it
imports are loaded first, then each module body is executed in a
depth-first traversal of the dependency graph, avoiding cycles by
skipping anything already executed.
Hope this will help someone.
I'm using require('dotenv').config() on my main nodejs .js entry file and it works just fine.
From the docs:
Path
Default: .env
You can specify a custom path if your file containing environment
variables is named or located differently.
require('dotenv').config({path: '/custom/path/to/your/env/vars'})
use may use:
require('dotenv').config({ path: require('find-config')('.env') })
This will recurse parent directories until it finds a .env file to use.
You can also alternatively use this module called ckey inspired from one-liner above.
.env file from main directory.
# dotenv sample content
USER=sample#gmail.com
PASSWORD=iampassword123
API_KEY=1234567890
some js file from sub-directory
const ck = require('ckey');
const userName = ck.USER; // sample#gmail.com
const password = ck.PASSWORD; // iampassword123
const apiKey = ck.API_KEY; // 1234567890
If you're using a mono-repo which uses a single .env file across multiple packages/work-spaces you can use the following to find the root .env file.
Install the find-up package from npm: https://www.npmjs.com/package/find-up
import find from 'find-up';
export const findEnv = () => find.sync(process.env.ENV_FILE || '.env');
you have to set the dotenv configs at the very top level of your app:
import dotenv from 'dotenv'
dotenv.load({
path: '../',
silent: process.env.NODE_ENV === 'production'
})
(...)
import auth from './middleware/auth'
auth()
// Instantiate app
const app = express();
The order of imports in this case matters since you are loading the environment variables.
I use Gulp to build a small web application based on the React framework.
To compile the client scripts, my task starts like that :
gulp.task( 'buildClientScripts', function () {
// Get all the js and jsx scripts
// Starts with the app.js file
return gulp.src( [
'app/app.js',
'app/clientScripts/**/*.jsx',
'app/clientScripts/**/*.js',
] )
The order of the files is my problem. For this file structure :
- clientScripts
---- components
-------- subComponents
------------ mysubComponent.js
-------- myComponent.js
---- main.js
The load order will be : main.js, myComponent.js, mysubComponent.js. But obviously, my top files need the deeper files to work.
How do I ask gulp to load the deepest files first ?
You can use gulp-sort to order the files after gulp.src reads them.
Count slashes in path as crude way to determine depth.
var sort = require('gulp-sort');
var path = require('path');
gulp.task( 'buildClientScripts', function () {
// Get all the js and jsx scripts
// Starts with the app.js file
return gulp.src( [
'app/app.js',
'app/clientScripts/**/*.jsx',
'app/clientScripts/**/*.js',
] )
.pipe(sort(function(file1, file2) {
return countSlashes(file2) - countSlashes(file1);
function countSlashes(file) {
return file.path.split(path.sep).length - 1;
}
})
I am trying to export a module to my routes file.
My file tree goes like
routes.js
app.js
controllers/users.js
posts.js
on my app.js I exported var route = require('./routes'); and that works.
now on my routes.js I tried to export require('./controllers');.
But it keeps telling me that it cannot find module controllers.
Doing this works:
require('./controllers/users')
But I am trying to follow expressjs sample initial projects format.
And it is bugging me because the example of expressjs shows: (express routes is a folder)
var routes = require('./routes');
and loads it like
app.get('/', routes.index);
with no error. and that ./routes is a folder. I am just following the same principle.
If you try to require a directory, it expects there to be an index.js file in that directory. Otherwise, you have to simply require individual files: require('./controllers/users'). Alternatively, you can create an index.js file in the controllers directory and add the following:
module.exports.users = require('./users');
module.exports.posts = require('./posts');
and then import: var c = require('./controllers');. You can then use them via c.users and c.posts.
You have to understand how require() works.
In your case it fails to find a file named controller.js so it assumes it's a directory and then searches for index.js specifically. That is why it works in the express example.
For your usecase you can do something like this -
var controllerPath = __dirname + '/controllers';
fs.readdirSync(controllerPath).forEach(function(file) {
require(controllerPath + '/' + file);
});
From:
http://nodejs.org/api/modules.html
LOAD_AS_DIRECTORY(X)
If X/package.json is a file, a. Parse X/package.json, and look for "main" field. b. let M = X + (json main field) c.
LOAD_AS_FILE(M)
If X/index.js is a file, load X/index.js as JavaScript text. STOP
If X/index.node is a file, load X/index.node as binary addon. STOP
So, if a directory has an index.js, it will load that.
Now, look # expressjs
http://expressjs.com/guide.html
create : myapp/routes
create : myapp/routes/index.js
Taking some time to really read how modules work is time well spent. Read here
Project Intro
My project is a single page storefront. The project has multiple modules, and each module contains a set of controller.js, view.js and model.js files, as well as a template.html file. And uses requirejs to manage dependencies.
Problem Statement
I want to use mainConfigFile to provide paths to reference modules in grunt-requirejs.
Part of my mainConfigFile's require.config is stored in separate file (base.dependency.config), and require.config.paths are pieced together by underscore at runtime.
base.dependency.config
config = {
baseDependencyConfig: {
paths: { ... }
shim: { ... }
}
}
main.js
var dependencies = config.baseDependencyConfig;
var basePaths = config.baseDependencyConfig.paths;
var extensionPaths = {
// extra sets of paths
};
// combine base paths and extension paths at runtime using underscore
var dependencyPaths = _.extend(basePaths, extensionPaths);
dependencies.paths = dependencyPaths;
require.config(dependencies);
// application startup
require(['app', 'eventbus']) {
// code
}
Error
However, grunt requirejs is ignoring mainConfigFile, grunt requirejs tries to find 'app.js' under root, when in fact, 'app' is defined under require.config paths as
'app': 'modules/base/app/base.app.controller'
my gruntFile:
module.exports = function (grunt) {
grunt.initConfig({
// ... other plugin config
requirejs: {
options: {
baseUrl: 'public',
// the paths for the named modules such as 'app' are defined
// in main.js under require.config paths
name: 'main',
include: [
'app',
'cart',
'category'
],
out: 'public/build/app-optimized.js',
mainConfigFile: 'public/main.js',
findNestedDependencies: true,
optimizeCss: 'none',
cssImportIgnore: 'style/style.css, style/mocha.css',
}
}
})
}
my file structure
public
|--modules/
| |--base/
| | |--cart
| | |--category
| | |--category.controller.js
| | |--category.view.js
| | |--category.model.js
| | └-category.template.html
| |
| └--extension/
|
|--style/
|--image/
|--main.js <-- main config file
|--other .js files
mainConfigFile, main.js lives in root, along with a few other application startup js files
main bulk of application files lives inside modules folder
each module folder contains its controller, view and model js file, as well as a template.html file
Edit
the gruntFile worked before, with different mainConfigFile (main.js) setup:
require.config({
paths: {...}
shim: {...}
})
// application startup
require(['app', 'eventbus']) {
// code
}
r.js uses Esprima as Javascript parser to extract the config object from the specified mainConfigFile. It only looks for certain signatures in the code.
Look at
hasRequire(): determine the AST node is a configuration call candidate
findConfig(): calls the above deciding how to extract the config
I've created a patch making it aware of recognizing
requirejs.config(_VariableToExport = { ... });
This is limited and the Javascript parser approach makes it very complicated to make r.js able to extract configurations that were created by functions (like in your code) or so. This patch has not been submitted to the project yet. I'm struggling with bureaucracy yet.
I think the only working workaround so far is
not to use mainConfigFile
exporting the config as NodeJS module
requiring the main.js/config.js in Node (Grunt)
passing the object as value to the config attribute or method
See my comment to this issue for a scribble.
This approach is proven in another, a bit older project I'm working on.
Related to r.js 2.1.11.