Sails.js, Nunjucks & LiveReload - javascript

I've managed to get Nunjucks working with Sails.js, however it seems that the changes are not being picked up until I restart the server. I'll automatically see the changes reflected once or twice, but after that, even manually refreshing the browser will not show my changes.
I implemented LiveReload with the advice here:
Get livereload to work with Sails.js
but I don't suspect it's an issue with LiveReload.
Has anyone else gotten Sails.js and Nunjucks to play nicely together? If so, how?

The problem is nunjucks itself. It has a watch option which by default is set to false:
You can enable it in sails/config/bootstrap.js:
var nunjucks = require('nunjucks')
module.exports.bootstrap = function(cb) {
nunjucks.configure({
watch:true
})
// It's very important to trigger this callback method when you are finished
// with the bootstrap! (otherwise your server will never lift, since it's waiting on the bootstrap)
cb();
};
In combination with the livereload everything works fine.

in /config/views.js
engine: {
ext: 'html',
fn: function (str, options, fn) {
var engine = require('nunjucks');
engine.configure('views', {
autoescape : true,
throwOnUndefined : true,
trimBlocks : true,
lstripBlocks : true,
express : sails.hooks.http.app,
watch : true,
noCache : false,
web : {
useCache : true,
async : false
}
});
engine.render(str, options, fn);
}
},

For Sails.js 1 the solution has slightly changed:
In /config/views.js
module.exports.views = {
...
getRenderFn: () => {
// Import nunjucks.
const nunjucks = require('nunjucks');
// Configure nunjucks.
const env = nunjucks.configure('views', {
autoescape : false,
throwOnUndefined : true,
trimBlocks : true,
lstripBlocks : true,
watch : true,
noCache : false,
web : {
useCache : true,
async : false
}
});
// Here you can add filter
env.addFilter('filtername', (name) => {
return name;
});
return nunjucks.render;
}
}
Hope this will help someone ;)

Related

How to let chokidar watcher keep running in the background in electron JS/ Node JS

I am using chokidar library for keeping track of files.
So I created this function:
function StartWatcher(username){
console.log(username)
const chokidar = require('chokidar');
const folderLocation='watch-folder'
const watcher = chokidar.watch(folderLocation,{
persistent: false,
ignoreInitial: true,
ignored: [ 'watch-folder/ignore-1.txt', 'watch-folder/ignore-2.txt' ],
ignorePermissionErrors: false,
interval: 100,
binaryInterval: 300,
disableGlobbing: false,
enableBinaryInterval: true,
useFsEvents: false,
usePolling: false,
atomic: true,
followSymlinks: true,
awaitWriteFinish: false
})
watcher.on('ready',async()=>{
console.log("I am ready to watch files for ",username)
console.log(folderLocation)
})
watcher.on('add',async (path) => {
console.log(path,'File Path ....... for',username)
var today = new Date();
var fileAddingDate=today.getDate()+"/"+(today.getMonth()+1)+"/"+today.getFullYear()+" "+today.getHours()+":"+today.getMinutes()+":"+today.getSeconds()
fs.readFile(path,async function(error,data){
console.log(data)
})
})
watcher.on('change',async (path)=>{
console.log(path,'Content change in the file... for',username);
var today = new Date();
var fileAddingDate=today.getDate()+"/"+(today.getMonth()+1)+"/"+today.getFullYear()+" "+today.getHours()+":"+today.getMinutes()+":"+today.getSeconds()
fs.readFile(path,async function(error,data){
console.log(data)
})
})
}
And now I am calling this function on some condition like this.
StartWatcher(devansh)
But I am having problem. Only ready event is working. Rest all events are not working. I thinks it's because when I am calling the function it got executed only once and stopped. Need some help.
I don't know if you found a solution to this problem yet but, looking at your function and what is happening to you, your problem is that you setted "persistent" as "false", which causes no more events to be emitted after "ready" event as you can check in it's API: https://www.npmjs.com/package/chokidar#user-content-persistence

MoleculerJs with Jaeger tracing: how to trace follow up action calls (new spans) in one trace

