手摸手,打造屬於本身的 React 組件庫01 — 基礎篇

第一部分 - 基礎篇:從 0 到 1,還原一個後臺項目

原文連接javascript

引言

2020年,做爲一名普通前端打字員,我平時工做的主要目標仍是使用 React 構建應用程序。去年一直想創建一個屬於本身的 NPM 庫,用於沉澱本身的業務組件、Hooks,可是因爲不少概念都不是很瞭解的緣故,又感受這個目標有點高不可攀。css

可是其實只要明白一些原理和細節以後,構建本身的 NPM 庫實際上是一件很簡單的事情。不只能夠拓寬視野,還能夠將本身在多個項目中反覆使用的某些相同的組件編譯到一個組件庫中,推廣給其餘小夥伴使用,貢獻開源,豈不美哉。前端

教程部分

本篇文章,是這個系列的第一篇:基於 React 和 Antd,從 0 到 1,還原一個後臺項目java

  • 第一部分:從 0 到 1,還原一個後臺項目
  • 第二部分:單元測試
  • 第三部分:項目打包,併發布至 NPM

技術棧

讓咱們看看在 2020 年,一個普通的後臺項目,須要的技術棧有哪些:node

  • React:最流行的 UI 層 JavaScript 庫
  • Antd:西湖區最流行的 UI 設計語言
  • Create React App:官方 Cli 腳手架
  • React-Router:處理路由
  • TypeScript:9012 年成長最快的前端編程語言,提供了類型系統對 ES6 的支持
  • eslint & prettier & husky:整合代碼規範,統一編碼風格。
  • less:參考 Antd 文檔,配合 react-app-rewired 等庫讓咱們的構建工具支持 less。

項目準備

具體實現,能夠參考這個:Demo 項目react

預覽地址:https://jokingzhang.github.io...git

使用 React + TypeScript 開始項目

此處首先肯定下,咱們已經安裝了 npm 模塊,沒有安裝的童鞋能夠去 Node 官網 下載一個安裝包安裝一下,而後你就有 npm 了😑。es6

執行下面的命令,初始化項目:github

sudo npm i -g npx
npx create-react-app my-app --template typescript
cd my-app
npm install --save typescript @types/node @types/react @types/react-dom @types/jest
npm start

這個時候,應該能夠看到一個經典的初始化頁面了~typescript

安裝 Antd

npm install antd --save

安裝 React Router

npm install --save react-router-dom @types/react-router-dom

使用 eslint & prettier & husky 整合代碼規範,統一編碼風格

安裝依賴
npm install -D eslint eslint-config-prettier eslint-config-react-app eslint-plugin-flowtype eslint-plugin-import eslint-plugin-jsx-a11y eslint-plugin-prettier eslint-plugin-react eslint-plugin-react-hooks lint-staged prettier husky

依賴安裝好以後,就能夠爲項目增長一些配置文件了

tsconfig.json

tsconfig.json 文件中指定了用來編譯這個項目的根文件和編譯選項。這是當前項目所用到的配置文件:

{
  "compilerOptions": {
    "target": "es5",
    "lib": [
      "es6",
      "dom"
    ],
    "downlevelIteration": true,
    "allowJs": true,
    "skipLibCheck": true,
    "esModuleInterop": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "module": "esnext",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "jsx": "preserve",
    "sourceMap": true,
    "baseUrl": "./src",
    "allowSyntheticDefaultImports": true,
    "moduleResolution": "node"
  },
  "exclude": [
    "node_modules"
  ],
  "include": [
    "src"
  ]
}
.eslintrc

.eslintrc 文件中,容許你指定你想要支持的 JavaScript 語言選項。這是當前項目所用到的配置文件:

{
    "extends": "react-app",
    "plugins": ["prettier"],
    "rules": {
      "prettier/prettier": "error",
      "no-unused-vars": "off",
      "@typescript-eslint/no-unused-vars": ["error", {
        "vars": "all",
        "args": "after-used",
        "ignoreRestSiblings": false
      }]
    }
}
.eslintignore

你能夠經過在項目根目錄建立一個 .eslintignore 文件告訴 ESLint 去忽略特定的文件和目錄。.eslintignore 文件是一個純文本文件,其中的每一行都是一個 glob 模式代表哪些路徑應該忽略檢測。

node_modules/*
.prettierrc.js

prettierrc 的配置文件,打造適合大家團隊的代碼配置

module.exports = {
  singleQuote: true,
  trailingComma: 'all',
  printWidth: 100,
  proseWrap: 'never',
  overrides: [
    {
      files: '.prettierrc',
      options: {
        parser: 'json',
      },
    },
  ],
};
.vscode/settings.json

若是你是使用 Visual Studio Code 來開發項目的話,這個配置文件就能夠方便的統一團隊的編輯器配置,解決項目中,縮進是「2個空格」仍是「4個空格」的問題。

{
  "editor.tabSize": 2,
  "eslint.autoFixOnSave": true,
  "eslint.validate": [
    "javascript",
    "javascriptreact",
    { "language": "typescript", "autoFix": true },
    { "language": "typescriptreact", "autoFix": true }
  ],
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": true
  }
}
.env

當咱們搜索 create-react-app 是如何快速解決 alias 的問題時,Dan 給出的答案是添加 .env 這個文件:

NODE_PATH=src

到這裏,就整理完了全部須要的配置文件

使用 Less

更加詳細的解析,請參考 Antd 的文檔

安裝下面依賴:

npm i -D react-app-rewired customize-cra babel-plugin-import less less-loader
修改 package.json
/* package.json */
"scripts": {
-   "start": "react-scripts start",
+   "start": "react-app-rewired start",
-   "build": "react-scripts build",
+   "build": "react-app-rewired build",
-   "test": "react-scripts test",
+   "test": "react-app-rewired test",
}
config-overrides.js

