Module not found: Can't resolve 'fs' - NextJS - reactjs

I'm trying to use node-jsencrypt with NextJS (tsx):
index.tsx
import JSEncrypt from 'node-jsencrypt';
package.json
"node-jsencrypt": "^1.0.0"
Log
error - ./node_modules/node-jsencrypt/index.js:2:0
Module not found: Can't resolve 'fs'
Notes:
I didn't find the 'webpack.config.js' file, as I saw in some topics.

Ok, I played around with this issue & I think I have what cover all possible combinations. In the repo you can find working examples. There are 3 possible approaches, and the right one will depend on what's already in your project - details that were unspecified in the original question.
Solution while using webpack 5 next.config.js
module.exports = {
future: {
webpack5: true, // by default, if you customize webpack config, they switch back to version 4.
// Looks like backward compatibility approach.
},
webpack(config) {
config.resolve.fallback = {
...config.resolve.fallback, // if you miss it, all the other options in fallback, specified
// by next.js will be dropped. Doesn't make much sense, but how it is
fs: false, // the solution
};
return config;
},
};
Solution while using webpack 4 - next.config.js
module.exports = {
webpack(config) { // we depend on nextjs switching to webpack 4 by default. Probably they will
// change this behavior at some future major version.
config.node = {
fs: "empty", // webpack4 era solution
};
return config;
},
};
You could consider using other library. According to node-jsencrypt readme they are node port of jsencrypt, and here I assume you try to build for browser. The node library got stuck at version 1, while the original library is already at version 3. As I checked in the last commit on main, if you use this library, it's building just fine without any issues.
Original, nextjs unaware answer:
Since version 5, webpack doesn't include polyfiles for node libraries. In your case, you most likely need to add resolve.fallback.fs: false to your webpack config.
More about this option- https://webpack.js.org/configuration/resolve/#resolvefallback
It mentioned in v4 to v6 migration guide, if this is your case:
https://webpack.js.org/migrate/5/

In the next.config.js file add the code below
build: {
extend(config, {}) {
config.node = {
fs: 'empty'
}
}
},

Related

Create React App with TypeScript and NPM Link: Enums causing Module parse failed

