Usage of recoil in custom NPM component - reactjs

I'm trying to use recoil in a custom npm component so that I can publish and use it in an application but upon usage getting error as below:
Invalid hook call. Hooks can only be called inside of the body of a function component...
> const useStoreRef = () => useContext(AppContext);
I'm using following rollupjs to build package:
rollup.config.js
import babel from "#rollup/plugin-babel";
import commonjs from "#rollup/plugin-commonjs";
import resolve from "#rollup/plugin-node-resolve";
import external from "rollup-plugin-peer-deps-external";
import postcss from "rollup-plugin-postcss";
import postcssImport from "postcss-import";
import packageJSON from "./package.json";
const input = "./src/index.js";
const PLUGINS = [
babel({
exclude: "node_modules/**",
}),
external(),
resolve({
jsnext: true,
main: true,
browser: true,
}),
commonjs(),
postcss({
plugins: [postcssImport()],
}),
];
export default [
// CommonJS
{
input,
output: {
file: packageJSON.main,
format: "cjs",
sourcemap: true,
},
plugins: PLUGINS,
},
];
.babelrc
{
"presets": ["#babel/preset-env", "#babel/preset-react"],
"plugins": ["#babel/plugin-proposal-class-properties"]
}
src/index.js
import React, { useEffect, useState, useCallback } from "react";
import { useRecoilState, useSetRecoilState } from "recoil";
import {atomState} from '../recoil/atom';
const Component = () => {
const [state, setState] = useRecoilState(atomState);
...
...
return <div>
...
{state}
...
</div>
}
In application, the published component is used as below:
App.js
import {Component} from "NPM_PACKAGE_NAME";
import {RecoilRoot} from "recoil";
<RecoilRoot>
<Component />
</RecoilRoot>
Please help resolve this. I'm new to recoil js. Thanks in advance.
Note: I'm using yarn link to use the package

I saw a few GitHub issues on this. Apparently this problem exists only if you are using yarn link to use package in your application. If I am publishing to npm registry and use, it works as expected.

Related

Rollup error with Styled Components - Error: 'ThemeContext' is not exported by node_modules\styled-components\dist\styled-components-macro.esm.js

I'm using the following rollup configuration:
import peerDepsExternal from "rollup-plugin-peer-deps-external";
import { nodeResolve } from "#rollup/plugin-node-resolve";
import commonjs from "#rollup/plugin-commonjs";
import typescript from "rollup-plugin-typescript2";
import postcss from "rollup-plugin-postcss";
import json from "#rollup/plugin-json";
const packageJson = require("./package.json");
export default {
input: "src/library-index.ts",
external: ['styled-components'],
output: [
{
file: packageJson.main,
format: "cjs",
sourcemap: true
},
{
file: packageJson.module,
format: "esm",
sourcemap: true
}
],
plugins: [
peerDepsExternal(),
nodeResolve({ preferBuiltins: false }),
commonjs({
include: 'node_modules/**'
}),
json(),
typescript(),
postcss()
]
};
Which is throwing the following error:
Error: 'ThemeContext' is not exported by node_modules\styled-components\dist\styled-components-macro.esm.js, imported by src\components\Card\index.tsx
And the corresponding code in src\components\Card\index.tsx is:
import styled, {ThemeContext} from 'styled-components\macro'
This code compiles perfectly well in its original create-react-app context, but now I'm trying to build a component library with Rollup and getting the above error.
I've been looking everywhere with no success so far. Any ideas?
The issue didn't come from Rollup, it was the import in the Card component that was wrong. macro was there by mistake:
import styled, {ThemeContext} from 'styled-components'
The above syntax fixed everything.

How do I make React components import extracted scss modules files with Rollup?

