search
HomeWeb Front-endJS TutorialTake you step by step to create and publish npm packages from scratch

It’s 2202, is there anyone who still doesn’t know how to publish npm packages? The following article will share with you the whole process of creating and publishing npm from scratch. I hope it will be helpful to you!

Take you step by step to create and publish npm packages from scratch

Background

An article was published in April, Come and upgrade the axios package in your project, Repeated requests say goodbye, introduces the secondary encapsulation of axios to support regular requests and custom requests, and intercepts the same requests within the same time (If you have not read this article, it is recommended that you spend 3 minutes to understand it roughly). It just so happens that I am preparing to write a cross-framework component library recently (the workload is very heavy, and the three front-end friends are working on it in their free time. They will share it with everyone after the component library is completed, so stay tuned). I need to learn to publish npm packages. Yesterday I I thought about using my free time to publish the axios package I wrote before to remove duplicate requests as an npm package to facilitate code reuse and apply what I learned while giving back to the community.

Read this article, you will gain:

  • The whole process of creating and publishing npm from scratch. [Recommended related tutorials: nodejs video tutorial, Programming teaching]

  • A continuously iterative and simple and practical axios request deduplication tool library.

Tool library preparation

Create a new project, including package.json

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

Function implementation/src/index.js

npm i qs axios

The main idea is to use the requested URL and parameters as keys to record the request queue. When repeated requests occur, subsequent requests are interrupted and the results of the previous requests are returned and shared with subsequent requests. .

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 };

New sample code folder/example

Sample entry 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);

Global request encapsulation request. 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);
};

Test function

After the code is written, we need to verify whether the function is normal. Add

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

to package.json to execute npm run test

Take you step by step to create and publish npm packages from scratch

The function is normal and the tool library is ready.

(eslint and prettier readers can choose according to the situation)

Packaging

Generally, webpack is used for packaging of projects, while rollup is used for packaging of tool libraries

Install Rollup

Install through the following commandRollup:

npm install --save-dev rollup

Create configuration file

Create a new file in the root directory rollup.config.js

export default {
  input: "src/index.js",
  output: {
    file: "dist/drrp.js",
    format: "esm",
    name: &#39;drrp&#39;
  }
};
  • input - the file to be packaged
  • output.file - the output file (if there is no this parameter, it will be output directly to the console)
  • output.format - File type output by Rollup

Install babel

If you want to use es6 syntax for development, you also need to use babel to compile the code into es5 . Because the module mechanism of rollup is ES6 Modules, other es6 syntaxes will not be compiled.

Installation module

rollup-plugin-babel Perfectly combines rollup and babel.

npm install --save-dev rollup-plugin-babel@latest
npm install --save-dev @babel/core 
npm install --save-dev @babel/preset-env

Create .babelrc in the root directory

{
    "presets": [
      [
        "@babel/preset-env",
        {
          "modules": false
        }
      ]
    ]
}

Compatible with commonjs

rollup provides the plug-in rollup-plugin-commonjs so that For referencing the commonjs specification package in rollup. The function of this plug-in is to convert commonjs modules into es6 modules.

rollup-plugin-commonjs is usually used together with rollup-plugin-node-resolve, which is used to resolve dependent module paths.

Install module

npm install --save-dev rollup-plugin-commonjs rollup-plugin-node-resolve

Compress bundle

Adding UglifyJS can be greatly improved by removing comments, shortening variable names, and reorganizing the code. Reduce the size of the bundle - This reduces the readability of the code to a certain extent, but makes network communication more efficient.

Install plugin

Use the following command to install 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源,需要在上网工具内复制终端代理命令后到终端执行才能正常连接。

Take you step by step to create and publish npm packages from scratch

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

Take you step by step to create and publish npm packages from scratch

修改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就搞定啦

Take you step by step to create and publish npm packages from scratch

Take you step by step to create and publish npm packages from scratch

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

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

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

The above is the detailed content of Take you step by step to create and publish npm packages from scratch. For more information, please follow other related articles on the PHP Chinese website!

Statement
This article is reproduced at:掘金社区. If there is any infringement, please contact admin@php.cn delete
C   and JavaScript: The Connection ExplainedC and JavaScript: The Connection ExplainedApr 23, 2025 am 12:07 AM

C and JavaScript achieve interoperability through WebAssembly. 1) C code is compiled into WebAssembly module and introduced into JavaScript environment to enhance computing power. 2) In game development, C handles physics engines and graphics rendering, and JavaScript is responsible for game logic and user interface.