I have a basic create-react-app TypeScript project (client). Just directory up, I have a server and a shared folder. Inside the shared folder I have a number of interfaces and enums that I share between the server and the client.
I wish to link this shared folder to both the client and server packages.
First, I went to shared and ran $ yarn link and then ran $ yarn link shared from both the client and the server folders.
The server is as happy as can be, and for the most part the client is too. However, as soon as I use one of the enums from the shared directory in the client, I get an error:
../shared/src/models/Roles.ts 4:0
Module parse failed: The keyword 'enum' is reserved (4:0)
File was processed with these loaders:
* ./node_modules/#pmmmwh/react-refresh-webpack-plugin/loader/index.js
You may need an additional loader to handle the result of these loaders.
| $RefreshSetup$(module.id);
|
> enum Roles {
| RW_ORG = "rw_org", // can modifiy organization and it's users, nothing else
I'm importing it like so:
import {Roles} from "shared";
but have tried numerous other ways as well.
I'm exporting it from the shared index.ts like so
import Roles from "./models/Roles";
export type {
// all of my interfaces
};
export { Roles }
All of my interfaces are usable, so I don't understand. What the hell is going on here?
Well, it turns out that these errors are all cause by create-react-app's default webpack.config.js. If you navigate to code node_modules/react-scripts/config/webpack.config.js you fill find a line include: paths.appSrc which basically limits Babel to the src/ folder of the react app itself.
That means, if you've yarn linked a folder outside of it, Babel will not transpile it to normal JS, and thus React cannot use it.
There are two hacky solutions, but I would like a better one.
Manually (or via a build script) delete the include: paths.appSrc line from react-scripts every time you install a node module
Make a script that copies the external directory into your React src directory every time the external directory is modified.
I really wish there were an official way around this...
Based on #foxtrotuniform6969's answer, i created a #cracro/craco configuration that gets rid of the misbehaving setting by itself.
module.exports = {
webpack: {
configure: (webpackConfig) => ({
...webpackConfig,
module: {
...webpackConfig.module,
rules: webpackConfig.module.rules.map((rule) => {
if (!rule.oneOf) return rule;
return {
...rule,
oneOf: rule.oneOf.map((ruleObject) => {
if (
!new RegExp(ruleObject.test).test('.ts') ||
!ruleObject.include
)
return ruleObject;
return { ...ruleObject, include: undefined };
}),
};
}),
},
}),
},
};
https://gist.github.com/PhilippMolitor/00f427d12a9c5bca84309058d88846b7
It is possible to automatically remove the include path setting mentioned in the other answer using react-app-rewired.
The following config-overrides.js works for react-scripts:4.0.3 and causes babel to also transpile files in node-modules.
// config-overrides.js
module.exports = function override(config, env) {
// This line might break with other react-script versions
delete config.module.rules[1].oneOf[2].include
return config
}
The other answers to this question suggest removing the include in react-scripts' webpack.config (either with craco or react-app-rewired). I found this worked with yarn start, but when I made a production build with yarn build I got the error Uncaught ReferenceError: exports is not defined at runtime.
Instead of removing the include, I had to add the other project's src in addition to the existing src directory.
Here's my config-overrides.js to be used with react-app-rewired.
For react-scripts 4:
const path = require("path");
module.exports = function override(config) {
// See https://stackoverflow.com/questions/65893787/create-react-app-with-typescript-and-npm-link-enums-causing-module-parse-failed.
config.module.rules[1].oneOf[2].include = [
path.join(__dirname, './src'),
path.join(__dirname, '../backend/src')
];
return config
}
For react-scripts 5:
const path = require("path");
module.exports = function override(config) {
// See https://stackoverflow.com/questions/65893787/create-react-app-with-typescript-and-npm-link-enums-causing-module-parse-failed.
config.module.rules[1].oneOf[3].include = [
path.join(__dirname, './src'),
path.join(__dirname, '../backend/src')
];
return config
}
My craco config, does the same thing as Phil Mo's version as far as I can tell but is easier to understand
module.exports = {
webpack: {
configure: (webpackConfig) => {
webpackConfig.module.rules[0].oneOf.find(
({ test: t }) =>
t != null &&
!Array.isArray(t) &&
t.toString().includes('ts')
).include = undefined
return webpackConfig
}
}
}

Create-react-app + TypeScript + CSS Modules: Auto-generating type definitions without ejecting from CRA

Problem
create-react-app v2+ supports TypeScript and CSS Modules out of the box... separately. The problem arises when you try to use the two together. Facebook had an extensive discussion about this issue and ultimately closed it off on GitHub. So developers have to use hacks and other workarounds to get these two technologies to play nicely together alongside CRA.
Existing workaround:
You can manually create ComponentName.module.css.d.ts files with type definitions like this: export const identifierName: string. This allows you to take advantage of TypeScript's typing and VS Code's auto-complete when you go to import ComponentName.module.css. Unfortunately, this is extremely tedious.
Solution (?):
The folks over at Dropbox created typed-css-modules-webpack-plugin to address this issue; it auto-genertes those *.d.ts files for you. They show how to install it with yarn or npm and then give this minimal code example:
const path = require('path');
const {TypedCssModulesPlugin} = require('typed-css-modules-webpack-plugin');
module.exports = {
entry: './src/index.ts',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js',
},
module: {
rules: [
{
test: /\.tsx?$/,
loader: 'ts-loader',
},
{
test: /\.css$/,
use: [
'style-loader',
// Use CSS Modules
{
loader: 'css-loader',
options: {
modules: true,
},
},
],
},
],
},
// Generate typing declarations for all CSS files under `src/` directory.
plugins: [
new TypedCssModulesPlugin({
globPattern: 'src/**/*.css',
}),
],
};
Unfortunately, it's not immediately clear how I can use this with create-react-app. I'm not very knowledgeable when it comes to Webpack, and I'm using customize-cra to avoid ejecting out of create-react-app so I can customize the Webpack configs for some things I need. For example, Ant Design lets you import components on demand by using babel-plugin-import as detailed here:
https://ant.design/docs/react/use-in-typescript#Use-babel-plugin-import
Question: How can I convert the above Webpack configuration code to a customize-cra equivalent so that I don't have to eject out of CRA?
Okay, so I eventually did figure this out, and I wrote a blog post on the subject for anyone who runs into a similar issue:
https://aleksandrhovhannisyan.github.io/blog/dev/how-to-set-up-react-typescript-ant-design-less-css-modules-and-eslint/#3-create-react-app-css-modules-and-typescript-
The solution uses the typescript-plugin-css-modules plugin. Here are the relevant bits from my blog post:
yarn add -D typescript-plugin-css-modules
After it’s installed, add the plugin to your tsconfig.json:
{
"compilerOptions": {
"plugins": [{ "name": "typescript-plugin-css-modules" }]
}
}
Next, create a file named global.d.ts under your src directory. You don’t have to name it global, by the way; you can name the file whatever you want, as long as it has the .d.ts extension. Enter these contents:
declare module '*.module.less' {
const classes: { [key: string]: string };
export default classes;
}
If you want to also use SASS or CSS, simply add more module declarations and change the .less extension.
We’re almost done! Per the plugin’s usage instructions, if you want intellisense to work in VS Code, you’ll need to force VS Code to use your workspace version of TypeScript instead of the globally installed version. Remember when we installed TypeScript via CRA at the very beginning? That’s our workspace version of TypeScript.
Here’s how to use the workspace version of TypeScript in VS Code:
Open any TypeScript file.
Click the version number on the blue status bar at the bottom of VS Code.
Select Use Workspace Version (3.7.3 as of this writing).
Here’s a screenshot to make that clearer:
Once you do that, VS Code will create a .vscode directory in your project for workspace settings.
At this point, you're all set to use CSS Modules with TypeScript.
UPDATE 2022
Note: If you're using react-scripts#2.1.x or higher you don't need to use custom definitions like
declare module '*.module.less' {
const classes: { [key: string]: string };
export default classes;
}
Custom definitions
Note: Create React App users can skip this section if you're using react-scripts#2.1.x or higher.
Also you can add this VS code setting to you local JSON settings file:
{
"typescript.tsdk": "node_modules/typescript/lib",
"typescript.enablePromptUseWorkspaceTsdk": true
}
This will ensure that VS Code will use the project’s version of Typescript instead of the VS Code version and will prompt you to do so if you aren’t already.
Well, everything is correct as said AlexH.
1 in tsconfig.ts.
{
"compilerOptions": {
"plugins": [{ "name": "typescript-plugin-css-modules" }]
}
}
2 in global.d.ts
declare module '*.module.less' {
const classes: { [key: string]: string };
export default classes;
}
But Also in tsconfig you should write
"include": [
"global.d.ts",
...
]

