雖說(shuō)現(xiàn)在市面上組件庫(kù)相當(dāng)多了,但是還有一些組件特定場(chǎng)景市面上沒(méi)有,公司內(nèi)部一些不同項(xiàng)目,有類似相同組件可以直接復(fù)用,避免重復(fù)造輪子,就可以直接制作一個(gè)npm包,下次直接使用。
注意:文中的每一步都很重要,都是踩過(guò)的坑
一、準(zhǔn)備前提
1、注冊(cè)npm賬號(hào)
地址:https://www.npmjs.com/signup
注意:注冊(cè)完后,記得驗(yàn)證你的郵件地址!一定!否則會(huì)在提交組件包的時(shí)候報(bào)403錯(cuò)誤,那是因?yàn)闆](méi)有驗(yàn)證你的郵箱。
二、創(chuàng)建空工程
1、創(chuàng)建新的文件夾
2、進(jìn)入該文件夾,使用cmd命令,npm進(jìn)入安裝項(xiàng)目流程
//安裝
npm init
3、對(duì)應(yīng)的字段:
package name: 組件包名稱,注意不能和npm上面已經(jīng)存在的同名
version: (1.0.0) 版本
description: 描述
entry point: (index.js) 入口文件,默認(rèn)為index
test command: (可以為空)
git repository: (可以為空)
keywords: (可以為空)
author: 作者
license: (ISC)
創(chuàng)建完成后,該目錄下會(huì)多一個(gè)package.json文件,內(nèi)容如下
上面截圖的文件可隨意修改,但是發(fā)布時(shí)候需遵守規(guī)則:
1、版本號(hào)必須每次都修改
2、名稱保持和上一次不變
三、安裝工程需要的依賴包
npm install react react-dom -D
npm install @babel/cli @babel/core @babel/plugin-syntax-jsx @babel/plugin-transform-runtime @babel/preset-env @babel/preset-react -D
npm install style-loader css-loader babel-loader less-loader less -D
npm install html-webpack-plugin webpack webpack-cli webpack-dev-server -D
上面的安裝依賴我把它分為4部分好理解:
1、react基礎(chǔ)部分,react依靠react、react-dom(vue的話可以自行查看需要啥)
react :react語(yǔ)法
react-dom:react和頁(yè)面的dom打交道依賴
2、編譯必須要的模塊
@babel/cli
@babel/core: 把開(kāi)發(fā)的nodejs編譯成前端可以運(yùn)行的js代碼
@babel/preset-react: 把react編譯成可執(zhí)行js
@babel/preset-env
@babel/plugin-transform-runtime
@babel/plugin-syntax-jsx
3、項(xiàng)目各種loader依賴
style-loader:處理 dom style 標(biāo)簽里面的css(處理行內(nèi)樣式)
css-loader:處理css樣式
less-loader :處理less樣式
less:less樣式依賴(樣式我用less,需要scss的同學(xué)自行安裝scss)
babel-loader:負(fù)責(zé)調(diào)用上面所有@babel的依賴模塊
4、webpack腳手架
webpack:webpack主程序 ,webpack-cli:webpack編譯工具腳手架
html-webpack-plugin: 插件,處理html的工具
webpack-dev-server: 編譯運(yùn)行工具,npm run start 實(shí)際調(diào)用的方法
其中 - D的意思是將依賴安裝到devDependencies這里,一般來(lái)會(huì)默認(rèn)安裝到dependencies字段里,區(qū)別是dependencies會(huì)在打包時(shí)候進(jìn)dist文件夾
有需要可以自行安裝自己要的依賴,上面幾個(gè)是我寫(xiě)組件必要的幾個(gè)依賴,因?yàn)槲覜](méi)有寫(xiě)對(duì)應(yīng)的依賴版本所以安裝時(shí)候會(huì)以最新版本安裝。
四、開(kāi)始配置工程
1、新建如下目錄結(jié)構(gòu)和文件
#目錄結(jié)構(gòu)如下
├── package.json 依賴包管理文件
├── .gitignore 上傳git時(shí)候忽略不傳的文件
├── public
├── index.html html靜態(tài)頁(yè)面
└── app.js webpack入口文件
└── src 組件包源碼文件夾
├── index.jsx
├── index.less
├── index.js 暴露你的組件入口文件,即引用組件包時(shí)的入口文件,文件名和package.json中main字段同名
├── webpack.config.js webpack配置文件
├── babel.config.js @babel的配置文件(webpack4版本的叫做.babelrc )

