我發(fā)布了我的第一個(gè) npm 組件,一個(gè)基于 react 的 3d 標(biāo)簽云組件。在這途中我也是遇到了很多的坑,花在完善整個(gè)發(fā)布流程的時(shí)間遠(yuǎn)多于寫(xiě)這個(gè)組件本身的時(shí)間,所以我記錄下我覺(jué)得一個(gè)正常的 react 組件的發(fā)布流程
最后記錄這篇文章花的時(shí)間比我完成整個(gè)組件的時(shí)間都多,最終希望能給新手帶來(lái)幫助
在整個(gè)發(fā)布組件的過(guò)程我做了如下幾件事兒:
- 開(kāi)發(fā)組件
- 編寫(xiě) Readme
- 推送到 github,并且把 demo 放到 github page 上
- 發(fā)布組件到 npm 上
開(kāi)發(fā)組件
創(chuàng)建項(xiàng)目文件夾并初始化 npm package ,確保你創(chuàng)建的組件名稱(chēng)沒(méi)有在 npm 上被使用過(guò), 這里我們用 react-demo 作為示例
mkdir react-demo
cd react-demo
npm init
npm init 是生成初始的 package.json 的命令,在 npm init 的時(shí)候,你可以根據(jù)你自己的需要進(jìn)行填寫(xiě)你的組件信息?;蛘咧苯邮褂?npm init -y 采用默認(rèn)的,后面自己再去修改。
首先安裝 react 相關(guān)的包:
npm i react react-dom -D
采用 babel 編譯相關(guān)的依賴(lài):
npm i @babel/cli @babel/core @babel/preset-env @babel/preset-react -D
采用 webpack 做構(gòu)建,webpack-dev-server 作為本地開(kāi)發(fā)服務(wù)器,所以需要安裝如下依賴(lài):
npm i webpack webpack-cli webpack-dev-server -D
我這里為了簡(jiǎn)單演示,只安裝 babel-loader 用來(lái)編譯 jsx,其他 loader 安裝自己的需要自己安裝。
npm i babel-loader -D
另外再安裝一個(gè) webpack 插件 html-webpack-plugin ,用來(lái)生成 html:
npm i html-webpack-plugin -D
然后再添加上常規(guī)的 start 和 build 腳本,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": {}
}
當(dāng)然,你也可以直接把我這個(gè) package.json 復(fù)制過(guò)去,然后 npm install 進(jìn)行依賴(lài)的安裝,也可以一個(gè)一個(gè)的安裝。
一個(gè)最基本的組件只需要編譯 jsx,所以我這里沒(méi)有安裝 css 以及處理其他的 loader,這篇文章的重點(diǎn)不是講 webpack 的,所以其他的自行解決,有 webpack 問(wèn)題可以私聊我。
然后我們?cè)賱?chuàng)建如下的目錄結(jié)構(gòu):
├── example // 示例代碼,在自己測(cè)試的時(shí)候可以把測(cè)試文件放到 src 里
│ └── src // 示例源代碼
│ ├── index.html // 示例 html
│ └── app.js // 添加到 react-dom 的文件
├── package.json
├── src // 組件源代碼
│ └── index.js // 組件源代碼文件
├── .babelrc
├── .editorconfig // 不必須的,但是建議有
├── .gitignore // 如果要放到 github 上,這個(gè)是需要有的
└── webpack.config.js
下面我們?cè)賱?chuàng)建一個(gè)最簡(jiǎn)單的組件,來(lái)進(jìn)行演示:
/*** src/index.js ***/
import React from 'react';
const ReactDemo = () => (
<h1>這是我的第一個(gè) react npm 組件</h1>
);
export default ReactDemo;
接下來(lái)添加一個(gè) 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 中導(dǎo)入的
接下來(lái)配置非常簡(jiǎn)單的 webpack, 在項(xiàng)目根路徑下創(chuàng)建 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 作為項(xiàng)目入口,處理資源文件的依賴(lài)關(guān)系
- 通過(guò) babel-loader 來(lái)編譯處理 js 和 jsx 文件
- 通過(guò) html-webpack-plugin 自動(dòng)注入編譯打包好的腳本文件
- 為 demo 啟動(dòng)端口為 3001 的服務(wù)
然后再配置一下 babel,咱們的 babel 主要做兩件事,將 jsx 編譯成 es5,然后再加一個(gè)通用的 env,所以 .babelrc 配置如下:
{
"presets": ["@babel/preset-env", "@babel/preset-react"]
}
可以看到之前的 package.json ,我這里 babel 安裝的是 7.x,那么 babel-loader 就應(yīng)該是 8.x 才行,然后 babel 7.x 相對(duì)于之前的配置是不同的,要用這個(gè)配置,版本一定要跟我的相同,不然配置可能會(huì)不一樣。
然后現(xiàn)在執(zhí)行 npm start,然后再訪(fǎng)問(wèn) localhost:3001 就可以訪(fǎng)問(wèn)到了。
編寫(xiě) README
編寫(xiě) README,如果你不知道該如何編寫(xiě),我給你提幾點(diǎn)建議,你可以選擇你覺(jué)得必要的點(diǎn)來(lái)寫(xiě):
- logo
- 官方主頁(yè)
- 介紹
- 安裝
- 快速開(kāi)始
- 功能列表
- 截圖
- todoList
- 不足之處
- FAQ
- Change Log(更新日志)
添加徽章
當(dāng)你寫(xiě)完 README 之后,我們將添加一些來(lái)自 shields.io 的時(shí)髦徽章,讓人們知道我們又酷又專(zhuān)業(yè)。
想添加什么樣的徽章看自己喜歡吧,種類(lèi)有很多。
可以點(diǎn)擊這里看我之前寫(xiě)的 3d 標(biāo)簽云的 README。
現(xiàn)在基本上可以發(fā)布了,但是要是能提供一個(gè)在線(xiàn)的 demo 讓別人在用這個(gè)組件的時(shí)候可以看到效果就更好了。
在 GitHub Pages 上發(fā)布一個(gè)在線(xiàn) demo
發(fā)布在線(xiàn) demo 可以直接用 Github Pages 來(lái)幫助我們托管,通過(guò) webpack 構(gòu)建生產(chǎn)環(huán)境版本,然后發(fā)到 Github 上去即可。
首先去 Github 創(chuàng)建一個(gè)用來(lái)存放你組件代碼的倉(cāng)庫(kù)。
然后把你的項(xiàng)目初始化成 git 項(xiàng)目:
git init
再添加遠(yuǎn)程倉(cāng)庫(kù),將本地倉(cāng)庫(kù)和遠(yuǎn)程倉(cāng)庫(kù)關(guān)聯(lián)起來(lái)。
git remote add origin git@github.com:crazylxr/react-demo.git
接下來(lái)我們可以安裝 gh-pages 來(lái)幫助我們發(fā)布到 github pages:
npm i gh-pages -D
為了方便記憶,后續(xù)能更快的發(fā)布,這些命令我們可以寫(xiě)成 npm-scriprt,所以我們?cè)黾觾蓚€(gè)腳本:
{
"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,以后需要發(fā)布 demo 的時(shí)候只需要 npm run publish-demo 即可。
然后我們就可以 build 項(xiàng)目之后再將 expamples/dist 發(fā)布到 gh-pages 分支:
npm run build
npm run deploy
或者直接
npm run publish-demo
注意:這里只會(huì)將 expample/src 下的文件發(fā)布到 ph-pages 分支,master 分支依然沒(méi)有到 github 上,如果你要把源碼放到 github 的 master 或者其他分支上,還是需要自己 push 的。
這個(gè)時(shí)候,我們可以通過(guò) crazylxr.github.io/react-demo 訪(fǎng)問(wèn)到我們寫(xiě)的 demo。crazylxr 是 github 的 username,react-demo 是倉(cāng)庫(kù)名,注意改成你自己的。
編譯源碼
我們現(xiàn)在的源碼是 jsx 的,所以我們需要通過(guò) babel 把 jsx 編譯為正常瀏覽器能訪(fǎng)問(wèn)的代碼。我們可以通過(guò) babel-cli 來(lái)編譯我們代碼,直接編譯 src 目錄,到 lib 文件夾。更多命令見(jiàn) babel-cli
npx babel src --out-dir lib
執(zhí)行完這個(gè)命令,就把生成一個(gè) lib 文件夾,然后里面的 index.js 就是編譯過(guò)后的文件,是可以直接發(fā)布到 npm 的文件。
然后將這個(gè)編譯命令寫(xiě)到 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 下面的代碼,只需要執(zhí)行:
npm run compile
現(xiàn)在我們已經(jīng)有編譯好的代碼了,接下來(lái)就可以發(fā)布到 npm 供其他人使用了。
發(fā)布 npm 包
在發(fā)布以前我們是需要一些準(zhǔn)備:
注冊(cè) npm 賬戶(hù):
在這里](https://www.npmjs.com/) 注冊(cè)一個(gè) npm 賬號(hào)。
登錄
在終端輸入:
npm adduser
也可以用:
npm login
然后你會(huì)得到一個(gè)讓你輸入username、password 和 **email ** 的提示,把它們填在相應(yīng)的位置。
關(guān)于 package.json 需要注意的點(diǎn)
package.json 里面的配置信息非常重要,我解釋一下幾個(gè)重要的配置。
name: 包名,如果你學(xué)習(xí)的話(huà)建議加一個(gè) scoped,就是我上面的 @taoweng/react-demo 而不是 react-demo,因?yàn)?npm 包特別的多,很容易重復(fù)。這樣這個(gè)包就會(huì)是私有的,可以通過(guò)
npm publish --access=public將這個(gè)包變?yōu)楣灿械陌?/p>description:包的簡(jiǎn)介。
repository:適合寫(xiě) Github 地址,建議寫(xiě)成::username/:repository。
license:認(rèn)證。不知道該用什么的,就寫(xiě)MIT 吧。
main:包的入口文件。就是引入這個(gè)包的時(shí)候去加載的入口文件。
keywords:添加一些關(guān)鍵詞更容易使你的包被搜索到。
更詳細(xì)的 package.json 配置可見(jiàn)官網(wǎng)。
我這里簡(jiǎn)單的添加了這些信息:
{
"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": {}
}
這些配置信息都會(huì)在 npm 包的頁(yè)面顯示出來(lái)的,所以能填還是填一下:
最后我們?cè)陧?xiàng)目中添加 .npmignore 文件,跟 .gitignore 的作用一樣,就是在發(fā)布 npm 的時(shí)候需要忽略的文件和文件夾:
# .npmignore
src
examples
.babelrc
.gitignore
webpack.config.js
這個(gè)時(shí)候我們就可以發(fā)布到 npm 了:
npm publish
如果你是私有包,可以這樣發(fā)布:
npm publish --access=public
結(jié)語(yǔ)
以后發(fā)布新版本的時(shí)候,只需要更改一下 package.json 里面的 version 版本號(hào),然后執(zhí)行 npm publish 和 npm run publish-demo 就可以同步 npm 和 demo。
不過(guò)如果想讓你的組件在社區(qū)里給更多人用,你需要把 README 寫(xiě)得更好一點(diǎn),然后添加好自動(dòng)化測(cè)試,不然別人不太敢用。
另外在寫(xiě)組件之前可以先了解下有沒(méi)有類(lèi)似的組件了,如果有就直接用吧,咱們就站在巨人的肩膀上,把自己寶貴的時(shí)間放在創(chuàng)造價(jià)值上。
最后整個(gè)項(xiàng)目的源代碼見(jiàn) github
參考文章
另外
同時(shí)你也可以在這些地方找到這篇文章:
另外有興趣可以關(guān)注我的公眾號(hào):前端桃園