自己书写一个npm包并发布到npm上面
说到npm包都会给人一种特别高大上的感觉,并且自己写了一个包之后如果有人用那么就会产生莫大的成就感,程序员的快乐就是这么简单。
想必有产生写npm包想法的人都对模块化比较熟悉,并且对于react、vue两者之一都比较熟练了。
下面呢我们就是使用react来写一个自己的npm包,我们呢会使用自己封装的webpack脚手架来写,如果有兴趣同学可以来看一下我的自我沉淀webpack5+react+eslint+tslint文章。 接下来的内容呢也是基于此来说明的。
这里也有现成的脚手架
一、不同点
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 = () => <ReactDemo />; render(<App />, document.getElementById('root'));
index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Document</title> </head> <body> <div id="root"></div> </body> </html>
然后在src/index.jsx文件中 导出
import App1 from './App'; export default App1;
二 配置npm包的打包运行文件
在 config文件夹中新建webpack.npm.js文件
配置文件内容差不多。 如下: 详细配置请移步 自我沉淀webpack5+react+eslint+tslint
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 的项目名字段) 网络原因 镜像源问题 新注册的用户邮箱未激活。 登陆你的邮箱去激活(如下)
2、 如果出现
需要在你的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上面就搜索不到了