我正在使用React和带有Babel 7的TypeScript创建一个模块化组件库。
我希望我的图书馆用户以类似于以下的语法导入组件:
import SomeComponent from "my-awesome-lib/SomeComponent"
SomeComponent是my-awesome-lib软件包中的TSX模块:
import * as React from "react";
export default function () {
return <h1>SomeComponent</h1>
}
my-awesome-component的package.json文件的main
字段是:
"main": "src/index.ts"
我不想发布组件库的编译版本,因为我正在组件中导入CSS和其他资产,并且我希望我的软件包的所有用户都可以通过某些特定的配置使用Webpack。
现在我的问题是`从“ my-awesome-lib / SomeComponent”导入SomeComponent失败,并出现解析错误:
ERROR in ../node_modules/wtf/index.tsx 4:9
Module parse failed: Unexpected token (4:9)
You may need an appropriate loader to handle this file type.
|
| export default function () {
> return <h1>WTF</h1>
| }
似乎Webpack不会在node_modules中加载或转换TSX文件。
我在用户应用程序的根目录(导入my-awesome-lib)中使用了tsconifg.json:
{
"compilerOptions": {
"outDir": "./dist",
"module": "commonjs",
"target": "es5",
"jsx": "react",
"allowSyntheticDefaultImports": true,
"moduleResolution": "node",
"resolveJsonModule": true,
"esModuleInterop": true,
"downlevelIteration": true,
"lib": ["es5", "es2015", "dom", "scripthost"],
"typeRoots": ["node_modules/@types", "src/@types"],
},
"include": ["src/**/*", "node_modules/**/*"],
"exclude": []
}
Webpack的相关配置为:
const tsModules = {
test: /\.(js|jsx|ts|tsx)$/,
include: [path.resolve('src')],
exclude: /node_modules/,
loader: 'babel-loader'
}
const resolve = {
alias: {
},
modules: [
'node_modules'
],
extensions: ['.tsx', '.ts', '.js']
}
module.exports = {
...
context: resolve('src'),
resolve: resolve,
module: {
rules: [
tsModules,
...
]
}
}
如何使Webpack从node_modules加载和转换my-awesome-lib的TSX模块?
答案 0 :(得分:1)
您正在排除node_modules
目录(通常是好事):
const tsModules = {
test: /\.(js|jsx|ts|tsx)$/,
include: [path.resolve('src')],
exclude: /node_modules/,
loader: 'babel-loader'
}
除了明确排除node_modules
文件夹之外,您还只允许src
处理babel-loader
文件夹的内容,因为您在{{1 }}。所以这个错误:
../node_modules/wtf/index.tsx中的ERROR 4:9模块解析失败: 意外令牌(4:9)
很有道理。
如果您删除了include
属性并更改了tsModules
中的正则表达式,则仍然可以排除node_modules
到单个文件夹之外的内容:
tsModules.include
或者可以,但是我还没有测试过,请将tsModules.exclude
目录添加到const tsModules = {
// ...
exclude: /node_modules\/(?!my-awesome-lib)\/*/
// ...
}
数组中:
my-awesome-lib
然后include
目录中的文件将通过const tsModules = {
// ...
include: [
path.resolve(__dirname, './src'),
path.resolve(__dirname, './node-modules/my-awesome-lib')
]
// ...
}
,它将转换打字稿代码。
编辑:我认为您的node_modules/my-awesome-lib
文件与babel-loader
引起了混淆。 Babel正在编译您的代码,而不是打字稿。因此,在根目录中有一个tsconfig.json
文件可能会帮助您的IDE(特别是如果您使用的是Microsoft的VScode),但对"include": ["src/**/*", "node_modules/**/*"],
和tsconfig.json
的代码转换方式没有影响。>
答案 1 :(得分:0)
此设置假定您使用的是样式组件,并且没有css / scss。
这里重要的是,您在tsconfig中具有“模块”:commonJS,而在webpack配置中具有libraryTarget:“ commonJS”。外部人员告诉webpack不要将您的库与React,React-DOM或样式化组件捆绑在一起,而是在要导入的项目内查找那些包。
您还需要从package.json依赖项中删除React,react-dom和styled-components并将这些包置于对等项依赖项中
const path = require("path");
const fs = require("fs");
const TerserPlugin = require('terser-webpack-plugin');
const appIndex = path.join(__dirname, "../src/main.tsx");
const appBuild = path.join(__dirname, "../storybook-static");
const { TsConfigPathsPlugin } = require('awesome-typescript-loader');
module.exports = {
context: fs.realpathSync(process.cwd()),
mode: "production",
bail: true,
devtool: false,
entry: appIndex,
output: {
path: appBuild,
filename: "dist/Components.bundle.js",
publicPath: "/",
libraryTarget: "commonjs"
},
externals: {
react: {
root: 'React',
commonjs2: 'react',
commonjs: 'react',
amd: 'react'
},
'react-dom': {
root: 'ReactDOM',
commonjs2: 'react-dom',
commonjs: 'react-dom',
amd: 'react-dom'
},
"styled-components": {
root: "styled-components",
commonjs2: "styled-components",
commonjs: "styled-components",
amd: "styled-components"
}
},
optimization: {
minimizer: [
new TerserPlugin({
terserOptions: {
parse: {
ecma: 8,
},
compress: {
ecma: 5,
warnings: false,
comparisons: false,
inline: 2,
},
mangle: {
safari10: true,
},
output: {
ecma: 5,
comments: false,
ascii_only: true,
},
},
parallel: true,
cache: true,
sourceMap: false,
})
],
},
resolve: {
extensions: [".web.js", ".mjs", ".js", ".json", ".web.jsx", ".jsx", ".ts", ".tsx"],
alias: {
"react-native": "react-native-web",
},
},
module: {
strictExportPresence: true,
rules: [
{ parser: { requireEnsure: false } },
{
test: /\.(ts|tsx)$/,
loader: require.resolve("tslint-loader"),
enforce: "pre",
},
{
oneOf: [
{
test: /\.(tsx?)$/,
loader: require.resolve('awesome-typescript-loader'),
options: {
configFileName: 'tsconfig.prod.json'
}
},
],
},
],
},
plugins: [
new TsConfigPathsPlugin()
],
node: {
dgram: "empty",
fs: "empty",
net: "empty",
tls: "empty",
child_process: "empty",
},
performance: false,
};
注意:将应用程序中的一个点定位为仅包含要导出的组件的条目非常重要。
IE对我来说是Main.tsx,而在Main.tsx内看起来像这样。
export { Checkbox } from "./components/Checkbox/Checkbox";
export { ColorUtils } from "./utils/color/color";
export { DataTable } from "./components/DataTable/DataTable";
export { DatePicker } from "./components/DateTimePicker/DatePicker/DatePicker";
export { DateTimePicker } from "./components/DateTimePicker/DateTimePicker/DateTimePicker";
export { Disclosure } from "./components/Disclosure/Disclosure";
这意味着webpack不会捆绑您无意导出的内容。要测试您是否捆绑了作品,请尝试从捆绑中导入具有require语法的内容,以避开打字稿类型,并在tsconfig中将allowJS设置为true。
类似 const Button = require(“ ../ path / to / js / bundle”)。Button console.log(Button);
答案 2 :(得分:0)
我发现create-react-library
很有帮助