I'm making a React Component Library with Rollup with the following component setup:
//component A
import styles from './stylesA.module.scss'
const ComponentA = () => {
return(
<div className={styles.red}>Component A Styled</div>
)
}
export { ComponentA }
//stylesA.module.scss
.red {
color: red;
}
How do I configure Rollup so that my output components auto-import the generated .css files into my component? Note that I don't want the styles to be bundled into the .js files nor do I want to import the styles manually when I import the final package with import 'my-library/dist/stylesA.css'
My rollup.config.js looks like this for the moment:
// rollup.config.js
import resolve from '#rollup/plugin-node-resolve';
import babel from '#rollup/plugin-babel';
import postcss from 'rollup-plugin-postcss';
import pkg from './package.json'
export default {
input: 'src/index.js',
output: [{
dir: './dist',
format: 'cjs'
}],
plugins: [
resolve(),
babel({
exclude: 'node_modules/**',
babelHelpers: 'bundled'
}),
postcss({
modules: true,
extract: true,
minimize: true
})
],
external: Object.keys(pkg.peerDependencies || {})
};

Making package with React + TS + Storybook + Rollup problems

I'm making my own design system with React + Typescript + Storybook + Rollup.
Before publishing my lib to NPM, I wanted to test this lib in my local env.
I built my project and install like npm i ../my_lib.
I wanted to import my Button component, so I wrote a Login page.
import React from "react";
import { Button } from "#myLib/ui/src";
const Login = () => {
return (
<div>
<Button>Hello</Button>
</div>
);
};
export default Login;
In VSCode, there's no error.
But I started my dev server, this message occured.
Module parse failed: Unexpected token (1:7)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
> export interface IconProps {
| size?: number;
| fillColor?: string;
I think the rollup.config.js has problem. I tried many cases, but only interface got error.
Here is my rollup.config.js.
import commonjs from 'rollup-plugin-commonjs';
import resolve from 'rollup-plugin-node-resolve';
import babel from 'rollup-plugin-babel';
import typescript from 'rollup-plugin-typescript2';
import pkg from './package.json';
import svgr from '#svgr/rollup';
import url from 'rollup-plugin-url';
import peerDepsExternal from 'rollup-plugin-peer-deps-external';
const extensions = ['.js', '.jsx', '.ts', '.tsx'];
process.env.BABEL_ENV = 'production';
export default {
input: './src/index.ts',
plugins: [
peerDepsExternal(),
resolve({ extensions }),
commonjs({
include: 'node_modules/**',
}),
typescript({ useTsconfigDeclarationDir: true }),
babel({ extensions, include: ['src/**/*'], runtimeHelpers: true }),
url(),
svgr(),
],
output: [
{
file: pkg.main,
format: 'es',
},
],
};
Is there any wrong field in my config file?

Module not found: Error: Can't resolve FILE in PATH - Webpack or Babel issue

Src folder structure:
| index.tsx
|
+---components
| Nav.tsx
|
\---pages
login.tsx
index.tsx:
import { BrowserWindow, app } from "electron";
import React from "react";
import ReactDOM from "react-dom";
import Login from "./pages/login";
const main = async () => {
ReactDOM.render(<Login />, document.getElementById("app"));
};
main();
login.tsx:
import React from "react";
interface loginProps {}
const Login: React.FC<loginProps> = ({}) => {
return (
<div>
<h1>HelloWorld</h1>
</div>
);
};
export default Login;
webpack:
const HtmlWebpackPlugin = require("html-webpack-plugin");
const path = require("path");
module.exports = {
entry: "./src/index.tsx",
module: {
rules: [
{
test: /\.tsx?$/,
use: ["babel-loader", "ts-loader"],
include: [path.resolve(__dirname, "src")],
},
],
},
output: {
publicPath: "public",
filename: "bundle.js",
path: path.resolve(__dirname, "public"),
},
resolve: {
fallback: {
path: require.resolve("path-browserify"),
},
},
plugins: [
new HtmlWebpackPlugin({
template: "./public/index.html",
}),
],
target: "electron-main",
};
babel:
{
"presets": ["#babel/preset-env", "#babel/preset-react"]
}
I can't provide much more information on this since the compiler only outputs the error mentioned in title:
ERROR in ./src/index.tsx
Module not found: Error: Can't resolve './pages/login' in '..\src'. Something is probably not linked correctly. webpack 5.5.1 compiled with 1 error in 4971 ms
The problem was that I needed to add resolving extensions in the webpack config. Under resolve add:
extensions: [".ts", ".tsx", ".json", ".js"]
Also after that polyfill is needed refer to this post if you need help about it.
Webpack cant resolve TypeScript modules
Change the import of login, you have exported the login as default, but imported as normal export.
index.tsx:
import { BrowserWindow, app } from "electron";
import React from "react";
import ReactDOM from "react-dom";
import Login from "./pages/login"; // <== Changed this line
const main = async () => {
ReactDOM.render(<Login />, document.getElementById("app"));
};
main();
Login.tsx
import React from "react";
interface loginProps {}
const Login: React.FC<loginProps> = ({}) => { //<== Changed this line
return (
<div>
<h1>HelloWorld</h1>
</div>
);
};
export default Login;

Rollup React Library Output Multiple Build Folders?

I have created a React Library with rollup, however, I have a large number of components that get exported so the file size is relatively large.
So in a project where I import the library doing the following;
import { ComponentExampleOne, ComponentExampleTwo } from 'my-react-library';
It imports the whole index file outputted via rollup (including all other components and any 3rd party dependencies), so when a user first hits the page with the import above they need to download the whole file, which is a lot bigger than I would like it to be.
For the likes of lodash where I just want to access a single function and not the entire library, I would do the following;
import isEmpty from 'lodash/isEmpty';
I want to achieve similar functionality with rollup so I can do something like
import { ComponentExampleOne } from 'my-react-library/examples';
import { ButtonRed } from 'my-react-library/buttons';
So I only import what is exported in the index.js file within an examples and buttons folder with this is as my folder structure in my library.
my-react-library/
-src/
--index.js
--examples/
---ComponentExampleOne.js
---ComponentExampleTwo.js
---ComponentExampleThree.js
---index.js
--buttons/
---ButtonRed.js
---ButtonGreen.js
---ButtonBlue.js
---index.js
I have no idea to achieve this with rollup?
This is my current rollup.config.js
import babel from 'rollup-plugin-babel';
import peerDepsExternal from 'rollup-plugin-peer-deps-external';
import resolve from 'rollup-plugin-node-resolve';
import commonjs from 'rollup-plugin-commonjs';
import postcss from 'rollup-plugin-postcss';
import filesize from 'rollup-plugin-filesize';
import localResolve from 'rollup-plugin-local-resolve';
import json from 'rollup-plugin-json';
import pkg from './package.json';
import externals from 'rollup-plugin-node-externals';
import builtins from 'rollup-plugin-node-builtins';
import globals from 'rollup-plugin-node-globals';
import image from 'rollup-plugin-inline-image';
import { terser } from 'rollup-plugin-terser';
const config = {
input: 'src/index.js',
watch: {
chokidar: {
usePolling: true,
paths: 'src/**'
}
},
output: [
{
file: pkg.browser,
format: 'umd',
name: 'Example'
},
{
file: pkg.main,
format: 'cjs',
name: 'Example'
},
{
file: pkg.module,
format: 'es'
},
],
external: Object.keys(pkg.peerDependencies || {}),
plugins: [
globals(),
builtins(),
externals(),
babel({ exclude: 'node_modules/**', presets: ['#babel/env', '#babel/preset-react'] }),
commonjs({
include: "node_modules/**",
namedExports: {
// left-hand side can be an absolute path, a path
// relative to the current directory, or the name
// of a module in node_modules
'node_modules/formik/node_modules/scheduler/index.js': ['unstable_runWithPriority'],
}
}),
peerDepsExternal(),
postcss({ extract: true }),
json({ include: 'node_modules/**' }),
localResolve(),
resolve({
browser: true,
dedupe: ['react', 'react-dom'],
}),
filesize(),
image(),
terser()
]
};
export default config;
Any help would be greatly appreciated.
You don't really need to do that if you use named exports and any modern bundler for building the app.
When Rollup detects you are not using some export it will be removed due to tree-shaking.
If you still want to do it pass an object with the different entries you want to the input option:
// ...
const config = {
input: {
examples: 'examples/entry/file.js',
buttons: 'buttons/entry/file.js'
},
// ...
}

Resources