visual studio react image path cannot reach - reactjs

So i have a visual studio project created with react.js.
I am trying to link to an image dynamically, but failing. This is the code I am trying:
At the top im setting a variable for the first part of the path:
this.LogoPath = '../images/'
And then im dynamically grabbing the name of the image from an api call.
this.setState({ imageNamePath: this.state.location.imageName })
And then im concatinating them:
{`${this.LogoPath}${this.state.location.imageName}`}
In the console, im getting:
img src='../images/the-images-name-here.png'
So it seems to be working, but it is not. I get no errors, and I have broken images. My best guess is that react is changing the images to something like:
image-name-here.6a131799.png
Surely someone has run across this before, but my google search pulled up little help.
So how do i get the images to show?

Webpack is a smart tool. One of it's strength is the trash code/files elimination from the bundle.
That means that if a file is not imported using import myFile from '../myPath/myFile.jpg'; or require('../myPath/myFile.jpg');` it won't be a part of the final bundle.
In your case you're not importing the file. You're creating a string variable instead which means nothing to webpack.
There are different options that could work in your case:
Option 1: Pre-import all images and map them in an object:
import React, {Component} from 'react';
import image1 from '../assets/image1.png';
import image2 from '../assets/image2.png';
import image3 from '../assets/image3.png';
const imageTypes = {
image1,
image2,
image3,
}
export default class MyComponent extends Component {
constructor(props) {
super(props);
this.state = {
imageType: 'image1'
}
}
render() {
return (
<img src={imageTypes[this.state.imageType]} />
)
}
}
Option 2: Not recommended - Use require to dynamically import files (webpack configurations might be needed in order to include all possible required images in the production bundle):
class MyComponent {
constructor(props) {
super(props);
this.state = {
image: 'file1.png'
}
}
render() {
return (
<img src={require(`./assets/${this.state.image}`)} />
)
}
}
Option 3: Send the image blob (in base64) from the API.
I suggest you to use the Option 1 or Option 3, based on your requirements, such as: how often will be images be changed/added/removed. It's not normal to import files dynamically from ReactJS bundle and you might end up having a non-existing image in your project requested by the data coming from an external source.
For Option 2 you also might have some problems configuring the webpack in order to include in the bundle all the images that you'll probably need to render, even though they are not imported (hardcoded) somewhere in the JS files. Keep in mind that the React Application in production ends up being a collection of static files. You'll need to treat them as follows.

Related

Getting "Unsafe attempt to load URL data:image/svg+xml..." in Safari using a through React component

I'm using rollup to bundle a react npm package that contains an icon component that takes a name as a prop and returns an Icon with that name wrapped by a react component.
This is the component code:
import sprite from './public/sprite.svg';
function Icon({ name }) {
return <svg className="svg-wrapper">
<use href={`${sprite}#${name}`} />
</svg>
);
}
The folder structure is the following:
- src
- - public
- - - sprite.svg
- - icons
- - - some-icon.svg
- - - some-other-icon.svg
- - index.tsx # component with the code mentioned above
And this is my rollup config:
export default {
plugins: [
esbuild({
sourceMap: false,
target: "esnext"
}),
image(),
svgicons({
inputFolder: "src/icons",
output: "public/sprite.svg"
}),
json()
]
}
This works fine in Chrome (although it does inline all the svg inside of the href which I think it's the purpose of this approach) but in Safari it triggers the following error:
Unsafe attempt to load URL data:image/svg+xml,%3c%3fxm ....
Domains, protocols and ports must match.
The thing is, as mentioned, this is an npm package that packages the icons as part of the js bundle (inlining) so there's not much control over how this component is served since this is handled by the browser caching (also one of the key points of using this approach). I'm quite familiar with CORS and I know that perhaps avoiding to use data:image/svg+xml uri links would fix this but would increase the complexity of the build steps of this package (needing to build the icons using svgr/svgo and then have some kind of lookup table to give back the right icon based on the name prop i.e.).
So, ultimately my question is, with the sprite approach in a react component library is there a foolproof way of avoiding these kind of issues and cross-browser inconsistencies?
Thanks in advance for any help provided.
I have been struggling with this issue for a while. I guess this is a bug on Safari throwing an error because is dealing with a dataURI as if it was an external URL.
About your code, you could expose your sprite in a public folder or publish it in a cdn (good for caching purposes) and change the way rollup is handling your svg (it seems it is packing your svg as a dataURI). Alternatively, I implemented a workaround to convert the dataURI in a blob.
import sprite from './public/sprite.svg';
function dataURItoBlobUrl(dataURI: string) {
const svg = decodeURI(dataURI).split(',')[1];
const blob = new Blob([svg], { type: "image/svg+xml" });
return URL.createObjectURL(blob);
}
const blobUrl = dataURItoBlobUrl(sprite);
export const Icon: FC<IconProps> = ({ name, ...props }) => {
return (
<svg xmlns="http://www.w3.org/2000/svg" {...props}>
<use href={`${blobUrl}#${name}`}></use>
</svg>
);
};

Full-fledged PDF.js viewer in React

I'm looking to use the full-featured PDF.js in a React component in a Next.js project, as seen in Firefox and as on this online demo. Some important features here are being able to navigate to a certain page number by typing it in, and searching for text in the PDF. Is there a React component available for that?
The library react-pdf is nice for rendering a single page, but doesn't provide a toolbar or a convenient way of lazily loading pages in a scrollable view.
Similar to the questions How to use full PDF.js viewer with toolbar in webpack and Vuejs? (where the accepted answer provides a Vue component) and Embed Full Mozilla pdf.js viewer in vue.js ( using webpack via vue-cli ), but for React.js.
I tried including including /web/viewer.html as part of the inner HTML of a React component by doing the following, but it didn't work out.
Download the latest release and extract it to a folder part of my Next.js project (which I called pdfjs). I tried several folders, such as /client, /client/components, /pages, /node_modules, and /.
Run npm install --save-dev html-loader
Use this Webpack loader that parses HTML files, by changing next.config.js to the following:
module.exports = {
// …
webpack: (config, options) => {
config.module.rules.push({
test: /\.html$/,
exclude: /node_modules/,
use: { loader: 'html-loader' }
});
return config;
},
}
Create a simple page under /pages as follows:
import React from 'react';
import PdfViewer from '../pdfjs/web/viewer.html'
export default function () {
return (
<div className="content" dangerouslySetInnerHTML={{ __html: PdfViewer }} />
);
};
After running next in terminal to start a dev server and navigating to that page in the browser, I get an error about the JavaScript heap running out of memory.
Even if my computer had enough memory, I'm not sure that this would actually result in the PDF rendering – not to mention the danger of using dangerouslySetInnerHTML. It looks like a better solution would probably be to have an actual React component rather than trying to embed an HTML file.
I think this might be more of what your after. I wrapped it in a component for you already but this is a document viewer which can view PDF documents with out much work.
import React,{ Component } from 'react';
import ReactDOM from 'react-dom';
class DocView extends React.Component{
constructor(props){
super(props);
}
render(){
var url = "https://docs.google.com/viewerng/viewer?url="+this.props.src+"&embedded=true";
return(
<iframe style={this.props.style} src={url}></iframe>
);
}
}
export default DocView;
CloudPDF offers a React PDF viewer. It is basically pdf.js but then pre-rendered on the server. This gives the possibility for lazy loading of large pdf files and still keeping performance. And by default has a nice layout for the viewer.
import CloudPdfViewer from '#openbook/cloudpdf-viewer';
export default function () {
return (
<CloudPdfViewer documentId="346467a6-fa61-43ad-b45a-d1fdc3da0007" width="100%" height="500px" />
);
};
Disclamer: I am working for CloudPDF and it is still a beta version.

Is there a way to import an MDX or MD markdown file in React and use it in a data array?

I want to make a list of blog posts and therefor I thought it would be easy to use MDX because it helps with styling each blog text. But I don't know if it's possible to import a MDX file and put it in blogs.text.
I tried to use the npm package mdx.macro with it's function importMDX, but I get an error which says that the imported file is outside the src/.
mdx.macro documentation: https://www.npmjs.com/package/mdx.macro
import React, { lazy } from 'react';
import { importMDX } from 'mdx.macro';
const blog1 = lazy(() => importMDX('./blog1.md'));
export const blogs = [
{
title: "Hello World",
subtitle: "subtitle",
text: blog1
}
];
export default blogs;
I import this file in my blog and loop through all the items. But the importMDX keeps giving me the following error:
Module not found: You attempted to import
node_modules\.cache\mdx.macro\Content.6cbf05377c.mdx.js
which falls outside of the project src/ directory.
Relative imports outside of src/ are not supported.
Maybe there's an easier option than this?
Thanks in advance!
Adding to #mfakhrusy's answer , I had to change my blogs.js file to
import { mdx } from 'mdx.macro';
import Blog1 from './Blog1.js';
export const blogs = [
{
title: "My experiences as an intern working without getting paid",
subtitle: "And the difficulties that come along with being undervalued by a company",
text: <Blog1 />
}
];
export default blogs;
And my Blog1.js file contains this
import React from 'react';
import { mdx } from 'mdx.macro';
export const Blog1 = mdx`
# Don't Panic
Since we decided a few weeks ago to adopt the leaf as legal tender, we have, of course, all become immensely rich.
`
export default Blog1;
So now I can write blogs in markdown format and loop through them to show them on my website!
According to The create-react-app imports restriction outside of src directory
It's a restriction from CRA developer. You can try to eject your CRA app and try it again. (see eject script on package json), and remove ModuleScopePlugin from webpack config. Be careful though, eject is a one-way trip, you cannot go back.
It happens because from what I've seen from the doc, the package tries to generate a cache file which being imported later by the app, and CRA would prohibit that by throwing that error you encountered.

React: How to reference an image url in require

I have a data file api that has bunch of images url stored locally
const url =[
{ title:img1,
img_src="./img/img1.png"
},
{ title:img2,
img_src="./img/img2.png"
},
{ title:img3,
img_src="./img/img3.png"
}
]
And using react/redux I pass the url state as props to my react components.Next I want to display them in my components by using require
<img src=require(?)/>
What's the appropriate syntax here? I've used es6 template string ${this.props.urls.img_src} but it throws an error that it couldn't resolve the path. I've tried to require("./img/img1.png") just to test to rule out broken path and it worked. But still wouldnt work if you reference it using a prop.
Solution
After researching, and thanks to Rei Dien for the input, I now can use variables in require by using context require
<img src={require("./img/"+this.props.img_src)}/>
Since you passed the url in the props, you can do this :
this.props.url.map(n => {
return (
<img src={n.img_src}/>
)
})
this will diplay all the images.
since require works in static mode during build process on node only so follow following steps.
1) take all image urls and store them in a javascript file
so
//imageURLs.js
import image1 from "path_to_image_file_1";
import image2 from "path_to_image_file_2";
import image3 from "path_to_image_file_3";/**do like this for all images stored locally, image1, image2,.. are the image identifiers(title in your case) you would get in api call**/
export const urls = {image1, image2, image3};
//image usage file
read api for identifier and
import imageURLs from './imageURLs.js';
<img src={imageURLs[image_id_from_api]}/>

