詳解從 0 釋出 react 元件到 npm 上

桃翁發表於2019-01-31

我釋出了我的第一個 npm 元件,一個基於 react 的 3d 標籤雲元件。在這途中我也是遇到了很多的坑,花在完善整個釋出流程的時間遠多於寫這個元件本身的時間,所以我記錄下我覺得一個正常的 react 元件的釋出流程

最後記錄這篇文章花的時間比我完成整個元件的時間都多,最終希望能給新手帶來幫助

在整個釋出元件的過程我做了如下幾件事兒:

  1. 開發元件
  2. 編寫 Readme
  3. 推送到 github,並且把 demo 放到 github page 上
  4. 釋出元件到 npm 上

開發元件

建立專案資料夾並初始化 npm package ,確保你建立的元件名稱沒有在 npm 上被使用過, 這裡我們用 react-demo 作為示例

mkdir react-demo
cd react-demo
npm init
複製程式碼

npm init 是生成初始的 package.json 的命令,在 npm init 的時候,你可以根據你自己的需要進行填寫你的元件資訊。或者直接使用 npm init -y 採用預設的,後面自己再去修改。

首先安裝 react 相關的包:

npm i react react-dom -D
複製程式碼

採用 babel 編譯相關的依賴:

npm i @babel/cli @babel/core @babel/preset-env @babel/preset-react -D
複製程式碼

採用 webpack 做構建,webpack-dev-server 作為本地開發伺服器,所以需要安裝如下依賴:

npm i webpack webpack-cli webpack-dev-server -D
複製程式碼

我這裡為了簡單演示,只安裝 babel-loader 用來編譯 jsx,其他 loader 安裝自己的需要自己安裝。

npm i babel-loader -D
複製程式碼

另外再安裝一個 webpack 外掛 html-webpack-plugin ,用來生成 html:

npm i html-webpack-plugin -D
複製程式碼

然後再新增上常規的 startbuild 指令碼,package.json 如下:

{
  "name": "react-demo",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "webpack-dev-server --open development",
    "build": "webpack --mode production"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "@babel/cli": "^7.2.3",
    "@babel/core": "^7.2.2",
    "@babel/preset-env": "^7.3.1",
    "@babel/preset-react": "^7.0.0",
    "babel-loader": "^8.0.5",
    "html-webpack-plugin": "^3.2.0",
    "react": "^16.7.0",
    "react-dom": "^16.7.0",
    "webpack": "^4.29.0",
    "webpack-cli": "^3.2.1",
    "webpack-dev-server": "^3.1.14"
  },
  "dependencies": {}
}
複製程式碼

當然,你也可以直接把我這個 package.json 複製過去,然後 npm install 進行依賴的安裝,也可以一個一個的安裝。

一個最基本的元件只需要編譯 jsx,所以我這裡沒有安裝 css 以及處理其他的 loader,這篇文章的重點不是講 webpack 的,所以其他的自行解決,有 webpack 問題可以私聊我。

然後我們再建立如下的目錄結構:

├── example // 示例程式碼,在自己測試的時候可以把測試檔案放到 src 裡
│   └── src // 示例原始碼
│       ├── index.html // 示例 html
│       └── app.js // 新增到 react-dom 的檔案
├── package.json 
├── src // 元件原始碼
│   └── index.js // 元件原始碼檔案
├── .babelrc
├── .editorconfig // 不必須的,但是建議有
├── .gitignore // 如果要放到 github 上,這個是需要有的
└── webpack.config.js
複製程式碼

下面我們再建立一個最簡單的元件,來進行演示:

/*** src/index.js ***/
import React from 'react';
const ReactDemo = () => (
 <h1>這是我的第一個 react npm 元件</h1>
);
export default ReactDemo;
複製程式碼

接下來新增一個 demo

<!-- examples/src/index.html -->
<html>
<head>
    <title>My First React Component</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
</head>
<body>
    <div id="root"></div>
</body>
</html>
複製程式碼
/*** examples/src/app.js ***/
import React from 'react'
import { render } from 'react-dom'
import ReactDemo from '../../src'

const App = () => <ReactDemo />
render(<App />, document.getElementById('root'))

複製程式碼

注意 demo 中的 ReactDemo 是從 ../../src 中匯入的

接下來配置非常簡單的 webpack, 在專案根路徑下建立 webpack.config.js 檔案

const path = require('path');
const HtmlWebpackPlugin = require("html-webpack-plugin");
const htmlWebpackPlugin = new HtmlWebpackPlugin({
	template: path.join(__dirname, "./example/src/index.html"),
	filename: "./index.html"
});

module.exports = {
	entry: path.join(__dirname, "./example/src/app.js"),
	output: {
		path: path.join(__dirname, "example/dist"),
		filename: "bundle.js"
	},
	module: {
		rules: [{
			test: /\.(js|jsx)$/,
			use: "babel-loader",
			exclude: /node_modules/
		}]
	},
	plugins: [htmlWebpackPlugin],
	resolve: {
		extensions: [".js", ".jsx"]
	},
	devServer: {
		port: 3001
	}
};