React-router issues using static-render-webpack-plugin

I just started working with React last week, and I'm having trouble following a tutorial for the static-render-webpack-plugin.
I've put the code online at GitHub if you want to take a closer look.
After following the tutorial and making a couple of changes (I added babel-core, I changed the js loader to babel-loader and the entry point url needed a small correction), when I try to run webpack -p to generate the static files I get the following error:
ERROR in ./src/entry.js
Module build failed: SyntaxError: .../src/entry.js: Unexpected token (10:2)
8 |
9 | const routes = (
> 10 | <Route path="/" handler={RootPage}>
| ^
I think it might have something to do with the changes made with the latest version of react-router. I'm using the latest version, but the syntax for the tutorial looks like it might have been written prior to v.1.0. For example, I think the part of the tutorial that says to add this to the src/entry.js file:
if (typeof document != 'undefined') {
Router.run(routes, path, (Root) => {
React.render(<Root/>, document);
});
}
probably needs to be rewritten to something like this (but I'm not sure if this is quite right):
if (typeof document != 'undefined') {
ReactDOM.render(routes, document);
}
There's obviously more going on though since I get the same error message when I try that rewritten snippet then run webpack-dev-server -- which is the only time it should hit that code. (Yes, I added import ReactDOM from 'react-dom'; to the top of the page and "react-dom": "^0.14.7", to the package.json.)
I am sure this part (also on src/entry.js) needs to be rewritten to match the latest react-router too but I'm not sure how:
export default function(path, props, callback) {
Router.run(routes, path, (Root) => {
const html = React.renderToString(<Root/>);
callback('<!doctype html>' + html);
});
}
Thanks in advance for any help or hints you can give.
Your code is breaking because Webpack doesn't know how to transpile the JSX to ES5. You've specified babel-loader as your loader for JS files in your webpack config, but unfortunately Babel 6 does not do anything out of the box, you need to include "plugins" that contain the rules for compiling different syntaxes down to ES5. In this case, you'll want the es2015 preset to support all ES6 syntax, and the react preset to support JSX. You're also missing the extract-text-webpack-plugin you are trying to import into your webpack config. Snag these through NPM:
npm i -D babel-preset-2015 babel-preset-react extract-text-webpack-plugin
Then, add the presets to your webpack.config.js file in the loaders section for js/jsx files:
{
test: /\.(js|jsx)?$/,
loader: 'babel',
exclude: /node_modules/,
query: {
presets: ['es2015', 'react']
}
}
I forked your repo and made these changes and was able to get a bit further through the compilation process. It seems like there are module dependencies specific to your project you'll still need to resolve.

Cannot assign to read only property '__esModule'

When compiling a React and Redux application with Webpack and Babel I get:
Uncaught TypeError: Cannot assign to read only property '__esModule' of #<Object>
In some older browsers (<= Chrome 1, Android 4, Safari 5).
This issue seems to stem from redux and react-redux outputting the line exports.__esModule = true; in the lib build but my application using Object.defineProperty instead (because they build loosely and I do not).
Two solutions are:
Building my application in loose mode also.
Importing react-redux/src and redux/src and building it with the same .babelrc as the application (everything is not loose).
As long as they are consistent and both:
Object.defineProperty(exports, "__esModule", {
value: true
});
and exports.__esModule = true; do not co-exist in my output, everything works.
My question is, what is the right solution? Why does this only affect older browsers? And why do they conflict?
Here is a similar question.
Object.defineProperty is broken on some Android 4 stock browser versions and probably other browsers that made use of a buggy implementation in Webkit.
Check this bug report
and and this other one reported to the chromium project.
The good news is you can apply this polyfill to fix the problem.
To make thing easy, you can simply copy and paste that polyfill on a <script> tag before your bundle.
This will fix your issues.
My guess is, you need to install babel-plugin-add-module-exports and in your .babelrc register this plugin:
"plugins": [
"babel-plugin-add-module-exports"
]
For more information visit this website.
In my case, I solved to add babel-register library in entry points.
In webpack.config.js (Webpack 1.x version of configuration)
// As is
entry: {
main: 'index.js'
},
// To be
entry: {
main: ['babel-register', 'index.js']
},
We met this problem on Android 4.0 and currently we cannot cut the support for Android 4.0.
For webpack 1.0, just set loose: true when you are using babel-preset-env.
However for Webpack 2, loose mode can't resolve this problem.
Finally, we found this trick, a little ugly.
// client_patch.js, For Android 4.0
var defineProperty = Object.defineProperty;
Object.defineProperty = function (exports, name) {
if (name === '__esModule') {
exports[name] = true;
return;
}
return defineProperty.apply(this, arguments);
};
And in your webpack config file.
// webpack.config.js
entry: {
main: [
path.resolve(__dirname, 'client_patch.js'),
'index.js'
]
}

`_Symbol.'for'`: Is that actually valid ES6? Webpack built it from React source

I'm trying to take React 0.14 for a spin before I upgrade it in my project. However, with a simple "hello world" prototype, Webpack is throwing an error:
ERROR in ./~/react/lib/ReactElement.js
Module parse failed: /home/dan/Demos/reactiflux/node_modules/babel-loader/index.js!/home/dan/Demos/reactiflux/node_modules/react/lib/ReactElement.js Line 25: Unexpected string
You may need an appropriate loader to handle this file type.
| // The Symbol used to tag the ReactElement type. If there is no native Symbol
| // nor polyfill, then a plain number is used for performance.
| var REACT_ELEMENT_TYPE = typeof _Symbol === 'function' && _Symbol.'for' && _Symbol.'for'('react.element') || 0xeac7;
|
| var RESERVED_PROPS = {
# ./~/react/lib/ReactMount.js 18:19-44
I do have babel-loader configured, and when I downgrade to React 0.13, everything works. What really stands out to me, is _Symbol.'for', in the middle of the error message.
In react/lib/ReactElement.js on line 21 (not 25), that line looks much more correct, with square brackets around the 'for' key:
var REACT_ELEMENT_TYPE = typeof Symbol === 'function' && Symbol['for'] && Symbol['for']('react.element') || 0xeac7;
I assume that the code shown in the error message is either in an intermediate state during compilation, or is the final compiled output. Does anyone know what could cause Webpack to produce something that looks so wrong? Has anyone successfully used Webpack, Babel and React ~0.14.1 together yet?
update
There is an issue for this: https://github.com/babel/babel/issues/2377
It's closed, but it looks like it came back for me. This was fixed in 5.8.25, but I have 5.8.29 and I still hit the bug.
It appears that the problem has something to do with me including babel runtime. My .babelrc was copied from an older project:
{
"optional": "runtime",
"stage": 0
}
In this little hello-world demo, there is nothing that requires bundling the runtime, so I just removed it, after noticing that https://github.com/DominicTobias/universal-react/, which also uses the same build tools, does not need it. That was the only change I needed to make to get this to build.
My webpack config is super simple:
var path = require("path");
module.exports = {
entry: "./index.js",
output: {
path: path.join(__dirname, "/dist"),
filename: "index.min.js"
},
module: {
loaders: [{
test: /\.js$/,
loader: "babel"
}]
}
};
I guess that's what I get for copying a config file from a more complex project into what was supposed to be a simplest possible demo.
I see that there is a babel-plugin-runtime as well as a babel-runtime on NPM, but when I tried out BPR for the sake of completeness, Babel complains: Module build failed: ReferenceError: The plugin "runtime" collides with another of the same name. Since I don't actually need the runtime, the linked GH repo is a 404, and since this really belongs in the issue trackers after all, this is as far as I am going to take this for now.
No, that is not valid code. That was an issue in Babel project, but it has been fixed in the 6.0 version which was released recently.
I was run into this issue too, and now I have checked this with latest version, and it is works fine. Here is my test steps:
# install Babel and plugins
npm install babel-cli babel-preset-es2015 babel-plugin-transform-runtime
# install React
npm install react
# run babel against problem react file
./node_modules/.bin/babel node_modules/react/lib/ReactElement.js --plugins transform-runtime --presets es2015
It is provides valid output, so the issue seems to be resolved.
And there is good news for you, babel-loader for webpack already supports 6 version of Babel. Check out its docs for details

Resources