沒有發佈過npm包的同窗,可能會對NPM對開發有一種蜜汁敬畏,以爲這是一個很高大上的東西。甚至有次面試,面試官問我有沒有發過npm包,當時只用過還沒寫過,我想應該挺難的,就小聲說了沒有,而後就讓我回去了o(╯□╰)o。css
其實,在如今的我看來,npm包就是一個咱們平時常常寫的一個export出來的模塊而已,只不過跟其它業務代碼耦合性低,具備較高的獨立性。 固然,要發佈一個npm包,除了寫的模塊組件外,還須要作一些基礎的包裝工做。 下面我就以最近開發的react-loading組件爲例 源碼地址,若是對你有幫助的話但願不要吝嗇你的 Starhtml
本文主要記錄一下如何開發react組件(以react-loding爲例),並在 npm 上發佈。廢話很少說,進入正題node
在github上新建一個倉庫,名字能夠本身取。確保你建立的組件名稱沒有在 npm 上被使用過, 這裏咱們用 wsm-loading做爲示例。打開編輯器將項目拉到本身本地並初始化react
git clone https://github.com/xxx/wsm-loading.git
cd wsm-loading
npm init
複製代碼
運行npm init問題提示列表能夠根據本身的我的愛好填寫,也能夠採起默認的選項。webpack
我麼須要開發的是一個React的loading組件,因此咱們要先在項目中安裝react依賴git
npm i react react-dom -Des6
咱們的項目將經過webpack4進行構建,安裝項目所需的webpack依賴github
npm i webpack webpack-cli webpack-dev-server html-webpack-plugin style-loader css-loader babel-core babel-loader babel-preset-env babel-preset-react -Dweb
在項目中咱們常常會用到scss做爲css的編譯,所以咱們在安裝webpack面試
npm install sass sass-loader node-sass webpack -D
這時上面安裝的依賴已經被添加到根目錄下的 package.json中了,接下來咱們添加一個 start的腳本,用於啓動咱們本地開發的服務器, start以下:
{
"name": "wsm-loading",
"version": "0.0.1",
"description": "這是一個react-loading組件",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "webpack-dev-server --mode development",
},
複製代碼
如今讓在咱們的項目中建立組件和示例代碼目錄,目錄樹結構以下
├── examples // 示例代碼存放目錄
│ └── src
├── node_modules
├── package.json
└── src // 組件源代碼和樣式存放目錄
└── .babelrc // es6及jsx語法編譯
└── .gitignore // git提交管理
└── package-lock.json
└── package.json
└── webpack.config.js webpack配置
複製代碼
lodaing組件接收兩個props,一個size控制loading的大小,一個color控制loading的顏色
/*** src/index.js ***/
import React, { Component } from "react";
import "./index.scss";
export default class MyComponent extends Component {
render() {
const { color, size } = this.props;
const sizeStyle = {
width: `${size}px`,
height: `${size}px`
};
const colorStyle = {
border: `1px solid ${color}`,
borderColor: `${color} transparent transparent transparent`
};
const ringStyle = Object.assign({}, colorStyle, sizeStyle);
return (
<div className="loading" style={sizeStyle}>
<div className="loading__ring" style={ringStyle} />
<div className="loading__ring" style={ringStyle} />
<div className="loading__ring" style={ringStyle} />
</div>
);
}
}
MyComponent.defaultProps = {
size: '36',
color: '#000'
}
複製代碼
loading組件的樣式這裏就不給了,能夠直接從個人代碼庫中複製到你的項目裏css。
接下來咱們添加一個演示demo
<!-- examples/src/index.html -->
<html>
<head>
<title>My Component Demo</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/index.js ***/
import React from 'react';
import { render} from 'react-dom';
import MyComponent from '../../src';
const App = () => (
<MyComponent size='36' color='red' />
);
render(<App />, document.getElementById("root"));
複製代碼
以上就完成了一個基本的loading組件,可是咱們還有一個疑問,就是如今引入的loading是在類名爲root的元素之中,而一些被普遍使用的UI框架中的loading組件確實在body層,不管你在哪裏引入,這樣就能夠防止loading組件受到父組件的樣式的干擾。
咱們平時普通的組件的html結構如上圖,可見咱們的loading是嵌套在咱們的主體root元素中的。在仔細看下面這張圖。 想要實現這種效果,咱們必須得先了解React自帶的特性:Portals(傳送門)。這個特性是在16版本以後添加的。咱們哎src目錄下新建一個newPortal/newPortal.js文件
import React from 'react';
import ReactDOM from 'react-dom';
class NewPortal extends React.Component {
constructor(props) {
super(props)
this.node = document.createElement('div');
document.body.appendChild(this.node);
}
render() {
const { children } = this.props;
return ReactDOM.createPortal(
children,
this.node,
);
}
}
export default NewPortal
複製代碼
將其引入到咱們的loading組件中
import NewPortal from './newPortal/newPortal'
並對組件進行一層包裹
<NewPortal>
<div className="loading" style={sizeStyle}>
<div className="loading__ring" style={ringStyle} />
<div className="loading__ring" style={ringStyle} />
<div className="loading__ring" style={ringStyle} />
</div>
</NewPortal>
複製代碼
這裏做者是參考這篇文章對組件進行優化的。你們感興趣能夠去了解下。
接下來配置 webpack, 在項目根路徑下建立 webpack.config.js文件。關於webpack配置不太瞭解或不熟悉的能夠參考我以前之篇文章webpack詳細配置,這裏講不在一一講解。
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const htmlWebpackPlugin = new HtmlWebpackPlugin({
template: path.join(__dirname, "examples/src/index.html"),
filename: "./index.html"
});
module.exports = {
entry: path.join(__dirname, "examples/src/index.js"),
output: {
path: path.join(__dirname, "examples/dist"),
filename: "bundle.js"
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
use: "babel-loader",
exclude: /node_modules/
},
{
test: /\.css$/,
use: ["style-loader", "css-loader"]
},
{
test: /\.scss$/,
use: ["style-loader", "css-loader", "sass-loader"]
}
]
},
plugins: [htmlWebpackPlugin],
resolve: {
extensions: [".js", ".jsx"]
},
devServer: {
port: 3001
}
};
複製代碼
最後須要指定 Babel 須要對哪些文件進行編譯,毫無疑問 React 中使用的 JSX 文件須要被編譯,讓它轉換成被主流瀏覽器都支持的 ES5 ,通用的配置也很簡單,只須要添加一對 presets,在項目根目錄下添加文件.babelrc
{
"presets": ["env", "react"]
}
複製代碼
接下來運行 demo
npm start 啓動完成後打開瀏覽器輸入 http://localhost:3001,你將會在頁面上看到你寫的組件,你能夠修改你的代碼並保存,頁面將會自動刷新,咱們的開發環境已經處於監控模式
咱們要發佈被 babel 編譯且被壓縮後的版本,要讓沒有使用 babel 的項目也可以正常的使用,好比不能出現 JSX 語法。 首先須要安裝 babel cli
npm i babel-cli -D
如今咱們添加 transpile腳本,以便使用 Babel 編譯咱們的源代碼,同時拷貝一些靜態文件(如:css 文件)到目標打包目錄dist下 同時指定被編譯後的版本爲組件的主入口,更改後的 package.json以下
{
"name": "test",
"version": "1.0.0",
"description": "ceshi",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "webpack-dev-server --mode development",
"transpile": "babel src -d dist --copy-files"
},
複製代碼
嘗試編譯
npm run transpile
最後讓咱們在項目的根目錄下添加.npmignore文件,告訴 npm,咱們項目中哪些文件和文件夾是在發佈的包中被忽略掉的
# .npmignore
src
examples
.babelrc
.gitignore
webpack.config.js
複製代碼
發佈咱們的組件到 npm 上
npm publish
提交npm以前須要去npm上開通本身的帳號,並驗證郵箱,這樣才能正常的提交上去。在終端使用npm login登錄本身的信息
項目上傳到git以前,咱們須要配置下.gitignore,在項目的根目錄下添加.npmignore文件
# .gitignore
node_modules
dist
複製代碼
這樣咱們上傳時,不會上傳node_modules和dist的目錄
git add .
git commit -m 'react-loading組件'
git push
複製代碼
當咱們不停的陷於業務代碼的開發中,何不嘗抽出一點時間來作點本身喜歡作的事呢,好比將本身的業務組件抽出來作成一個npm,開源組件庫不只能夠提升本身還能接觸到原來接觸不到東西。這只是一個簡單的教程,但願能對你有所啓發。
感謝你的閱讀!