Webpack + Typscript 库导入在 React 项目中未定义
Webpack + Typscript library import is undefined in React project
我正在尝试使用 Typescript、Webpack 和 Babel 创建一个 React 库,但是我 运行 遇到了问题。如果我构建然后将库导入 React 项目,那么我的导入是 'undefined'(请参阅以下错误)。我认为这是因为在 bundle.js
中没有 module.exports
代表我的 class 的变量只有 __webpack_exports__["default"] = (ExampleComponent);
(但是我不确定这是什么在实践中确实如此,所以我可能是错的。)
我特别遇到了这个错误:
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.
我尝试过的:
- 将 tsconfig 目标更改为 es6,将模块更改为 commonjs
- 将 tsconfig 目标更改为 es6 并将模块更改为 esnext
- 将 tsconfig 目标更改为 es5 并将模块更改为 esnext
- 将 tsconfig 目标更改为 esnext,并将模块更改为 esnext
- 将 tsconfig 目标更改为 es6 并将模块更改为 es6
- 将 tsconfig 目标更改为 commonjs 并将模块更改为 es6
- 将库导入为 'import * as ExampleComponent from ...' 和 'import {ExampleComponent} from ...'(按预期)两次 'ExampleComponent' 未定义。
版本:
- babel-loader: ^8.1.0
- Webpack: ^4.43.0
- 打字稿:^3.8.3
代码:
React 项目:
import React from "react";
import { ExampleComponent } from "test-lib";
// This is always undefined
console.log(ExampleComponent);
function App() {
return <ExampleComponent />;
}
export default App;
图书馆项目:
index.ts:
import ExampleComponent from './ExampleComponent'
export { ExampleComponent }
ExampleComponent.tsx
import * as React from 'react'
import './ExampleComponent.css'
interface Props {
text: string
}
// prettier-ignore
const ExampleComponent: React.FC<Props> = ({ text }) => (
<h1 className="example-text">{text}</h1>
)
export default ExampleComponent
库配置:
tsconfig.json:
{
"compilerOptions": {
"outDir": "dist",
"module": "esnext",
"lib": ["dom", "esnext"],
"moduleResolution": "node",
"jsx": "react",
"sourceMap": true,
"declaration": true,
"esModuleInterop": true,
"noImplicitReturns": true,
"noImplicitThis": true,
"noImplicitAny": true,
"strictNullChecks": true,
"suppressImplicitAnyIndexErrors": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"allowSyntheticDefaultImports": true,
"target": "es5",
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true
},
"include": ["src", "tests"],
"exclude": ["node_modules", "dist", "example"]
}
.babelrc:
{
"presets": [
[
"@babel/preset-env",
{
"debug": true,
"useBuiltIns": "usage",
"corejs": 3
}
],
"@babel/preset-react",
"@babel/preset-typescript"
]
}
Webpack 配置:
const path = require('path')
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin')
module.exports = {
entry: {
bundle: './src/index.ts',
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].js',
},
resolve: {
extensions: ['.tsx', '.ts', '.js', '.json'],
},
devtool: 'source-map',
module: {
rules: [
{
test: /\.tsx?$/,
exclude: /node_modules/,
use: [{ loader: 'babel-loader' }, { loader: 'ts-loader' }],
},
{
test: /\.css$/,
loaders: ['style-loader', 'css-loader'],
},
{
test: /\.(gif|png|jpe?g|svg)$/,
use: [
'file-loader',
{
loader: 'image-webpack-loader',
options: {
disable: true,
},
},
],
},
{
test: /\.js$/,
enforce: 'pre',
loader: 'source-map-loader',
},
],
},
plugins: [new ForkTsCheckerWebpackPlugin()],
}
如果您想在此处查看完整代码,请从 link 到 Github Repo。
根据 Scovy 的评论,我可以使用 output.libraryTarget and output.globalObject 输出选项来实现此功能。
现在我在 webpack.base.config.js 中的输出条目如下所示:
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].js',
libraryTarget: 'umd',
globalObject: 'this',
},
更新:
上述更改并没有在 100% 的时间内正常工作,所以我找到了一个名为 esm-webpack-plugin 的库,它最终完美地工作了。
所以webpack配置中输出入口的最终代码是:
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].js',
library: 'LIB',
libraryTarget: 'var',
},
我还添加了插件:
plugins: [new ForkTsCheckerWebpackPlugin(), new EsmWebpackPlugin()],
我正在尝试使用 Typescript、Webpack 和 Babel 创建一个 React 库,但是我 运行 遇到了问题。如果我构建然后将库导入 React 项目,那么我的导入是 'undefined'(请参阅以下错误)。我认为这是因为在 bundle.js
中没有 module.exports
代表我的 class 的变量只有 __webpack_exports__["default"] = (ExampleComponent);
(但是我不确定这是什么在实践中确实如此,所以我可能是错的。)
我特别遇到了这个错误:
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.
我尝试过的:
- 将 tsconfig 目标更改为 es6,将模块更改为 commonjs
- 将 tsconfig 目标更改为 es6 并将模块更改为 esnext
- 将 tsconfig 目标更改为 es5 并将模块更改为 esnext
- 将 tsconfig 目标更改为 esnext,并将模块更改为 esnext
- 将 tsconfig 目标更改为 es6 并将模块更改为 es6
- 将 tsconfig 目标更改为 commonjs 并将模块更改为 es6
- 将库导入为 'import * as ExampleComponent from ...' 和 'import {ExampleComponent} from ...'(按预期)两次 'ExampleComponent' 未定义。
版本:
- babel-loader: ^8.1.0
- Webpack: ^4.43.0
- 打字稿:^3.8.3
代码:
React 项目:
import React from "react";
import { ExampleComponent } from "test-lib";
// This is always undefined
console.log(ExampleComponent);
function App() {
return <ExampleComponent />;
}
export default App;
图书馆项目:
index.ts:
import ExampleComponent from './ExampleComponent'
export { ExampleComponent }
ExampleComponent.tsx
import * as React from 'react'
import './ExampleComponent.css'
interface Props {
text: string
}
// prettier-ignore
const ExampleComponent: React.FC<Props> = ({ text }) => (
<h1 className="example-text">{text}</h1>
)
export default ExampleComponent
库配置:
tsconfig.json:
{
"compilerOptions": {
"outDir": "dist",
"module": "esnext",
"lib": ["dom", "esnext"],
"moduleResolution": "node",
"jsx": "react",
"sourceMap": true,
"declaration": true,
"esModuleInterop": true,
"noImplicitReturns": true,
"noImplicitThis": true,
"noImplicitAny": true,
"strictNullChecks": true,
"suppressImplicitAnyIndexErrors": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"allowSyntheticDefaultImports": true,
"target": "es5",
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true
},
"include": ["src", "tests"],
"exclude": ["node_modules", "dist", "example"]
}
.babelrc:
{
"presets": [
[
"@babel/preset-env",
{
"debug": true,
"useBuiltIns": "usage",
"corejs": 3
}
],
"@babel/preset-react",
"@babel/preset-typescript"
]
}
Webpack 配置:
const path = require('path')
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin')
module.exports = {
entry: {
bundle: './src/index.ts',
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].js',
},
resolve: {
extensions: ['.tsx', '.ts', '.js', '.json'],
},
devtool: 'source-map',
module: {
rules: [
{
test: /\.tsx?$/,
exclude: /node_modules/,
use: [{ loader: 'babel-loader' }, { loader: 'ts-loader' }],
},
{
test: /\.css$/,
loaders: ['style-loader', 'css-loader'],
},
{
test: /\.(gif|png|jpe?g|svg)$/,
use: [
'file-loader',
{
loader: 'image-webpack-loader',
options: {
disable: true,
},
},
],
},
{
test: /\.js$/,
enforce: 'pre',
loader: 'source-map-loader',
},
],
},
plugins: [new ForkTsCheckerWebpackPlugin()],
}
如果您想在此处查看完整代码,请从 link 到 Github Repo。
根据 Scovy 的评论,我可以使用 output.libraryTarget and output.globalObject 输出选项来实现此功能。
现在我在 webpack.base.config.js 中的输出条目如下所示:
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].js',
libraryTarget: 'umd',
globalObject: 'this',
},
更新:
上述更改并没有在 100% 的时间内正常工作,所以我找到了一个名为 esm-webpack-plugin 的库,它最终完美地工作了。
所以webpack配置中输出入口的最终代码是:
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].js',
library: 'LIB',
libraryTarget: 'var',
},
我还添加了插件:
plugins: [new ForkTsCheckerWebpackPlugin(), new EsmWebpackPlugin()],