Unable to import node modules in React components - reactjs

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

Related

How to import a compiled module from one app to another in npm workspace using webpack?

I'm using npm workspaces for the first time(node version v16.15.0 and npm v8.5.5 ). I need to import components from a react app in another app with some minor updates. We still need to continue to be able to deploy the legacy app. So I'm using monorepo structure to achieve this. I can start and build the app1 and app2 individually. Later I'm planning to move shared packages out of app2. But for now even though I've build the app2 when I import components from it in app1 I get an error "You may need an additional loader to handle the result of these loaders". I guess the import is still from the src whereas I want to import compiled files. How can I do that ?
- root
package.json
- apps
- app1
package.json
webpack.config.json
- app2
package.json
webpack.config.json
So I finally got everything working. I had shared react components from app2 that I wanted to import in app1. I could have moved the shared components into separate package/features/Feature.js[x]. But for the time being I'm importing it directly from app2. For this I needed to update my webpack config in app1 to resolve for
resolve: {
alias: {
'#scope/app2/src': path.resolve(__dirname, '../app2/src'),
},
},
NOTE: #scope/app2 is the package name in package.json
Additionally I added #scope/app2 as a dependency in app1 under package.json. I got the hint from this post here https://medium.com/edgybees-blog/how-to-move-from-an-existing-repository-to-a-monorepo-using-npm-7-workspaces-27012a100269#4223
By doing this I was able to teach webpack to transpile the src files imported from app2. Hope this helps anyone looking for more information on npm workspace 8

Module not found error using Yarn 2 to link React components

I've created a repository which contains a React app (created with create-react-app) and a components directory which contains a simple Material UI button. The folder structure is:
/components
/react-app
Both directories are set up to use Yarn 2, and are not in a workspace (as I'm trying to simulate projects in separate directories and simplify my real world scenario).
I build the components:
$ cd ~/components && yarn build
I then Yarn link the components to the React app:
$ cd ~/react-app & yarn link ../components -r -p
This results in a modification to package.json file in the react-app directory:
{
"name": "react-app",
...
"resolutions": {
"components": "portal:../components"
}
}
My App.tsx file looks like this:
import './App.css';
import { Button } from 'components';
import React from 'react';
function App() {
return (
<Button>Test</Button>
);
}
export default App;
However, when I run the React app using yarn start I get the following error:
./src/App.tsx
Module not found: Your application tried to access components, but it isn't declared in your dependencies; this makes the require call ambiguous and unsound.
I'm not sure what I'm doing wrong. If I add an explicit reference to the components directory within dependencies (which I don't believe I should have to do because I've already linked it) such as:
"dependencies": {
"components": "portal:../components"
}
Then I get the error:
./src/App.tsx
Module not found: You attempted to import ~/react-app/.yarn/$$virtual/components-virtual-de9a8055ab/2/components which falls outside of the project src/ directory. Relative imports outside of src/ are not supported.
Surely, I don't have to eject the app and find a way to bypass this error?
EDIT: According to the Yarn documentation "Webpack 5 will support PnP natively, but if you use Webpack 4 you'll need to add the pnp-webpack-plugin plugin yourself". At the time of writing, the latest version of create-react-app relies on v3.4.1 of react-scripts which in turn relies on Webpack 4. I therefore ejected my app to inspect the Webpack configuration, and it appears that this plugin is already installed. It's therefore not a CRA/Webpack issue. I also upgraded my version of Node from v10.16.0 to v12.16.3 to no avail.
TLDR; Add the package as a dependency then modify your React setup to import files outside of the /src directory.
In my case, it doesn't look like yarn link is doing anything other than adding a resolutions entry in package.json, which according to the documentation is only used to specify the version to resolve. Perhaps my understanding of Yarn link is wrong (even though it held up in v1).
To fix the issue I had to add the reference to dependencies in package.json (even though I'd already run yarn link):
"dependencies": {
"components": "portal:../components"
}
This caused the aforementioned You attempted to import components which falls outside of the project src/ directory error. To resolve this we either need to eject the React app and disable the ModuleScopePlugin in Webpack (therefore allowing the import of files outside the /src folder), or use craco with custom configuration. I've created yarn-eject and craco branches to demonstrate both.
It's not a particularly elegant solution, and I'm hoping someone can post a better alternative. I switched to Yarn 2 so that I could utilise the "Improved Peer Dependency Links" feature (so that I'm only relying on one version of react across my applications and shared components packages). I'd rather not have to eject my React app or use custom configuration if possible.

Yarn/NPM linked package is not showing changes in browser

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))(#.+?[\\/])?.+?)[\\/]/,
],
},
}

How to use Storybook components (and Lerna) in an external project done with Next.js?

I've just created my Storybook library of components (ES6 etc).
It is structured as a Lerna project (all components isolated in the packages/ folder). However, that's a private repo with no real publish feature so, I think Lerna won't work with a private (free) account.
I've pushed the storybook repo to my Bitbucket as it is.
Now, I'd like to use my storybook library of components from the main application which is a different repo (on Bitbucket) build on Next.js.
I was attempting to import the individual storybook components as follows
import MyComponent from 'storybook-repo/packages/my-component/my-component';
but it obviously doesn't work, returning this error:
Module parse failed: Unexpected token (8:9)
You may need an appropriate loader to handle this file type.
This, because MyComponent is a jsx file.
I was hoping Next.js to transpile the imported modules but this is not the case.
My questions are:
My guts say the import of the whole storybook as git+ssh://git#bitbucket.org/myusername/storybook-repo.git from package.json is not a good idea. Any better solutions?
Is it true that Lerna works only for public/Pro repos where I can publish my packages?
Why is Next.js not transpiling the imported jsx modules? At this point, how does this process work? Shall I transpile the storybook components from the remote repo or do the job from my main application?
Thanks
On my last project, we used Rollup.js to create a dist build of just the components we had developed in Storybook. Our components were located in src/components directory. We maintained an index.js for the components using an internal scaffolding tool. We published our dist folder as a privately scoped NPM package and then pulled in our components from there.
For local development, we used Webpack aliasing to check the current environment and either pull the published NPM package or pull directly from the storybook/dist folder that we were building to.
There's a great guide on building this here. Hope this points you in the right direction. As an alternative, I believe you can fiddle with next.config.js to override the Webpack config and make sure that your external imports get sucked up through the same Webpack, but, you also have to add a few rules to the .babelrc on the Storybook side to ensure that it gets ignored over there. We found it to be easier to just publish a package and bundle everything up.

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