I'm currently working on my first gatsby/react/typescript project and one of the requirements is to create a component library which should hold components commonly used in the upcoming applications.
My inital test with only one component (without the index.ts as the entry was the FancyBanner.tsx itself) worked. After adding a second component (FancyButton.tsx) and the index.ts, I can not use the component in my App. Following error occures:
Uncaught Error: 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.
Setup
- Gatsby 2
- React 16.5
- Typescript 3
- Local npm registry through Artifactory
Project structure (this is the stipped down version as the gatsby files is only needed for testing an not relevant built component library)
component-lib/
src/
lib/
fancy.css
FancyButton.tsx
FancyBanner.tsx
index.ts
index.d.ts
package.json
tsconfig.json
webpack.config.js
The two components are nearly identical but should replicate two individual components:
import * as React from 'react';
import './fancy.css'
interface Props {
text: string
}
interface State {
/* no state required */
}
export default class FancyBanner extends React.Component<Props, State> {
public static defaultProps: Partial<Props> = {
text: "this is a fancy component"
};
public render() {
return (
<div className={"fancy"}>
{this.props.text}
</div>
);
};
}
-
import * as React from 'react';
import './fancy.css'
interface Props {
text: string
}
interface State {
/* no state required */
}
export default class FancyButton extends React.Component<Props, State> {
public static defaultProps: Partial<Props> = {
text: "this is a fancy button"
};
public render() {
return (
<div className={"button fancy"}>
{this.props.text}
</div>
);
};
}
The index.ts simply exports the two componets
export * from "./fancy/FancyButton"
export * from "./fancy/FancyBanner"
The index.d.ts is "handmade" (maybe this is the problem?)
import * as React from "react";
export interface Props {
text: string;
}
export interface State {
}
export class FancyBanner extends React.Component<Props, State> {}
export class FancyButton extends React.Component<Props, State> {}
Finally, the different configuration files
{
"name": "company-component-lib",
"description": "makes your app fancy",
"version": "0.0.7-snapshot.10",
"main": "dist/bundle.js",
"types": "index.d.ts",
"dependencies": {},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "webpack --watch",
"build": "webpack",
"local-release": "npm run build && npm link",
"release": "npm run build && npm publish"
},
"devDependencies": {
"@types/node": "^10.10.3",
"@types/react": "^16.4.14",
"@types/react-dom": "^16.0.7",
"react": "^16.5.2",
"react-dom": "^16.5.2",
"react-helmet": "^5.2.0",
"typescript": "^3.0.3",
"css-loader": "^1.0.0",
"gatsby": "^2.0.8",
"gatsby-link": "^2.0.1",
"gatsby-plugin-react-helmet": "^3.0.0",
"gatsby-plugin-typescript": "^2.0.0",
"style-loader": "^0.23.0",
"webpack-cli": "^3.1.1",
"ts-loader": "^5.2.1"
},
"publishConfig": {
"type": "npm",
"registry": "<myrepo>"
},
"files": [
"dist/bundle.js",
"index.d.ts"
]
}
-
{
"compilerOptions": {
"outDir": "./dist/",
"module": "commonjs",
"target": "es5",
"jsx": "react",
"declaration": true,
"lib": ["dom", "es5"]
},
"include": [
"./src/lib/**/*"
]
}
-
var path = require('path');
module.exports = {
entry: './src/lib/index.ts',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js',
libraryTarget: 'commonjs2'
},
module: {
rules: [
{
test: /\.tsx$/,
include: path.resolve(__dirname, 'src/lib'),
exclude: /(node_modules|bower_components|public)/,
use: 'ts-loader'
},
{
test:/\.css$/,
use:['style-loader','css-loader']
}
]
},
externals: {
'react': 'commonjs react'
},
resolve: {
extensions: [".tsx", ".ts", ".js"]
}
};
After build and publish I can install my component library in my app and IntelliJ automatically adds the import
import * as React from 'react'
import Layout from "../components/layout";
import {FancyBanner} from "company-component-lib";
export default class Page_7 extends React.Component<any, any> {
public render() {
return (
<Layout>
<div>
<h1>Component Sample Page</h1>
<FancyBanner text={"WOOOHOOO!"}/>
</div>
</Layout>
)
}
}
I tried some of the suggestions from this quests but the error remains. As a react/typescript newby I somewhat have the feeling that the typescript declaration is the problem but cannot find the failure in my setup. Any hints or suggestions are appreciated.
##### UPDATE #####
After further research we dropped webpack
with babel
and simply use tsc
based on this tutorial. This tutorial helped us to create a commons library but sadly does not answer the intial question, why the module with webpack
and babel
cannot be imported (specificaly what we did wrong and if webpack
with babel
is suitable for this scenario).