ホームページ  >  記事  >  ウェブフロントエンド  >  npm パッケージを最初から作成して公開する手順を段階的に説明します。

npm パッケージを最初から作成して公開する手順を段階的に説明します。

青灯夜游
青灯夜游転載
2022-12-08 20:26:572720ブラウズ

2202 年ですが、まだ npm パッケージの公開方法を知らない人はいますか?次の記事では、npm を最初から作成して公開するプロセス全体を説明します。

npm パッケージを最初から作成して公開する手順を段階的に説明します。

背景

記事は 4 月に公開されました。ぜひ、プロジェクトの axios パッケージをアップグレードしてください。繰り返しのリクエスト別れを告げる 、通常のリクエストとカスタム リクエストをサポートするために axios の二次カプセル化を導入し、同じリクエストを同じ時間内にインターセプトします (この記事をまだ読んでいない場合は、 3分程度で大まかに理解できます。)たまたま最近、クロスフレームワーク コンポーネント ライブラリを作成する準備をしています (作業負荷が非常に重いので、フロントエンドの友人 3 人が空き時間に取り組んでいます。コンポーネント ライブラリの作成後に全員と共有する予定です) npm パッケージの公開方法を学ぶ必要があります。昨日、コードの再利用を促進し、コードの再利用を容易にするために、以前に作成した axios パッケージを npm パッケージとして削除し、自由な時間を使って公開することを考えました。コミュニティに貢献しながら学びました。

この記事を読むと、次のことがわかります:

ツール ライブラリの準備

package.jsonを含む新しいプロジェクトを作成します

{
    "name": "drrq",
    "type": "module",
    "version": "1.0.0"
}

Functionimplementation/src/index.js

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 = { &#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 };

新しいサンプル コード フォルダー/example

サンプル エントリindex.js

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

api list 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);

グローバル リクエストのカプセル化リクエスト.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);
};

テスト関数

コードを書いたら関数が正常か検証する必要があるので、package.jsonに

    "scripts": {
        "test": "node example"
    },

を追加してnpm run test

を実行します。

npm パッケージを最初から作成して公開する手順を段階的に説明します。

機能は正常で、ツール ライブラリは準備完了です。

(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: &#39;drrp&#39;
  }
};
  • input - パッケージ化するファイル
  • output.file - 出力ファイル (このパラメータがない場合、コンソールに直接出力されます)
  • output.format - Rollup によって出力されるファイル タイプ

babel

開発に 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
        }
      ]
    ]
}

commonjs と互換性があります

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 &#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(),
    ],
};

在package.json中加上

"scripts": {
    "build": "rollup -c"
},

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

发包前的准备

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

npm パッケージを最初から作成して公開する手順を段階的に説明します。

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

npm パッケージを最初から作成して公開する手順を段階的に説明します。

修改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": {
       ...
    }
}
  • 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就搞定啦

npm パッケージを最初から作成して公開する手順を段階的に説明します。

npm パッケージを最初から作成して公開する手順を段階的に説明します。

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

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

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

以上がnpm パッケージを最初から作成して公開する手順を段階的に説明します。の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はjuejin.cnで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。