如何正确构建 React 模块化库
How to propperly build react modular library
我正在尝试创建一个基于 Typescript 和 SASS 的 React 组件库。组件库将在多个其他 TypeScript 项目中使用,因此也需要类型导出。理想情况下,我想模仿类似“Material-UI”/“React-Bootrap”库 dist 输出解决方案。
示例项目结构:
|Tabs
+--Tabs.tsx
+--Tabs.scss
+--index.tsx
index.tsx
index.tsx
export { Tabs } from './Tabs/Tabs';
Tabs/index.tsx
import React from 'react';
import './Tabs.scss';
interface TabsProps {
...
}
export const Tabs: React.FC<TabsProps> = (props) => <div>...</div>
Tabs/index.tsx
export { Tabs } from './Tabs';
预期构建的 dist 结构应模仿 src 结构:
|Tabs
+--Tabs.js
+--Tabs.d.ts
+--index.js
+--index.d.ts
index.js
index.tsx
我尝试分析开源项目并了解它们是如何构建库的,但是我找不到使用我可以重复使用的相同方法的库。
我尝试过的解决方案:
Webpack:虽然我可以编译 typescript 和 sass 文件,但 webpack 总是只发出输出部分指定的一个文件,通常会被捆绑,我将失去从特定组件模块导入单个组件的能力。我知道我可以指定多个入口点,但该项目将有很多出口,手动指定它们不是一个选项...
我试过的示例配置:
const path = require('path');
const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin');
module.exports = {
entry: './src/index.tsx',
module: {
rules: [
// sass-loader is not used here yet, but should be once desired structure can be reached
{
test: /\.tsx?$/,
loader: 'babel-loader',
},
// All output '.js' files will have any sourcemaps re-processed by 'source-map-loader'.
{ test: /\.js$/, loader: "source-map-loader" }
]
},
// Enable sourcemaps for debugging webpack's output.
devtool: "source-map",
resolve: {
extensions: [".tsx", ".ts", ".js"],
plugins: [
new TsconfigPathsPlugin({ configFile: "./tsconfig.build.json" })
]
},
output: {
filename: '[name].js',
path: path.resolve(__dirname, 'dist')
}
};
Rollup:与webpack类似的情况
我试过的示例配置:
// rollup.config.js
import babel from 'rollup-plugin-babel';
import sass from 'rollup-plugin-sass';
import nodeResolve from 'rollup-plugin-node-resolve';
import commonjs from 'rollup-plugin-commonjs';
import react from 'react';
import reactDom from 'react-dom';
const babelOptions = {
exclude: /node_modules/,
// We are using @babel/plugin-transform-runtime
runtimeHelpers: true,
extensions: ['.js', '.ts', '.tsx'],
configFile: './babel.config.js',
};
const nodeOptions = {
extensions: ['.js', '.tsx', '.ts'],
};
const commonjsOptions = {
ignoreGlobal: true,
include: /node_modules/,
namedExports: {
react: Object.keys(react),
'react-dom': Object.keys(reactDom)
},
};
export default {
input: 'src/index.tsx',
output: {
name: '[name].js',
dir: 'dist',
format: 'umd',
sourcemap: true,
},
plugins: [
nodeResolve(nodeOptions),
sass(),
commonjs(commonjsOptions),
babel(babelOptions)
],
};
Babel:我设法编译了打字稿代码,但是一旦我接近转译 SASS 文件,我最终会建议使用 webpack。 .
TSC:我成功地 运行 打字稿编译器,它可以毫无问题地编译所有文件,并保持相同的结构。然而,TSC 不支持其他转译选项,所以经过大量搜索后,我最终会得到使用 webpack 和“ts-loader”或“babel-loader”的建议。.
tsconfig:
{
"extends": "../../tsconfig.build.json",
"compilerOptions": {
"lib": [ "es2015", "dom" ],
"outDir": "dist",
"baseUrl": ".",
"declaration": true,
"composite": true,
"module": "commonjs",
"target": "es5"
},
"include": [
"src/**/*"
],
"exclude": [
"node_modules",
"dist"
]
}
所需的解决方案:
在编译库并将其安装在另一个项目中后,我应该能够 运行 以下内容:
import { Tabs } from 'my-lib/Tabs';
import { Tabs } from 'my-lib';
经过大量尝试,我设法通过 rollup 产生了想要的结果。当前配置的唯一缺点是它不支持 --watch 模式下新添加的文件。魔法设置在output.preserveModules
下
配置:
// rollup.config.js
import commonjs from '@rollup/plugin-commonjs';
import typescript from '@rollup/plugin-typescript';
import postcss from 'rollup-plugin-postcss';
import postcssUrl from 'postcss-url';
import resolve from "@rollup/plugin-node-resolve";
import peerDepsExternal from "rollup-plugin-peer-deps-external";
export default {
input: 'src/index.tsx',
output: {
dir: 'dist',
format: 'es',
preserveModules: true,
sourcemap: true,
},
plugins: [
resolve(),
peerDepsExternal(),
commonjs(),
typescript({
tsconfig: 'tsconfig.build.json'
}),
postcss({
minimize: true,
modules: {
generateScopedName: "[hash:base64:5]"
},
plugins: [
postcssUrl({
url: "inline"
})
]
}),
],
};
希望这个配置对其他人也有帮助
您可以查看此存储库。我为创建一个库做了一些更改ui。
https://github.com/21paradox/react-webpack-typescript-starter
要使用如下所示的库:
import Input from 'my-custom-ui/entry/Input';
import { Input } from 'my-custom-ui';
找了很多,最终写了一个插件来手动生成webpack需要的webpack入口代码(用于building一个ui库)
多条目 + 手动生成的条目文件似乎适用于 单独的组件 & 无冗余代码。如果您想构建一个基于 vue 的库,这也非常有用。
我正在尝试创建一个基于 Typescript 和 SASS 的 React 组件库。组件库将在多个其他 TypeScript 项目中使用,因此也需要类型导出。理想情况下,我想模仿类似“Material-UI”/“React-Bootrap”库 dist 输出解决方案。
示例项目结构:
|Tabs
+--Tabs.tsx
+--Tabs.scss
+--index.tsx
index.tsx
index.tsx
export { Tabs } from './Tabs/Tabs';
Tabs/index.tsx
import React from 'react';
import './Tabs.scss';
interface TabsProps {
...
}
export const Tabs: React.FC<TabsProps> = (props) => <div>...</div>
Tabs/index.tsx
export { Tabs } from './Tabs';
预期构建的 dist 结构应模仿 src 结构:
|Tabs
+--Tabs.js
+--Tabs.d.ts
+--index.js
+--index.d.ts
index.js
index.tsx
我尝试分析开源项目并了解它们是如何构建库的,但是我找不到使用我可以重复使用的相同方法的库。
我尝试过的解决方案:
Webpack:虽然我可以编译 typescript 和 sass 文件,但 webpack 总是只发出输出部分指定的一个文件,通常会被捆绑,我将失去从特定组件模块导入单个组件的能力。我知道我可以指定多个入口点,但该项目将有很多出口,手动指定它们不是一个选项...
我试过的示例配置:
const path = require('path');
const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin');
module.exports = {
entry: './src/index.tsx',
module: {
rules: [
// sass-loader is not used here yet, but should be once desired structure can be reached
{
test: /\.tsx?$/,
loader: 'babel-loader',
},
// All output '.js' files will have any sourcemaps re-processed by 'source-map-loader'.
{ test: /\.js$/, loader: "source-map-loader" }
]
},
// Enable sourcemaps for debugging webpack's output.
devtool: "source-map",
resolve: {
extensions: [".tsx", ".ts", ".js"],
plugins: [
new TsconfigPathsPlugin({ configFile: "./tsconfig.build.json" })
]
},
output: {
filename: '[name].js',
path: path.resolve(__dirname, 'dist')
}
};
Rollup:与webpack类似的情况
我试过的示例配置:
// rollup.config.js
import babel from 'rollup-plugin-babel';
import sass from 'rollup-plugin-sass';
import nodeResolve from 'rollup-plugin-node-resolve';
import commonjs from 'rollup-plugin-commonjs';
import react from 'react';
import reactDom from 'react-dom';
const babelOptions = {
exclude: /node_modules/,
// We are using @babel/plugin-transform-runtime
runtimeHelpers: true,
extensions: ['.js', '.ts', '.tsx'],
configFile: './babel.config.js',
};
const nodeOptions = {
extensions: ['.js', '.tsx', '.ts'],
};
const commonjsOptions = {
ignoreGlobal: true,
include: /node_modules/,
namedExports: {
react: Object.keys(react),
'react-dom': Object.keys(reactDom)
},
};
export default {
input: 'src/index.tsx',
output: {
name: '[name].js',
dir: 'dist',
format: 'umd',
sourcemap: true,
},
plugins: [
nodeResolve(nodeOptions),
sass(),
commonjs(commonjsOptions),
babel(babelOptions)
],
};
Babel:我设法编译了打字稿代码,但是一旦我接近转译 SASS 文件,我最终会建议使用 webpack。 .
TSC:我成功地 运行 打字稿编译器,它可以毫无问题地编译所有文件,并保持相同的结构。然而,TSC 不支持其他转译选项,所以经过大量搜索后,我最终会得到使用 webpack 和“ts-loader”或“babel-loader”的建议。.
tsconfig:
{
"extends": "../../tsconfig.build.json",
"compilerOptions": {
"lib": [ "es2015", "dom" ],
"outDir": "dist",
"baseUrl": ".",
"declaration": true,
"composite": true,
"module": "commonjs",
"target": "es5"
},
"include": [
"src/**/*"
],
"exclude": [
"node_modules",
"dist"
]
}
所需的解决方案: 在编译库并将其安装在另一个项目中后,我应该能够 运行 以下内容:
import { Tabs } from 'my-lib/Tabs';
import { Tabs } from 'my-lib';
经过大量尝试,我设法通过 rollup 产生了想要的结果。当前配置的唯一缺点是它不支持 --watch 模式下新添加的文件。魔法设置在output.preserveModules
下配置:
// rollup.config.js
import commonjs from '@rollup/plugin-commonjs';
import typescript from '@rollup/plugin-typescript';
import postcss from 'rollup-plugin-postcss';
import postcssUrl from 'postcss-url';
import resolve from "@rollup/plugin-node-resolve";
import peerDepsExternal from "rollup-plugin-peer-deps-external";
export default {
input: 'src/index.tsx',
output: {
dir: 'dist',
format: 'es',
preserveModules: true,
sourcemap: true,
},
plugins: [
resolve(),
peerDepsExternal(),
commonjs(),
typescript({
tsconfig: 'tsconfig.build.json'
}),
postcss({
minimize: true,
modules: {
generateScopedName: "[hash:base64:5]"
},
plugins: [
postcssUrl({
url: "inline"
})
]
}),
],
};
希望这个配置对其他人也有帮助
您可以查看此存储库。我为创建一个库做了一些更改ui。
https://github.com/21paradox/react-webpack-typescript-starter
要使用如下所示的库:
import Input from 'my-custom-ui/entry/Input';
import { Input } from 'my-custom-ui';
找了很多,最终写了一个插件来手动生成webpack需要的webpack入口代码(用于building一个ui库)
多条目 + 手动生成的条目文件似乎适用于 单独的组件 & 无冗余代码。如果您想构建一个基于 vue 的库,这也非常有用。