从0到1教你如何发布自己的NPM包

从0到1教你如何发布自己的NPM包

1. 创建一个项目

▲ 新建一个文件夹并打开终端初始化项目:

npm init

此时会根据你所填信息自动生成 package.json 的配置文件,这里主要包含了项目名称、版本号、作者、许可证等信息,同时可以记录项目的依赖信息以及自定义的脚本生成package.json文件

  • name 字段指定了项目的名称为 bian-base64
  • version 字段指定了项目的版本号为 1.0.0
  • description 字段提供了项目的简要描述。
  • type 字段指定了项目模块的类型为 module,支持CommonJS和ES模块。
  • main 字段指定了项目的主入口文件为 dist/index.js
  • types 字段指定了项目的类型声明文件为 dist/index.d.ts
  • files 字段指定了项目发布时应包含的文件夹为 dist
  • scripts 字段定义了项目的脚本,用于构建项目。其中 build 脚本命令使用了 rollup -c 来构建项目。
  • keywords 字段是项目的关键词列表,用于搜索和分类。
  • author 字段指定了项目的作者为 bian 534893106@qq.com
  • license 字段指定了项目的许可协议为 ISC
{
  "name": "bian-base64",
  "version": "1.0.0",
  "description": "这是一个base64工具包",
  "type": "module",
  "main": "dist/index.js",
  "types": "dist/index.d.ts",
  "files": ["dist"],
  "scripts": {
    "tsc": "tsup --config=tsup.config.miniprogram.ts",
    "prebuild": "rimraf dist",
    "build": "tsc && rollup -c rollup.config.ts",
    "start": "rollup -c rollup.config.ts -w"
  },
  "keywords": ["base64"],
  "author": "bian <534893106@qq.com>",
  "license": "ISC"
}

2. 安装打包工具

  • Webpack:是一个非常强大的模块打包器,它能够处理多种类型的模块(包括JavaScript、CSS、图片等),通过加载器(loaders)和插件(plugins)支持各种静态资源的处理和优化。Webpack支持代码拆分、懒加载等高级特性,适用于大型和复杂的项目构建。
  • Rollup:专注于ES模块的打包工具,以其小巧、高效著称。Rollup擅长将小到中型的代码库打包成高性能的、适合浏览器或Node.js使用的模块。与Webpack相比,Rollup在处理纯ES模块项目时更为轻量级和快速,特别适合库的开发。
  • Parcel:是一款快速、零配置的Web应用打包工具。Parcel强调开箱即用,自动处理诸如代码转换(如Babel)、样式处理(如PostCSS)、图片优化等任务,无需繁琐的配置。它的目标是提供一个简单而高效的开发体验,特别适合快速原型开发或是对配置要求不高的项目。

常见的打包工具有webpackrollupparcel等,这里选择rollup,因为rollup可以支持ES模块和CommonJS模块,并且可以支持TypeScript,所以安装rolluptypescripttsup用于打包TypeScript代码

npm install rollup typescript rimraf tsup -D

3. 创建包的入口文件

