Electron, React and Webpack, how to make HMR work? - javascript

It is hard to comprehend the complexities of webpack and I need some help getting HMR to work, I have started a new project using electron-forge using the typescript-webpack template.
The project got created with the following structure:
You can see the ts-loader configuration is already in there, afterwards I added react and react-dom and set up a hello world App component, the problem is now, when I change that component, I get a webpack HMR error:
not sure how to solve this issue, react-hot-loader seems to be the library to go to get this working but not sure how to make it work with ts-loader, could anybody point out how to get this set up working? Thanks!
Edit 1: I tried adding react-hot-reload but I get a require is not defined error...

Well, after fumbling around with the react-hot-loader package I just could not get it to work, so I stumbled upon the default webpack hot reloading way:
on the index file (where you import your root react component, you can use something like:
declare let module: { hot: any };
if (module.hot) {
module.hot.accept("./App", () => {
const NewApp = require("./App").default;
render(<NewApp />, document.getElementById("app"));
});
}
At least it seems to be working so far

Related

requestAnimationFrame is not defined nest.js/vue [duplicate]

I'm working on Next.js and React-Native-Web. I managed to run them together following the official Next.js example but when I'm trying to use the Animated package from the react-native it fails with Error that the requestAnimationFrame isn't defined. Basically this functionality does the node_modules package but I set the alias in webpack to translate all react-native requires to the react-native-web so even the node_modules package should use the react-native-web.
Any suggestions on how to solve it?
ReferenceError: requestAnimationFrame is not defined
at start (...node_modules\react-native-web\
dist\cjs\vendor\react-native\Animated\animations\TimingAnimation.js:104:11)
enter code here
Thanks for any help!
The problem is in the missed RequestAnimationFrame functionality at the server. This error happens when Next.js tries to render the component during SSR.
Unfortunately, there is no polyfill, etc. for such purpose so I just decided to use the Next.js dynamic imports for a Component that has animation functionality.
Next.js Official documentation
My own case оust to show how code looks:
import dynamic from 'next/dynamic';
const AutocompleteDropdown = dynamic(
() => import(
'myAwesomeLib/components/dropdown/autocomplete/AutocompleteDropdown'
),
{
ssr: false,
}
);
Now you can use the AutocompleteDropdown as the standard JSX component
I'm coding an App with React Native Web and NextJS 12, and in 2021 I encounter this problem and I fixed it, but now I know my fix was only for Next Dev, because it returned for Next Production Build.
Solution details:
No Dynamic import (which is useful too, but can be annoying when having lot of components using it)
Using RAF polyfill and Webpack ProvidePlugin.
Main thing to have in mind is that next.config.js with webpack 5 is going to check the codes first before even reach next entry points _documents.js and _app.js. It means that, you can put polyfill in those entry point files, it will still raise error of RAF undefined. You have to make requestAnimationFrame ready for config check.
DEV approach that will work on Next DEV only. Install RAF package https://www.npmjs.com/package/raf and In next.config.js add codes:
const raf = require('raf');
raf.polyfill();
This will add requestAnimationFrame and cancelAnimationFrame function to global and window object if they don't have it. In our case, it would add it in global for NodeJS.
But this solution won't work when executing npm run dev. I don't know why, if anyone knows why Next or Webpack 5 act differently from DEV to PRODUCTION, let me know.
Complete Solution:
Use ProvidePlugin config of webpack 5 https://webpack.js.org/plugins/provide-plugin/ . Create a file to use as modules, let's say: raf.js in root project or anywhere you want:
const raf = require('raf');
const polys = {};
raf.polyfill(polys);
module.exports = polys.requestAnimationFrame;
And in next.config.js use it inside webpack: () = {} like:
webpack: (config, options) => {
// console.log('fallback', config.resolve.fallback);
if (options.isServer) {
// provide plugin
config.plugins.push(
new options.webpack.ProvidePlugin({
requestAnimationFrame: path.resolve(__dirname, './raf.js'),
}),
);
}
And now, it's up to you to adapt to your existing config logic. By doing this, in Production Build, NextJS is injecting the requestAnimationFrame function in Server Side everywhere a module is using it.

Next.js - TypeError: Cannot read properties of null (reading 'useMemo')

Since refactoring my code to move generic hooks and components to their own git submodules within my project I get TypeError: Cannot read properties of null (reading 'useMemo') whenever I call one of my custom hooks referring to useMemo.
I removed all the logic from a hook to make sure it didn't come from undefined arguments, so now my file looks like:
import { useMemo } from 'react'
export function useMyCustomHook() {
return useMemo(() => [], []) // Does nothing useful, but fails anyway
}
export function useMyCustomHookWithoutMemo() {
return [] // Does nothing useful, doesn't fail
}
I'm using next.js at the lastest version and
the project structure is like this:
components/
component.js (this is where I call useMyCustomHook imported from 'generics')
hooks/
pages/
index.js (returns component)
generics/
index.js (with export * from './hooks/useMyCustomHook')
hooks/
useMyCustomHook.js
I also have a jsconfig.json file with the following content, so I can write stuff like import Component from 'components/component':
{
"compilerOptions": {
"baseUrl": "."
}
}
Is next.js not compiling code in my generics folder? How can I get useMemo to work with this folder structure?
I tried moving useMyCustomHook.js to the hooks folder and it works there, so I'm guessing it has to do with a webpack config? I don't know much about those, that's why I love next.js
I started from scratch and moved files one by one into a libs folder, and added paths in jsconfig.json so I wouldn't have long imports into my libs and it seems to work for now. Probably a bug with next.js, webpack and git submodules
maybe you can add a console line after import line to ensure if useMemo exist. like this:
import { useMemo } from 'react';
console.log(useMemo);
the point is to find the variable whose value is null.
This might be a case of circular imports in your code. Webpack doesn't handle them well.
Make sure that you're not importing from components folder to generics or hooks. Try to run no-cycle eslint rule on your app, it might help to identify those: https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-cycle.md
useMemo() is available for react 16.8.6+, So if your react is not updated, you should update it, otherwise, i would try something like:
useMemo(()=>console.log("test),[])
and check dev tab in browser.
For me the issue was that had placed the useMemo out of the function component by mistake

Why are some components in my React TS component library throwing Minified React error #321

I am building a React component library with TypeScript and webpack and I test it with webpack serve on a blank html page. Now the weird thing is that when I use the components like that every single component works perfectly fine. However if I want to use them in another project (install the library with npm) e. g. with a create-react-app a few throw a Minified React error #321. I have no idea why this is happening. Also I cant see a pattern in the Not-working components.
If you want to give it a try yourself: https://www.npmjs.com/package/athenic-ui
I've just looked at your repo and I think the problem Minified React error #321 is likely from including react/react-dom into the build your library. Then having more than one React instances after consuming project getting built.
So in order to fix you would have to exclude react/react-dom as external deps where should be included at parent project level which consumes your library.
// webpack.config.js
exports.module = [
// your dev one
// { ... },
// your prod one
{
// ...
externals: {
react: "react",
'react-dom': "react-dom"
},
}
]
PS: After having done above step, you might recognize your main bundle file would significantly be reduced in size as well :)

Electron-Bootstrap-Vue doesn't want to show my toast, and throw me errors I don't understand

So I wanted to develop a desktop application using Electron. As I wanted to practice Bootstrap-Vue too, I chose the Electron-Vue boilerplate which seems really simple to use and cool. To create a new project with Electron-Vue, I ran vue init simulatedgreg/electron-vue my-project
Electron-Vue doesn't come with booostrap-vue, it only comes with vue. Using npm, I was able to put it into my project with npm install bootstrap bootstrap-vue portal-vue (Yes, I also installed portal because I wanted to use the toast system).
And after that, I modified the main.js to include bootstrap and bootstrap-vue :
/*personnal addings*/
import BootstrapVue from 'bootstrap-vue'
import PortalVue from 'portal-vue'
import 'bootstrap/dist/css/bootstrap.css'
import 'bootstrap-vue/dist/bootstrap-vue.css'
Vue.use(BootstrapVue)
Vue.use(PortalVue)
And yay ! Everything seemed to works !
But that was before I ran into a major problem :
/home/kisis/ENSEIRB-MATMECA/ENSEIRB/troisième-semestre/sgbd/my-project/node_modules/vue/dist/vue.runtime.common.dev.js:621 [Vue warn]: $attrs is readonly.
found in
---> <Portal>
<BToastPop>
<Sgbd2> at src/renderer/App.vue
<Root>
and :
/home/kisis/ENSEIRB-MATMECA/ENSEIRB/troisième-semestre/sgbd/my-project/node_modules/vue/dist/vue.runtime.common.dev.js:621 [Vue warn]: $listeners is readonly.
found in
---> <Portal>
<BToastPop>
<Sgbd2> at src/renderer/App.vue
<Root>
Noooo ! Everything ran so smoothly before that :'(
Thus, this error pop whenever I want to use the toast-on-demand system of bootstrap (which is used with $bvToast.toast ). And on top of that, my toast doesn't even show. I think that the error prevents it from even existing.
But I had Google at least, I thought. So I searched and I searched, seeing that I was not the only one with this error. Alas, the majority of those problems were solved by modifying the webpack configuration to add
resolve: {
alias: {
// If using the runtime only build
vue$: 'vue/dist/vue.runtime.common.js'
// Or if using full build of Vue (runtime + compiler)
// vue$: 'vue/dist/vue.esm.js'
}
}
Sadly, this doesn't work at all with me. I tried everything, even ran npm run pack to "refresh" the webpack configuration after the modification, but this doesn't change anything. I don't know what to do, really. I would be glad if someone could help me on this one, because I don't understand at all what is happening.
Thanks in advance !

Create-React-App with Moment JS: Cannot find module "./locale"

Just ran an npm update on my web application and now Moment JS appears to be failing with the following message:
Error: Cannot find module "./locale"
\node_modules\moment\src\lib\moment\prototype.js:1
> 1 | import { Moment } from './constructor';
Not sure what version of Moment JS I had prior to my update, but my application has been working for months.
I created another react app and ran an npm install moment --save and modified the source to display the time and ended up with the same error described above.
Not sure if there is a fail-proof way to integrate Moment JS using Create-React-App currently short of ejecting to manage the webpack settings myself, but I really don't want to do this. Anyone else seeing these issues or having success? If so, a short write up would go along way to helping out.
Appears this has already been identified as an issue for Moment JS version 2.19. If you have upgraded to 2.19 run npm install moment#2.18.1 to revert back to previous version until it is fixed!
See thread: https://github.com/moment/moment/issues/4216
Application built with Create React App and using Moment 2.24.0, the following seems to be working fine:
import moment from 'moment';
import 'moment/min/locales';
Instead of importing moment-with-locales directly. Alternatively, also possible to only import required locales:
import moment from 'moment';
import 'moment/locale/fr';
import 'moment/locale/ru';
The answer above, though I have no doubt works for some, does not work for me. The solution I found is fairly quick and easy, but is a little more complicated than simple downgrading.
This problem originates as a result of and can be fixed with webpack. So we're going to have to add a few lines of code to our webpack.config.js file. If you don't have one yet, you can add one to the root webpack directory:
YOURAPPNAME/node-modules/webpack/
So now that you're inside your webpack.config.js file, you need to add a few lines of code. Just copy and paste this inside the new file or adapt it to the code you already have in webpack.config.js.
module.exports = {
resolve: {
alias: {
moment$: 'moment/moment.js'
}
}
};
Your import statement of moment in your index.js (or otherwise named) file should look like this:
import moment from 'moment'
You should now be able to use moment completely normally. For example:
var tomorrow = moment().add(1, "day")
If you have a fresh install, or upgraded moment to 2.25 and are getting this warning now, try forcing all your packages to use 2.24.
UPDATE: New release 2.25.3 has been reported to fix this problem! Try to first just update.
If you depend on some library that didn't upgrade yet, tell them to upgrade. And in the meantime, if you need 2.25, you can force also your sub-dependencies to use this version.
If you're using yarn add these lines into package.json
"resolutions": {
"**/moment": ">=2.25.3"
},
This is to be added inside packages.json at the top level, i.e. with the same indentation as "dependencies".

Categories