Node app variables passed into stylus file - node.js

I am building a little node app and using Express with Jade and Stylus to render some basic HTMl pages.
I was curious if there is a way for me to pass some variables INTO the .styl file that are generated from Node? I am well aware that i can define variables inside of the .styl file but I have a need to be more dynamic. Specifically i was looking for an easy way to store some colors in the db, have node grab those values, then insert those into the .styl file so that when the page is rendered these variables are passed in. It seems like this should be do-able but i am lacking on the details. Any help is appreciated. Thanks!

Thanks to #ebohlman as his advice was close to what i ultimately implemented.
basically i was trying to figure out how to do this on top of the Connect Middleware and here is what i came up with:
when doing app.configure i used the custom compile compile function (key 'compile') like so:
app.use(require('stylus')
.middleware({
src: app.root + '/app/public',
compile: compile
})
);
then i created a couple of functions:
var stylus = require('stylus');
var mylib = function(style){
style.define('themeColor1', function(){
//call to the db that returns a color
color = 'blue';
color = color ? color : 'orange';
return new stylus.nodes.Literal(color);
});
};
var compile = function(str, path) {
return stylus(str)
.use(mylib);
};
then inside of the .styl file i do:
background-color themeColor1();
the ternary operator in the themeColor1 function allows for easy defaults and an override. It took me a bit to figure out the API based upon the examples but it seems like this COULD be a solution others would want to know how to do. If anyone has any downfalls of this approach please let me know.

You can use the Stylus API's define() function to set Stylus variables and make JS functions available to it.

Related

How do I find what files use a specific function or file in a Node project, using VSCode?

I'm working with a Node project using VSCode. I'd like to be able to follow the tree upwards from functions/files at a lower level. That is, if I have an exported function doSomething in file dosomething.js, I'd like to see what code calls this function, and/or see what code requires this file.
// index.js
const { doSomething } = require('./tricky-stuff')
// tricky-stuff.js
const doSomething = function() {}
module.exports = {doSomething}
If I'm browsing tricky-stuff.js, is there a built-in feature to VSCode that allows me to see usages of either the function doSomething or where the file tricky-stuff.js is required/imported, so that it would show me the file index.js in this case (as well as perhaps other files where tricky-stuff is used)? Is there any extension? I seem to recall that WebStorm could do this, but I can't remember. (I know I could search for strings, but that seems inelegant).
I think it largely depends on how much VScode knows about your code, via the TypeScript language service or JSDoc comments etc...
Typically you can right click on a function and select the peek all references or find all references options:
In this case, it will show you all the places where that function is called or referenced.

Node.js dynamic relative require path

I need to be able to use require() on a dynamic relative path - meaning that the relative path needs to change depending on the current environment.
What is the best practice for this type of situation?
I thought of something like this:
var module = require(process.env.MY_MODULES_PATH + '/my-module');
However environment variables are not very convenient.
Are there other possibilities?
Maybe use package.json post-install script to set the environment variable for me?
Maybe there's a built in solution in node I don't know about?
EDIT
I just realized that this is a special case of require() "mocking". Is there a best practice for how to mock require() for unit-tests for example?
MockedRequire.js
var path = require('path');
function MockedRequire(module) {
return require(path.join('/path/to/modules', module));
}
module.exports = MockedRequire;
Use:
var mymodule = require('./MockedRequire.js')('mymodule');
To be honest I haven't actually tested this but it should work without issues.
Webpack needs to know what files to bundle at compile time, but expression only be given value in runtime, you need require.context:
/* If structure like:
src -
|
-- index.js (where these code deploy)
|
-- assets -
|
--img
*/
let assetsPath = require.context('./assets/img', false, /\.(png|jpe?g|svg)$/);
// See where is the image after bundling.
// console.log(assetsPath('./MyImage.png'));
// In fact you could put all the images you want in './assets/img', and access it by index: './otherImg.jpg'
var newelement = {
"id": doc.id,
"background": assetsPath('./MyImage.png');
};
I would suggest using a configuration loader. It will select your path based on your NODE_ENV variable, but its much cleaner than what you suggested because you keep all of the environment specific config within a single external file.
Examples:
https://github.com/uber/zero-config
https://github.com/vngrs/konfig
Roll your own

how to pass a shared variable to downstream modules?

