チーム用のパブリックスタイルのnpmライブラリを構築する方法

1.背景

現在、インターネット企業はフロントエンドチームによって複数のプロジェクトを維持していることが多く、これらの複数のプロジェクトにはいくつかの重複するスタイルや共通の基本機能があることがよくあります。現時点では、チームの内部保守のために関連するパブリックコンポーネントnpmパッケージを開発する必要があります。 。一般に、2つのパブリックコンポーネントが維持されます。1つはパブリックスタイルの沈殿用で、もう1つは機能機能(アップロード、ハンガリー語のハンプ変換など)の沈殿用です。比較的完全なパブリックコンポーネントライブラリはエンジニアリングに沿ったものであり、次の点を満たす必要があると思います。
(1)最新のフロントエンド開発(typescript、sass)のニーズを満たす
(2)コード仕様機能(eslint)を備えている
(3 )自動化テスト機能(jest)
(4)開発環境でUI機能を備えているため、開発者はnpmリリース前にUIステータスを簡単に表示できます(ストーリーブック)(5)完全なコミットアクセス制御とスクリプトアクセス制御(commitlint、husky)
(6)自動ログ機能、自動バージョン管理(標準バージョン)付き
(7)非常に便利なバージョンリリース

以下は、上記の要件を満たすnpmスタイルのライブラリを構築する方法の完全なプロセスです。もちろん、それが公立の能力ライブラリーである場合、sass、ストーリーブックなどのすべてのステップを導入する必要はないかもしれません。

2.開発関連の建設

1.プロジェクトを初期化します

npm init
复制代码

2.React関連のパッケージをインストールします

yarn add react react-dom
yarn add @types/react --dev
复制代码

3.typescriptをインストールします

yarn add typescript --dev

tsc --init
复制代码

ここで、tsconfig.jsonは、tsの構成ファイルであるルートディレクトリに生成されます。jsxの設定項目をreact-jsxに変更します

{
    ...
    "jsx": "react-jsx", 
    ...
}
复制代码

4.eslintをインストールします

yarn add eslint --dev

eslint --init
复制代码

対応する構成を選択すると、ルートディレクトリにeslint構成ファイル.eslintrc.jsが生成されます。そして、package.jsonファイルにlintコマンドを追加します。

scripts: {
    ...
    "lint": "eslint --ext .tsx,.ts,.js src --cache --fix",
    ...
}
复制代码

図に示すように、スクリプトコマンドyarnlintを実行した後image.png

5.コードディレクトリを作成します

--
  ...
  --src
    --components
      --MyFirstComponent
        index.tsx
    --index.ts
  tsconfig.json
  .eslintrc.js
  ...
复制代码

各コンポーネントは、コンポーネント、MyFirstComponent/index.tsxコードの下にあります。

import React from 'react';
function FirstComponent() {

  return (
    <div >
      这是第一个组件
    </div>
  );
}
export default FirstComponent;
复制代码

エントリファイルindex.tsを作成します

export { default as FirstComponent } from './components/FirstComponent';
复制代码

6,引入测试组件ts-jest以及相关依赖包

yarn add --dev jest ts-jest @types/jest @testing-library/react
复制代码

根目录创建jest配置文件jest.config.js,这里指定了匹配*.test.tsx文件。

module.exports = {
    preset: 'ts-jest',
    testEnvironment: 'jsdom',
    testMatch: [
        '**/*.test.tsx',
    ],
};
复制代码

添加在package.json中添加jest脚本命令

"scripts": {
  ...
  "test": "npx jest",
  ...
}
复制代码

在组件目录下添加相应的测试脚本文件,FirstComponent.test.tsx

  --src
    --components
      --MyFirstComponent
        + FirstComponent.test.tsx
        index.tsx
    --index.ts
复制代码

其中内容就jest的脚本执行文件

import React from 'react';
import { render } from '@testing-library/react';
import FirstComponent from './index';
    
test('rende my test', () => {
  render(<FirstComponent />);
});
复制代码

执行yarn test如图

image.png

7,安装storybook

storybook可以更加方便的让我们本地就可以看到组件的样式以及真实使用情况,这里需要根据自己的需求选择相应的配置项目

npx sb init 
复制代码

执行完成之后会在根目录下生成.storybook文件夹,以及在src目录下生成stories文件夹。.storybook目录下为storybook的配置文件。src下的stories文件夹直接删除。

--
  --.storybook
     main.js
     preview.js
  --src
  ...
复制代码

并在会在package.json自动生成相应的脚本命令。

"scripts": {
  "test": "npx jest",
  "lint": "eslint --ext .tsx,.ts,.js src --cache --fix",
  "storybook": "start-storybook -p 6006",
  "build-storybook": "build-storybook",
},
复制代码

在相应的组件目录下添加.stories文件,./src/components/FirstComponent/FirstComponent.stories.tsx

  --src
    --components
      --MyFirstComponent
        FirstComponent.test.tsx
        + FirstComponent.stoires.tsx
        index.tsx
    --index.ts
