tl;dr
Is there a way to use Jade completely client-side like any of the other JavaScript template engines (e.g., Mustache, Handlebars or Nunjucks), so that it loads includes via ajax?
More Info:
I have a web application that is not running on Node (unfortunately due to various vendors not providing libraries for Node yet) and I have really started liking the syntax and capabilities of Jade. Unfortunately, it seems like everything in Jade requires Node in some capacity, either in the development flow or on the server side. I definitely cannot use it server-side and would prefer not to introduce it to the development cycle just for templating.
It seems like all that would be necessary is to package up the dependencies (this can be done with browserify) and to implement fs to read files with ajax. Is there some implementation of this already?
Also, the time taken to compile once per file, per session is not really a concern for this application.
I actually found out the way to do this, completely on the client side:
Use browserify CDN to obtain a client-side bundle for the node package.
Implement the 'readFileSync' function in the 'fs' module in the bundle to use a synchronous XmlHttpRequest and retrieve the file from the server (it is currently empty so no function exists)
Viola!
UPDATE:
Here is my implementation:
2:[function(require,module,exports){
module.exports = {
cache: { },
readFileSync: function(path){
return this.cache[path] || (this.cache[path] = (function(){
var request = new XMLHttpRequest();
request.open('GET', path + '?_=' + $.time(), false);
request.send();
if (request.status === 200) {
return request.responseText;
}
else {
throw 'Unable to load template: ' + path;
}
}).call());
}
}},{}]
Related
I am currently making a project using vue-cli which generates a Node project with webpack. I can build all scripts and use the pug language within .vue files. When building, the project uses HTML-Webpack-Plugin, though, which outputs the code as static HTML with client-side scripts.
How do I pass variables from the server-side to these client-side scripts? I previously was using pug, which made this process easy, but since it now gets built into .html files, this can no longer be done.
I have two attempts, both suboptimal:
1. Send variables into clientside scripts
script.
const clinetSideVar = `!{serverSideVar}`;
The problem with this approach is that I cannot pass this variable into the vue instance, since it gets obfuscated when built and I have no way of accessing it (or do I? I haven't found a way).
2. Using AJAX requests
I could also make a restful API for server-side site data and retrieve it using AJAX, but this seems like a real hack and this would lose quite a bit of performance over just sending the data plainly through a pug template (with no. 1 I'd too, since client-side JS would have to insert the data into the DOM).
I'd recommend using JSONP (since your index.html is built ahead of time in Vue-cli).
In your public/index.html (which is a template)
<head>
...
<script>function getServerData(data) { window.__SERVER_DATA__ = data; }</script>
<script src="/api/server-data.json?callback=getServerData"></script>
</head>
In your Node Express routes definition
const app = express();
// ...
app.get('/api/server-data.json', (req, res) => {
res.jsonp({
foo: 'foo',
bar: 'bar'
});
});
Then just access window.__SERVER_DATA__ from within any Vue component.
Hello is there any way to use JS environment built in ArangoDB to execute custom JS? I'd like to set up path to my JS files which would be executed instead of foxx application files.
Via GitHub: https://github.com/arangodb/arangodb/issues/1723#issuecomment-183289699
You are correct that modules are cached independently of the routing
cache. Clearing the module cache (or preventing a module from being
cached) is currently not supported.
The actions mechanism is really only intended as an internal API and
only supported for backwards compatibility with early ArangoDB
versions and some edge cases.
As you may have noticed while digging through the ArangoDB source
code, Foxx provides a per-service module cache which is cleared
whenever a Foxx service is reloaded. I would strongly encourage you to
see whether Foxx fits your use case before continuing to dig into the
actions mechanism.
It's actually possible to create a Foxx service with just two files (a
manifest and a controller file) and without using repositories or
models (you can just use the same APIs available in actions).
You just need a controller file like this (e.g. ctrl.js):
'use strict';
const Foxx = require('org/arangodb/foxx');
const ctrl = new Foxx.Controller(applicationContext);
ctrl.get('/', function (req, res) {
res.send('Hello World');
});
with a manifest.json like this:
{
"name": "my-foxx",
"version": "0.0.0",
"controllers": "ctrl.js",
"defaultDocument": "",
"engines": {"arangodb": "^2.8.0"}
}
You can then mount the service (upload a zip bundle) at a path like
/db and access it:
curl http://localhost:8529/_db/_system/db
The upcoming 3.0 release will remove a lot of the existing conceptual
overhead of Foxx which will hopefully make it even easier to get
started with it.
Yes, this can be done with User Actions. Foxx was created as a more comfortable alternative and is likely a better choice for non-trivial applications. The documentation can be intimidating but Foxx services can actually be very lightweight and simple (see my other answer). If you really don't want to use Foxx for this, here's how to do it manually:
First create a virtual module in the _modules system collection:
var db = require('org/arangodb').db;
db._modules.save({
path: '/db:/ownTest',
content: `
exports.do = function (req, res, options, next) {
res.body = 'test';
res.responseCode = 200;
res.contentType = 'text/plain';
};
`
});
Then create a route that uses it:
db._routing.save({
url: '/ourtest',
action: {
controller: 'db://ownTest'
}
});
Finally, tell ArangoDB to update its routing cache so it notices the new route:
require('internal').reloadRouting();
If you install your JavaScript module to the js/common/ or the js/server/ directory you can use the module name (e.g. myOnDiskModule) instead of the virtual module name "db://owntest" in the controller.
For smaller modules you can just define the function inline using callback instead of controller:
db._routing.save({
url: '/hello/echo',
action: {
callback: `
function (req, res) {
res.statusCode = 200;
res.body = require('js-yaml').safeDump({
Hello: 'World',
are: 'you here?'
});
}
`
}
});
Remember to always update the routing cache after changes to the routing collection:
require('internal').reloadRouting();
Note: the callback implementation in 2.8 has a bug that will be fixed in 2.8.3. If you want to apply the fix manually, it's in commit b714dc5.
I need to make an API request to an external API using an API Key. I know how to make this API request in React by writing a onSubmit function. But since I have an API key that I want to keep a secret I am going to write a simple Node app to house env variables.
Besides messing around in node this is my first production experience with Node and I am wondering if my thought process is correct and if not, the better way to do this.
Most of this question will be pseudo code since I haven't started with the Node portion yet.
The idea is that from within the React component it would call the Node app who in turn would call the external API.
React -> Node -> External API
So the React component would be something like so:
handleSubmit: function() {
var data = this.refs.testData.getDomNode().value;
$.ajax({
url: '/my-node-endpoint',
dataType: 'json',
type: 'POST',
data: { test: data },
success: function(data) {
// Whatever success call I want to make
}.bind(this)
})
}
And then in my Node app it would like something like this:
app.post('/my-node-endpoint', function(req, res) {
// Store the values we are posting as JSON
// Start the post request
// On End tell the React component everything is ok
// Prosper
});
As always, thanks for any help that is offered.
Your thought process looks right to me.
If the API you are calling is from a different domain, you will have to build a wrapper on your node server like you did here. Unless the external API supports cross-origin requests with no domain restrictions (such as MapBox web services), you will have to do this.
Several improvements to your code:
As far as I know, you can use React.findDOMNode(this.refs.testData).value instead of this.refs.testData.getDomNode().value. getDomNode() is deprecated in v0.13.
For all the AJAX calls, you can use the Store concept in Flux. The store keeps the states of the data, including updating data through AJAX request. In your React UI code, you just need to call the methods of the store, which makes your UI code clean. I usually create a store class myself without using Flux.
I am building a node.js application that uses pdf.js to read pdf files, but much like other js, pdf.js does not allow cross origin requests. So, I need a way to save files selected with a file input to my pdf directory. I'm not so great with node so make it as simple as possible if you can.
Here is a basic idea of what you need:
1st, require and use module 'connect-multiparty'. This will expose the req.files object in node.
var multipart = require('connect-multiparty');
app.use(multiparty({});
Then, in your controller method, require the 'fs' module, and use it to save the uploaded file.
var fs = require('fs');
fs.writeFileSync("myFileName", req.files.file.ws.path, function(err) {
if(err) { console.log(err); }
else { console.log("file uploaded"); }
});
Being familiar with node will help, but the two basic libraries you need to perform this are the aforementioned https://www.npmjs.com/package/connect-multiparty and http://nodejs.org/api/fs.html
edit: see the link in the comments below. this answer is incomplete and is better explained in the link
I want to share a piece of coffeescript code between the server and the client on Express.
I linked the file from the server directory into the /public directory, so it can be loaded by the client.
It does have external dependencies, which I resolve statically for the client. To remove the error messages when the client tries to call require, I thought a simple conditional declaration would do.
console.log require
unless require?
require = (what) ->
console.info "this is the client, you asked me to load #{what}"
return {}
However, when run on the server, undefined will be printed and require will be overridden. The same happens for embedded Javascript:
`if( typeof require == "undefined" )
var require = function(what) {
console.info( "this is the client, you asked me to load "+what );
return {};
}
`
If I only run:
console.log require
on the server, it prints an object structure, as expected.
It seems that require is injected after at least the conditional has been evaluated and executed.
How can I override require safely, or what other paradigm might I use for sharing code between client and server?
I recommend using browserify for sharing code between the client and server. It allows you to write your javascript as you would for the server following the common js pattern, but provides a mechanism to build your module for client-side where require() works in the browser.
CoffeeScript is supported with browserify via a transform process. Coffeeify is one implementation of a transform implementation for CoffeeScript.