How to write Autodesk.Viewing.Extensions with webpack and react?

I was write code within view3D v2.11, React, ES6 and webpack. But I don't know how to write Autodesk.Viewing.Extensions within webpack and React. Can anyone show me some examples?
Using webpack to write a viewer extension is no different than using webpack to write any other js application. Take a look at my extensions library repo, each extension is bundled into a separate .js or .min.js whether you build the project in dev or prod: library-javascript-viewer-extensions.
This is designed this way so each extension can be loaded dynamically independently, however if you build an entire application around the viewer, you may simply include the code for each extension along with the rest of the app and generate a single webpack bundle.
This React project contains multiple viewer extensions (some are extracted from the library mentioned above) and is bundling extensions code along with the rest of the app: forge-rcdb.
As far as React and the viewer are concerned, it's not very relevant because the viewer is a 3D component which is created dynamically, all WebGL canvas and viewer 2D elements are being generated after your app loads a model, whereas React lets you declare 2D components when the app is starting. I was playing a bit with injecting dynamically React components to the viewer div, you can take a look in that same project here:
this.viewer = new Autodesk.Viewing.Private.GuiViewer3D(this.viewerContainer)
// Experimental !
// This this to render dynamic components
// inserted after the viewer div has been created
const reactViewerNode = document.createElement('div')
this.viewer.container.appendChild(reactViewerNode)
this.viewer.react = {
node: reactViewerNode,
components: [],
addComponent: (component) => {
this.viewer.react.components.push(component)
},
render: (props) => {
ReactDOM.render(
<div>
{
React.Children.map(
this.viewer.react.components,
(child) => React.cloneElement(child, props))
}
</div>,
reactViewerNode)
}
}
I then render those dynamic components by overriding componentDidUpdate:
componentDidUpdate () {
if (this.viewer && this.viewer.react) {
if(this.viewer.react.components.length) {
this.viewer.react.render(this.props)
}
}
}
and there is an example of use:
viewer.react.addComponent(
<DBDropdown key="test" className="react-div">
</DBDropdown>
)
I actually haven't implemented any feature using that in the live version of the app, but it should give you an idea.
Hope that helps.

Resources