Webpack/react hot reload reloading whole page? - reactjs

This is probably asked all the time, but I've tried every approach under the sun and can't find a solution.
I've created a repo to make it easier to get help. You can clone it, run npm install and then npm start:dev to see a quick local server on http://localhost:8080.
It works, and when I change a file (say, src/components/Note/Note.css) the app does reload. However, I want to only reload the component, not the whole page. I'm not sure what I'm doing wrong. Any help will be appreciated!

To debug issues like this, enable "Preserve log" in Chrome DevTools console settings to preserve console log across page refresh.
The error was:
Uncaught RangeError: Maximum call stack size exceeded
This was fixed once the following changes were made:
Remove new webpack.HotModuleReplacementPlugin() from plugins (as webpack-dev-server is started with --hot)
Also opt-out of babel transpiling ES6 modules by updating presets in .babelrc to ["react", ["env", { "modules": false }]].
"modules": false is to tell babel to not compile import/exports and let webpack handle it as described here and here (Check step 3.3.c).

For anyone using Next.js:
If you edit a file in pages/, the whole page will reload. Bummer, state is lost.
If you edit a file in components/, only the relevant module will re-load (i.e., hot reload as you expect).
My recommendation: keep the files in your pages/ folder simple.
Iterate your design/details in a component file in the components/ folder.
For example:
// pages/welcome.jsx
import WelcomePage from "../components/welcomePage";
export default function Welcome() {
return <WelcomePage />;
}
// components/welcomePage.jsx
import React from "react";
import Layout from "./layout";
import { useContext, useEffect, useState } from "react";
import PlayerContext from "../../context/playerContext";
export default function WelcomePage() {
const { songTitle } = useContext(PlayerContext);
return (
<Layout>
<div className="...">
<div className="...">
Welcome! Let's play {songTitle}.
</div>
</div>
</Layout>
);
}
Then you can go ahead and make small edits to components/welcomePage.jsx without losing state in your browser.

Related

Using Material UI for React on Rails 7

I'm currently toying around with react on rails "the proper way", AKA using import maps as exemplified by DHH. Instead of creating everything by myself, I want to use material's components.
So, I have run ./bin/importmap pin react react-dom htm and my importmaps.rb file looked like:
#standard stuff, turbo rails etc.
...
pin_all_from "app/javascript/components", under: "components"
pin "htm", to: "https://ga.jspm.io/npm:htm#3.1.1/dist/htm.module.js"
pin "react", to: "https://ga.jspm.io/npm:react#18.2.0/index.js"
pin "react-dom", to: "https://ga.jspm.io/npm:react-dom#18.2.0/index.js"
pin "process", to: "https://ga.jspm.io/npm:#jspm/core#2.0.0-beta.24/nodelibs/browser/process-production.js"
pin "scheduler", to: "https://ga.jspm.io/npm:scheduler#0.23.0/index.js"
under javascripts/components I have
//htm_create_element.js
import { createElement } from "react"
import htm from "htm"
export default htm.bind(createElement)
and
//index.js
import { render } from "react-dom"
import h from "components/htm_create_element"
render(
h`<h1> Hi from HTM</h1>`,
document.getElementById("root")
)
It was all okay (even with a hand-made clock component) and properly shown. Then, I wanted to start using material components, so I ran ./bin/importmap pin #mui/material which added about 200 lines to my importmap.rb file (does this amount make any sense?). Next, I tried addind an empty Rating component, as can be seen here. So now, my index.js is
import { render } from "react-dom"
import h from "components/htm_create_element"
import Rating from "#mui/material/Rating"
render(
h`<h1> Hi from HTM</h1> <${Rating} name="no-value" value={null} />`,
document.getElementById("root")
)
but nothing shows (no component is rendered) and devtools console gives me
Uncaught ReferenceError: process is not defined
at chainPropTypes (chainPropTypes.js:2:7)
at elementAcceptingRef.js:47:29
Any ideas on what went wrong?

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.

Images won't load after build when using React with Electron

