如何從零開源一個React組件

有沒有遇到這樣一種狀況,你花了很大精力在業務項目中寫了一個組件,你以爲這個組件很通用,除了當前的業務場景還應該有其餘的應用場景,因此你想開源這個組件,但又不知道從何入手。這篇文章就來聊聊如何開源一個前端組件,不管是業務中已有的組件仍是新的組件。css

1. 初始化

1.1 Git

能夠在 Github 上新建一個項目,這裏取名 "component-example",而後使用 git clone 命令克隆到本地進行開發。也能夠先在本地建好文件,而後使用 git remote add 命令將本地項目與遠程項目進行綁定。前端

1.2 NPM

進入項目根目錄,執行 npm init 命令初始化項目,這裏沒什麼注意點,一路默認便可,命令執行結束後會獲得一個 "package.json" 文件。node

1.3 React

在項目根目錄新增 "src" 文件夾,進入 "src",新建 "index.js"、"index.css"、"App.js" 和 "App.css" 4 個文件。react

"index.js"webpack

import React from 'react';
import ReactDOM from 'react-dom';
import styles from './index.css';
import App from './App';

ReactDOM.render(<App />, document.getElementById('root'));

"APP.js"git

import React from 'react';
import styles from './App.css';

export default class APP extends React.Component {
    render() {
        return <div>Hello, React Component!</div>
    }
}

安裝 react 和 react-dom:web

npm install --save react react-dom

2. 構建

2.1 Webpack

這裏使用 webpack 做爲打包構建工具。執行下面命令安裝 webpack:npm

npm install --save webpack webpack-cli

新建 "webpack.common.js"、"webpack.dev.js" 和 "webpack.prod.js" 3 個文件,用於配置 webpack。由於開發環境和生產環境的須要不同,好比開發環境須要 source map 以便快速定位問題,而生產環境須要文件儘可能小以減小網絡加載時間,因此須要維護兩套不一樣的構建配置。雖然是兩套配置,但仍然有不少配置是相同的,因此將相同的配置抽成 "webpack.common.js" 文件,開發環境特有的配置放在 "webpack.dev.js",生產環境特有的配置放在 "webpack.prod.js" 中。json

"webpack.common.js"bash

const path = require("path");

module.exports = {
  entry: "./src/index.js",
  output: {
    path: path.resolve(__dirname, "dist"),
    filename: "component-example.js",
    libraryTarget: "umd"
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        loader: "style-loader!css-loader?modules"
      },
      {
        test: /\.(jpg|png)$/,
        loader: "url-loader?limit=25000"
      }
    ]
  },
  resolve: {
    extensions: [".jsx", ".js"]
  },
  plugins: []
};

"webpack.dev.js"

const merge = require("webpack-merge");
const common = require("./webpack.common.js");

module.exports = merge(common, {
  mode: "development",
  devtool: "inline-source-map",
  watch: true
});

"webpack.prod.js"

const merge = require("webpack-merge");
const common = require("./webpack.common.js");

module.exports = merge(common, {
  mode: "production",
  externals: ["react", "react-dom"]
});

上面的配置中用到了 style-loadercss-loaderurl-loaderwebpack-merge,也須要安裝一下:

npm install --save-dev css-loader style-loader url-loader webpack-merge

"webpack.common.js" 中,output 的 path 和 filename 指定構建結果存在 /dist/component-example.js 中;libraryTarget 的值爲 umd,這條配置必不可少,代表將 component-example.js 文件暴露爲全部模塊定義下都能運行的方式,便可以被當作 CommonJS 模塊、 AMD 模塊等不一樣類型的模塊,從而能夠在不一樣環境下運行。

另外,在 "webpack.common.js" 中還引入了 3 個 loader: style-loadercss-loaderurl-loader,前二者幫助 webpack 預處理樣式文件,這裏指 CSS 文件;url-loader 用於將本地文件處理成 base64,通常用於引用背景圖時,若是沒有須要,也能夠刪除。

"webpack.dev.js" 中有 3 個額外的配置。

  • mode: 表明構建模式,有 developmentproduction 兩個值可選,不一樣的值會觸發 webpack 不一樣的 Plugin,好比 development 會觸發 NamedChunksPlugin,能夠將 chunk id 變成字符串標識符,而 production 則會觸發 UglifyJsPlugin,能夠 uglify 代碼;
  • devtool:表明是否生成以及如何生成 source map,這裏使用了 inline-source-map,source map 會轉換爲 DataUrl 後添加到 bundle 中,所以 bundle 會變得很大,但畢竟開發環境而且僅僅是個組件項目,大小可控;
  • watch:能夠監聽文件變化,文件修改後能夠自動從新編譯。

