admin管理员组

文章数量:1390192

I realize that there are several questions related to this error floating around, but as far as I can tell this is a unique situation and not related to an incorrect import statement.

I'm building a React ponent library with TypeScript and webpack.

My directory structure:

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

My tsconfig.json:

{
  "pilerOptions": {
    "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"
  ]
}

My 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"]
  }
};

My postcss.config.js:

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

src/index.ts is simply:

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

export {
  Button,
};

src/ponents/Button/index.ts:

import Button from './Button';

export { Button };

and src/ponents/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>
  );
}

My dist folder after running webpack looks like:

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

and dist/index.js seems to be piled correctly by webpack. In package.json, I have:

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

After running yarn link, I import and use my Button ponent in a standalone app like so:

import { Button } from 'my-ponents';

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

export default App;

and receive the following error:

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

undefined. You likely forgot to export your ponent from the file it's defined in, or you might have mixed up default and named imports.

Check the render method of `App`.

If I remove the Button ponent, App renders without any errors.

Testing by publishing a throwaway module to npm yields the same error.

Additionally, if anyone has any suggestions as to better ways to bundle this library, I'd love to hear them as this is my first time using postcss.

I realize that there are several questions related to this error floating around, but as far as I can tell this is a unique situation and not related to an incorrect import statement.

I'm building a React ponent library with TypeScript and webpack.

My directory structure:

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

My tsconfig.json:

{
  "pilerOptions": {
    "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"
  ]
}

My 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"]
  }
};

My postcss.config.js:

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

src/index.ts is simply:

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

export {
  Button,
};

src/ponents/Button/index.ts:

import Button from './Button';

export { Button };

and src/ponents/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>
  );
}

My dist folder after running webpack looks like:

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

and dist/index.js seems to be piled correctly by webpack. In package.json, I have:

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

After running yarn link, I import and use my Button ponent in a standalone app like so:

import { Button } from 'my-ponents';

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

export default App;

and receive the following error:

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

undefined. You likely forgot to export your ponent from the file it's defined in, or you might have mixed up default and named imports.

Check the render method of `App`.

If I remove the Button ponent, App renders without any errors.

Testing by publishing a throwaway module to npm yields the same error.

Additionally, if anyone has any suggestions as to better ways to bundle this library, I'd love to hear them as this is my first time using postcss.

Share Improve this question edited Apr 11, 2018 at 23:08 adrice727 asked Apr 11, 2018 at 23:02 adrice727adrice727 1,49212 silver badges17 bronze badges 2
  • Did you omit your export statement in your App.tsx file...? – Andrew Commented Apr 11, 2018 at 23:03
  • @Andrew No, I just didn't include it in the code snippet. I'll make an edit so it's not confusing. – adrice727 Commented Apr 11, 2018 at 23:06
Add a ment  | 

2 Answers 2

Reset to default 7

As it turns out, this was due to an issue with my webpack config. Adding the following lines to output fixed the error:

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

It looks like you made a small mistake importing in index.ts. Since it's a default export, no curly braces should be used.

import Button from './ponents/Button';

本文标签: javascriptTypeScriptReact Element type is invalid expected a string (for builtin components)Stack Overflow