2202 年ですが、まだ npm パッケージの公開方法を知らない人はいますか?次の記事では、npm を最初から作成して公開するプロセス全体を説明します。
記事は 4 月に公開されました。ぜひ、プロジェクトの axios パッケージをアップグレードしてください。繰り返しのリクエスト別れを告げる 、通常のリクエストとカスタム リクエストをサポートするために axios の二次カプセル化を導入し、同じリクエストを同じ時間内にインターセプトします (この記事をまだ読んでいない場合は、 3分程度で大まかに理解できます。)たまたま最近、クロスフレームワーク コンポーネント ライブラリを作成する準備をしています (作業負荷が非常に重いので、フロントエンドの友人 3 人が空き時間に取り組んでいます。コンポーネント ライブラリの作成後に全員と共有する予定です) npm パッケージの公開方法を学ぶ必要があります。昨日、コードの再利用を促進し、コードの再利用を容易にするために、以前に作成した axios パッケージを npm パッケージとして削除し、自由な時間を使って公開することを考えました。コミュニティに貢献しながら学びました。
この記事を読むと、次のことがわかります:
npm を最初から作成して公開するプロセス全体。 [推奨される関連チュートリアル: nodejs ビデオ チュートリアル 、プログラミング教育 ]
継続的に反復可能なシンプルで実用的な axios リクエスト重複排除ツール ライブラリ。
package.jsonを含む新しいプロジェクトを作成します
{ "name": "drrq", "type": "module", "version": "1.0.0" }
npm i qs axios
主なアイデアは、リクエストされた URL とパラメーターをキーとして使用してリクエスト キューを記録することです。リクエストが繰り返されると、後続のリクエストは中断され、前のリクエストの結果が返されて共有されます。後続のリクエストも同様です。
import qs from "qs"; import axios from "axios"; let pending = []; //用于存储每个ajax请求的取消函数和ajax标识 let task = {}; //用于存储每个ajax请求的处理函数,通过请求结果调用,以ajax标识为key //请求开始前推入pending const pushPending = (item) => { pending.push(item); }; //请求完成后取消该请求,从列表删除 const removePending = (key) => { for (let p in pending) { if (pending[p].key === key) { //当前请求在列表中存在时 pending[p].cancelToken(); //执行取消操作 pending.splice(p, 1); //把这条记录从列表中移除 } } }; //请求前判断是否已存在该请求 const existInPending = (key) => { return pending.some((e) => e.key === key); }; // 创建task const createTask = (key, resolve) => { let callback = (response) => { resolve(response.data); }; if (!task[key]) task[key] = []; task[key].push(callback); }; // 处理task const handleTask = (key, response) => { for (let i = 0; task[key] && i < task[key].length; i++) { task[key][i](response); } task[key] = undefined; }; const getHeaders = { 'Content-Type': 'application/json' }; const postHeaders = { 'Content-Type': 'application/x-www-form-urlencoded' }; const fileHeaders = { 'Content-Type': 'multipart/form-data' }; const request = (method, url, params, headers, preventRepeat = true, uploadFile = false) => { let key = url + '?' + qs.stringify(params); return new Promise((resolve, reject) => { const instance = axios.create({ baseURL: url, headers, timeout: 30 * 1000, }); instance.interceptors.request.use( (config) => { if (preventRepeat) { config.cancelToken = new axios.CancelToken((cancelToken) => { // 判断是否存在请求中的当前请求 如果有取消当前请求 if (existInPending(key)) { cancelToken(); } else { pushPending({ key, cancelToken }); } }); } return config; }, (err) => { return Promise.reject(err); } ); instance.interceptors.response.use( (response) => { if (preventRepeat) { removePending(key); } return response; }, (error) => { return Promise.reject(error); } ); // 请求执行前加入task createTask(key, resolve); instance(Object.assign({}, { method }, method === 'post' || method === 'put' ? { data: !uploadFile ? qs.stringify(params) : params } : { params })) .then((response) => { // 处理task handleTask(key, response); }) .catch(() => {}); }); }; export const get = (url, data = {}, preventRepeat = true) => { return request('get', url, data, getHeaders, preventRepeat, false); }; export const post = (url, data = {}, preventRepeat = true) => { return request('post', url, data, postHeaders, preventRepeat, false); }; export const file = (url, data = {}, preventRepeat = true) => { return request('post', url, data, fileHeaders, preventRepeat, true); }; export default { request, get, post, file };
サンプル エントリindex.js
import { exampleRequestGet } from './api.js'; const example = async () => { let res = await exampleRequestGet(); console.log('请求成功 '); }; example();
api list api.js
import { request } from './request.js'; // 示例请求Get export const exampleRequestGet = (data) => request('get', '/xxxx', data); // 示例请求Post export const exampleRequestPost = (data) => request('post', '/xxxx', data); // 示例请求Post 不去重 export const exampleRequestPost2 = (data) => request('post', '/xxxx', data, false); // 示例请求Post 不去重 export const exampleRequestFile = (data) => request('file', '/xxxx', data, false);
グローバル リクエストのカプセル化リクエスト.js
import drrq from '../src/index.js'; const baseURL = 'https://xxx'; // 处理请求数据 (拼接url,data添加token等) 请根据实际情况调整 const paramsHandler = (url, data) => { url = baseURL + url; data.token = 'xxxx'; return { url, data }; }; // 处理全局接口返回的全局处理相关逻辑 请根据实际情况调整 const resHandler = (res) => { // TODO 未授权跳转登录,状态码异常报错等 return res; }; export const request = async (method, _url, _data = {}, preventRepeat = true) => { let { url, data } = paramsHandler(_url, _data); let res = null; if (method == 'get' || method == 'GET' || method == 'Get') { res = await drrq.get(url, data, preventRepeat); } if (method == 'post' || method == 'POST' || method == 'Post') { res = await drrq.post(url, data, preventRepeat); } if (method == 'file' || method == 'FILE' || method == 'file') { res = await drrq.file(url, data, preventRepeat); } return resHandler(res); };
コードを書いたら関数が正常か検証する必要があるので、package.jsonに
"scripts": { "test": "node example" },
を追加してnpm run test
を実行します。
機能は正常で、ツール ライブラリは準備完了です。
(eslint と prettier の読者は状況に応じて選択できます)
通常、プロジェクトのパッケージ化には webpack が使用され、ツール ライブラリのパッケージ化には rollup が使用されます。
次のコマンドでインストールしますRollup:
npm install --save-dev rollup
構成ファイルの作成
Createルート ディレクトリの新しいファイル rollup.config.js
export default { input: "src/index.js", output: { file: "dist/drrp.js", format: "esm", name: 'drrp' } };
開発に es6 構文を使用する場合はインストールしますまた、babel を使用してコードを es5 にコンパイルする必要があります。ロールアップのモジュール機構は ES6 モジュールであるため、他の es6 構文はコンパイルされません。
rollup-plugin-babel rollup と babel を完全に組み合わせます。
npm install --save-dev rollup-plugin-babel@latest npm install --save-dev @babel/core npm install --save-dev @babel/preset-env
ルート ディレクトリに .babelrc を作成します
{ "presets": [ [ "@babel/preset-env", { "modules": false } ] ] }
rollup はプラグインを提供します rollup-plugin-commonjs ロールアップの commonjs 仕様パッケージを参照するため。このプラグインの機能は、commonjs モジュールを es6 モジュールに変換することです。
rollup-plugin-commonjs は通常、依存モジュールのパスを解決するために使用される rollup-plugin-node-resolve と一緒に使用されます。
モジュールのインストール
npm install --save-dev rollup-plugin-commonjs rollup-plugin-node-resolve
コメントを削除し、変数名を短縮し、コードを再編成することで、UglifyJS の追加を大幅に改善できます。バンドルのサイズ - これにより、コードの可読性がある程度低下しますが、ネットワーク通信はより効率的になります。
プラグインのインストール
次のコマンドを使用して、rollup-plugin-uglify:
をインストールします。npm install --save-dev rollup-plugin-uglify
rollup.config.js 最终配置如下
import resolve from 'rollup-plugin-node-resolve'; import commonjs from 'rollup-plugin-commonjs'; import babel from 'rollup-plugin-babel'; import { uglify } from 'rollup-plugin-uglify'; import json from '@rollup/plugin-json' const paths = { input: { root: 'src/index.js', }, output: { root: 'dist/', }, }; const fileName = `drrq.js`; export default { input: `${paths.input.root}`, output: { file: `${paths.output.root}${fileName}`, format: 'esm', name: 'drrq', }, plugins: [ json(), resolve(), commonjs(), babel({ exclude: 'node_modules/**', runtimeHelpers: true, }), uglify(), ], };
在package.json中加上
"scripts": { "build": "rollup -c" },
即可执行npm run build将/src/index.js打包为/dist/drrq.js
准备npm账号,通过npm login或npm adduser。这里有一个坑,终端内连接不上npm源,需要在上网工具内复制终端代理命令后到终端执行才能正常连接。
完整的package.json如下
{ "name": "drrq", "private": false, "version": "1.3.5", "main": "/dist/drrq.js", "repository": "https://gitee.com/yuanying-11/drrq.git", "author": "it_yuanying", "license": "MIT", "description": "能自动取消重复请求的axios封装", "type": "module", "keywords": [ "取消重复请求", ], "dependencies": { "axios": "^1.2.0", "qs": "^6.11.0" }, "scripts": { "test": "node example", "build": "rollup -c" }, "devDependencies": { ... } }
每个 npm 包都需要一个版本,以便开发人员在安全地更新包版本的同时不会破坏其余的代码。npm 使用的版本系统被叫做 SemVer,是 Semantic Versioning 的缩写。
不要过分担心理解不了相较复杂的版本名称,下面是他们对基本版本命名的总结: 给定版本号 MAJOR.MINOR.PATCH,增量规则如下:
MAJOR 版本号的变更说明新版本产生了不兼容低版本的 API 等,
MINOR 版本号的变更说明你在以向后兼容的方式添加功能,接下来
PATCH 版本号的变更说明你在新版本中做了向后兼容的 bug 修复。
表示预发布和构建元数据的附加标签可作为 MAJOR.MINOR.PATCH 格式的扩展。
最后,执行npm publish就搞定啦
本文的完整代码已开源至gitee.com/yuanying-11… ,感兴趣的读者欢迎fork和star!
转载地址:https://juejin.cn/post/7172240485778456606
更多node相关知识,请访问:nodejs 教程!
以上がnpm パッケージを最初から作成して公開する手順を段階的に説明します。の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。