I would like to display all my traces like in the examples from the moleculer-jaeger package:
But what i get is something like this:
All spans you can see in this picture should be within the main trace (gateway).
Here is my moleculer.config:
tracing: {
enabled : true,
stackTrace: true,
actions : true,
exporter : {
type : 'Jaeger',
options: {
// HTTP Reporter endpoint. If set, HTTP Reporter will be used.
endpoint: 'http://jaeger:14268/api/traces',
// UDP Sender host option.
host : 'api.dev.host.com',
// UDP Sender port option.
port : 6832,
// Jaeger Sampler configuration.
sampler : {
// Sampler type. More info: https://www.jaegertracing.io/docs/1.14/sampling/#client-sampling-configuration
type : 'Const',
// Sampler specific options.
options: {
}
},
// Additional options for `Jaeger.Tracer`
tracerOptions: {},
// Default tags. They will be added into all span tags.
defaultTags : {
appName: 'core',
}
}
},
tags: {
action: {
// Always add the response
response: true,
},
},
},
My jaeger-service is just one of the examples:
const JaegerService = require('moleculer-jaeger')
module.exports = {
mixins : [ JaegerService ],
settings: {
host : 'jaeger-server',
port : 6832,
sampler: {
type : 'Const',
options: {
decision: 1
}
}
}
}
I tried several different configurations for sampling but nothing worked the way i would like it to have.
Here is some code where you can see the action calls i do:
// serviceX endpoint:
resolveByName: {
rest : 'GET resolve/name/:name',
params: {
name: { type: 'string' }
},
handler(ctx) {
return resolveByNameHandler(this.broker, ctx.params, 'serviceY')
}
},
// handler code
// please do not focus on the code itself. What i wanted to show is how i call the other
// services.
const { NotFoundError } = require(`${process.env.INIT_CWD}/util/error`)
module.exports = (broker, params, dataSource) => {
const { name } = params
const query = { name: name }
const rejectRequest = (name, data) => Promise.reject(new NotFoundError(name, data))
const getSourceData = result => broker.call(`${dataSource}.find`, { query: { id: result[0].ownerId } })
.then(sourceData => sourceData.length === 0
? rejectRequest(dataSource, sourceData)
: mergeResult(sourceData, result))
const mergeResult = (sourceData, result) => ({ ...sourceData[0], origin: { ...result[0], source: 'serviceX' } })
return broker.call('serviceX.find', { query: query })
.then(result => result.length === 0 ? rejectRequest('serviceX', query): result)
.then(result => result[0].ownerId ? getSourceData(result) : rejectRequest('noOwnerId', query))
}
What i also tried is to not use the moleculer-jaeger package but to use the jaeger all-in-one docker image. Same results though...
# from the docker-compose.yml
jaeger-server:
image: jaegertracing/all-in-one:latest
ports:
- 5775:5775/udp
- 6831:6831/udp
- 6832:6832/udp
- 5778:5778
- 16686:16686
- 14268:14268
- 9411:9411
networks:
- internal
What i do not want to do is to set the spans manually in every service. I have tried it already but it did not work at all, so if this would be the only solution i would be very happy to see an example.
Thanks in advance!
*edit:
The Versions i use:
{
"jaeger-client": "^3.18.1",
"moleculer": "^0.14.13",
"moleculer-db": "^0.8.12",
"moleculer-db-adapter-mongoose": "^0.8.9",
"moleculer-jaeger": "^0.2.3",
"moleculer-web": "^0.9.1",
"mongoose": "^5.12.5",
}
This version already has a built-in jager tracer, see the documentation.
In order for the events to be nested, it is necessary to transfer the context inside the actions, use ctx.call calls instead of broker.call, so they will be nested.
To quickly receive support for the moleculer, join us in discord!

i18next load json from api using i18next-xhr-backend

I try to load a translation JSON file from API in React Native and parse it but it seems that load does not work because the parse method never invokes.
function initI18Next(onInit) {
return (
i18n
.use(initReactI18next)
.use(XHR)
.init({
...initOptions,
backend : backendOptions
}).then(onInit())
)}
initOptions :
export const initOptions = {
fallbackLng : 'es',
defaultNS : 'translation',
lng : 'es',
debug: true,
keySeparator : false,
initImmediate: false,
preload : ['en', 'es'],
react: {
wait: true,
useSuspense: false
},
interpolation: {
escapeValue: true // not needed for react as it escapes by default
},
resources : i18nResources
}
backend options :
export const backendOptions = {
loadPath: 'http://www.mocky.io/v2/5ecd0fe73200006400236655.json',
parse(data) {
console.log('data', data);
return data;
}
};
i18next-xhr-backend is deprecated, use i18next-http-backend instead...
Then try to set i18next debug option to true and have a look at the developer console logs.
Btw: the load path looks strange to me. It should be more like this: https://github.com/i18next/i18next-http-backend#backend-options

How can I tell whether chrome.proxy.settings.set is correctly setting my proxies