▲ 根目录下创建 src 文件夹,并在其中创建 index.ts 文件,用于编写代码` 配置文件

 class Base64Utility {
    private static readonly _keyStr: string = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";

    public static encode(input: string): string {
        let output = "";
        let chr1, chr2, chr3, enc1, enc2, enc3, enc4;
        let i = 0;

        input = Base64Utility._utf8Encode(input);

        while (i < input.length) {
            chr1 = input.charCodeAt(i++);
            chr2 = input.charCodeAt(i++);
            chr3 = input.charCodeAt(i++);

            enc1 = chr1 >> 2;
            enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
            enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
            enc4 = chr3 & 63;

            if (isNaN(chr2)) {
                enc3 = enc4 = 64;
            } else if (isNaN(chr3)) {
                enc4 = 64;
            }

            output = output + 
                Base64Utility._keyStr.charAt(enc1) + 
                Base64Utility._keyStr.charAt(enc2) + 
                Base64Utility._keyStr.charAt(enc3) + 
                Base64Utility._keyStr.charAt(enc4);
        }

        return output;
    }

    public static decode(input: string): string {
        let output = "";
        let chr1, chr2, chr3;
        let enc1, enc2, enc3, enc4;
        let i = 0;

        input = input.replace(/[^A-Za-z0-9+/=]/g, "");

        while (i < input.length) {
            enc1 = Base64Utility._keyStr.indexOf(input.charAt(i++));
            enc2 = Base64Utility._keyStr.indexOf(input.charAt(i++));
            enc3 = Base64Utility._keyStr.indexOf(input.charAt(i++));
            enc4 = Base64Utility._keyStr.indexOf(input.charAt(i++));

            chr1 = (enc1 << 2) | (enc2 >> 4);
            chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
            chr3 = ((enc3 & 3) << 6) | enc4;

            output = output + String.fromCharCode(chr1);

            if (enc3 !== 64) {
                output = output + String.fromCharCode(chr2);
            }
            if (enc4 !== 64) {
                output = output + String.fromCharCode(chr3);
            }
        }

        output = Base64Utility._utf8Decode(output);

        console.log("开始解码-结果为",output)

        return output;
    }

    private static _utf8Encode(input: string): string {
        let output = "";
        for (let n = 0; n < input.length; n++) {
            let charCode = input.charCodeAt(n);
            if (charCode < 128) {
                output += String.fromCharCode(charCode);
            } else if (charCode > 127 && charCode < 2048) {
                output += String.fromCharCode((charCode >> 6) | 192);
                output += String.fromCharCode((charCode & 63) | 128);
            } else {
                output += String.fromCharCode((charCode >> 12) | 224);
                output += String.fromCharCode(((charCode >> 6) & 63) | 128);
                output += String.fromCharCode((charCode & 63) | 128);
            }
        }
        return output;
    }

    private static _utf8Decode(input: string): string {
        let output = "";
        let i = 0;
        let c1, c2, c3;
        while (i < input.length) {
            c1 = input.charCodeAt(i++);
            if (c1 < 128) {
                output += String.fromCharCode(c1);
            } else if (c1 > 191 && c1 < 224) {
                c2 = input.charCodeAt(i++);
                output += String.fromCharCode(((c1 & 31) << 6) | (c2 & 63));
            } else {
                c2 = input.charCodeAt(i++);
                c3 = input.charCodeAt(i++);
                output += String.fromCharCode(((c1 & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
            }
        }
        return output;
    }
}

export default Base64Utility;

4. 配置rollup

执行以下命令,安装rollup相应配置依赖

npm install rollup-plugin-node-resolve rollup-plugin-commonjs rollup-plugin-json rollup-plugin-sourcemaps rollup-plugin-terser rollup-plugin-typescript2 rimraf tsup -D

rollup-plugin-node-resolve 用于解析第三方模块
rollup-plugin-commonjs 用于将CommonJS模块转换为ES模块
rollup-plugin-typescript2 用于TypeScript编译
rollup-plugin-json 用于处理JSON文件
rollup-plugin-terser 用于压缩代码
rimraf 用于删除文件

▲ 根目录下创建 rollup.config.js 配置文件

import resolve from 'rollup-plugin-node-resolve'  // 用于解析第三方模块
import commonjs from 'rollup-plugin-commonjs'   // 用于将CommonJS模块转换为ES模块
import typescript from 'rollup-plugin-typescript2'  //用于TypeScript编译
import json from 'rollup-plugin-json' // 用于处理JSON文件
import { terser } from 'rollup-plugin-terser' // 用于压缩代码

export default {
  // 指定输入文件的路径,这里是项目的入口点
  input: `src/index.ts`,
  output: {
     // 指定输出文件的全局变量名,以便在全局范围内引用
    name: 'Base64Utility',
    // 指定输出文件的路径和名称
    file: 'dist/index.js',
     // 指定输出文件的格式,这里是UMD格式,可以在浏览器和Node.js环境中使用
    format: 'umd'
  },
   // 使用的插件列表,这里只包含typescript插件,用于编译TypeScript代码
  plugins: [
    json(),
    typescript({ useTsconfigDeclarationDir: true }),
    commonjs(), // 将CommonJS模块转换为ES模块
    resolve(), // 解析第三方模块
    terser()
  ],
}

▲ 根目录下创建 tsup.config.miniprogram.ts 配置文件
tsup.config.miniprogram.ts是一个配置文件,用于TSUP(TypeScript Utility Program)这一工具。TSUP是一个零配置的打包工具,特别适合于打包TypeScript库或Node.js应用程序,但它也可以通过配置文件进行更细致的控制。

import { defineConfig } from "tsup"
 
export default defineConfig({
  entry: ["./src/index.ts"],
  clean: true,
  outDir: "miniprogram_dist",
  dts: true,
  minify: true, // 开启压缩选项
  format: ["iife"],
  target: "es5",
  noExternal: ["@noble/curves"],
  tsconfig: "tsconfig.json",
  esbuildOptions(options) {
    if (options.define) {
      options.define.__BUILD_TS__ = Date.now().toString()
      options.define.import = "require"
    }
    options.globalName = "Base64Utility" // 将您的方法暴露到全局作用域
    options.supported = {
      "dynamic-import": false,
    }
  },
})


5. 配置 TypeScript

▲ 根目录下创建 tsconfig.json 配置文件,添加如下配置:

{
    "compilerOptions": {
      "moduleResolution": "node",
      "target": "es5",
      "module":"es2015",
      "lib": ["es2015", "es2016", "es2017", "dom"],
      "strict": true,
      "declaration": true,
      "allowSyntheticDefaultImports": true,
      "experimentalDecorators": true,
      "emitDecoratorMetadata": true,
      "declarationDir": "dist/types",
      "outDir": "lib",
      "typeRoots": [
        "node_modules/@types"
      ]
    },
    "include": [
      "src"
    ]
  }
  • moduleResolution: 指定模块解析策略,采用Node.js风格
  • compilerOptions: 译器选项配置,用于指导TypeScript如何编译代码
  • target: 指定编译器输出的JavaScript版本为ES5。
  • module: 定模块系统,使用ES2015模块系统
  • esModuleInterop: 启用ES模块的互操作性。
  • lib: 指定编译器使用的库,包含ES2015、ES2016、ES2017和DOM。
  • strict: 启用严格的类型检查。
  • declaration: 生成类型声明文件(.d.ts 文件)。
  • allowSyntheticDefaultImports : 启用默认导入的语法。
  • experimentalDecorators : 启用装饰器语法。
  • emitDecoratorMetadata: 启用装饰器元数据的编译。
  • declarationDir : 指定类型声明文件的输出目录为dist/types。
  • outDir: 指定编译后的JavaScript代码的输出目录为lib。
  • typeRoots: 指定类型声明文件的根目录,这里是node_modules/@types。
  • include: 指定要编译的源代码文件,这里是src目录下的所有文件。

6. 构建打包

执行npm run build 此时会在根目录下生成dist目录,里面有index.js和types/index.d.ts两个文件。

7. 发布packege包到npm

  • 首先需要注册一个npm账号,可以去npm官网按照步骤完成注册。
  • 登录npm账号,登录前先检查一下npm源,很多人开发是已将把npm 源换成了淘宝镜像或者自己公司内部的,但是发布需要npm本身的源:https://registry.npmjs.org/
  • 项目根路径输入 npm login 后按要求填写账号密码,然后输入 npm publish 发布包。

8. 测试使用

发布完成后我们要自己测试一下是否真的将包发布到npm社区了。

首先我们可以用账号登录npm,进入到个人的信息页面,点击头像,选择package,就会进入到个人的包管理页面了。
项目中引入刚刚发布的包
npm i bian-base64

9. package后期迭代更新

  • 给package添加一个readme文件,顺便测试一下怎么更新包。在文件目录下新建了一个README文件,编辑好内容保存
  • 内容改好或者修改代码后不能直接发布,我们需要修改package的version号,修改之前先了解下npm维护package版本的规则x.y.z
x: 主版本号,通常有重大改变或者达到里程碑才改变;
y: 次要版本号,或二级版本号,在保证主体功能基本不变的情况下,如果适当增加了新功能可以更新此版本号;
z: 尾版本号或者补丁号,一些小范围的修修补补就可以更新补丁号.
npm version patch <=> z++
npm version minor <=> y++ && z=0
npm version major <=> x+= && y=0 && z=0

-我们当前的版本号是1.0.0,这里只是加了个readme.md文件,那就将这次版本修改为1.0.1,在包的根目录下,命令行运行以下命令:

// 更新一个补丁版本 1.0.1
npm version patch
// 更新到npm
npm publish

常用的操作package的npm命令

// 查看当前依赖的所有版本信息
npm view [包名] 

// 更新当前依赖版本为最新
npm update  [包名] 

  • 44
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值