自己书写一个npm包并发布到npm上面

说到npm包都会给人一种特别高大上的感觉,并且自己写了一个包之后如果有人用那么就会产生莫大的成就感,程序员的快乐就是这么简单。

想必有产生写npm包想法的人都对模块化比较熟悉,并且对于react、vue两者之一都比较熟练了。

下面呢我们就是使用react来写一个自己的npm包,我们呢会使用自己封装的webpack脚手架来写,如果有兴趣同学可以来看一下我的自我沉淀webpack5 react eslint tslint[1]文章。接下来的内容呢也是基于此来说明的。

这里也有现成的脚手架[2]

一、不同点

npm包的目录结构和普通的脚手架结构有所不同

  1. 启动目录不同:以往我们习惯将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":"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的项目名字段) 网络原因 镜像源问题 新注册的用户邮箱未激活。登陆你的邮箱去激活(如下) 复制代码

最流行的npm(教你写第一个NPM包惊艳其他人)(1)

image.png

2、 如果出现

最流行的npm(教你写第一个NPM包惊艳其他人)(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

,