I am working on node express server which generates reports (tables, charts) for data stored in database (MongoDB). What makes it hard is that the report should be downloadable as a single file and viewable offline. Which means that all the data and javascript should be inside the html file.
By searching stackoverflow I found this question - Inline CSS/Javascript into a HTML file. One of the solutions is command-line tool which visits the page and bundles together all assets, other solutions use other languages. In my case it doesn't make sense to visit the page and download the files as they are already in memory and should be imported from node server.
So here is example of how I've been doing it so far.
Server.js:
// Templating library
const mustache = require("mustache");
// Javascript to be imported into html as inline script
const someFunction = require("./src/someFunction.js").toString();
app.get("/:id", async (req, res) => {
// Get data from DB
const data = await MongooseSchema.find({ id: req.params.id });
// Read html view
const view = fs.readFileSync("./views/report.html", "utf8"});
// Render with mustache
const html = mustache.to_html(view, {
data,
javascript: { someFunction }
});
// Send rendered html
res.send(html);
});
And report.html includes this script tag:
<script>
const data = {{{data}}};
{{{javascript.someFunction}}}
</script>
I am importing javascript files as strings and then rendering them inside the html file using mustache templating library. This approach seems kind of hacky, there should be a better way.
Also I am thinking about implementing some bundler (webpack/parcel/rollup) to combine all the js files into one which I could then manually import into html as inline script.
And maybe even use some framework like react to make my life easier.
So my question is, is this approach viable? Are there any better ways to do this?
Related
I am very new to node so I need help with this one. I understand how to display a html file using nodejs such as this:
(node)
var http = require('http');
let fs = require("fs");
http.createServer(function (req, res) {
fs.readFile("test.html",(err, data) => {
if(!err) {
res.writeHead(200, {'Content-Type': 'text/html'});
res.end(data);
}
});
}).listen(8080);
However, I want to know how I would use this to do things you would do in js such as
(js)
document.getElementById("thisElement").style.backgroundColor = "#234";
document.getElementById("thisElement").addEventListener("click",() => {
doThings();
});
And other related js stuff.
I understand how to display a html file using nodejs such as this:
That does not "display an HTML file using nodejs".
That sends an HTML file to a an HTTP client such as a web browser.
A web browser can display an HTML file.
However, I want to know how I would use this to do things you would do in js such as
Web browsers take HTML, generate a DOM, run JavaScript with client-side Web APIs and provide a UI for the user to interact with it.
Node.js doesn't.
The JavaScript programming language is a general purpose programming language.
Web browsers provide particular APIs for doing things that are useful to do in a web browser.
Node.js provides APIs for doing things in other contexts (such as running an HTTP server or writing command line utilities).
You can't take JS designed to run in a web browser and run it in Node. It doesn't make sense.
(You can write code which runs in both contexts (generating a random number to take a trivial example) but most code isn't that generic).
You see this line on your codes
fs.readFile("test.html",(err, data) => {
this line goes and pick test.html file, which is available on your client side
now, anything relating to this test.html file is a client thing
since its html, in it you will declare tags and javascript file references as below
<html>
<body>
<script src = "../../to/js/files.js"></script>
<!-- or as below -->
<script>
//now in here you get to do your fun stuffs as you asked above
document.getElementById("thisElement").style.backgroundColor = "#234";
document.getElementById("thisElement").addEventListener("click",() => {
doThings();
});
</script>
</body>
</html>
I don't think you can do it on this way with node because it's not its purpose, node was made to serve things not to change html or act on browser stuff as you want, there's no DOM on node.
BUT, You can try reading the file and editing it inserting content, but it will be such an hard thing to do once you will need to change the text and it will probably being an array or you can try it with express termplate engine, you can use templates that are mutable when you serve it with node, so you can use variables as html values.
https://expressjs.com/en/resources/template-engines.html
I am writing a site in Laravel to complement a game written in Node. It pulls information directly from the game's .js files stored on GitHub and the plan is to use Vue to generate some nice HTML to display the data.
The .js files are of the form:
'use strict'
let x = {...};
exports.x = x;
I can import the files using a PHP request (simply using 'file') and pass them to JS with either jQuery.getScript or axios.get (so far). However, I am having real trouble coming up with a way to extract the 'x' values here under exports. If I were writing a JS app in node, I would simply do the following:
var xFile = require('xFile');
var x = xFile.x;
However, I can't figure out how to do that here as both GET methods return a string, not a JS file. JSON.parse() doesn't work, and I would like to come up with a solution that doesn't just replace the non-JSON text as I would need a reusable solution for other files. I don't suppose anybody has any ideas?
Thanks so much!
You could try something like below.
you could create the script tag dynamically and attach the script in the body and add your javascript code using innerHTML.
You call this script in your ajax response code.
let script = document.createElement('script');
script.innerHTML = 'alert("Hi")';
document.querySelector('body').appendChild(script);
I managed to figure it out! It's a little janky, but you can run a node file in PHP with the exec command. I just wrote a node file to import the file and return the useful data. This probably isn't an optimal solution, but it works for me since I'm much more confident with JS than with PHP.
I have a project where I use turbolinks in conjunction with Webpack's dynamic imports.
What I have is that the initial javascript file is as small as possible and then for each page, I load the relevant javascript code:
document.addEventListener('turbolinks:load', () => {
const moduleName = document.body.dataset.route;
if (!moduleName) return;
const chunkName = moduleName.replace('.', '/');
import(`#pages/${chunkName}.js`)
.catch((e) => {console.error(e);});
});
This is a great approach as each page gets its own minimal JS file.
The only issue is that we wait until the page has fully loaded before we fetch the page's javascript which makes initial page loads feel slightly slow. Ideally, I would love to preload the assets for the page when the page loads.
I thought that maybe adding a link rel=preload would solve this issue but the thing is that I do not know which chunks I need to preload on each page. This is logic that only Weboack knows.
My webpack.config.js file looks like:
output: {
chunkFilename: 'js/chunks/[name].js?id=[chunkhash]',
},
So basically each chunk is put in the js/chunks directory and its name is 0.js, 1.js, 2.js etc.
I would love to maybe somehow generate an additional json file where webpack can build a map for me. It would basically look like this (chunk key: modules that are within it):
{
0: ['#pages/tips/index.js', '#pages/tips/show.js'],
1: ['#pages/destinations/index.js', '#pages/tips/show.js'],
}
Then, I would read the file on each page and dynamically create the link rel=preload. For example, say I render the tips/show page now, I would scan the file above for each key that contains the #pages/tips/show.js and render a link rel=preload for each file (0.js and 1.js file in this case).
I'm using Webpack Commons Chunk plugin to extract the same vendors and modules to their own chunk file.
Is doing such a thing is even possible?
Thanks!
Webpack has something that is called stats that contains a-lot of info regarding the compilation.
It also contains the separation of chunks.
You can checkout what react-loadable webpack plugin does in order to generate similar task.
Hope this helps.
EDIT
You will need to write a webpack plugin that hooks on emit phase and then you will have an access to the compilation object that has all the data.
I started with a meteor project and I noticed that code is growing rapidly.
The stuff that goes inside
if (Meteor.isClient) { .... }
is getting big now. Its all Template.box...., Template.bar...., etc code, so I think it could be placed into its own file. Is this possible ?
Yes, they should be placed in their own files and you should put your isClient code under the client directory and your isServer code under the server directory. The examples each use a single .js file because it makes it easy to read when you are only dealing with a few lines of code. However, that isn't how you should build a large project.
Typically your client code would be broken out by view or url path into files where each is responsible for a single template or a collection of a few related templates. For more ideas see the unofficial-meteor-faq.
I was trying to convince a fellow co-worker into using Mustache/Hogan in the front-end of a project and I proposed the following:
Having a templates.js file, which could roughly look like this:
var tpl_alert = '<div class="alert">{{msg}}</div>';
var tpl_welcome = '<p class="user-{{type}}">Welcome, {{name}}</p>';
...
Then, we would include templates.js and use the corresponding tpl in the Mustache/Hogan.js rendering.
My proposal was turned down, since we're hardcoding html templates into js variables.
Is this really that bad? Which are other alternatives to this?
To answer your question, putting your templates in javascript variables inside a static JavaScript file makes it difficult to maintain your templates. You need to worry about string escaping whenever you want to make a simple change. And 1 syntax error will crash your app.
However, putting all your templates in a single JavaScript file is the fastest way to load your templates.
Your alternatives are:
Storing your templates in seperate files and generating the static template.js file as a prebuild step.
Loading your html template files async through AJAX into javascript variables.
Using a library like Require.js that will load your templates asynchronously as needed into variables.
My preferred way of doing this is to create a separate template file that can be loaded dynamically in development and baked into pure js for production.
Specifically I use eco templates (I wouldn't recommend them unless you're familiar with coffee script) and Stitch for node.js. Stitch supports custom engines tied to file extensions, so when it finds an eco file in my project directory it compiles it into a Javascript function. I can now include that function in any other part of my application using the stitch provided require function using the original path of the eco file. So if the template resided in src/views/listItem.eco I would run var listItemView = require('views/listItem'); to fetch it and use it like this
var html = listItemView({item: items[i]});
$someElement.html(html);
You could use require.js instead of stitch if course, or any other similar framework.