In my Google Chrome Extension, my popup.js includes:
function setProxyToUse() {
var enable = {
mode: "fixed_servers",
rules: {
proxyForHttps: {host: localStorage["surveyHTTPS"]},
proxyForHttp: {host: localStorage["surveyHTTP"]}
}
};
var disable = {mode: "system"}
if (localStorage["proxyOn"] == true) {var config = enable} else {var config = disable}
chrome.proxy.settings.set({value: config, scope: 'regular'},function() {});
chrome.proxy.settings.get({}, function(config) {console.log(config.value.host);} );
}
The last line simply writes undefined to the console. How can I check which proxy host I'm using?
By default proxy value is a string "system" which doesn't have the property you're trying to display (.host).
If you want to read the value you've just set, do it in the callback of .set because chrome API is asynchronous:
chrome.proxy.settings.set({value: config, scope: 'regular'}, function() {
chrome.proxy.settings.get({}, function(config) {
console.log(config.value, config.value.host);
});
});

jsdom not triggering internal <script>

I am trying to sample a page that has a script on it that changes the CSS of certain elements such that an attribute toggles between "active" and "inactive" based on the width of the window.
I have written nodeJS code that gathers and analyzes the page, but I cannot seem to trigger, or detect the triggering of the script. I suspect it has to do with defaultDocumentFeatures, but I could be wrong.
The script opens the page in JSDOM with a default width, then changes it to a specified block of other widths. This should result in changes in the output, but it does not. I am getting the same results for all situations. I suspect that the script on the page simply isn't running, but need help to make it do so
Here is my code (expurgated for public viewing.)
var express = require('express');
var router = express.Router();
var jsdom=require('jsdom');
router.get('/getSamplePage', function(req, res) {
getaEpicPage(req, res, function(contents){
console.log("got an sample page"+contents+"000000000");
//contents gets replaced by the actual results that will be processed upstream
res.send({'msg':'', 'contents':contents});
});
});
var getaSamplePage=function (req, res, callback) {
jsdom.defaultDocumentFeatures={
FetchExternalResources : ['script', 'css'],
ProcessExternalResources : ['script', 'css'],
MutationEvents : '2.0',
QuerySelector : false
};
var elementLocations=[
'sample_01',
'sample_02',
'sample_03'];
var contents=[{label:'DIV ID', value:'Is Populated', width: "Screen Width", position:"element size"}];
var windowWidths=[
479,
481,
781,
783,
1023,
1025,
]
for (var i in windowWidths){
jsdom.env({
url:'http://sourcefilelocation/',
scripts: ['http://code.jquery.com/jquery.js'],
created: function(errors, tstWindow) {
tstWindow.tstWindowWidth=windowWidths.pop();
tstWindow.addEventListener('resize', function() {
//verify that resize is triggered
console.log('Resize event completed');
});
tstWindow.constructor.prototype.resize = function (width){
//defining a "resize" event, since that may be what triggers things
console.log("resize has been attempted");
tstWindow.originalWidth=tstWindow.innerWidth;
tstWindow.outerWidth=tstWindow.innerWidth=width;
}
tstWindow.readyState="complete";
},
done: function(errors, tstWindow) {
setTimeout(function () {
//setting a timeout to ensure that any elements have finished I have put this as high as ten seconds.
console.log("ready state "+tstWindow.readyState);
tstWindow.resize(tstWindow.tstWindowWidth)
$=tstWindow.$;
for (var sampleLocation in sampleLocations) {
var sampleID=sampleLocations[sampleLocation];
$('div > [sampleAttribute='+sampleID+']').each(function(){
//If the script I am trying to watch work triggers, it should change the "content" attribute
var elementActive=$(this).css('content');
var position=$(this).attr('sample-position');
console.log("element css>>>>>> "+tstWindow.innerWidth+" "+sampleID+" "+position+" "+elementActive);
if (elementActive=='"active"'){
contents.push({label:sampleID, value: elementActive, width: tstWindow.originalWidth+"/"+tstWindow.innerWidth, position:position});
}
});
};
}, 50);
}
});
};
setTimeout(function () { callback(contents);}, 100);
};
module.exports = router;
Per suggestion I added this to my jsDom config object, just after the url:
FetchExternalResources : ['script', 'css'],
ProcessExternalResources : ['script', 'css'],
MutationEvents : '2.0',
QuerySelector : false,
But it has made no apparent difference.
As per the jsdom Readme when you're using jsdom.env the default feature set does not include processing scripts.
You have to pass the FetchExternalResources and ProcessExternalResources to jsdom.env specifically.
jsdom.env({
html: input,
url: url,
features: {
FetchExternalResources: ["script", "img", "css", "frame", "iframe", "link"],
ProcessExternalResources: ["script"]
},
created: function (err, window) {
console.log('Created');
},
loaded: function (err, window) {
console.log('Loaded');
}
});
jsdom.env doesn't use the jsdom.defaultDocumentFeatures object.

Categories

Resources