如何写npm通用插件(教你写第一个NPM包惊艳其他人)
如何写npm通用插件(教你写第一个NPM包惊艳其他人)如果是第一次发布包,执行以下命令,然后输入前面注册好的NPM账号,密码和邮箱,将提示创建成功{ "name":"new_webpack_action2" "version":"1.0.24" "m":"" "main":"dist/index.js" "private":false "flies":[ "dist" ] "scripts":{ "test":"echo\"Error:notestspecified\"&&exit1" "dev":"exportNODE_ENV=development&
自己书写一个npm包并发布到npm上面说到npm包都会给人一种特别高大上的感觉,并且自己写了一个包之后如果有人用那么就会产生莫大的成就感,程序员的快乐就是这么简单。
想必有产生写npm包想法的人都对模块化比较熟悉,并且对于react、vue两者之一都比较熟练了。
下面呢我们就是使用react来写一个自己的npm包,我们呢会使用自己封装的webpack脚手架来写,如果有兴趣同学可以来看一下我的自我沉淀webpack5 react eslint tslint[1]文章。接下来的内容呢也是基于此来说明的。
这里也有现成的脚手架[2]
一、不同点
npm包的目录结构和普通的脚手架结构有所不同
- 启动目录不同:以往我们习惯将entry文件写在src中,但是npm包的入口文件不能写在src中,因为npm是将我们的源代码打包,不可以包括html。所以将index.jsx和index.html文件提取到example文件中。【注意】example文件要和src同级。结构和内容如下index.jsx
 
importReactfrom'react';
import{render}from'react-dom';
importReactDemofrom'../src';
constApp=()=><ReactDemo/>;
render(<App/> document.getElementById('root'));
复制代码
    
index.html
    
<!DOCTYPEhtml>
<htmllang="en">
<head>
<metacharset="UTF-8"/>
<metahttp-equiv="X-UA-Compatible"content="IE=edge"/>
<metaname="viewport"content="width=device-width initial-scale=1.0"/>
<title>Document</title>
</head>
<body>
<divid="root"></div>
</body>
</html>
复制代码
    
然后在src/index.jsx文件中 导出
    
importApp1from'./App';
exportdefaultApp1;
复制代码
    
## 二 配置npm包的打包运行文件
在 config文件夹中新建webpack.npm.js文件
配置文件内容差不多。如下:详细配置请移步 [自我沉淀webpack5 react eslint tslint](https://juejin.cn/post/7002157698108096543 "https://juejin.cn/post/7002157698108096543")
externals划重点:这个可以告诉npm打包的时候不许将下面几种东西打包进去哦。
    
const{resolve}=require('path');
constcssLoaders=[
'style-loader' 
{
loader:'css-loader' 
options:{
importLoaders:1 
modules:{
auto:(resourcePath)=>resourcePath.endsWith('.less') 
localIdentName:'[local]_[hash:base64:10]' 
} 
} 
} 
{
loader:'postcss-loader' 
options:{
postcssOptions:{
plugins:[['autoprefixer'] require('postcss-preset-env')()] 
} 
} 
} 
];
module.exports={
entry:'./src/index.tsx' 
mode:process.env.NODE_ENV 
externals:{
antd:'antd' 
react:'React' 
} 
output:{
libraryTarget:'umd' 
filename:'index.js' 
path:resolve(resolve(__dirname '..') 'dist') 
clean:true 
} 
resolve:{
alias:{
'@':resolve(resolve(__dirname '..') 'src/') 
} 
extensions:['.ts' '.tsx' '.js' '.jsx' '.json'] 
mainFiles:['index'] 
} 
devServer:{
hot:true 
port:3002 
host:'127.0.0.1' 
compress:true 
open:true 
proxy:{
'/api':{
target:'http://127.0.0.1:3002' 
pathRewrite:{'^/api':''} 
secure:false 
} 
} 
} 
module:{
rules:[
{
test:/\.(js|jsx)$/ 
include:resolve(resolve(__dirname '..') '') 
exclude:/node_modules/ 
enforce:'pre' 
use:[
{
loader:'babel-loader' 
options:{
presets:['@babel/preset-env' '@babel/preset-react'] 
//缓存:第二次构建时,会读取之前的缓存
cacheDirectory:true 
} 
} 
] 
} 
{
test:/\.tsx$/ 
loader:'ts-loader' 
exclude:/node_modules/ 
} 
{
test:/\.css$/ 
use:[...cssLoaders] 
} 
{
test:/\.less$/ 
use:[...cssLoaders 'less-loader'] 
} 
{
test:/\.s[ac]ss$/ 
use:[...cssLoaders 'sass-loader'] 
} 
{
exclude:/.(html|less|css|sass|js|jsx|ts|tsx)$/ 
test:/\.(jpg|jpe|png|gif)$/ 
loader:'file-loader' 
options:{
name:'imgs/[name].[ext]' 
outputPath:'other' 
} 
} 
{
test:/\.(ect|ttf|svg|woff)$/ 
use:{
loader:'file-loader' 
options:{
name:'icon/[name].[ext]' 
} 
} 
} 
] 
} 
};
复制代码
    
下面着重说一下package.json中的内容
- name: 包名,后续在npm中搜索全靠它
 - version:版本号,每发布一次npm包就要增加一个版本,每个版本不能重复。
 - description:描述
 - main: 本包向外暴露的文件,很重要,一定要和你打包出来的文件名一模一样,我的叫做"dist/index.js"
 - private: true/false 是否为私有。一般为false否则只有自己能使用
 - flies: 暴露的文件夹 有哪些文件夹提交到npm上面 格式为[ "dist" ]
 - keywords: npm检索的关键字
 - author: 作者
 - license: ISC
 - peerDependencies: 代表着当前npm包依赖下面这几种环境。
 
- 完整配置
 
{
"name":"new_webpack_action2" 
"version":"1.0.24" 
"m":"" 
"main":"dist/index.js" 
"private":false 
"flies":[
"dist"
] 
"scripts":{
"test":"echo\"Error:notestspecified\"&&exit1" 
"dev":"exportNODE_ENV=development&&npxwebpackserve--configconfig/webpack.dev.js" 
"build":"exportNODE_ENV=production&&npxwebpack--configconfig/webpack.prod.js" 
"npm":"exportNODE_ENV=production&&npxwebpack--configconfig/webpack.npm.js"
} 
"keywords":[
"react" 
"javascript" 
"npm"
] 
"author":"919022572@qq.com" 
"license":"ISC" 
"devDependencies":{
"@ant-design/icons":"4.7.0" 
"@babel/core":"^7.15.0" 
"@babel/preset-env":"^7.15.0" 
"@babel/preset-react":"^7.14.5" 
"@types/lodash":"^4.14.178" 
"@types/react":"^17.0.19" 
"@types/react-dom":"^17.0.11" 
"@types/react-router-dom":"^5.3.3" 
"@typescript-eslint/eslint-plugin":"^5.11.0" 
"@typescript-eslint/parser":"^5.11.0" 
"autoprefixer":"^10.3.2" 
"babel-loader":"^8.2.2" 
"babel-plugin-import":"^1.13.3" 
"css-loader":"^6.2.0" 
"css-minimizer-webpack-plugin":"^3.0.2" 
"eslint":"^8.8.0" 
"eslint-config-airbnb":"^19.0.4" 
"eslint-plugin-import":"^2.25.4" 
"eslint-plugin-jsx-a11y":"^6.5.1" 
"eslint-plugin-react":"^7.28.0" 
"eslint-plugin-react-hooks":"^4.3.0" 
"eslint-webpack-plugin":"^3.1.1" 
"file-loader":"^6.2.0" 
"html-webpack-externals-plugin":"^3.8.0" 
"html-webpack-plugin":"^5.5.0" 
"less":"^4.1.1" 
"less-loader":"^10.0.1" 
"lodash":"^4.17.21" 
"mini-css-extract-plugin":"^2.2.0" 
"postcss-loader":"^6.1.1" 
"postcss-preset-env":"^7.4.2" 
"sass":"^1.38.0" 
"sass-loader":"^12.1.0" 
"speed-measure-webpack-plugin":"^1.5.0" 
"style-loader":"^3.2.1" 
"stylelint":"^13.13.1" 
"stylelint-config-standard":"^22.0.0" 
"terser-webpack-plugin":"^5.1.4" 
"thread-loader":"^3.0.4" 
"ts-loader":"^9.2.5" 
"tslint":"^6.1.3" 
"typescript":"^4.5.5" 
"webpack":"^5.68.0" 
"webpack-cli":"^4.8.0" 
"webpack-dev-server":"^4.0.0" 
"webpack-merge":"^5.8.0" 
"workbox-webpack-plugin":"^6.4.2"
} 
"dependencies":{
"antd":"4.18.8" 
"axios":"^0.26.0" 
"react":"17.0.2" 
"react-dom":"17.0.2" 
"react-router-dom":"5.2.0"
} 
"peerDependencies":{
"@ant-design/icons":"4.7.0" 
"antd":"4.18.8" 
"bizcharts":"4.1.15" 
"rc-footer":"0.6.6" 
"react":"17.0.2" 
"react-dom":"17.0.2" 
"react-router-dom":"5.2.0"
} 
"browserslist":{
"development":[
"last1chromeversion" 
"last1firefoxversion" 
"last1safariversion"
] 
"production":[
">0.2%" 
"notdead" 
"notop_miniall"
]
}
}
复制代码
    
三、发布
如果是第一次发布包,执行以下命令,然后输入前面注册好的NPM账号,密码和邮箱,将提示创建成功
npmadduser
复制代码
    
如果不是第一次发布包,执行以下命令进行登录,同样输入NPM账号,密码和邮箱
npmlogin
复制代码
    
注意:npm adduser成功的时候默认你已经登陆了,所以不需要再进行npm login了
接着先进入项目文件夹下,然后输入以下命令进行发布
npmpublish
复制代码
    
当终端显示如下面的信息时,就代表版本号为1.0.0(你的package.json中的版本号)的包发布成功啦!前往NPM官网就可以查到你的包
 你的文件名@0.1.0
复制代码
    
四、报错
1、如果出现
npmERR!codeE403
npmERR!403403Forbidden-PUThttps://registry.npmjs.org/ghost-watermarkdemo-Forbidden
npmERR!403Inmostcases youoroneofyourdependenciesarerequesting
npmERR!403apackageversionthatisforbiddenbyyoursecuritypolicy or
npmERR!403onaserveryoudonothaveaccessto.
复制代码
    
以下几种原因会导致
账号密码错误(请检查npm官网的账号密码)
包重名(请检查npm官网上是否有同名项目,名字取决于package.js的项目名字段)
网络原因
镜像源问题
新注册的用户邮箱未激活。登陆你的邮箱去激活(如下)
复制代码
    

image.png
2、 如果出现

image.png
需要在你的package.json中 private改为false或者删除
更新已经发布的包
更新包的操作和发布包的操作是一样的
npmpublish
复制代码
    
但是每次更新时,必须修改版本号后才能更新,比如将1.0.0修改为1.0.1后才能更新发布。
这里的包版本管理规则都是一样的,采用的是semver(语义化版本),意思就是版本号:大改.中改.小改
五、## 从npm上面卸载自己发布的包
进入自己项目的目录执行。npm unpublish --force 出现:
npmWARNusing--forceRecommendedprotectionsdisabled.
-包名@0.1.0
复制代码
    
则卸载成功,这时在npm上面就搜索不到了
关于本文
来自:夏末海棠
https://juejin.cn/post/7072652104837365774