而後在項目根目錄建立一個 config-overrides.js 用於修改默認配置。

const { override, fixBabelImports, addLessLoader } = require('customize-cra');

module.exports = override(
  fixBabelImports('import', {
    libraryName: 'antd',
    libraryDirectory: 'es',
    style: true,
  }),
  addLessLoader({
    javascriptEnabled: true,
  }),
);

到此,咱們就能夠在項目中,愉快的使用 less 了~

項目結構

此時,使用編輯器打開項目,咱們能夠看到以下的 src 目錄結構:

├── src
|  ├── App.css
|  ├── App.test.tsx
|  ├── App.tsx
|  ├── index.css
|  ├── index.tsx
|  ├── logo.svg
|  ├── react-app-env.d.ts
|  ├── serviceWorker.ts
|  └── setupTests.ts

這是腳手架爲咱們準備的初始目錄結構。接下來,咱們須要在這個基礎上,進行一些改造。以一個最爲簡單的 EmptyLine 組件爲例子,看看咱們須要增長哪些文件。

處理路由

首先,增長兩個文件夾 , pages 用來存放路由相關的組件,以及components 用來存放通用組件。
此處不作贅述,感興趣的小夥伴能夠看下 demo 的實現

此時,代碼結構以下:

├── src
|  ├── App.less
|  ├── App.test.tsx
|  ├── App.tsx
|  ├── components
|  |  ├── empty-line
|  |  |  ├── EmptyLine.tsx
|  |  |  ├── demo.tsx
|  |  |  ├── index.tsx
|  |  |  └── style
|  |  └── index.tsx
|  ├── config.tsx
|  ├── index.css
|  ├── index.tsx
|  ├── logo.svg
|  ├── pages
|  |  ├── Component
|  |  |  ├── index.tsx
|  |  |  └── style.less
|  |  ├── Home
|  |  |  ├── index.tsx
|  |  |  └── style.less
|  |  └── NotFound
|  |     └── index.tsx
|  ├── react-app-env.d.ts
|  ├── serviceWorker.ts
|  └── setupTests.ts

pages 下面的目錄結構比較容易理解,只存放了組件,以及樣式文件。

components 下的目錄結構,主要參考了 Antd 的源碼實現。這樣寫的有以下好處:

  • 分離了樣式組件,結構清晰
  • 代碼結構更加清晰,便於以後組件的導出
  • 因爲咱們使用 babel-plugin-import 來進行按需加載 Antd,當咱們想使用 ES module 的方式引入組件的時候,它會對咱們 es 目錄下的文件有所要求:
下面摘自 babel-plugin-import 的文檔:
  • { "libraryName": "antd" }
import { Button } from 'antd';
ReactDOM.render(<Button>xxxx</Button>);

      ↓ ↓ ↓ ↓ ↓ ↓

var _button = require('antd/lib/button');
ReactDOM.render(<_button>xxxx</_button>);
  • { "libraryName": "antd", style: "css" }
import { Button } from 'antd';
ReactDOM.render(<Button>xxxx</Button>);

      ↓ ↓ ↓ ↓ ↓ ↓

var _button = require('antd/lib/button');
require('antd/lib/button/style/css');
ReactDOM.render(<_button>xxxx</_button>);
  • { "libraryName": "antd", style: true }
import { Button } from 'antd';
ReactDOM.render(<Button>xxxx</Button>);

      ↓ ↓ ↓ ↓ ↓ ↓

var _button = require('antd/lib/button');
require('antd/lib/button/style');
ReactDOM.render(<_button>xxxx</_button>);

因此,不論以後時使用 commonjs 的方式打包,仍是使用 es 的方式打包,組件的目錄結構最好和 Antd 的組件目錄結構保持一致,不然 babel-plugin-import 這個插件會找不到對應的文件所在。

增長第一個組件

如今,咱們能夠開始寫咱們的第一個組件了,<EmptyLine />:產生一個空行,而且能夠根據 props 改變高度。

src/index.tsx
export { default as EmptyLine } from './empty-line';
src/empty-line/index.tsx
import './style/index.less';
import EmptyLine from './EmptyLine';

export default EmptyLine;
src/empty-line/EmptyLine.tsx
import React from 'react';
import './style/index.less';

export interface IEmptyLineProps {
  height?: number;
}

const EmptyLine = ({ height = 20 }: IEmptyLineProps) => {
  return <div className="empty-line" style={{ height }} />;
};

export default EmptyLine;
src/empty-line/style/index.less
.empty-line {
    width: 100%;
    height: 20px;
}
src/empty-line/demo.tsx
import React from 'react';
import EmptyLine from './EmptyLine';

const demo = () => {
  return (
    <div>
      <h3>組件名稱:空行(EmptyLine)</h3>
      <p>自定義組件,默認高度 20 ,寬度 100%</p>
      <p>第一行文字</p>
      <EmptyLine />
      <p>第二行文字</p>
    </div>
  );
};

export default demo;

到這裏,組件就完成了,這是:預覽地址

image

結束語

咱們已經從頭開始建立了 React 組件庫!在接下來的章節中,還會和你們討論測試,和打包的話題,敬請期待吧~

相關文章
相關標籤/搜索