Reactjs require image url in variable is not working - node.js

Strange problem
I'm dynamically including the path to an image in the source directory.
Putting the image directory in as a string works Fine (the part I commented out), but as soon as I put it in a variable it gives me the error " Cannot find module ".""
var imageDir="assets/img/MyImage.png";
--Working // const imageData= require('assets/img/MyImage.png');
--Not Working const imageData= require(imageDir);
Any one know why?
Same-ish problem Here
No answer unfortunately

Webpack needs to know what files to bundle during compile-time, but the real path value for expression(variable) only be given in runtime, you need require.context:
/* If the structure is like:
src -
|
-- index.js (where these codes are deployed)
|
-- assets -
|
--img
*/
let assetsPath = require.context('./assets/img', false, /\.(png|jpe?g|svg)$/);
// See where are the images after bundling.
// console.log(assetsPath('./MyImage.png'));
// You can put all the images you want in './assets/img', and access it.
var newElement = {
"id": doc.id,
"background": assetsPath('./MyImage.png');
};

If you wish use image on your react web application you can use next code
when use directly in html tag, but if you can use in part of java script, you must use const image = require('../Assets/image/03.jpg') and call letter this constant like this {image} between example tags

Related

React: add HTML from generic file path at server-side build time

The use case I'm trying to fulfill:
Admin adds SVG along with new content in CMS, specifying in the CMS which svg goes with which content
CMS commits change to git (Netlify CMS)
Static site builds again
SVG is added inline so that it can be styled and/or animated according to the component in which it occurs
Now - I can't figure out a clean way to add the SVG inline. My logic tells me - everything is available at build time (the svgs are in repo), so I should be able to simply inline the svgs. But I don't know how to generically tell React about an svg based on variables coming from the CMS content. I can import the svg directly using svgr/weback, but then I need to know the file name while coding, which I don't since it's coming from the CMS. I can load the svg using fs.readFileSync, but then the SVG gets lost when react executes client-side.
I added my current solution as an answer, but it's very hacky. Please tell me there's a better way to do this with react!
Here is my current solution, but it's randomly buggy in dev mode and doesn't seem to play well with next.js <Link /> prefetching (I still need to debug this):
I. Server-Side Rendering
Read SVG file path from CMS data (Markdown files)
Load SVG using fs.readFileSync()
Sanitize and add the SVG in React
II. Client-Side Rendering
Initial Get:/URL response contains the SVGs (ssr worked as intended)
Read the SVGs out of the DOM using HTMLElement.outerHTML
When React wants to render the SVG which it doesn't have, pass it the SVG from the DOM
Here is the code.
import reactParse from "html-react-parser";
import DOMPurify from "isomorphic-dompurify";
import * as fs from "fs";
const svgs = {}; // { urlPath: svgCode }
const createServerSide = (urlPath) => {
let path = "./public" + urlPath;
let svgCode = DOMPurify.sanitize(fs.readFileSync(path));
// add id to find the SVG client-side
// the Unique identifier is the filepath for the svg in the git repository
svgCode = svgCode.replace("<svg", `<svg id="${urlPath}"`);
svgs[urlPath] = svgCode;
};
const readClientSide = (urlPath) => {
let svgElement = document.getElementById(urlPath);
let svgCode = svgElement.outerHTML;
svgs[urlPath] = svgCode;
};
const registerSVG = (urlPath) => {
if (typeof window === "undefined") {
createServerSide(urlPath);
} else {
readClientSide(urlPath);
}
return true;
};
const inlineSVGFromCMS = (urlPath) => {
if (!svgs[urlPath]) {
registerSVG(urlPath);
}
return reactParse(svgs[urlPath]);
};
export default inlineSVGFromCMS;

Marko Dynamic Tag with Component

