一步步写一个react组件库并打包发布到npm

1,573 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第5天,点击查看活动详情

1 初始化项目

  • 使用脚手架创建react项目:npx create-react-app wison-uilib
  • 简化目录,运行yarn eject暴露webpack配置文件
    • 简化目录结构,修改index.js如下图,运行yarn start启动项目
//简化后的index.js
import React from "react";
import ReactDOM from "react-dom/client";
import "./index.less";
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<div>test</div>);

image.png

  • 添加less支持 修改config目录下的webpack.config.js
...
const sassRegex = /\.(scss|sass)$/;
const sassModuleRegex = /\.module\.(scss|sass)$/;
//搜索上面sassModuleRegex关键字并在后面新增以下两行
const lessRegex = /\.less$/; 
const lessModuleRegex = /\.module\.less$/;
...

然后在module对象的rules属性下新增下面两条格则

{
    test: lessRegex,
    exclude: lessModuleRegex,
    use: getStyleLoaders(
      {
        importLoaders: 3,
        sourceMap: isEnvProduction
          ? shouldUseSourceMap
          : isEnvDevelopment,
      },
      "less-loader"
    ),
    sideEffects: true,
  },
  {
    test: lessModuleRegex,
    use: getStyleLoaders(
      {
        importLoaders: 3,
        sourceMap: isEnvProduction
          ? shouldUseSourceMap
          : isEnvDevelopment,
        modules: {
          getLocalIdent: getCSSModuleLocalIdent,
        },
      },
      "less-loader"
    ),
  }
  • 关闭shouldUseSourceMap
// const shouldUseSourceMap = process.env.GENERATE_SOURCEMAP !== 'false';注释这行,新增下行
const shouldUseSourceMap = false;
  • 配置别名(也可以跳过不配置,看个人喜好) 找到resolve对象下的alias属性,新增下行
"@": path.resolve(__dirname, "../src")

2 开始编写组件

  • 在componetns目录下新增Loading文件夹,写入代码,并修改index.js重新启动项目 image.png
//components/Button/index.jsx
import React from "react";
import "./index.less";
export default function Loading() {
  return (
    <div className="loading-wrapper">
      <svg width="100" height="100">
        <g>
          <text x="50" y="55">
            loading···
          </text>
          <circle cx="50" cy="50" r="40" />
        </g>
      </svg>
    </div>
  );
}
//components/Button/index.less
.loading-wrapper {
  g {
    text {
      font-size: 14px;
      text-anchor: middle;
      fill: #418bfd;
    }
    circle {
      fill: none;
      stroke-width: 5px;
      stroke: #418bfd;
      stroke-dasharray: 300;
      stroke-dashoffset: 300;
      animation: svg-loading-rolling 1.5s linear infinite;
    }
  }
  @keyframes svg-loading-rolling {
    from {
      stroke-dasharray: 600;
      stroke-dashoffset: 600;
      transform: rotate(0);
      transform-origin: 50px 50px;
    }
    to {
      stroke-dashoffset: 0;
      transform: rotate(720deg);
      transform-origin: 50px 50px;
      opacity: 0.1;
    }
  }
}
//index.js
import React from "react";
import ReactDOM from "react-dom/client";
import "./index.less";
import Loading from "@/components/Loading";
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<Loading />);

3 打包发布npm

  • 在根目录下新建dist文件夹用来存放npm包文件
  • cd dist 进入dist目录执行npm init
    • 根据提示完成配置
      image.png
    • 往其中添加peerDependencies配置,设置组件库的核心依赖
  "peerDependencies": {
    "react": ">=16.8.0",
    "react-dom": ">=16.8.0"
  },

image.png

  • 运行yarn build,发现脚手架默认配置产物加上了哈希值,但是我们需要固定一个index.js文件名 image.png
  • 我们修改下webpack配置自定下我们想要的产物文件名,并把文件输出到dist文件夹下的lib目录下 1)修改output下的path属性设置输出目录
// path: paths.appBuild,
path: path.join(__dirname, "../dist"),

2)在output下新增libraryTarget属性指明模块系统的兼容性

output: {
   ...
   libraryTarget: 'umd',//该方案支持commonjs、commonjs2、amd,可以在浏览器、node中通用。
   ...
   }

3)找到output对象的filename属性,修改如下

filename: isEnvProduction
// ? 'static/js/[name].[contenthash:8].js' 修改这一行为'lib/index.js'
? 'lib/index.js'

4)继续修改css产物文件名

new MiniCssExtractPlugin({
// filename: 'static/css/[name].[contenthash:8].css',修改这一行为下面的'lib/index.css'
filename: 'lib/index.css',
chunkFilename: 'static/css/[name].[contenthash:8].chunk.css',
}),

5)关闭index.html,asset-manifest.json及LICENSE.txt文件的输出 在plugins数组下注释掉WebpackManifestPlugin插件 image.png 在plugins数组下修改HtmlWebpackPlugin使其仅在开发环境下输出index.html

image.png 在new TerserPlugin最后新增下面两行关闭LICENSE.txt文件输出

parallel: true,            //此处为新增配置
extractComments: false,    //此处为新增配置

image.png

  • 修改index.js入口文件后重新打包
//index.js
export { default as Loading } from "./components/Loading"; //这是下面两行的简写
// import {default as Loading} from './components/Loading'
// export Loading

image.png

  • 注册npm账号注册入口
  • 如果设置了其他npm镜像源的务必要换回官方源
  • 登录 npm login 按提示操作 image.png
  • npm publish 发布(注意要在dist目录下) image.png
  • 如果发布错误可执行npm unpublish 包名@版本号 删除该版本 image.png
  • 但注意执行了删除操作后同名的包只能在删除命令执行完24小时后才能再publish(如果不想等24小时再发布可换个包名发布) image.png image.png

4 在其他项目中使用发布后的包

  • yarn add weison-react-uilib
import React from "react";
import ReactDOM from "react-dom";
import {Loading} from 'weison-react-uilib'
import 'weison-react-uilib/lib/index.css'
ReactDOM.render(<Loading />, document.getElementById("root"));

image.png

5 组件库文档docz的使用

待更新

6 单元测试

待更新

7 按需加载

待更新

最后

github链接