2、編寫(xiě)webpack.config.js的配置,以下是最基礎(chǔ)的配置
const path = require('path');
const HtmlWebpackPlugin = require("html-webpack-plugin");
/**
* webpack插件將打包好的文件注入到html模板里
* @type {HtmlWebpackPlugin}
*/
const htmlWebpackPlugin = new HtmlWebpackPlugin({
template: path.join(__dirname, "./public/index.html"),
filename: "./index.html"
});
module.exports = {
mode: 'development',
entry: path.join(__dirname, "./public/app.js"), //入口文件
output: {
path: path.resolve(__dirname, "dist"),
filename: "bundle.js"
},
module: {
rules: [{
test: /\.js$|.jsx/, //正則匹配文件名稱
use: "babel-loader", //會(huì)去調(diào)用babel.config.js里的所有babel的配置
exclude: /node_modules/
}, {
test: /\.css|l.ess$/,
use: ["style-loader", "css-loader", "less-loader"]
}]
},
plugins: [htmlWebpackPlugin], //插件:自動(dòng)注入編譯打包好的文件
resolve: {
extensions: [".js", ".jsx"]
},
devServer: {
port: 3001, //端口號(hào)
open: true, // 自動(dòng)打開(kāi)瀏覽器
compress: true, // 啟動(dòng)gzip壓縮
}
};
上面的less-loader沒(méi)有啟用lessmodules模塊化比較不好,假設(shè)現(xiàn)在項(xiàng)目有好幾個(gè)組件,那么模塊化就可以避免我們不同組件的樣式污染,如果不開(kāi)啟就不生效,如下例子:
// index.jsx文件
import './exp1.less'; //普通用法
import styles from './exp2.less'; //less module寫(xiě)法
<div className='box'>
<p className={styles.pf}>如果沒(méi)有啟用模塊化這種寫(xiě)法樣式將不生效,dom元素上不會(huì)有class樣式</p>
</div>
所以得將webpack.config.js修改如下:
const path = require('path');
const HtmlWebpackPlugin = require("html-webpack-plugin");
/**
* webpack插件將打包好的文件注入到html模板里
* @type {HtmlWebpackPlugin}
*/
const htmlWebpackPlugin = new HtmlWebpackPlugin({
template: path.join(__dirname, "./public/index.html"),
filename: "./index.html"
});
module.exports = {
mode: 'development', //這個(gè)值有3種:production、development、none
entry: path.join(__dirname, "./public/app.js"),
output: {
path: path.resolve(__dirname, "dist"),
filename: "bundle.js"
},
module: {
rules: [{
test: /\.js$|.jsx/,
use: "babel-loader",
exclude: /node_modules/
},
{
test: /\.css$/,
use: [
{loader: "style-loader"},
{loader: "css-loader"}], //打包處理css樣式表的第三方loader
}, {
//只為less啟用模塊化
test: /\.less$/,
use: [
{loader: "style-loader"},
{
loader: "css-loader", options: {
modules: {localIdentName: "[path][name]-[local]-[hash:5]"}
}
},
{loader: "less-loader"},
]
}]
},
plugins: [htmlWebpackPlugin], //插件:自動(dòng)注入編譯打包好的文件
resolve: {
extensions: [".js", ".jsx"]
},
devServer: {
port: 3001, //端口號(hào)
open: true, // 自動(dòng)打開(kāi)瀏覽器
compress: true, // 啟動(dòng)gzip壓縮
}
};
接下來(lái)往babel.config.js添加編譯時(shí)候需要的loader配置:
module.exports = {
"presets": ["@babel/preset-env", "@babel/preset-react"],
"plugins": ["@babel/plugin-syntax-jsx", "@babel/plugin-transform-runtime"]
}
3、編寫(xiě)組件
這個(gè)是核心部分,就是說(shuō)這里是你的組件
------------- ./src/index.jsx
import React, {Component, useState, memo} from 'react';
import styles from './index.less';
function Index() {
return <div className={styles.color}>
組件包測(cè)試
</div>
}
export default memo(Index);
------------- ./src/index.less
.color {
color: red;
}
4、對(duì)外暴露組件,編輯根目錄下的index.js文件
我這里叫Test,使用組件包引入時(shí)候就是Test組件。別人在引用組件包時(shí)候會(huì)從該文件作為入口(package.json的main字段可以配置),這個(gè)文件有兩種寫(xiě)法,第一種:
'use strict';
var Test = require('./src/index.jsx');
module.exports = Test;
第二種:
import Test from './src/index.jsx'
export default Test
5、編寫(xiě)webpack讀取的入口文件 public/app.js
webpack啟動(dòng)、編譯、打包都會(huì)從這個(gè)文件作為入口(webpack那邊配置的)
import React from 'react'
import {render} from 'react-dom'
import ReactDemo from '../src/index.jsx' //引入組件
const App = () => {
return <ReactDemo/>
// return <div>1111111111111</div>
};
render(<App/>, document.getElementById('root')); //獲取虛擬dom的掛載節(jié)點(diǎn)
6、編寫(xiě)html模板,public/index.html文件。
我們知道spa單頁(yè)面都是依據(jù)一個(gè)html模板上面引入js創(chuàng)建虛擬dom生成到這個(gè)html上面,所以需要有一個(gè)掛載的實(shí)例模板。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>第一個(gè)組件包</title>
</head>
<body>
<div id="root"></div>
</body>
</html>
7、編寫(xiě).gitignore文件
這個(gè)文件可以配置git上傳時(shí)候忽略哪些文件不想傳上去,同時(shí)發(fā)布組件包的時(shí)候它也會(huì)按照這個(gè)文件來(lái),忽略哪些不上傳。
# Created by .ignore support plugin (hsz.mobi)
node_modules/
dist/
8、添加項(xiàng)目啟動(dòng)命令:修改package.json文件
給該文件的scripts里添加兩個(gè)系統(tǒng)命令,一個(gè)是啟動(dòng)命令,一個(gè)是打包命令(制作組件包用的比較少)。注意webpack4的版本可能不是 webpack server --mode development,這個(gè)需要自己對(duì)應(yīng)版本。
"scripts": {
"start": "webpack server --mode development",
"build": "webpack --mode development"
},
接下來(lái)本地啟動(dòng)試下看下效果,命令:npm run start ,如果啟動(dòng)時(shí)候報(bào)錯(cuò):[webpack-cli] ReferenceError: BigInt is not defined
說(shuō)明是node版本問(wèn)題,需要安裝高點(diǎn)版本的node,可以使用nvm來(lái)管理node版本,這里不多說(shuō),我切換為node 12.0.0版本就可以。

五、發(fā)布
到此為止,我們已經(jīng)配置好了工程,接下來(lái)需要把組件包發(fā)布上去
1、發(fā)布規(guī)則
1、組件包名稱不能與npm上已經(jīng)存在的一致,必須唯一性
2、每次發(fā)布必須修改版本號(hào)
3、發(fā)布的源必須是npm,有的設(shè)置了淘寶或者其他源,需要設(shè)置回npm源。
例如你是淘寶源你需要:
查看設(shè)置過(guò)的所有的源:npm config get registry
設(shè)置當(dāng)前源為npm:npm config set registry https://registry.npmjs.org/
發(fā)布完成后設(shè)置回淘寶源:npm config set registry https://registry.npm.taobao.org
2、發(fā)布流程
1、登錄注冊(cè)好的npm賬號(hào):npm login
輸入對(duì)應(yīng)的賬號(hào)、密碼、郵箱即可

2、發(fā)布上去:npm publish
沒(méi)有報(bào)錯(cuò)則表示成功