I have a marko website where I have some dynamic components being called via a for loop:
/pages/note/index.marko
import layout from "../../layouts/base"
<${layout} title="test">
<for|card| of=input.cards>
<${card} />
</for>
</>
this is given a set of "notes" (just other marko files with the content) that I want to fill the page with dynamically based on the request (this is handled in the server just fine). It is loading these notes fine.
However, when I have the card marko file use a component, the component ony half works.
note1/index.marko
<math>5x+1=11</math>
math/index.marko
class {
onCreate() {
console.log("CREATED") // runs
}
onMount() {
console.log("MOUNTED") // doesn't run
// eventually I plan to run some math rendering code here
}
}
<span><${input.renderBody} /></span>
The issue is that the browser side of things never run. Also, I am getting this inexplicable error in the browser
edit: changed the rendering in the routing. somehow the error went away
routes.js
...
app.get("/note.html", async (req, res, next) => {
let title = req.query.title || "" // get the requested card
let dependencies = request(`./notes/${title}/dependencies.json`) || [] // get all of the linked cards to the requested card
let cards = [title, ...dependencies].map(note => request(`./notes/${note}`)) // get the marko elements for each card
// by this point, "cards" is a list with marko templates from the /notes/ directory
// render
let page = request(`./pages/note`, next)
let out = page.render({"title": title, "cards": cards}, res)
}
...
My file structure is set up like this:
server.js
routes.js
pages/
note/
index.marko
notes/
note1/
index.marko
note2...
components/
math/
index.marko
layouts/
base/
index.marko
Using: node, express, marko, & lasso.
Your custom tag of <math> is colliding with the native MathML <math> element, which is why you’re getting that error only in the browser.
Try naming it something else, like <Math> or <my-math>.

Server Side rendering in mongo with dust

Is it possible to fetch data from MongoDB and render a html template on the server side itself for a node-js project?
As of now in my serverside js file I've done the following.
//Failing array will be populated by a db.find later on.
var failing = [
{ name: "Pop" },
{ name: "BOB" }
];
/*Now i have to send a mail from the server for which I'm using nodemailer.
Where do i store the template ? This is what I've done in the same file */
var template = "<body>{#failing} <p>{.name}</p> {/failing}</body>"
// Add this as the body of the mail and send it.
I'm not sure how to render the data and how to get it displayed. I'm aware storing the template in the variable isn't right but I'm not sure what else to do.
If your template is that short, you can store it in a variable without problem. Obviously, you can store it in a file also.
Let's say you decide to store it in a file index.dust:
<body>{#failing} <p>{.name}</p> {/failing}</body>
Now, in your node controller you need to load the file and generate the html content from it:
const fs = require('fs');
const dust = require('dustjs-linkedin');
// Read the template
var src = fs.readFileSync('<rest_of_path>/index.dust', 'utf8');
// Compile and load it. Note that we give it the index name.
var compiled = dust.compile(src, 'index');
dust.loadSource(compiled);
// Render the template with the context. Take into account that this is
// an async function
dust.render('index', { failing: failing }, function(err, html) {
// In html you have the generated html.
console.log(html);
});
Check the documentation in order not to have to compile the template every time you have to use it.

Render Image Stored in Mongo (GridFS) with Node + Jade + Express

I have a small .png file stored in Mongo using GridFS. I would like to display the image in my web browser using Node + Express + Jade. I can retrieve the image fine e.g.:
FileRepository.prototype.getFile = function(callback,id) {
this.gs = new GridStore(this.db,id, 'r');
this.gs.open(callback);
};
but I don't know how to render it using the Jade View Engine. There doesn't seem to be any
information in the documentation.
Can anyone point me in the right direction?
Thanks!
I figured this out (thanks Timothy!). The problem was my understanding of all these technologies and how they fit together. For anyone else who's interested in displaying images from MongoDB GridFS using Node, Express and Jade ...
My Document in MongoDB has a reference to the Image stored in GridFS which is an ObjectId stored as
a string. e.g. MyEntity {ImageId:'4f6d39ab519b481eb4a5cf52'} <-- NB: String representation of ObjectId. The reason I stored it as a string was because storing the ObjectId was giving me a pain
in the Routing as it was rendering as binary and I couldn't figure out how to fix this. (Maybe someone can help here?). Anyway, the solution I have is below:
FileRepository - Retrieve the image from GridFS, I pass in a String Id, which I then convert to
a BSON ObjectId (you can also get the file by file name):
FileRepository.prototype.getFile = function(callback,id) {
var gs = new GridStore(this.db,new ObjectID(id), 'r');
gs.open(function(err,gs){
gs.read(callback);
});
};
Jade Template - Render the HTML Markup:
img(src='/data/#{myentity.ImageId}')
App.JS file - Routing (using Express) I setup the '/data/:imgtag' route for dynamic images:
app.get('/data/:imgtag', function(req, res) {
fileRepository.getFile( function(error,data) {
res.writeHead('200', {'Content-Type': 'image/png'});
res.end(data,'binary');
}, req.params.imgtag );
});
And that did the job. Any questions let me know :)
I'm a little confused about what you're trying to do here, as Jade is a condesed markup language for text output (such as HTML), not binary content.
Since you're using Jade you probably have something like this:
app.get/'images/:imgtag', function(req, res) {
res.render('image', {imgtag: req.params.imgtag);
});
So try this:
app.get/'images/:imgtag', function(req, res) {
filerep.getFile( function(imgdata) {
res.header({'Content_type': 'image/jpeg'})
res.end(imgdata);
}, req.params.imgtag );
});
That will send the raw file as a response to the HTTP request with the correct mime type. If you want to use Jade to deliver a template (such as an image popup) you could use a different route for the popup or even use a data: uri and encode the image data in the page.

