TypeScript + React:元素类型无效:期望一个字符串(对于内置组件)

时间:2018-04-11 23:02:02

标签: javascript reactjs typescript webpack postcss

我意识到有几个问题与此错误有关,但据我所知,这是一个独特的情况,与错误的import语句无关。

我正在使用ReactTypeScript构建webpack组件库。

我的目录结构:

- src
  - index.ts
  - components
    - Button
      - Button.tsx
      - index.ts
      - Button.css
      - Button.d.css (generated by webpack plugin)
- package.json
- tsconfig.json
- webpack.config.js
- postcss.config.js

我的tsconfig.json

{
  "compilerOptions": {
    "allowSyntheticDefaultImports": true,
    "module": "es2015",
    "target": "es5",
    "lib": ["es6", "dom"],
    "sourceMap": true,
    "allowJs": false,
    "jsx": "react",
    "moduleResolution": "node",
    "rootDir": "src",
    "outDir": "dist",
    "noImplicitReturns": true,
    "noImplicitThis": true,
    "noImplicitAny": true,
    "strictNullChecks": true,
    "declaration": true
  },
  "include": [
    "src/**/*"
  ],
  "exclude": [
    "node_modules",
    "build",
    "dist",
    "scripts",
    "acceptance-tests",
    "webpack",
    "jest",
    "src/setupTests.ts",
    "**/*/*.test.ts",
    "examples"
  ]
}

我的webpack.config.js

const path = require("path");
const ExtractTextPlugin = require("extract-text-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");

module.exports = {
  entry: "./src/index.ts",
  output: {
    path: path.resolve(__dirname, "dist"),
    filename: "index.js"
  },
  mode: "development",
  module: {
    rules: [
      {
        test: /\.tsx?$/,
        loader: "awesome-typescript-loader",
      },
      {
        test: /\.css$/,
        use: [
          MiniCssExtractPlugin.loader,
          {
            loader: 'typings-for-css-modules-loader',
            options: {
              modules: true,
              namedExport: true,
              banner: "/* This file is generated during the webpack build. Please do not edit/remove. */",
              localIdentName: '[name]__[local]'
            }
          },
          {
            loader: 'postcss-loader',
            options: {
              config: {
                path: './postcss.config.js'
              }
            }
          }
        ]
      },
      {
        test: /\.(jpg|png|gif|svg)$/,
        use: [
          {
            loader: "file-loader",
            options: {
              name: "[name].[ext]"
            }
          }
        ]
      }
    ]
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: "[name].css",
      chunkFilename: "[id].css"
    })
  ],
  devtool: "source-map",
  resolve: {
    extensions: [".js", ".ts", ".tsx", ".css"]
  }
};

我的postcss.config.js

module.exports = {
    modules: true,
    plugins: [
        require('precss'),
        require('postcss-simple-vars'),
        require('autoprefixer'),
        require('postcss-nested'),
    ]
}

src/index.ts只是:

import { Button } from './components/Button';

export {
  Button,
};

src/components/Button/index.ts

import Button from './Button';

export { Button };

src/components/Button/Button.tsx

import * as React from 'react';
import { ReactNode } from 'react';
import { Link } from 'react-router-dom';
import * as styles from './Button.css';

export interface IButtonPropTypes {
  onClick?: React.MouseEventHandler<any>;
  label: string;
  children?: ReactNode[] | string;
  kind?: 'link' | 'action';
  style?: { [key: string]: string };
  href?: string;
  target?: string;
  className?: string;
}

export default function Button({
  onClick,
  label,
  children,
  kind = 'action',
  style = {},
  href,
  target,
  className,
}: IButtonPropTypes) {
  const text = label || children;
  const kindStyle = styles[kind] || '';
  const classes = className || '';
  if (href) {
    return (
      <Link
        className={`${style.btn} ${kindStyle} ${classes}`}
        to={href}
        target={target}
        onClick={onClick}
        style={style}
      >
        <span className={style.background} />
        <span>{text}</span>
      </Link>
    );
  }

  return (
    <button className={`${style.btn} ${kindStyle}`} onClick={onClick} style={style}>
      <div>{text}</div>
    </button>
  );
}
运行dist后,

我的webpack文件夹如下所示:

- dist
  - index.js
  - index.js.map
  - index.d.ts
  - main.css
  - main.css.map
  - components
    - Button
      - Button.d.ts
      - index.d.ts

dist/index.js似乎由webpack正确编译。在package.json,我有:

  "main": "dist/index.js",
  "types": "dist/index.d.ts",
  "files": ["dist"]

运行yarn link后,我在一个独立的应用中导入并使用我的Button组件,如下所示:

import { Button } from 'my-components';

class App extends React.Component {
  render() {
    return (
      <div className="App">
        <Button label="click me" />
      </div>
    );
  }
}

export default App;

并收到以下错误:

Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got:
     

未定义。您可能忘记从文件中导出组件   它是在中定义的,或者您可能混淆了默认导入和命名导入。

Check the render method of `App`.

如果我删除Button组件,App呈现没有任何错误。

通过将一次性模块发布到npm进行测试会产生相同的错误。

此外,如果有人对更好地捆绑此库的方法有任何建议,我很乐意听到它们,因为这是我第一次使用postcss

2 个答案:

答案 0 :(得分:0)

看起来你在index.ts中输入了一个小错误。由于它是默认导出,因此不应使用花括号。

import Button from './components/Button';

答案 1 :(得分:0)

事实证明,这是由于webpack配置问题造成的。将以下行添加到output修复了错误:

  output: {
    . . . 
    library: "opentok-ux-components",
    libraryTarget: 'umd',
    umdNamedDefine: true
  },