前言
从开始接触react也有差不多四个月时间了,用的频繁了之后,也越发的“默契”。最近在项目中要开发一些定制化组件,写了些组件想要集中的管理,就打算把组件放在npm上,在网上查找资料学习了下,下面就是通过npm发布自己的第一个React组件的实现过程
注册
npm的注册就跟我们注册微博等其他社交账号一样,基本都是输入邮箱、用户名等等信息,十分简单也不耗时
新建项目
在github上新建一个项目(这里不做过多赘述,相信使用过github的盆友应该会很熟悉),然后git clone下来之后进入到项目目录,执行npm init,按提示输入信息,主要有
- name:发布的名称
- version:版本号
- entry:入口文件
刚开始没填好没关系,后期也可以修改
具体封装实现
我在这个项目里面封装了一个react-hover-menu的组件
这是完成后的项目树:
配置package.json
npm相关信息
"name": "react-hover-menu",
"version": "1.0.3",
"description": "react hover or click menu component",
"main": "dist/bundle.js",
"files": [
"dist"
],
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack"
},
-
main: 这里是我们组件的入口文件。开发者在 import 我们的组件的时候会引入这里 export 的内容
-
files: 申明将要发布到 npm 的文件。如果省略掉这一项,所有文件包括源代码会被一起上传到 npm
-
scripts: 加入一个 build 指令来运行 webpack,此时运行的 webpack 是这个当前文件夹内安装的 webpack 而不是 global 的 webpack
依赖
"dependencies": {
"antd": "^3.10.5",
"prop-types": "^15.6.0",
"react": "^16.2.0",
"react-dom": "^16.6.1"
},
"devDependencies": {
"babel-core": "^6.26.3",
"babel-loader": "^7.1.2",
"babel-plugin-import": "^1.11.0",
"babel-preset-env": "^1.6.1",
"babel-preset-react": "^6.24.1",
"css-loader": "^0.28.11",
"less": "^3.8.1",
"less-loader": "^4.1.0",
"postcss-loader": "^3.0.0",
"react-hot-loader": "^4.3.12",
"react-scripts": "^1.1.0",
"style-loader": "^0.19.1",
"webpack": "^3.10.0",
"webpack-node-externals": "^1.6.0"
}
这些依赖是我这个组件需要用到的,具体依赖得根据具体项目需要添加
配置webpack(webpack.config.js)
-
通过babel准换JSX和ES6的代码
-
通过css-loader, sytle-loader 引入 css 到打包文件
-
通过exclude:/src/, css-loader对antd的样式做处理
-
通过style-loader,css-loader,postcss-loader,less-loader对less样式做处理
-
webpack-node-externals 可以避免把 node_modules 里面的依赖包引入打包文件
-
libraryTarget: "commonjs2" 使测试项目可以找到我们打包后的组件
const path = require('path')
const nodeExternals = require('webpack-node-externals')
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist'),
libraryTarget: 'commonjs2'
},
module: {
rules: [
{// 通过babel准换JSX和ES6的代码
test: /(\.jsx|\.js)$/,
loader: 'babel-loader',
exclude: /node_modules/,
query:
{
presets:["env", "react"],
plugins: [
[ "import",{libraryName: "antd", style: "css"}] // antd按需加载
]
}
},
{// CSS处理
test: /\.css$/,
loader: "style-loader!css-loader?modules",
exclude: /node_modules/,
},
{// antd样式处理
test:/\.css$/,
exclude:/src/,
use:[
{ loader: "style-loader",},
{
loader: "css-loader",
options:{
importLoaders:1
}
}
]
},
{// less样式处理
test: /\.less$/,
use:
[
"style-loader",
{
loader: 'css-loader',
options: {
sourceMap: 1,
modules:true
}
},
{
loader: "postcss-loader",
options: { // 如果没有options这个选项将会报错 No PostCSS Config found
plugins: (loader) => [
require('autoprefixer')(), //CSS浏览器兼容
]
}
},
{
loader: "less-loader",
options: {
modifyVars: {
'primary-color': '#1DA57A',
'link-color': '#1DA57A',
'border-radius-base': '2px',
},
javascriptEnabled: true,
}
}
]
},
]
},
externals: [nodeExternals()]
}
配置babel(.babelrc)
- transpile JSX and ES6 code
{
"presets": ["react","env"],
"plugins": ["react-hot-loader/babel",["import", { "libraryName": "antd", "libraryDirectory": "lib", "style": "css" }]],
"env": {
"production":{
"preset":["react-optimize"]
}
}
}
测试
完成上述步骤后我们就可以在src文件夹里面完成自己的组件,这个时候就可以打包并link让测试项目引入这个打包后的组件进行测试
npm run build
npm link (可能会提示需要管理员权限)
cd [test project folder]
npm link react-hover-menu
创建测试项目
在本地做一个测试项目按上述步骤引入组件就可以看到成果了
使用create-react-app 创建一个 react 项目,并 link 我们刚才完成的组件:
create-react-app demo-menu
cd demo-menu
npm link react-hover-menu
link之后我们就可以直接在页面中引入组件
import HoverMenu from 'react-hover-menu'
发布到NPM
首先先登录npm
npm login
然后发布组件到npm
npm publish
取消发布
npm unpublish
更改版本
更改 package.json 里面的版本号并重新发布
出现的问题
解决引入antd样式无效问题
刚开始配置的时候,发现了一个如果同时引入css modules和按需引入antd,antd样式无效的问题
官网给出的按需加载解决方案,需要先安装babel-plugin-import
- babel-loader的query/options字段加入
plugins: [
[ "import",{libraryName: "antd", style: "css"}] // antd按需加载
]
- webpack中plugins字段这样配置
module: {
rules: [
{// 通过babel准换JSX和ES6的代码
test: /(\.jsx|\.js)$/,
loader: 'babel-loader',
exclude: /node_modules/,
query:
{
presets:["env", "react"],
plugins: [
[ "import",{libraryName: "antd", style: "css"}] // antd按需加载
]
}
},
{// CSS处理
test: /\.css$/,
loader: "style-loader!css-loader?modules",
exclude: /node_modules/,
}
]
}
测试后发现还是不行
解决办法
如果同时需要使用antd和css modules,处理样式时,需要分别处理
webpack加入以下处理
{// CSS处理
test: /\.css$/,
loader: "style-loader!css-loader?modules",
exclude: /node_modules/,
},
{// antd样式处理
test:/\.css$/,
exclude:/src/,
use:[
{ loader: "style-loader",},
{
loader: "css-loader",
options:{
importLoaders:1
}
}
]
},
引入less
由于后期要修改ant上的样式,根据官网上给出的提示,必须加装less格式
继续在webpack加入以下处理
{// less样式处理
test: /\.less$/,
use:
[
"style-loader",
{
loader: 'css-loader',
options: {
sourceMap: 1,
modules:true
}
},
{
loader: "postcss-loader",
options: { // 如果没有options这个选项将会报错 No PostCSS Config found
plugins: (loader) => [
require('autoprefixer')(), //CSS浏览器兼容
]
}
},
{
loader: "less-loader",
options: {
modifyVars: {
'primary-color': '#1DA57A',
'link-color': '#1DA57A',
'border-radius-base': '2px',
},
javascriptEnabled: true,
}
}
]
},
好了,可以开森的npm组件了
Github Repo
查看我创建的前端React呼出菜单组件