Connect and Express utils

I'm new in the world of Node.js
According to this topic: What is Node.js' Connect, Express and “middleware”?
I learned that Connect was part of Express
I dug a little in the code, and I found two very interesting files :
./myProject/node_modules/express/lib/utils.js
and better :
./myProject/node_modules/express/node_modules/connect/lib/utils.js
These two files are full of useful functions and I was wondering how to invoke them correctly.
As far, in the ./myProject/app.js, that's what I do:
var express = require('express')
, resource = require('express-resource')
, mongoose = require('mongoose')
, expresstUtils =
require('./node_modules/express/lib/utils.js');
, connectUtils =
require('./node_modules/express/node_modules/connect/lib/utils.js');
But I found it a little clumsy, and what about my others files?
e.g., here is one of my routes:
myResources = app.resource(
'myresources',
require('./routes/myresources.js'));
and here is the content of myresources.js:
exports.index = function(req, res)
{
res.render('./myresources.jade', { title: 'My Resources' });
};
exports.show = function(req, res)
{
fonction resourceIsWellFormatted(param)
{
// Here is some code to determine whether the resource requested
// match with the required format or not
// return true if the format is ok
// return false if not
}
if (resourceIsWellFormatted(req.params['myresources']))
{
// render the resource
}
else
{
res.send(400); // HEY! what about the nice Connect.badRequest in its utils.js?
}
};
As you can see in the comment after the res.send(400), I ask myself if it is possible to use the badRequest function which is in the utils.js file of the Connect module.
What about the nice md5 function in the same file?
Do I have to place this hugly call at the start of my myresources.js to use them?:
var connectUtils =
require('../node_modules/express/node_modules/connect/lib/utils.js');
or, is there a more elegant solution (even for the app.js)?
Thank you in advance for your help!
the only more elegant way i came up with is (assuming express is inside your root "node_modules" folder):
require("express/node_modules/connect/lib/utils");
the node installation is on windows, node version 0.8.2
and a bit of extra information:
this way you don't need to know where you are in the path and be forced to use relative paths (./ or ../), this can be done on any file nesting level.
i put all my custom modules inside the root "node_modules" folder (i named my folder "custom_modules") and call them this way at any level of nesting:
require("custom_modules/mymodule/something")
If you want to access connect directly, I suggest you install connect as a dependency of your project, along with express. Then you can var utils = require('connect').utils.

Resources