自己书写一个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
?import?React?from?'react';
?import?{?render?}?from?'react-dom';
?import?ReactDemo?from?'../src';
?const?App?=?()?=>? ;
?render( ,?document.getElementById('root'));
?
????复制代码
index.html
?
?
???
?????
?????
?????
?????Document
???
???
?????
???
?
????复制代码
然后在src/index.jsx文件中 导出
?import?App1?from?'./App';
?export?default?App1;
????复制代码
## 二 配置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');
?const?cssLoaders?=?[
???'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:?no?test?specified\"?&&?exit?1",
??????"dev":?"export?NODE_ENV=development?&&?npx?webpack?serve?--config?config/webpack.dev.js",
??????"build":?"export?NODE_ENV=production?&&?npx?webpack???--config?config/webpack.prod.js",
??????"npm":?"export?NODE_ENV=production?&&?npx?webpack???--config?config/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":?[
????????"last?1?chrome?version",
????????"last?1?firefox?version",
????????"last?1?safari?version"
??????],
??????"production":?[
????????">0.2%",
????????"not?dead",
????????"not?op_mini?all"
??????]
????}
??}
??
??
??复制代码
三、发布
如果是第一次发布包,执行以下命令,然后输入前面注册好的NPM账号,密码和邮箱,将提示创建成功
??npm?adduser
??
??复制代码
如果不是第一次发布包,执行以下命令进行登录,同样输入NPM账号,密码和邮箱
??npm?login
??
??复制代码
注意:npm adduser成功的时候默认你已经登陆了,所以不需要再进行npm login了
接着先进入项目文件夹下,然后输入以下命令进行发布
??npm?publish
??
??复制代码
当终端显示如下面的信息时,就代表版本号为1.0.0(你的package.json中的版本号)的包发布成功啦!前往NPM官网就可以查到你的包
?+?你的文件名@0.1.0
?
??复制代码
四、报错
1、如果出现
??npm?ERR!?code?E403
??npm?ERR!?403?403?Forbidden?-?PUT?https://registry.npmjs.org/ghost-watermarkdemo?-?Forbidden
??npm?ERR!?403?In?most?cases,?you?or?one?of?your?dependencies?are?requesting
??npm?ERR!?403?a?package?version?that?is?forbidden?by?your?security?policy,?or
??npm?ERR!?403?on?a?server?you?do?not?have?access?to.
??复制代码
以下几种原因会导致
??账号密码错误???(请检查npm官网的账号密码)
??包重名?????(请检查npm官网上是否有同名项目,名字取决于?package.js?的项目名字段)
??网络原因???
??镜像源问题?
??新注册的用户邮箱未激活。??登陆你的邮箱去激活(如下)
???
??复制代码
image.png
2、 如果出现
image.png
需要在你的package.json中 private改为false或者删除
更新已经发布的包
更新包的操作和发布包的操作是一样的
???npm?publish
???
复制代码
但是每次更新时,必须修改版本号后才能更新,比如将1.0.0修改为1.0.1后才能更新发布。
这里的包版本管理规则都是一样的,采用的是semver(语义化版本),意思就是版本号:大改.中改.小改
五、## 从npm上面卸载自己发布的包
进入自己项目的目录执行。npm unpublish --force 出现:
???npm?WARN?using?--force?Recommended?protections?disabled.
-包名@0.1.0
复制代码
则卸载成功,这时在npm上面就搜索不到了
关于本文
来自:夏末海棠
https://juejin.cn/post/7072652104837365774