Maison > interface Web > js tutoriel > le corps du texte

Vous guide étape par étape pour créer et publier des packages npm à partir de zéro

青灯夜游
Libérer: 2022-12-08 20:26:57
avant
2757 Les gens l'ont consulté

Nous sommes en 2202, y a-t-il quelqu'un qui ne sait toujours pas comment publier des packages npm ? L'article suivant partagera avec vous tout le processus de création et de publication de npm à partir de zéro. J'espère qu'il vous sera utile !

Vous guide étape par étape pour créer et publier des packages npm à partir de zéro

Contexte

Un article a été publié en avril Venez mettre à niveau le package axios dans votre projet et dites adieu aux requêtes répétées Il a introduit le package secondaire d'axios pour prendre en charge les requêtes régulières et les requêtes automatiques. Définissez la requête et interceptez la même requête dans le même temps(Si vous n'avez pas lu cet article, il est recommandé de passer 3 minutes pour le comprendre grossièrement). Il se trouve que je me prépare récemment à écrire une bibliothèque de composants multi-framework (la charge de travail est très lourde et les trois amis front-end y travaillent pendant leur temps libre. Ils la partageront avec tout le monde après la bibliothèque de composants est terminé, alors restez à l'écoute). J'ai besoin d'apprendre à publier des packages npm. Hier, j'ai pensé à utiliser mon temps libre pour publier le package axios que j'ai écrit auparavant pour supprimer les demandes en double en tant que package npm afin de faciliter la réutilisation du code et d'appliquer ce que j'ai écrit. appris tout en redonnant à la communauté.

Lisez cet article, vous gagnerez :

  • L'ensemble du processus de création et de publication de npm à partir de zéro. [Tutoriels associés recommandés : Tutoriel vidéo Nodejs, Enseignement de la programmation]

  • Une bibliothèque d'outils de déduplication de requêtes axios continuellement itérative, simple et pratique.

Préparation de la bibliothèque d'outils

Créez un nouveau projet, y compris package.json

{
    "name": "drrq",
    "type": "module",
    "version": "1.0.0"
}
Copier après la connexion

Function Implementation/src/index.js

npm i qs axios

L'idée principale est d'utiliser l'URL et les paramètres demandés comme clé pour enregistrer la file d'attente des demandes, lorsqu'une demande répétée se produit, la demande suivante est interrompue et le résultat de la demande précédente est partagé avec la demande suivante lorsqu'il est renvoyé.

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 = { &#39;Content-Type&#39;: &#39;application/json&#39; };
const postHeaders = { &#39;Content-Type&#39;: &#39;application/x-www-form-urlencoded&#39; };
const fileHeaders = { &#39;Content-Type&#39;: &#39;multipart/form-data&#39; };

const request = (method, url, params, headers, preventRepeat = true, uploadFile = false) => {
    let key = url + &#39;?&#39; + 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 === &#39;post&#39; || method === &#39;put&#39; ? { data: !uploadFile ? qs.stringify(params) : params } : { params }))
            .then((response) => {
                // 处理task
                handleTask(key, response);
            })
            .catch(() => {});
    });
};

export const get = (url, data = {}, preventRepeat = true) => {
    return request(&#39;get&#39;, url, data, getHeaders, preventRepeat, false);
};
 export const post = (url, data = {}, preventRepeat = true) => {
     return request(&#39;post&#39;, url, data, postHeaders, preventRepeat, false);
 };
 export const file = (url, data = {}, preventRepeat = true) => {
     return request(&#39;post&#39;, url, data, fileHeaders, preventRepeat, true);
 };
export default { request, get, post, file };
Copier après la connexion

Nouvel exemple de dossier/exemple de code

Exemple d'entrée index.js

import { exampleRequestGet } from &#39;./api.js&#39;;
const example = async () => {
    let res = await exampleRequestGet();
    console.log(&#39;请求成功 &#39;);
};
example();
Copier après la connexion

Liste d'api api.js

import { request } from &#39;./request.js&#39;;
// 示例请求Get
export const exampleRequestGet = (data) => request(&#39;get&#39;, &#39;/xxxx&#39;, data);

// 示例请求Post
export const exampleRequestPost = (data) => request(&#39;post&#39;, &#39;/xxxx&#39;, data);

// 示例请求Post 不去重
export const exampleRequestPost2 = (data) => request(&#39;post&#39;, &#39;/xxxx&#39;, data, false);

// 示例请求Post 不去重
export const exampleRequestFile = (data) => request(&#39;file&#39;, &#39;/xxxx&#39;, data, false);
Copier après la connexion

Requête d'encapsulation de requête globale.js

import drrq from &#39;../src/index.js&#39;;
const baseURL = &#39;https://xxx&#39;;

// 处理请求数据  (拼接url,data添加token等) 请根据实际情况调整
const paramsHandler = (url, data) => {
    url = baseURL + url;
    data.token = &#39;xxxx&#39;;
    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 == &#39;get&#39; || method == &#39;GET&#39; || method == &#39;Get&#39;) {
        res = await drrq.get(url, data, preventRepeat);
    }
    if (method == &#39;post&#39; || method == &#39;POST&#39; || method == &#39;Post&#39;) {
        res = await drrq.post(url, data, preventRepeat);
    }
    if (method == &#39;file&#39; || method == &#39;FILE&#39; || method == &#39;file&#39;) {
        res = await drrq.file(url, data, preventRepeat);
    }
    return resHandler(res);
};
Copier après la connexion

Fonction de test

Une fois le code écrit, nous devons vérifier La fonction est-elle normale ? Ajoutez

    "scripts": {
        "test": "node example"
    },
Copier après la connexion

à package.json et exécutez npm run test

Vous guide étape par étape pour créer et publier des packages npm à partir de zéro

La fonction est normale et la bibliothèque d'outils est prête.

(les lecteurs d'Eslint et les plus jolis peuvent choisir en fonction de la situation)

Emballage

L'emballage général du projet utilise webpack, tandis que l'emballage de la bibliothèque d'outils utilise rollup

Installez Rollup

Installez via la commande suivanteRollup:

npm install --save-dev rollup
Copier après la connexion

Créer un fichier de configuration

Créez un nouveau fichier rollup.config.js dans le répertoire racine

export default {
  input: "src/index.js",
  output: {
    file: "dist/drrp.js",
    format: "esm",
    name: &#39;drrp&#39;
  }
};
Copier après la connexion
  • input - le fichier à empaqueter
  • output.file - le fichier de sortie (s'il n'y a pas ce paramètre, il sera sortie directement sur la console)
  • output.format - Sortie du type de fichier par Rollup

Installer babel

Si vous souhaitez utiliser la syntaxe es6 pour le développement, vous devez également utiliser babel pour compiler le code dans es5. Étant donné que le mécanisme de module de cumul est constitué de modules ES6, les autres syntaxes es6 ne seront pas compilées.

Module d'installation

rollup-plugin-babel combine parfaitement rollup et babel.

npm install --save-dev rollup-plugin-babel@latest
npm install --save-dev @babel/core 
npm install --save-dev @babel/preset-env
Copier après la connexion

Créer .babelrc dans le répertoire racine

{
    "presets": [
      [
        "@babel/preset-env",
        {
          "modules": false
        }
      ]
    ]
}
Copier après la connexion

Compatible avec commonjs

rollup fournit le plug-in rollup-plugin-commonjs pour faciliter la référence des packages standards commonjs dans le rollup. La fonction de ce plug-in est de convertir les modules commonjs en modules es6.

rollup-plugin-commonjs est généralement utilisé avec rollup-plugin-node-resolve, qui est utilisé pour résoudre les chemins de modules dépendants.

Module d'installation

npm install --save-dev rollup-plugin-commonjs rollup-plugin-node-resolve
Copier après la connexion

Compress bundle

L'ajout d'UglifyJS peut réduire considérablement la taille du bundle en supprimant les commentaires, en raccourcissant les noms de variables et en réorganisant le code - Cela réduit le code dans une certaine mesure. Lisible, mais devient plus efficace dans la communication réseau.

Installez le plugin

Utilisez la commande suivante pour installer rollup-plugin-uglify :

npm install --save-dev rollup-plugin-uglify
Copier après la connexion

完整配置

rollup.config.js 最终配置如下

import resolve from &#39;rollup-plugin-node-resolve&#39;;
import commonjs from &#39;rollup-plugin-commonjs&#39;;
import babel from &#39;rollup-plugin-babel&#39;;
import { uglify } from &#39;rollup-plugin-uglify&#39;;
import json from &#39;@rollup/plugin-json&#39;

const paths = {
    input: {
        root:  &#39;src/index.js&#39;,
    },
    output: {
        root:  &#39;dist/&#39;,
    },
};

const fileName = `drrq.js`;

export default {
    input: `${paths.input.root}`,
    output: {
        file: `${paths.output.root}${fileName}`,
        format: &#39;esm&#39;,
        name: &#39;drrq&#39;,
    },
    plugins: [
        json(),
        resolve(),
        commonjs(),
        babel({
            exclude: &#39;node_modules/**&#39;,
            runtimeHelpers: true,
        }),
        uglify(),
    ],
};
Copier après la connexion

在package.json中加上

"scripts": {
    "build": "rollup -c"
},
Copier après la connexion

即可执行npm run build将/src/index.js打包为/dist/drrq.js

发包前的准备

准备npm账号,通过npm login或npm adduser。这里有一个坑,终端内连接不上npm源,需要在上网工具内复制终端代理命令后到终端执行才能正常连接。

Vous guide étape par étape pour créer et publier des packages npm à partir de zéro

准备一个简单清晰的readme.md

Vous guide étape par étape pour créer et publier des packages npm à partir de zéro

修改package.json

完整的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": {
       ...
    }
}
Copier après la connexion
  • name 包名称 一定不能与npm已有的包名重复,想一个简单易记的
  • private 是否为私有
  • version 版本
  • main 入口文件位置
  • repository git仓库地址
  • author 作者
  • license 协议
  • description 描述
  • keywords 关键词,便于检索

每个 npm 包都需要一个版本,以便开发人员在安全地更新包版本的同时不会破坏其余的代码。npm 使用的版本系统被叫做 SemVer,是 Semantic Versioning 的缩写。

不要过分担心理解不了相较复杂的版本名称,下面是他们对基本版本命名的总结: 给定版本号 MAJOR.MINOR.PATCH,增量规则如下:

  • MAJOR 版本号的变更说明新版本产生了不兼容低版本的 API 等,

  • MINOR 版本号的变更说明你在以向后兼容的方式添加功能,接下来

  • PATCH 版本号的变更说明你在新版本中做了向后兼容的 bug 修复。

表示预发布和构建元数据的附加标签可作为 MAJOR.MINOR.PATCH 格式的扩展。

最后,执行npm publish就搞定啦

Vous guide étape par étape pour créer et publier des packages npm à partir de zéro

Vous guide étape par étape pour créer et publier des packages npm à partir de zéro

本文的完整代码已开源至gitee.com/yuanying-11… ,感兴趣的读者欢迎fork和star!

转载地址:https://juejin.cn/post/7172240485778456606

更多node相关知识,请访问:nodejs 教程

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Étiquettes associées:
source:juejin.cn
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal
À propos de nous Clause de non-responsabilité Sitemap
Site Web PHP chinois:Formation PHP en ligne sur le bien-être public,Aidez les apprenants PHP à grandir rapidement!