Vite, NPM, React Component Library Invalid hook call, externals problem? - reactjs

I was able to bundle my React Component library in Rollup, but I wanted the features of Vite for development and installed in over the weekend. My problem is that now I'm getting the following error when I try to npm link my vite generated distribution with another react probject.
Basically it's saying that it can't use useContext when it gets the 'Provider" which is really just a react context. It seems like it's having a problem here in the bundle when it tries to load it:
var Context=/*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__.createContext(null);
My vite config looks as such:
export default defineConfig({
plugins: [react(), dts({ insertTypesEntry: true })],
build: {
lib: {
entry: path.resolve(__dirname, "src/lib/index.ts"),
name: "MyLib",
formats: ["umd", "es"],
fileName: (format) => `my-lib.${format}.js`,
},
rollupOptions: {
external: [ "react", "react-dom" ]
}
},
});
Searching said that it might be a problem with my dependencies, using two versions of react or react-dom. I've tried it with every dependency configuration I can think of and it all breaks in different ways. I think maybe npm cacheing could be confusing me or something though.
Have any ideas? Vite works fine in 'dev' mode, and the components were working ok in Rollup so I feel like it's just a dumb configuration thing I don't understand

Related

rollup bundled react development resources

I'm using "vite": "^2.8.6" for React project. What I know is that Vite is using Rollup as module bundler, but I stumbled on a problem where Rollup still bundling my react-dom.development.js and react.development.js. I've used "rollup-plugin-replace" to replace my 'process.env.NODE_ENV' to production, but the problem still occur. Here is the my rollup config:
rollupOptions: {
// https://reactjs.org/docs/optimizing-performance.html#rollup
plugins: [
rollupPluginReplace({
'process.env.NODE_ENV': JSON.stringify('production')
}),
rollupPluginCommonjs(),
terser(),
visualizer()
],
},
When I analyze with rollup-visualizer, you can see that rollup bundled both production and development dependency, which supposedly only bundled one of them right?
The problem with this is that there is extra 1MB of dead code in the bundle, it will be great if I can eliminate it.
This generally means that rollup does not understand that your app is directed towards production code. In my case it was because I had set up library mode.
lib: {
entry: './src/app.ts',
fileName: 'app.ts',
name: 'AppClass',
formats: ['iife'],
}
Removing this block finally generated a build which was sane in size. For more information, see the vite documentation.
If you were also trying to get vite/rollup to build your app as an IIFE, setting rollupOptions worked for me:
rollupOptions: {
output: {
entryFileNames: `[name].js`,
assetFileNames: `app.[ext]`,
format: 'iife',
},
input: ['./src/app.ts'],
},

How to re-use a React library with hooks

I'm writing my own library to help building forms with React.
The goal is to be able to re-use it in any React application (made from scratch, with create-react-app, nextjs, other ?)
My problem is that I can't firgure out how to re-use it.
Here is the first issue I encountered when I tried to reuse my library in another project :
Invalid Hook Call Warning
React says that the reason could be one of the following :
You might have mismatching versions of React and React DOM.
You might be breaking the Rules of Hooks.
You might have more than one copy of React in the same app.
After investigation, I've excluded points 1. and 2.
I was using Parcel in the first place to build my library but I needed to exclude React from the bundle to solve 3.
That's why I switched to Webpack and moved the React dependency to the peerDependencies + devDependencies.
I've tried different webpack configurations :
const config: webpack.Configuration = {
...
externals: {
react: 'React'
}
}
--> which leads to the following error in the consuming application :
React is not defined
const config: webpack.Configuration = {
...
externals: {
react: {
root: 'React',
amd: 'react',
commonjs: 'react',
commonjs2: 'react',
umd: 'react',
}
}
}
--> which leads to the following error :
Cannot read property 'createContext' of undefined
I've tried to use my library with npm link and also by publishing it on npm but the result is the same.
Step to reproduce :
Install #mlaopane/formhook in your react application (npm i #mlaopane/formhook or yarn add #mlaopane/formhook)
Try to use a component, for example
import { Form } from '#mlaopane/formhook'
export default function App() {
return <Form />
}
You should see the error in the console
Thank you for helping me with this :)
NB: This is my first issue, please tell if more information is needed.
I've finally found a solution, inspired by create-react-library.
It looks like Rollup is a better candidate for bundling React libraries.
Even if I still can't link my library locally, it can be used when published.

create-react-app can't find react in tests when aliased with preact

I have created a project with "create-react-app". I have added preact to the project by ejecting it and using alias in webpack config.
alias: {
'react': 'preact-compat-enzyme',
'react-dom': 'preact-compat-enzyme',
'react-dom/server': 'preact-render-to-string',
'react-addons-test-utils': 'preact-test-utils',
'react-addons-transition-group': 'preact-transition-group'
}
This works in the code and I am able to render the app. But, in tests I am getting the following error
Cannot find module 'react' from 'App.test.js'
Why can't it find the module? Is there something that we have to add to config other than alias?
This took some digging but, I got it working by adding following in in moduleNameMapper package.json.
"moduleNameMapper": {
"^react$": "preact-compat-enzyme",
"^react-dom$": "preact-compat-enzyme",
"^react-dom/server$": "preact-render-to-string",
"^react-addons-test-utils$": "preact-test-utils",
"^react-addons-transition-group$": "preact-transition-group",
},

Syntax Error In IE 11 for this node_moduels

I am getting a syntax error in IE when this component of react is loaded in the webpage. Has anybody got the same problem? This is an inherited package, and a syntax error from node_modules makes no sense?
"use strict";
/* WEBPACK VAR INJECTION */(function(module) {
const colorConvert = __webpack_require__(/*! color-convert */ "./node_modules/color-convert/index.js");
const wrapAnsi16 = (fn, offset) => function () {
const code = fn.apply(colorConvert, arguments);
return `\u001B[${code + offset}m`;
};
const wrapAnsi256 = (fn, offset) => function () {
const code = fn.apply(colorConvert, arguments);
return `\u001B[${38 + offset};5;${code}m`;
};
If you are using newer versions of Node/NPM, check your package.json file -> "browserslist" section.
This is the default "browserslist" created for you if you do not have one defined:
In this case, if you run "npm start" on your LOCAL Environment, Babel will not create Polyfills for IE11 because its not included as a target browser in "development". To get this working, I deleted my node_modules directory completely, ran 'npm install', updated package.json with:
and ran 'npm start.
The reason why this fails is that babel or your other favorite transpiler might ignore node_modules (if that's how its configured), so you need to include it manually because IE does not support arrow function syntax.
First, if you search for wrapAnsi16 or wrapAnsi256 function names online it'll point you to common npm packages, such as: ansi-styles, chalk or color-convert, debug, strip-ansi, etc.
If you are using Webpack you can add the following to your rules:
module: {
rules: [{
exclude: /node_modules\/(?!(color-convert|ansi-styles|strip-ansi|ansi-regex|debug|react-dev-utils|chalk)\/).*/
}]
}
or, easier to read:
module: {
rules: [{
include: [
path.resolve(__dirname, 'node_modules/ansi-styles'),
path.resolve(__dirname, 'node_modules/strip-ansi'),
... other's here...
path.resolve(__dirname, 'src'),
]
}]
}
Hope this helps somebody in the future ;)
TLDR; you don't need this library, just run
npm run build
And it will be excluded from your build.
I have same problem with create-react-app, and I solve it (no). From my discovery, this library should not appear in browser, because it was designed for nodejs environment. Also I found, this library come to me as dependency of jest, and jest is dependency for tests and it come as dependency for react.
So, I run
npm run build
server -s build
And try my application in IE. And it work. So, when you run
npm start
It make file including dev dependencies and other garbage that should not appear in production and in browser at all. When you run
npm run build
It make file only with required project libraries.
I had similar issue #punkbit solution and installing 'react-app-polyfill'
and importing it at the top of the index.js file solved it
import 'react-app-polyfill/ie11';
import 'react-app-polyfill/stable';
If it still does not work delete node-modules and reinstall also clear cache in IE.
All the best :)
This problem occurs because your compiled code contains (modern) ES6 syntax whilst IE11 only supports ES5.
A way to fix this is to instruct webpack to specifically compile the mentioned packages into ES5;
module: {
rules: [{
test: /\.(tsx?|js)$/,
include: [
// These dependencies have es6 syntax which ie11 doesn't like.
// Whenever you see a "SyntaxError" that crashes IE11 because of a new lib, add it here.
path.join(__dirname, 'node_modules/react-intl'),
path.join(__dirname, 'node_modules/pkce-challenge'),
path.join(__dirname, 'node_modules/fuse.js')
],
use: [{
loader: 'ts-loader', // Or whatever loader you're using
}]
}]
}
for me this was: fuse.js, pkce-challenge and react-intl.

Can react-loadable be used in create-react-app server-side?

I am attempting to do some code-splitting in my create-react-app application that utilizes server side rendering.
I am utilizing 'react-loadable` to do the code-splitting: https://github.com/thejameskyle/react-loadable
As of now I simply have split my Home.js component away from the rest of my app, just to see if it works. In development mode (read: not SSR), it's chunked off and works fine.
However, I can't get things to work on the server. I'm following the guide on their Github page and am stuck because of the webpack changes needed. In create-react-app applications, you don't have access to webpack as it's hidden away.
The error I receive when starting the server is:
return (0, _importInspector.report)(import('../components/home/Home'), {
^^^^^^
SyntaxError: Unexpected token import
at createScript (vm.js:80:10) ...
I'm pretty sure it's because I don't have webpack configured correctly as stated in the guide.
In the guide, it clearly states for SSR:
First we need Webpack to tell us which bundles each module lives inside. For this there is the React Loadable Webpack plugin.
Import the ReactLoadablePlugin from react-loadable/webpack and include it in your webpack config. Pass it a filename for where to store the JSON data about our bundles.
// webpack.config.js
import { ReactLoadablePlugin } from 'react-loadable/webpack';
export default {
plugins: [
new ReactLoadablePlugin({
filename: './dist/react-loadable.json',
}),
],
};
I don't think this is possible without ejecting.
Anyone have any idea if react-loadable can be used in a create-react-app server-side-rendered application?
import these modules at the top of your server file
require('ignore-styles');
require('babel-polyfill')
require('babel-register')({
ignore: [ /(node_modules)/ ],
presets: ['es2015', 'react-app'],
plugins: [
'syntax-dynamic-import',
'dynamic-import-node',
'react-loadable/babel'
]
});

Resources