I'm developing an app using React and Electron.
I'm storing the images in src/assets/images. When I run the app in development using react-scripts start and electron . everything works fine.
The problem occurs when the react app is built using react-scripts build. When the first view is loaded the path is correctly resolved, for example file:///D:/Projects/app-name/build/static/media/logo.e99ed458.png and the image is displayed.
Now, when the route changes, the image no longer works. In the network tab in devTools the request URL is file:///D:/main/static/media/logo.e99ed458.png which is obviously incorrect.
This is my component code:
import React from "react";
import Logo from '../../assets/images/ad.png';
const Logo = () => {
return (
<React.Fragment>
<img src={Logo} alt="no image" />
</React.Fragment >
);
};
export default Logo;
And in electron.js
mainWindow.loadURL(url.format({
protocol: 'file',
slashes: true,
pathname: require('path').join(__dirname, '../build/index.html')
}));
I've been trying to solve this problem for two days now. Does anyone know a solution?
EDIT:
I have also tried using PUBLIC_URL according to https://create-react-app.dev/docs/using-the-public-folder/
But the result is the same, the path is resolved correctly when the first view is displayed and after that it resolves to file:///D:/assets/images/logo.png.
When I log process.env.PUBLIC_URL it says that PUBLIC_URL is equal to ".".
I solved this issue by changing the routers instead of using BrowserRouter you should use HashRouter
This article https://www.freecodecamp.org/news/building-an-electron-application-with-create-react-app-97945861647c/ has a good example but Does not have the configurations of routers

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.

unable to load velocity with scrollmagic and react

I have a react project and I'd like to use scrollmagic with the velocity plugin. Here's what I did from terminal once I already have a react project set up
npm install scrollmagic
npm install velocity-react
This is what my src/App.js looks like
import React, { Component } from 'react';
import ScrollMagic from 'scrollmagic';
import Velocity from 'velocity-react';
class App extends Component {
componentDidMount() {
// init controller
var controller = new ScrollMagic.Controller();
// build scene
var scene = new ScrollMagic.Scene({triggerElement: "#trigger"})
// trigger a velocity opaticy animation
.setVelocity("#animate", {opacity: 0}, {duration: 400})
.addIndicators() // add indicators (requires plugin)
.addTo(controller);
}
render() {
return (
<div>
<div className="spacer s2"></div>
<div className="spacer s2"></div>
<div id="trigger" className="spacer s0"></div>
<div id="animate" className="box1 blue">
<p>Now you see me...</p>
view source
</div>
<div className="spacer s2"></div>
</div>
);
}
}
export default App;
Then I ran my webpack command without error. Now when I look in my Chrome browser, I see a blank page. And the debug console gives me these errors:
15:56:08:694 (ScrollMagic.Scene) -> ERROR calling setVelocity() due to
missing Plugin 'animation.velocity'. Please make sure to include
plugins/animation.velocity.js
15:56:08:694 (ScrollMagic.Scene) -> ERROR calling addIndicators() due
to missing Plugin 'debug.addIndicators'. Please make sure to include
plugins/debug.addIndicators.js
How do you get these Velocity and Indicator functiosn to work with scrollmagic in a reactjs environment?
I came across this issue in a recent project. There are a couple of hoops you need to jump through to get it up and running.
1) I had to add aliases for all the imports I wished to make. This was done via the webpack.app.config.js file.
module.exports = options => ({
resolve: {
alias: {
"TweenMax": "gsap/src/uncompressed/TweenMax.js",
"TimelineMax": "gsap/src/uncompressed/TimelineMax.js",
"ScrollToPlugin": "gsap/src/uncompressed/plugins/ScrollToPlugin.js",
"ScrollMagic": "scrollmagic/scrollmagic/uncompressed/ScrollMagic.js",
"ScrollMagicAddIndicators": "scrollmagic/scrollmagic/uncompressed/plugins/debug.addIndicators.js",
"ScrollMagicGSAP": "scrollmagic/scrollmagic/uncompressed/plugins/animation.gsap.js"
}
}
});
2) Once I had added this. I had to have the correct order of imports inside my runtime script.
import * as ScrollMagic from 'scrollmagic';
import 'TimelineMax';
import 'ScrollMagicGSAP';
import 'ScrollMagicAddIndicators';
This all worked with the following dependencies.
"gsap": "^1.20.3",
"scrollmagic": "^2.0.5",
Hope this helps.

Resources