复制代码
import React from 'react';
import FirstComponent from './index';

export default {
  title: 'FirstComponent',
  component: FirstComponent,
};

export function FirstComponentStories() {
  return <FirstComponent />;
}
复制代码

执行yarn storybook启动storybook就可以看到结果,如图,左边是组件名称,右边是组件的渲染结果。

image.png

8,引入sass,以及所需组件

完成上述步骤,基本能力就差不多了,这时候引入css相关配置。

yarn add node-sass --dev
yarn add classnames
复制代码

在src目录下创建styles的相关文件_varibales.scss,index.scss

--src
  --styles
    _variables.scss
    index.scss  
复制代码

相关变量配置文件_variables.scss,这里使用类名的前缀的方式来将当前组件中的css隔离出来,一般的组件库都是采取了这种方式,如ant-design。其实更好的方法是cssModules,但是在打包时会产生一些问题,这里不展开赘述了。

$css-prefix: 'cru'
复制代码

在相应组件中添加style.scss样式文件

  --src
    --components
      --MyFirstComponent
        FirstComponent.test.tsx
        FirstComponent.stoires.tsx
        + styles.scss
        index.tsx
    --index.ts
复制代码
$first-component-prefix: 'first-component';

.#{$css-prefix} {
  &-#{$first-component-prefix} {
    &-red{
      color: red;
    }
  }
}
复制代码

创建样式入口文件,index.scss,并引入所有scss文件。

@import "variables";
@import './src/components/FirstComponent/style';
复制代码

创建公共前缀获取js代码src/utils,前缀和scss保持一致。

const cssPrefix = 'cru';
const getCssPrefix = (suffixCls: string) => `${cssPrefix}-${suffixCls}`;

export default getCssPrefix;
复制代码

在相应的组件中引入样式,修改./src/components/FirstComponent/index.tsx文件

import React from 'react';
import classNames from 'classnames';
import getCssPrefix from '../../utils';

function FirstComponent() {
  const cssPrefix = getCssPrefix('first-component');
  const wrapperClass = classNames(
    `${cssPrefix}-red`,
    `${cssPrefix}-font-size`,

  );
  return (
    <div className={wrapperClass}>
      这是第一个组件啊
    </div>
  );
}

export default FirstComponent;
复制代码

在storybook全局中引入入口样式文件,修改.storybook/preview.js。

import '../src/styles/index.scss'
export const parameters = {
  actions: { argTypesRegex: "^on[A-Z].*" },
  controls: {
    matchers: {
      color: /(background|color)$/i,
      date: /Date$/,
    },
  },
}
复制代码

这时候启动storybook是会报错的,原因是storybook内部引入webpack,并启动了一个devserver,这时候还无法识别scss文件,所以需要引入相关的loader。这里最好按照如下的版本,因为storybook中的webpack版本问题,无法识别较高版本的loader,所以自动安装的版本会报错。

yarn add [email protected]  [email protected] [email protected] --dev
复制代码

安装loader后,我们还需要让storybook引入loader配置项目,storybook为我们留了一个入口,这里修改main.js,添加webpackFinal这一字段。

const path = require('path')
module.exports = {
  "stories": [
    "../src/**/*.stories.mdx",
    "../src/**/*.stories.@(js|jsx|ts|tsx)"
  ],
  "addons": [
    "@storybook/addon-links",
    "@storybook/addon-essentials",
    "@storybook/addon-interactions"
  ],
  "framework": "@storybook/react",
  "webpackFinal": async (config) => {
    // `configType` has a value of 'DEVELOPMENT' or 'PRODUCTION'
    // You can change the configuration based on that.
    // 'PRODUCTION' is used when building the static version of storybook.

    // Make whatever fine-grained changes you need
    config.module.rules.push({
      test: /.scss$/,
      use: ['style-loader', 'css-loader', 'sass-loader'],
      include: path.resolve(__dirname, '../'),
    });

    // Return the altered config
    return config;
  }
}
复制代码

这之后启动storybook,如图,发现样式已经变了,说明已经成功。

image.png

三,代码打包相关能力搭建

1,打包ts文件

在根目录下配置,config/tsconfig.build.json文件,配置*.test和*.stoires文件,输出

{
  "compilerOptions": {
    "outDir": "../dist",
    "module": "esnext",
    "target": "es5",
    "declaration": true,
    "jsx": "react",
    "moduleResolution":"Node",
    "allowSyntheticDefaultImports": true
  },
  "include": [
    "../src"
  ],
  "exclude": [
    "../src/**/*.test.tsx",
    "../src/**/*.stories.tsx"
  ]
}
复制代码

编写打包ts文件脚本命令,在package.json文件中添加

scripts: {
  ...
  "build-ts": "tsc -p ./config/tsconfig.build.json",
  ...
}
复制代码