From Websites to Apps: The Diverse Applications of JavaScriptFrom Websites to Apps: The Diverse Applications of JavaScriptApr 22, 2025 am 12:02 AM

JavaScript is widely used in websites, mobile applications, desktop applications and server-side programming. 1) In website development, JavaScript operates DOM together with HTML and CSS to achieve dynamic effects and supports frameworks such as jQuery and React. 2) Through ReactNative and Ionic, JavaScript is used to develop cross-platform mobile applications. 3) The Electron framework enables JavaScript to build desktop applications. 4) Node.js allows JavaScript to run on the server side and supports high concurrent requests.

Python vs. JavaScript: Use Cases and Applications ComparedPython vs. JavaScript: Use Cases and Applications ComparedApr 21, 2025 am 12:01 AM

Python is more suitable for data science and automation, while JavaScript is more suitable for front-end and full-stack development. 1. Python performs well in data science and machine learning, using libraries such as NumPy and Pandas for data processing and modeling. 2. Python is concise and efficient in automation and scripting. 3. JavaScript is indispensable in front-end development and is used to build dynamic web pages and single-page applications. 4. JavaScript plays a role in back-end development through Node.js and supports full-stack development.

The Role of C/C   in JavaScript Interpreters and CompilersThe Role of C/C in JavaScript Interpreters and CompilersApr 20, 2025 am 12:01 AM

C and C play a vital role in the JavaScript engine, mainly used to implement interpreters and JIT compilers. 1) C is used to parse JavaScript source code and generate an abstract syntax tree. 2) C is responsible for generating and executing bytecode. 3) C implements the JIT compiler, optimizes and compiles hot-spot code at runtime, and significantly improves the execution efficiency of JavaScript.

JavaScript in Action: Real-World Examples and ProjectsJavaScript in Action: Real-World Examples and ProjectsApr 19, 2025 am 12:13 AM

JavaScript's application in the real world includes front-end and back-end development. 1) Display front-end applications by building a TODO list application, involving DOM operations and event processing. 2) Build RESTfulAPI through Node.js and Express to demonstrate back-end applications.

JavaScript and the Web: Core Functionality and Use CasesJavaScript and the Web: Core Functionality and Use CasesApr 18, 2025 am 12:19 AM

The main uses of JavaScript in web development include client interaction, form verification and asynchronous communication. 1) Dynamic content update and user interaction through DOM operations; 2) Client verification is carried out before the user submits data to improve the user experience; 3) Refreshless communication with the server is achieved through AJAX technology.

Understanding the JavaScript Engine: Implementation DetailsUnderstanding the JavaScript Engine: Implementation DetailsApr 17, 2025 am 12:05 AM

Understanding how JavaScript engine works internally is important to developers because it helps write more efficient code and understand performance bottlenecks and optimization strategies. 1) The engine's workflow includes three stages: parsing, compiling and execution; 2) During the execution process, the engine will perform dynamic optimization, such as inline cache and hidden classes; 3) Best practices include avoiding global variables, optimizing loops, using const and lets, and avoiding excessive use of closures.

Python vs. JavaScript: The Learning Curve and Ease of UsePython vs. JavaScript: The Learning Curve and Ease of UseApr 16, 2025 am 12:12 AM

Python is more suitable for beginners, with a smooth learning curve and concise syntax; JavaScript is suitable for front-end development, with a steep learning curve and flexible syntax. 1. Python syntax is intuitive and suitable for data science and back-end development. 2. JavaScript is flexible and widely used in front-end and server-side programming.

See all articles

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

Video Face Swap

Video Face Swap

Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Tools

Atom editor mac version download

Atom editor mac version download

The most popular open source editor

Dreamweaver Mac version

Dreamweaver Mac version

Visual web development tools

PhpStorm Mac version

PhpStorm Mac version

The latest (2018.2.1) professional PHP integrated development tool

mPDF

mPDF

mPDF is a PHP library that can generate PDF files from UTF-8 encoded HTML. The original author, Ian Back, wrote mPDF to output PDF files "on the fly" from his website and handle different languages. It is slower than original scripts like HTML2FPDF and produces larger files when using Unicode fonts, but supports CSS styles etc. and has a lot of enhancements. Supports almost all languages, including RTL (Arabic and Hebrew) and CJK (Chinese, Japanese and Korean). Supports nested block-level elements (such as P, DIV),

EditPlus Chinese cracked version

EditPlus Chinese cracked version

Small size, syntax highlighting, does not support code prompt function