How to use React components from local npm package - javascript

I'm trying to create an npm package with some React components that I use for virtually all of my projects. Here's the folder structure and file contents:
/
dist/
bundle.js
src/
MyComponent.jsx
index.js
package.json
webpack.config.js
MyComponent.jsx
import React, { Component } from 'react';
class MyComponent extends Component {
render() {
return (
<p>Hello, world!</p>
);
}
}
export default MyComponent;
index.js
// eventually there will be more components imported/exported here
import MyComponent from './MyComponent.jsx';
exports.MyComponent = MyComponent;
webpack.config.js
module.exports = {
entry: './src/index.js',
output: {
path: './dist',
filename: 'bundle.js'
},
// some loaders...
};
package.json
{
"name": "my-library",
"files": [
"dist",
"src"
],
"main": "dist/bundle.js",
// the usual stuff...
}
This is my understanding of the process. First, I build the src files with webpack. This looks at /src/index.js, imports the MyComponent class, then exports it, making it available as MyComponent. This is all added to a bundle.js file in /dist.
Next, I pack the module with npm pack. This creates an archive file with the /src and /dist directories in it.
Then I go over to my other project and run npm install ../path/to/archive/file. This adds the module to my node_modules directory. The problem is that when I try to import and use MyComponent...
import React, { Component } from 'react';
import MyComponent from 'my-library';
class App extends Component {
render() {
console.log(<MyComponent />);
return (
<MyComponent />
);
}
}
export default App;
...and render that component, I get this warning and error:
Warning: React.createElement: type should not be null, undefined, boolean, or number. It should be a string (for DOM elements) or a ReactClass (for composite components). Check the render method of `App`.
Uncaught Error: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: object. Check the render method of `App`.
The output of the console.log is a React object, but the type is Object, which seems like what the warning is alluding to (it should be a string instead, I guess).
Any idea what I'm missing?
EDIT:
Well, I'm closer. I added library options to my webpack config:
output: {
library: 'my-library',
libraryTarget: 'umd'
}
...and then I was able to use the component like this:
import MyLibrary from 'my-library';
const MyComponent = MyLibrary.MyComponent;
But I don't want to have to do that for every component. My goal is this:
import { MyComponent, MyOtherComponent } from 'my-library';

You have to export your component from the component index.js file like shown below
import MyComponent from './MyComponent.jsx';
import MyOtherComponent from './MyOtherComponent.jsx';
export {
MyComponent,
MyOtherComponent
}
Then in your Main project, Import them using
import { MyComponent, MyOtherComponent } from 'my-library';

Related

Build React components library with Webpack 4

I'm currently building a library of React components and bundling it with Webpack 4.
Everything works just fine from building the library's bundle to publishing it on an npm registry.
But then, I'm not able to import any of its components in an other React application and get this error message at runtime:
Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.
And here is the related code:
A dumb component from my components library:
button/index.js
import React from "react";
const Button = () => <button>Foobar</button>;
export { Button };
The main entry point of my library index.js:
import { Button } from "./src/components/Button";
export { Button };
My Webpack config webpack.config.js:
const path = require("path");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
module.exports = {
entry: "./index.js",
plugins: [new CleanWebpackPlugin()],
module: {
rules: [
{
test: /\.m?js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader"
}
}
]
},
output: {
filename: "index.js",
path: path.resolve(__dirname, "dist"),
libraryTarget: "commonjs",
library: ""
}
};
And finally, the import of this component in an other application:
import { Button } from "my-design-system";
I guess I'm missing something in my Webpack config or one of the property may be wrong, but after reading multiple posts and tutorials, I can't figure which one.
You're exporting your library as commonjs and trying to import it via import/export syntax. You should change your output to
output: {
filename: "index.js",
path: path.resolve(__dirname, "dist"),
libraryTarget: "umd",
library: "my-design-system"
}
Found a lot of info here: https://webpack.js.org/guides/author-libraries/
What I would do is to export your components as default and then re-export as named from index.js:
/// Button.js
import React from "react";
const Button = () => <button>Foobar</button>;
export default Button ;
// index.js
export { default as Button } from "./src/components/Button";
Then you can do
import { Button } from "my-design-system";
Also make sure you have main set up, pointing to your index.js, in your design system's package.json
Additionally, if you still want to have named exports in some of your components, you can export everything from that component file:
//index.js
export * from "./src/components/ComponentWithNamedExports";
Either way you will make sure there's always one point of export for all your components.
EDIT: As noted in by Maaz Syed Adeeb, you have wrong libraryTarget in your config. I'd remove both libraryTarget and library from there.