複製程式碼

Webpack 的配置檔案主要做了如下事情:

  • 使用 example/src/index.js 作為專案入口,處理資原始檔的依賴關係
  • 通過 babel-loader 來編譯處理 js 和 jsx 檔案
  • 通過 html-webpack-plugin 自動注入編譯打包好的指令碼檔案
  • 為 demo 啟動埠為 3001 的服務

然後再配置一下 babel,我們們的 babel 主要做兩件事,將 jsx 編譯成 es5,然後再加一個通用的 env,所以 .babelrc 配置如下:

{
    "presets": ["@babel/preset-env", "@babel/preset-react"]
}
複製程式碼

可以看到之前的 package.json ,我這裡 babel 安裝的是 7.x,那麼 babel-loader 就應該是 8.x 才行,然後 babel 7.x 相對於之前的配置是不同的,要用這個配置,版本一定要跟我的相同,不然配置可能會不一樣。

然後現在執行 npm start,然後再訪問 localhost:3001 就可以訪問到了。

編寫 README

編寫 README,如果你不知道該如何編寫,我給你提幾點建議,你可以選擇你覺得必要的點來寫:

  1. logo
  2. 官方主頁
  3. 介紹
  4. 安裝
  5. 快速開始
  6. 功能列表
  7. 截圖
  8. todoList
  9. 不足之處
  10. FAQ
  11. Change Log(更新日誌)

新增徽章

當你寫完 README 之後,我們將新增一些來自 shields.io 的時髦徽章,讓人們知道我們又酷又專業。

詳解從 0 釋出 react 元件到 npm 上

想新增什麼樣的徽章看自己喜歡吧,種類有很多。

可以點選這裡看我之前寫的 3d 標籤雲的 README。

現在基本上可以釋出了,但是要是能提供一個線上的 demo 讓別人在用這個元件的時候可以看到效果就更好了。

在 GitHub Pages 上釋出一個線上 demo

釋出線上 demo 可以直接用 Github Pages 來幫助我們託管,通過 webpack 構建生產環境版本,然後發到 Github 上去即可。

首先去 Github 建立一個用來存放你元件程式碼的倉庫。

然後把你的專案初始化成 git 專案:

git init
複製程式碼

再新增遠端倉庫,將本地倉庫和遠端倉庫關聯起來。

git remote add origin git@github.com:crazylxr/react-demo.git
複製程式碼

接下來我們可以安裝 gh-pages 來幫助我們釋出到 github pages:

npm i gh-pages -D
複製程式碼

為了方便記憶,後續能更快的釋出,這些命令我們可以寫成 npm-scriprt,所以我們增加兩個指令碼:

{
  "name": "@taoweng/react-demo",
  "version": "1.0.0",
  "description": "react demo",
  "main": "lib/index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "webpack-dev-server --open development",
    "build": "webpack --mode production",
    "deploy": "gh-pages -d examples/dist",
    "publish-demo": "npm run build && npm run deploy"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "@babel/cli": "^7.2.3",
    "@babel/core": "^7.2.2",
    "@babel/preset-env": "^7.3.1",
    "@babel/preset-react": "^7.0.0",
    "babel-loader": "^8.0.5",
    "gh-pages": "^2.0.1",
    "html-webpack-plugin": "^3.2.0",
    "react": "^16.7.0",
    "react-dom": "^16.7.0",
    "webpack": "^4.29.0",
    "webpack-cli": "^3.2.1",
    "webpack-dev-server": "^3.1.14"
  },
  "dependencies": {}
}

複製程式碼

新增了 deploy 指令碼和 publish-demo,以後需要釋出 demo 的時候只需要 npm run publish-demo 即可。

然後我們就可以 build 專案之後再將 expamples/dist 釋出到 gh-pages 分支:

npm run build
npm run deploy
複製程式碼

或者直接

npm run publish-demo
複製程式碼

注意:這裡只會將 expample/src 下的檔案釋出到 ph-pages 分支,master 分支依然沒有到 github 上,如果你要把原始碼放到 github 的 master 或者其他分支上,還是需要自己 push 的。

這個時候,我們可以通過 crazylxr.github.io/react-demo 訪問到我們寫的 demo。crazylxr 是 github 的 username,react-demo 是倉庫名,注意改成你自己的。

編譯原始碼

我們現在的原始碼是 jsx 的,所以我們需要通過 babeljsx 編譯為正常瀏覽器能訪問的程式碼。我們可以通過 babel-cli 來編譯我們程式碼,直接編譯 src 目錄,到 lib 資料夾。更多命令見 babel-cli

npx babel src --out-dir lib
複製程式碼

執行完這個命令,就把生成一個 lib 資料夾,然後裡面的 index.js 就是編譯過後的檔案,是可以直接釋出到 npm 的檔案。

然後將這個編譯命令寫到 script 裡,package.json 如下:

{
  "name": "@taoweng/react-demo",
  "version": "1.0.0",
  "description": "react demo",
  "main": "lib/index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "webpack-dev-server --open development",
    "build": "webpack --mode production",
    "compile": "npx babel src --out-dir lib",
    "deploy": "gh-pages -d example/dist",
    "publish-demo": "npm run build && npm run deploy"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "@babel/cli": "^7.2.3",
    "@babel/core": "^7.2.2",
    "@babel/preset-env": "^7.3.1",
    "@babel/preset-react": "^7.0.0",
    "babel-loader": "^8.0.5",
    "gh-pages": "^2.0.1",
    "html-webpack-plugin": "^3.2.0",
    "react": "^16.7.0",
    "react-dom": "^16.7.0",
    "webpack": "^4.29.0",
    "webpack-cli": "^3.2.1",
    "webpack-dev-server": "^3.1.14"
  },
  "dependencies": {}
}

複製程式碼

那麼以後要編譯 src 下面的程式碼,只需要執行:

npm run compile
複製程式碼

現在我們已經有編譯好的程式碼了,接下來就可以釋出到 npm 供其他人使用了。

釋出 npm 包

在釋出以前我們是需要一些準備:

註冊 npm 賬戶:

在這裡](www.npmjs.com/) 註冊一個 npm 賬號。

登入

在終端輸入:

npm adduser
複製程式碼

也可以用:

npm login
複製程式碼

然後你會得到一個讓你輸入usernamepassword 和 **email ** 的提示,把它們填在相應的位置。

關於 package.json 需要注意的點

package.json 裡面的配置資訊非常重要,我解釋一下幾個重要的配置。

  • name: 包名,如果你學習的話建議加一個 scoped,就是我上面的 @taoweng/react-demo 而不是 react-demo,因為 npm 包特別的多,很容易重複。這樣這個包就會是私有的,可以通過 npm publish --access=public 將這個包變為共有的包。

  • version: 包的版本,每次釋出包的版本不能和上次一樣。詳細規範可見這裡

  • description:包的簡介。

  • repository:適合寫 Github 地址,建議寫成::username/:repository

  • license:認證。不知道該用什麼的,就寫MIT 吧。

  • main:包的入口檔案。就是引入這個包的時候去載入的入口檔案。

  • keywords:新增一些關鍵詞更容易使你的包被搜尋到。

更詳細的 package.json 配置可見官網

我這裡簡單的新增了這些資訊:

{
  "name": "@taoweng/react-demo",
  "version": "1.0.0",
  "description": "react demo",
  "main": "lib/index.js",
  "repository": "crazylxr/react-demo",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "webpack-dev-server --open development",
    "build": "webpack --mode production",
    "compile": "npx babel src --out-dir lib",
    "deploy": "gh-pages -d example/dist",
    "publish-demo": "npm run build && npm run deploy"
  },
  "keywords": ["react", "demo"],
  "author": "taoweng",
  "license": "MIT",
  "devDependencies": {
    "@babel/cli": "^7.2.3",
    "@babel/core": "^7.2.2",
    "@babel/preset-env": "^7.3.1",
    "@babel/preset-react": "^7.0.0",
    "babel-loader": "^8.0.5",
    "gh-pages": "^2.0.1",
    "html-webpack-plugin": "^3.2.0",
    "react": "^16.7.0",
    "react-dom": "^16.7.0",
    "webpack": "^4.29.0",
    "webpack-cli": "^3.2.1",
    "webpack-dev-server": "^3.1.14"
  },
  "dependencies": {}
}

複製程式碼

這些配置資訊都會在 npm 包的頁面顯示出來的,所以能填還是填一下:

詳解從 0 釋出 react 元件到 npm 上

最後我們在專案中新增 .npmignore 檔案,跟 .gitignore 的作用一樣,就是在釋出 npm 的時候需要忽略的檔案和資料夾:

# .npmignore 
src
examples
.babelrc
.gitignore
webpack.config.js
複製程式碼

這個時候我們就可以釋出到 npm 了:

npm publish
複製程式碼

如果你是私有包,可以這樣釋出:

npm publish --access=public
複製程式碼

結語

以後釋出新版本的時候,只需要更改一下 package.json 裡面的 version 版本號,然後執行 npm publish 和 npm run publish-demo 就可以同步 npm 和 demo。

不過如果想讓你的元件在社群裡給更多人用,你需要把 README 寫得更好一點,然後新增好自動化測試,不然別人不太敢用。

另外在寫元件之前可以先了解下有沒有類似的元件了,如果有就直接用吧,我們們就站在巨人的肩膀上,把自己寶貴的時間放在創造價值上。

最後整個專案的原始碼見 github

參考文章

另外

同時你也可以在這些地方找到這篇文章:

  1. 個人網站
  2. github blog

另外有興趣可以關注我的公眾號:前端桃園

詳解從 0 釋出 react 元件到 npm 上

相關文章