I have a node toplevel myapp variable that contains some key application state - loggers, db handlers and some other data. The modules downstream in directory hierarchy need access to these data. How can I set up a key/value system in node to do that?
A highly upticked and accepted answer in Express: How to pass app-instance to routes from a different file? suggests using, in a lower level module
//in routes/index.js
var app = require("../app");
But this injects a hard-coded knowledge of the directory structure and file names which should be a bigger no-no jimho. Is there some other method, like something native in JavaScript? Nor do I relish the idea of declaring variables without var.
What is the node way of making a value available to objects created in lower scopes? (I am very much new to node and all-things-node aren't yet obvious to me)
Thanks a lot.
Since using node global (docs here) seems to be the solution that OP used, thought I'd add it as an official answer to collect my valuable points.
I strongly suggest that you namespace your variables, so something like
global.myApp.logger = { info here }
global.myApp.db = {
url: 'mongodb://localhost:27017/test',
connectOptions : {}
}
If you are in app.js and just want to allow access to it
global.myApp = this;
As always, use globals with care...
This is not really related to node but rather general software architecture decisions.
When you have a client and a server module/packages/classes (call them whichever way you like) one way is to define routines on the server module that takes as arguments whichever state data your client keeps on the 'global' scope, completes its tasks and reports back to the client with results.
This way, it is perfectly decoupled and you have a strict control of what data goes where.
Hope this helps :)
One way to do this is in an anonymous function - i.e. instead of returning an object with module.exports, return a function that returns an appropriate value.
So, let's say we want to pass var1 down to our two modules, ./module1.js and ./module2.js. This is how the module code would look:
module.exports = function(var1) {
return {
doSomething: function() { return var1; }
};
}
Then, we can call it like so:
var downstream = require('./module1')('This is var1');
Giving you exactly what you want.
I just created an empty module and installed it under node_modules as appglobals.js
// index.js
module.exports = {};
// package.json too is barebones
{ "name": "appGlobals" }
And then strut it around as without fearing refactoring in future:
var g = require("appglobals");
g.foo = "bar";
I wish it came built in as setter/getter, but the flexibility has to be admired.
(Now I only need to figure out how to package it for production)

Require a javascript library inside Jade

How do I require a library so that it works inside Jade.
Like if I want to be able to use CircularJSON in Jade
script var object = #{CircularJSON.stringify(object)}
I would basically need to define the function from that library into Jade
- var CircularJSON = function(e,t){function l(e,t,o){var u=[],...//whole function
which would be impractical and possibly impossible for much more complex libraries.
Is there a way to somehow simply require it instead?
var myLib = require('../mylib');
response.render("index.jade", {
lib : myLib
});
index.jade now has the myLib object. Now just use as you would anywhere else.
Just require it in node and pass it to the template in the locals. locals can include functions as well entire modules, objects and scalar data.
I like to take an approach similar to Peter Lyons and Zhifeng Hu (in another post), but instead of requiring everything into locals, I just require "require", then I can pull things in as needed in my templates.
app.use((req, res, next) => { res.locals.require = require; next() })
and then in Jade/Pug
- const moment = require('moment')
div Created at: #{moment(data.createdAt).fromNow()}
Basically the same thing, but I can keep the require code in the template where it's used.

RequireJS Dynamic Paths Replacement

I have a requirejs module which is used as a wrapper to an API that comes from a different JS file:
apiWrapper.js
define([], function () {
return {
funcA: apiFuncA,
funcB: apiFuncB
};
});
It works fine but now I have some new use cases where I need to replace the implementation, e.g. instead of apiFuncA invoke my own function. But I don't want to touch other places in my code, where I call the functions, like apiWrapper.funcA(param).
I can do something like the following:
define([], function () {
return {
funcA: function(){
if(regularUseCase){
return apiFuncA(arguments);
} else {
return (function myFuncAImplementation(params){
//my code, instead of the external API
})(arguments);
}
},
funcB: apiFuncB
};
});
But I feel like it doesn't look nice. What's a more elegant alternative? Is there a way to replace the module (apiWrapper) dynamically? Currently it's defined in my require.config paths definition. Can this path definition be changed at runtime so that I'll use a different file as a wrapper?
Well, first of all, if you use Require.js, you probably want to build it before production. As so, it is important you don't update paths dynamically at runtime or depends on runtime variables to defines path as this will prevent you from running r.js successfully.
There's a lot of tools (requirejs plugins) out there that can help you dynamically change the path to a module or conditionnaly load a dependency.
First, you could use require.replace that allow you to change parts (or all) of a module URL depending on a check you made without breaking the build.
If you're looking for polyfilling, there's requirejs feature
And there's a lot more listed here: https://github.com/jrburke/requirejs/wiki/Plugins

Resources