npm build with Browserify - Error: Cannot find module

When running npm build with:
"build": "browserify -t [ babelify --presets [ es2015 react ] ] app/assets/app.jsx -o public/javascripts/app.js"
I am getting following error:
Error: Cannot find module 'components/maininput.jsx' from 'C:\Users\Work\Documents\NetBeansProjects\Project\app\assets'
Project structure looks like this:
app
|
└────assets
│ app.jsx
|
└───components
maininput.jsx
import in app.jsx looks like this:
import React from 'react';
import ReactDOM from 'react-dom';
import { MainInput } from '../components/maininput.jsx'
export in maininput.jsx looks like this:
export default class MainInput extends React.Component {
//some code and render()
}
I also created GulpFile and also there getting same error:
{ Error: Cannot find module '../components/maininput.jsx'
EDIT:
I have found out that it is working only if I provide full path to component, which is strange. Anyone knows what might cause this problem? Probably some enviroment variable or ?
Use ./ at the beginning of your import path:
import { MainInput } from './components/maininput.jsx'

React unable to import component -- module not found

I just started with React.js and I am unable to import component.
I have this structure as followed by this tutorial (YouTube link) :
-- src
----| index.html
----| app
------| index.js
------| components
--------| MyCompontent.js
This is my index.js:
import React from 'react';
import { render } from 'react-dom';
import { MyCompontent } from "./components/MyCompontent";
class App extends React.Component {
render() {
return (
<div>
<h1>Foo</h1>
<MyCompontent/>
</div>
);
}
}
render(<App />, window.document.getElementById('app'));
This is MyComponent.js:
import React from "react";
export class MyCompontent extends React.Component {
render(){
return(
<div>MyCompontent</div>
);
}
}
I am using this webpack file (GitHub link).
However, when I run this, my module fails to load.
I get this error in the browser console:
Error: Cannot find module "./components/MyCompontent"
[WDS] Hot Module Replacement enabled. bundle.js:631:11
[WDS] Errors while compiling. bundle.js:631:11
./src/app/index.js
Module not found: Error: Cannot resolve 'file' or 'directory' ./components/MyCompontent in /home/kuno/code/react-hoteli/src/app
resolve file
/home/kuno/code/react-hoteli/src/app/components/MyCompontent doesn't exist
/home/kuno/code/react-hoteli/src/app/components/MyCompontent.webpack.js doesn't exist
/home/kuno/code/react-hoteli/src/app/components/MyCompontent.web.js doesn't exist
/home/kuno/code/react-hoteli/src/app/components/MyCompontent.js doesn't exist
/home/kuno/code/react-hoteli/src/app/components/MyCompontent.json doesn't exist
resolve directory
/home/kuno/code/react-hoteli/src/app/components/MyCompontent/package.json doesn't exist (directory description file)
/home/kuno/code/react-hoteli/src/app/components/MyCompontent doesn't exist (directory default file)
[/home/kuno/code/react-hoteli/src/app/components/MyCompontent]
[/home/kuno/code/react-hoteli/src/app/components/MyCompontent.webpack.js]
[/home/kuno/code/react-hoteli/src/app/components/MyCompontent.web.js]
[/home/kuno/code/react-hoteli/src/app/components/MyCompontent.js]
[/home/kuno/code/react-hoteli/src/app/components/MyCompontent.json]
# ./src/app/index.js 11:20-56 bundle.js:669:5
Can't figure out what went wrong here.
For anyone coming here without a typo, and is using Webpack, be sure to check for a clause like this:
resolve: {
extensions: [".jsx", ".js"]
},
in your webpack.config.js.
This tells your transpiler to resolve statements like:
import Setup from './components/Setup'
to
import Setup from './components/Setup.jsx'
This way you don't need the extension.
You have a typo in your import. You're requesting MyCompontent. Change to:
import MyComponent from "./components/MyComponent";
And all typos as well.
You can try to import MyCompontent from "./components/MyCompontent.js"
like this
import MyCompontent from "./components/MyCompontent.js";
You have written that the filename is MyComponent.js.
Thus, your import should look like
import { MyCompontent } from './components/MyComponent.js'
The problem for me was that import line was not generated correctly. I have this scenario:
--src
----elements
-----myCustomText.tsx
this is myCustomText.tsx file:
export interface Props {
text: string;
}
const MyCustomText = ({ text }: Props) => (
<Text>{text}</Text>
);
export default MyCustomText
And the generated import was this:
import MyCustomText from '../../elements/MyCustomText';
and I changed it to this:
import MyCustomText from '../../elements/myCustomText'
I don't know why the generated import line was generated automatically wrong.
I found myself here without a typo and without a webpack issue.
The solution for me was to restart the typescript server via VS Code.
I just had this issue, no type or webpack config issues.
What fixed it was changing the import from relative to the app root directory to relative to the file:
import MyComponent from "src/components/MyComponent";
to
import MyComponent from "../components/MyComponent";
If you're getting this from Visual Studio Code auto-importing via the shortest route, you can change it so it imports relatively. By going here:
menu File → Preferences → Settings → User Settings,
"typescript.preferences.importModuleSpecifier": "relative"
export 'Component' (imported as 'Component') was not found in 'react'
if you find your self stuck with this error simply go to mini-create-react-context, and go to cjs, and go to index.js and add "React" example: you will find this (Component) solution (React.Component) only if you extends to React.Component in you pages
Note: I have only used this on VS Code

Having issues with ES6 based multiple (React) Node.JS Module imports

I've been working on a React project and I'm having an issue trying to use ES6 to import several exported React node modules.
This is my code:
I should be able to include the AddFriendInput and FriendList from the hello folder without any issue. But I get this error when webpack/babel compiles:
ERROR in ./src/common/containers/Menu/indexRender.js
Module not found: Error: Cannot resolve 'file' or 'directory' ../../hello in /Users/markpaul/Documents/projects/patient-portal-app/src/common/containers/Menu
# ./src/common/containers/Menu/indexRender.js 122:13-35
The content of my AddFriendInput.js file is like so:
import React, { Component, PropTypes } from 'react';
export default class AddFriendInput extends Component {
constructor(props, context) {
super(props, context);
this.state = {
name: this.props.name || ''
};
}
render() {
return (
<div>
</div>
);
}
}
I use webpack with babel to transpile my files. My Babel config is:
{
"presets": ["react", "es2015", "stage-1"]
}
The only way I can get it to work is to do this:
import AddFriendInput from '../../hello/AddFriendInput/AddFriendInput';
import FriendList from '../../hello/FriendList/FriendList';
But as you can see, this looks horrible.
Can someone please help.
Thanks in advance.
Create home/index.js
import AddFriendInput from './AddFriendInput'
import FriendList from './FriedList'
export { AddFriendInput, FriendList }
OLD ANSWER:
Rename AddFriendInput.js to index.js and after that you can import like this:
import AddFriendInput from '../../hello/AddFriendInput'
ES6 module doesn't automatically load nested directories/files
import by directory name (../../hello) implies that you have hello/index.js
updates
you could just create home/index.js as #Sergey mentioned or there is a module named auto-import that watch your directory and update index.js for you.
I think you are not understand the commonJS.
if the ../../hello is a folder, nodejs will find index.js file. so you must be have a file ../../hello/index.js.
import AddFriendInput from '../../hello/AddFriendInput/AddFriendInput';
import FriendList from '../../hello/FriendList/FriendList';
module.exports = {
AddFriendInput,
FriendList
};

how to config a module bundler divide by folder with webpack?

I get the file structure like this
before build
I want to make it like this below with webpack
after build
BTW, I also want to use ES6 import and export for the module loader,
such as in nav.js
class Nav extends Component {
// react code here
}
export defalt Nav
and in header.js
import Nav from `nav/bundle`
// header react code
// .......
export defalt Header
also need the bundle the redux and react-route npm package within the node_module
is it possible for webpack to do this stuff? some suggestions?
Here's a rough idea you could try to adapt:
{
// generate these dynamically through JavaScript
entry: {
footer: <path to footer js>,
...
},
output: {
path: './demo',
filename: '[name]/bundle.js' // name maps to entry keys
},
...
}

Categories