Yarn/NPM linked package is not showing changes in browser - reactjs

Context
I have two projects, main and styles.
Main uses styles as an npm package, importing it as #companyname/styles.
I need to make changes to styles and want to link it locally to see these changes in main.
This is a react app, using Webpack and babel. Yarn is the favoured package manager.
Problem
Using npm link OR yarn link works in so far as I can go into the node_modules/#companyname/styles folder in main and see my changes in there.
However, no changes are reflected in the browser.
I only use one or the other (yarn/npm) at a time, but problem exists with either one
Things I've tried
Deleting node_modules, reinstalling and re-linking
Unlinking and re-linking
Rebuilding
Clearing npm cache, clearing yarn cache
Viewing site in incognito
Deleting dist folder in main and reinstalling
Adding CleanWebpackPlugin to my webpack config
Adding hot: true, to my devServer config in webpack config.
TL;DR
Yarn/npm link not showing my changes in browser, however will show changes in node_modules. Something causing browser to not read changes. Please help.

Have you tried deleting the lock file?
rm package-lock.json
npm clean-install

the cause is in webpack configuration. It took me days to find the perfect combination for symlink packages.
In my case, my project was a Vue app.
So here's a summary of my findings for people from the future (for Webpack 5):
const path = require('path');
module.exports = {
resolve: {
symlinks: false // Important so that symlink packages are resolved to their symlinked location
// If your package contains frontend framework components, prevent two instances of the framework (React for example), one from the app and the other one from the symlink package
// Kudos to https://stackoverflow.com/a/68497876/11840890
alias: {
react: path.resolve('./node_modules/react'),
'#': path.resolve(__dirname, './src') // Add this alias if you get a new issue after setting up the first one
}
},
snapshot: {
// Even though added changes on the symlink package may trigger rebuild, they might not be seen on the browser (using HMR or not)
// To prevent reloading dev server every time, add this (it will include only node_modules but your package in the cache):
managedPaths: [
/^(.+?[\\/]node_modules[\\/](?!(#author[\\/]your-package))(#.+?[\\/])?.+?)[\\/]/,
],
},
}

Related

Next.JS issue with build vs local dev

Bug description
I am working with a library called react-carousel from brainhubeu in NextJS. Even when I am using dynamic import with ssr:false, The build UI looks strange but the dev UI is perfectly fine.
dev UI -
I have recreated it in Codesandbox too (this one is for dev environment is running npm run dev)-
https://codesandbox.io/embed/suspicious-volhard-460q8?fontsize=14&hidenavigation=1&theme=dark
However when I build it and then run the build by using npm run build && npm run start -
To recreate this in codesandbox -
In bottom right click on + sign for a new terminal
npm run build
npm run start (I have already added "start": "next start -p 8080" in the package.json file so a new tab will be created for the sandbox and can be accessed as https://460q8-8080.sse.codesandbox.io/ where 8080 signifies the port number )
Expected behavior
UI should be same as when seen with npm run dev.
Question
Why does my dev UI works fine but when I build and serve, the UI is strange. What exactly is the difference between npm run dev and npm run build && npm run start in context of NextJS?
Any solution to this problem?
My attempts
I have been trying to work on this problem and have asked this question on official Github discussions on NextJS. Couldnt find any answer.
I even created a Github Bug issue on react-carousel's Github, they couldn't help much.
Thanks for helping out.
I was able to resolve this issue. In my case, it was due to the difference between how I had set up (dev) and next build && next start. Take note of a few things to get it sorted -
If you have used an external library, chances are it doesn't support server-side rendering. I was using react-carousel from Brainhubeu and it having some issues. Resolve it by importing the library via next/dynamic imports with ssr:false option.
Another issue was that I was using/following an outdated boilerplate code for Tailwind and NextJS. Hence the way postcss.config.js was configured was error-prone. Here is the crux of the problem. at least for me - During the dev, everything worked fine because postcss didn't purge any of the classes of third party plugins/libraries that I imported, however, they were being purged when I did npm run build and npm run start
Now let's quickly see how you can solve this issue on your part -
Use the inbuilt purge option provided by TailwindCSS. For this, use the official starter-code/boilerplate code from the NextJS team. As they mention there - To control the generated stylesheet's filesize, this example uses Tailwind CSS' purge option to remove unused CSS.
Or you could try patching the problem if you don't want to go the previous way. I would only suggest this method if you are almost done with the project and just want to get this working because this is in no way a good solution. You will have to whitelist a bunch of css files from being purged. This is what I did but you can probably whitelist a lost more CSS classes as well -
// postcss.config.js
const purgecss = [
"#fullhuman/postcss-purgecss",
{
content: [
"./node_modules/#brainhubeu/react-carousel/lib/style.css",
"./node_modules/#brainhubeu/react-carousel/lib/style.css.map",
"./node_modules/react-toastify/dist/*.css",
"./components/**/*.js",
"./pages/**/*.js",
],
defaultExtractor: (content) => {
const broadMatches = content.match(/[^<>"'`\s]*[^<>"'`\s:]/g) || [];
const innerMatches = content.match(/[^<>"'`\s.()]*[^<>"'`\s.():]/g) || [];
return broadMatches.concat(innerMatches);
},
},
];
module.exports = {
plugins: [
"postcss-import",
"tailwindcss",
"autoprefixer",
...(process.env.NODE_ENV === "production" ? [purgecss] : []),
],
};
Still I would suggest go the first way and copy your code from old repo to new, use SSR:false to use client-side libraries that hate SSR, and you should be good to go.
You can reach out to my Twitter #toughyear if you need help with this.

create-react-app and relative subpaths in development

We are having a big environment where we have several applications under the same domain eg:
foo.org/a
foo.org/b
We have set up IIS to act in the same way on localhost, so we can type:
localhost/a
localhost/b
to reach the applications. The setup is done so to avoid CORS problems.
We are now trying to create a new application with "create-react-app" (https://github.com/facebook/create-react-app).
To add relative paths when you build for production is no problem, the problems occur when you try to run this with react-scripts start on localhost.
It seems it doesn't support relative paths so it always try to fetch build.js and other resources from /and there is not possible to set this without ejecting webpack.
So my question is, do you have any good ways of sorting this out? Ejecting webpack is not a good solution for us.
You can ejecting the config files by running: npm run eject
Then you'll find a config folder created in your project.
You will find your webpack config files init, where you should be able to change the "root" folder:
module.exports = {
...
resolve: {
modules: [
path.resolve(__dirname, 'node_modules'),
path.resolve(__dirname, './'), // "root" folder
]
}
...
}
Edit: Oh sorry - didn't see that ejecting is no option for you... And unfortunately I don't know any other solution.
"homepage": "/subfolder/path", in package json file should help

Unable to import node modules in React components

I am fiddling around with the following local drf-react setup. I'm really new to react and javascript overall and got absolutely no idea why I cannot import axios or any other node module for that matter in my react components, except for the modules that already shipped with the cookiecutter project itself. Is this related to the react-dev-utils..? I would like to use webpack, but I fail to set it up properly. My frontend docker container won't compose, telling me to install webpack-cli. Help is much appreciated.
https://github.com/moritz91/drf-react-app
You should run the command npm install inside your frontend folder:
Open the terminal
Find the frontend folder
Inside of it run the command npm install
This command will install the dependencies related to your package.json file, which is inside the frontend folder.
Inside your React files you will put the whole path to the node_modules folder.
The idea of using node_modules is to make it easier to control your dependencies in your project. You should consider again using webpack to handle these files from node_modules.
Wepack has a module called resolve which you have to fill with a list of directories and inside React components you don't need to use the whole path anymore, because Webpack will understand where to look:
// ALIAS
resolve: {
extensions: ['.js', '.jsx', '.scss'],
modules: [
'YOUR SOURCE FOLDER',
'YOUR NODE MODULES FOLDER',
'ANY OTHER FOLDER'
]
}
From the docs:
Tell webpack what directories should be searched when resolving modules.
The documentation: https://webpack.js.org/configuration/resolve/
Also, I have an example using Webpack + Bootstrap 4.
You can use to build your own Webpack config for React and Redux.
https://github.com/italoborges/webpack-bootstrap4-es6

react-scripts Invalid Host header

I created an app with react-create-app, I just dev it using npm start, that seems to do react-scripts start according to my package.json
Whenever I add a proxy to my package.json, I get this error message :
Invalid Host header
I get the idea, it's a security issue. What I don't get is how to fix it. I read several issues on github and QA here on the subject, the fix is easy enough, but I still don't get where to put it
in the end, I will add a whitelist of hosts. I think I saw it's possible.
but where do I put this config to start :
devServer: {
disableHostCheck: true
}
Another way to disable the host check would be to set the following environment variable: DANGEROUSLY_DISABLE_HOST_CHECK=true
That can be done by e.g. adding that line to .env file in the root of the project. Note that this is not a secure solution and should not be used in production.
You can manage it without changing stuff inside node_modules or by ejecting your project by using an npm package called react-app-rewired.
It basically has an option to override your default hardcoded settings for webpack that are inside a create-react-app boilerplate setup.
You put a config-overrides.js inside your root folder and change the scripts inside your package.json to match react-app-rewired instead of the react-scripts. This way you can override all the webpack config that's hard coded inside a react project by writing it down inside a config-overrides.js file.
The syntax is inside this link. There's also an article about it which can be found here.
I never found out where to put the webpack.config.js. It didn't work in the app root directory where I suppose it should go, it didn't do anything for me, I just ended up modifying where react-scripts invokes webpack-dev-server and then put the disableHostCheck to true directly before invoking.
Basically I changed the following line :
const serverConfig = createDevServerConfig(
proxyConfig,
urls.lanUrlForConfig
);
to :
var serverConfig = createDevServerConfig(
proxyConfig,
urls.lanUrlForConfig
);
serverConfig.disableHostCheck = true;
that's really not good practice (modify the code and disableHostCheck), but now I know I can actually modify settings, I'll just go for a whitelist, may be one day I'll understand why it doesn't care about my webpack.config.js ^^
Install react-app-rewired:
npm install react-app-rewired --save-dev
change package.json script to
"start": "set PORT=80&&react-app-rewired start",
then add a file named .env.development, add this line:
HOST=buzzbuzzenglish.com
then add config-overrides.js file (you can override some webpack settings there but don't have to - still, file have to be created)
finally you type npm start, then browser will open and navigate to buzzbuzzenglish.com and renders normally without the Invalid Host Header error.

How to avoid `loaded two copies of React` error when developing an external component?

I am developing an external component (let's say my-component, which I link to the project with npm link (as it is in process and I need the package to reflect changes).
In the my-component folder there are node_modules/react and node_modules/react-dom as they are its dependencies. However they are peerDependences, so I did not suppose to bring them into the project linking this package.
However when using npm link, it link the whole directory, including node_modules. So, when the project builds, it includes packages 2 times: from node_modules/* and from node_modules/my-component/node_modules/*.
This begins to affect when the component is using ReactDOM.findDOMNode, it causes this error:
Warning: React can't find the root component node for data-reactid value `.0.2.0`. If you're seeing this message, it probably means that you've loaded two copies of React on the page. At this time, only a single copy of React can be loaded at a time.
Also, it may help to understand what's happening: the problem only appears if there are both node_modules/my-component/node_modules/react and node_modules/my-component/node_modules/react-dom. If there is only one of them, there is no error message.
The usual package installation does not bring such error as there is no node_modules/react-dom there.
How is it supposed to develop an external component and the project at the same time?
The issue is twofold:
You cannot have 2 copies of react loaded.
npm link creates a symlink, however the "require" doesnt respect the
symlink and when it tries to navigate up the directory, it never
finds the react of the parent project.
Solution:
All you have to do is link the react and react-dom in your component to that of parent project's node_modules folder.
Go to your component project and remove the react and react-dom then do
npm link ../myproject/node_modules/react
npm link ../myproject/node_modules/react-dom
Fixed it by adding react-dom as an alias to my webpack config
alias: {
react$: require.resolve(path.join(constants.NODE_MODULES_DIR, 'react')),
'react-dom': require.resolve(path.join(constants.NODE_MODULES_DIR, 'react-dom'))
}
Someone clevererer than I (#mojodna) came up with this solution: remove the duplicate dependencies from the external component, and resolve them with your project's copies of those deps.
Step 1: Remove the dependencies from your external component's node_modules
As #cleong noted, you can't just remove the deps from the external component's node_modules, because your project's build step will fail when it hits the now-missing dependencies in the external component.
Step 2: Add your project's node_modules to NODE_PATH
To fix this, you can append the project's node_modules to the NODE_PATH environment variable when running your build step. Something like e.g. this:
NODE_PATH=$(pwd)/node_modules/ npm start
(where npm start is your script that bundles your external component, via e.g. Browserify, Webpack, etc.)
In fact, you could always append that NODE_PATH addition to your build scripts, and it would work whether or not you've npm linked anything. (Makes me wonder if it shouldn't be default npm behavior...)
Note: I left my existing answer because there's some conversation there, and this is a different (and better) solution.
I believe the answer is to specify react and react-dom as peerDependencies in your external component's package.json. As best as I can follow here and here, npm link should (as of npm#3) no longer install peerDependencies (or `devDependencies either).
Aaaand I just read your post more carefully and realized that you already are specifying them as peerDependencies. Therefore, I think the answer boils down to:
Upgrade to npm#3:
npm install -g npm#3.0-latest
The problem is with npm link. https://github.com/npm/npm/issues/5875
npm doesn't treat the linked directory as a child of the parent project.
Try alternatives to npm link:
1) Use relative path dependencies in package.json
2) Manually include your dependencies in your projects node_modules directory
3) Use url path
Basically anything but npm link
I am using ReactJS.net and setup webpack from the tutorial there and started using react-bootstrap aswell when i started getting this error. I found adding 'react-dom': 'ReactDOM' to the list of externals in webpack.config.js fixed the problem, the list of externals then looked like this:
externals: {
// Use external version of React (from CDN for client-side, or
// bundled with ReactJS.NET for server-side)
react: 'React',
'react-dom': 'ReactDOM'
This seems to be the first stack overflow link on google for this error, so i thought this answer might help someone here.
Adding the following in my webpack.config.js worked for me:
resolve: {
alias: {
react: path.resolve(__dirname, 'node_modules', 'react')
}
}
I also experimented with DedupePlugin (mentioned as a possible remedy here) but I couldn't get it to work.
What's also interesting is that I've encountered different (and perhaps more insidious) manifestations of the same problem when a module is found in multiple places in the dependency graph.
One such case was that my React.PropTypes.instanceOf(SomeType) constraints would emit warnings even though the type I passed in was correct. That was due to the module being present in multiple places in the node_modules directory tree. Due to duck-typing the code would still work, but my console was cluttered with these warnings. Going the resolve.alias way silenced those too.
YMMV
Strongly recommend using https://github.com/mweststrate/relative-deps.
Installs dependencies from a local checkout, and keeps them in sync, without the limitations of link.
This fixes the issue as it installs the local library just as npm install would, satisfying any dependency versions, etc.
If you're using Webpack in the main project, this solution may work. In my case, project-a requires project-b. Both require React and ReactDOM 0.14.x
I have this in project-a/webpack.config.js:
resolve: {
modulesDirectories: ['node_modules'],
fallback: path.join(__dirname, 'node_modules')
},
resolveLoader: {
fallback: path.join(__dirname, 'node_modules')
},
project-b requires React and ReactDOM as peerDependencies in project-b/package.json
project-a requires project-b as a devDependency (should also work required as a dependency) in project-a/package.json
local project-b is linked to project-a like so: cd project-a; npm link ../project-b
Now when I run npm run build within project-b, the changes appear immediately in project-a
I was getting this because I had already included react and react-dom as external scripts in my HTML markup.
The error was caused by adding an import ReactDOM from 'react-dom' to a component module. The error went away once I removed the import, and the module worked fine since the components were already available.

Resources