Javascript 如何恰当地构建模块化图书馆

Javascript 如何恰当地构建模块化图书馆,javascript,reactjs,typescript,webpack,build,Javascript,Reactjs,Typescript,Webpack,Build,我正在尝试创建一个基于Typescript和SASS的react组件库。组件库将用于多个其他typescript项目,因此也需要类型导出。理想情况下,我希望模拟“Material UI”/“React Bootrap”库dist输出解决方案 项目结构示例: |Tabs +--Tabs.tsx +--Tabs.scss +--index.tsx index.tsx |Tabs +--Tabs.js +--Tabs.d.ts +--index.js +--index.d.ts index.js

我正在尝试创建一个基于Typescript和SASS的react组件库。组件库将用于多个其他typescript项目,因此也需要类型导出。理想情况下,我希望模拟“Material UI”/“React Bootrap”库dist输出解决方案

项目结构示例:

|Tabs
+--Tabs.tsx
+--Tabs.scss 
+--index.tsx
index.tsx
|Tabs
+--Tabs.js
+--Tabs.d.ts
+--index.js
+--index.d.ts
index.js
index.tsx
index.tsx

export { Tabs } from './Tabs/Tabs';
import React from 'react';
import './Tabs.scss';

interface TabsProps {
    ...
}

export const Tabs: React.FC<TabsProps> = (props) => <div>...</div>
export { Tabs } from './Tabs';
选项卡/索引.tsx

export { Tabs } from './Tabs/Tabs';
import React from 'react';
import './Tabs.scss';

interface TabsProps {
    ...
}

export const Tabs: React.FC<TabsProps> = (props) => <div>...</div>
export { Tabs } from './Tabs';
预期建成的dist结构应模仿src结构:

|Tabs
+--Tabs.tsx
+--Tabs.scss 
+--index.tsx
index.tsx
|Tabs
+--Tabs.js
+--Tabs.d.ts
+--index.js
+--index.d.ts
index.js
index.tsx
我试着分析开源项目,看看它们是如何构建库的,但是我找不到使用相同的方法可以重用的库

我尝试过的解决方案:

网页包:虽然我可以编译typescript和sass文件,但网页包始终只会发出输出部分中指定的一个文件,这通常是捆绑的,我将失去从特定组件模块导入单个组件的能力。我知道我可以指定多个入口点,但该项目将有很多导出,手动指定它们不是一个选项

我尝试过的配置示例:

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')
    }
};
汇总:与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:我成功地编译了typescript代码,但是一旦我接近传输SASS文件,我就会建议使用webpack来完成这项工作

TSC:我成功地运行了typescript编译器,它可以毫无问题地编译所有文件,并保持相同的结构。然而,TSC不支持其他传输选项,所以在进行了大量搜索之后,我最终会建议使用webpack和“ts加载器”或“babel加载器”

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模式下新添加的文件。魔法设置在输出下。保存模块

配置:

// 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"
                })
            ]
        }),

    ],
};

我希望此配置也能帮助其他人

您可以签出此回购协议。我对构建库做了一些更改

要使用如下所示的库:

import Input from 'my-custom-ui/entry/Input';
import { Input } from 'my-custom-ui';
在进行了大量搜索之后,我最终编写了一个插件来手动生成webpack所需的webpack条目代码(用于构建ui库)


多重输入+手动生成的输入文件似乎适用于单独的组件无冗余代码。如果你想建立一个基于vue的图书馆,这也很有帮助。

我不能真正指导你,但我知道这让你感到沮丧。请尝试签出,这是大型NPM软件包经常使用的。@IgorBykov,谢谢,我会尝试一下,让您不断更新!