"webpack.prod.js" 中除了 mode,還有 externals 配置項,表示構建的 bundle 中排除對 react 和 react-dom 的依賴,由於是 React 組件,用到該組件的地方確定同時也引用了 react 和 react-dom,因此不必再在組件的 bundle 中引入,這樣又能夠大大減小構建完的文件大小。

2.2 Babel

Babel 可讓咱們使用 ES6 寫 JS,因此咱們也須要爲項目添加 Babel 配置。

新建 ".babelrc" 文件,輸入配置:

{
  "presets": ["@babel/preset-env", "@babel/preset-react"]
}

"webpack.common.js" 中添加 babel 相關的 配置:

rules: [
    {
    test: /\.(js|jsx)$/,
    exclude: /node_modules/,
    use: {
        loader: "babel-loader"
    }
  }
]

須要安裝:

npm install --save-dev @babel/core babel-loader @babel/preset-env @babel/preset-react

2.3 package.json

在 "package.json" 文件中根據 webpack 的 output 配置指定項目的入口文件,另外添加兩條命令,分別是開發時啓動命令和生產構建命令。

"main": "./dist/component-example.js",
"scripts": {
    "start": "webpack --config webpack.dev.js --progress --colors",
    "build": "webpack --config webpack.prod.js",
}

3. 調試

3.1 npm link

既然是組件,那便須要放入到一個完整的項目中去調試,這裏使用 npm link

首先須要進入剛剛的組件根目錄,執行 pwd,獲取組件的絕對路徑,而後進入一個完整的目標項目的根目錄,執行 npm link $path ,"$path" 指的是剛剛執行 pwd 後獲取到的路徑 ,這樣在目標項目的 "node_modules" 中建立了一個指向組件的軟連接,至關於在目標文件中執行了 npm install --save component-example,只不過任何在 "component-example" 中的修改都會當即反饋到目標項目中。

npm link 還有一種方式,即在 "component-example" 根目錄直接執行 npm link,那麼會在全局的 node_modules 中建立名爲 component-example 的 NPM 包,而後在目標項目中執行 npm link component-example 以引用組件文件。但這種方式會污染全局,通常不建議這麼作。

引入組件後,能夠像正常 NPM 包同樣 import 和使用:

import ComponentExample from 'component-example';

export default class FullProject extends React.Component {
  render() {
    return <ComponentExample />;
  }
}

在組件項目中啓動 npm start,任何更改能夠自動構建,變化也會隨時反饋到目標項目中。

開發結束後,記得在目標項目中解除 link:npm unlink component-example

3.2 CSS Modules

既然是前端組件,那 CSS 必不可少,如何引入 CSS 文件呢?這裏使用 CSS Modules。任何一個 CSS 樣式規則都是全局的,CSS Modules 的思路就是產生一個惟一的哈希字符串表示當前的規則,從而避免全局污染的狀況。

那怎麼使用呢?webpack 的 css-loader 即可以支持 CSS Modules,而且配置和使用起來都很方便。若是留意的話,你可能會發現 "webpack.common.js" 中引入 css-loader 時在後面添加了個參數: modules,這樣即可以打開 CSS Modules 功能。

"App.css"

.title {
    color: red;
}

"App.js"

import React from 'react';
import styles from './App.css';

export default class APP extends React.Component {
    render() {
        return <div className={styles.title}>Hello, React Component!</div>
    }
}

JS 文件引入 CSS 模塊,並命名爲 styles, JSX 經過 className={styles.title} 聲明類名。

4. 發佈

通過一番編碼調試,組件終於能夠發佈了,使用 npm run build 命令對項目進行構建,若是打開 "./dist/component-example.js" 的話,你會發現代碼與開發時有很大差異。再執行 npm publish 將組件發佈到 NPM 上。

使用 npm publish 時有幾個注意點,首先你須要註冊 NPM 帳號,沒有的話須要執行 npm adduser,註冊完畢後登陸 npm login,執行 npm who am i 驗證是否已經成功登陸,而後就能夠愉快地 npm publish 了。另一個注意點是每次發佈時須要更新 "package.json" 中的 version,執行 npm version *.*.* 指定當前發佈的版本,必定要大於上一次。

上面講了如何從零開源一個 React 組件,只是從技術角度出發,開源過程當中還會涉及其餘的方方面面,這裏再也不詳述。

相關文章
相關標籤/搜索