2,打包css文件

创建脚本命令build-css,使用node-sass帮忙打包sass文件

scripts: {
  ...
  "build-css": "node-sass ./src/styles/index.scss ./dist/index.css",
  ...
}
复制代码

3,创建打包总命令

安装删除组件组件,让我们每次打包的时候可以自动删除dist文件夹

yarn add rimraf --dev
复制代码

创建删除文件命令

scripts: {
  ...
  "clean": "rimraf ./dist",
  ...
}
复制代码

4,创建打包总命令

"scripts": {
  "test": "npx jest",
  "lint": "eslint --ext .tsx,.ts,.js src --cache --fix",
  "storybook": "start-storybook -p 6006",
  "build-storybook": "build-storybook",
  "build-css": "node-sass ./src/styles/index.scss ./dist/index.css",
  "build-ts": "tsc -p ./config/tsconfig.build.json",
  "clean": "rimraf ./dist",
  "build": "yarn clean && yarn build-ts && yarn build-css",
},
复制代码

执行yarn build,可以看到根目录下创建dist文件,其中内容就是打包后的内容。

image.png

四,代码门禁commitlint

代码相关代码门禁,将commit不符合要求的,以及未通过测试和编码规范的代码进行拦截,安装相关依赖。这里的husky使用4.2.5版本,原因是新版本的husky入口配置所有变更,有兴趣的同学可以自行研究并更新版本。

yarn add @commitlint/cli @commitlint/config-conventional [email protected] --dev
复制代码

在根目录添加commitlint.config.js相关文件,

module.exports = {
    extends: ['@commitlint/config-conventional'],
    rules: {
    },
};
复制代码

在package.json中添加一个新的字段husky

"husky": {
    "hooks": {
      "commit-msg": "commitlint -E HUSKY_GIT_PARAMS",
      "pre-commit": "npm run lint && npm run test"
    }
}
复制代码

这时候,当我们发起commit的时候,commit msg需要符合commitlint规范(feat: a new feat或fix: bug fix等等,具体配置可以参考相关文档)且需要通过lint和test命令。 当我们eslint未通过并发起commit时,如图,此时commit发起失败

image.png

当我们的commitlint不符合规范时

image.png

五,自动会发布流程

我们希望当我们更新代码并合入到master后,一行命令就帮助我们完成日志的生成以及版本的管理,并最终在npm上发布新的包。流程如下

Untitled Diagram.jpg

1,安装standard-version

standard-version可以根据我们的之前的commit内容自动生成日志,并修改package.json中的版本号,之后再发起一个commit命令

yarn add standard-version --dev
复制代码

当我们发起feat:xx的commit的时候,版本会更新一个大版本,1.0.0 -> 1.1.0。而当我们发起一个fix:xx的commit的时候,会更新一个小版本,从1.0.0 -> 1.0.1。添加脚本命令。

scripts: {
   ...
   update-log-and-version: "standard-version",
   ...
}
复制代码

执行yarn update-log-and-version,会在根目录下自动生成CHANGELOG.md文件,并且更新package中的version版本。

image.png 并已经发起了commit

image.png

2,发布版本

指定发布的代码,在package.json中添加新的files字段。指定发布dist之下也就是打包后的文件,并不需要发布相关源码。

...
"files": [
  "dist"
],
...
复制代码

修改package.json中的main.js字段,让使用的时候直接指向dist文件下的index.js

...
"main": "dist/index.js",
...
复制代码

在上述基础上我们只需要push代码并发布即可,添加相关脚本命令

scripts: {
  ...
  "update-npm-and-git": "git push --follow-tags origin master && npm publish",
  "release": "yarn build && standard-version && yarn update-npm-and-git"
  ...
}
复制代码

这时候我们执行yarn release就会完成发布的全流程。完成的scripts脚本如下。

"scripts": {
  "test": "npx jest",
  "lint": "eslint --ext .tsx,.ts,.js src --cache --fix",
  "storybook": "start-storybook -p 6006",
  "build-storybook": "build-storybook",
  "build-css": "node-sass ./src/styles/index.scss ./dist/index.css",
  "build-ts": "tsc -p ./config/tsconfig.build.json",
  "clean": "rimraf ./dist",
  "build": "yarn clean && yarn build-ts && yarn build-css",
  "publish": "npm publish  public",
  "update-npm-and-git": "git push --follow-tags origin master && npm publish",
  "release": "yarn build && standard-version && yarn update-npm-and-git"
},
复制代码

六,开发人员所需要做的

开发人员只需要编写相关代码,并合入master,由版本管理员更新最新的master代码,并执行yarn release即可。

七,如何使用

和使用大部分公共样式组件一样,直接安装后,引入样式文件以及相应组件即可

yarn add common_react_utils
复制代码

image.png

おすすめ

転載: juejin.im/post/7084624678873989133