最近一直在写前端项目、然后又使用strapi在写后端服务,在使用到加解密这快内容,相同的代码需要复制粘贴,索性写一个工具吧,于是带着研究,百度了一番,目前常见的工具有webpack、vite、rollup,相对主流的vite和rollup目前比较流行,webpack实在是卡顿

于是我又找找看看,又翻翻看,看到了tsup,构建方式简单,不用繁琐的配置,这不正是我想要的嘛

介绍一下tsup

tsup 是一个用于打包web脚本的轻量级工具,它基于 esbuild,旨在提供快速且简单的打包体验。tsup 支持多种输出格式,如 CommonJS、ES 模块、UMD 等

特点

  1. 快速打包:利用 esbuild 的高性能,tsup 能够非常快速地打包 TypeScript 项目
  2. 多格式输出:支持多种输出格式,包括 CommonJS (cjs)、ES 模块 (esm)、UMD 等
  3. 零配置:默认情况下,tsup 可以自动检测项目配置并进行打包,无需复杂的配置文件
  4. 灵活配置:可以通过命令行参数或配置文件进行灵活配置
  5. 树摇优化:自动进行树摇优化,减少最终包的大小
  6. TypeScript 支持:原生支持 TypeScript,无需额外配置

看下如何使用

需要先安装它,我们先npm init,初始化基本项目项目环境,然后进行安装

npm i tsup -D
# Or Yarn
yarn add tsup --dev
# Or pnpm
pnpm add tsup -D

安装完成

在根目录下手动建一个tsup.config.ts文件,这个就是tsup的配置文件,这里我列出我的配置文件

import {  defineConfig } from 'tsup';

export default defineConfig([
    {
        format: ['esm', 'cjs', 'iife'], // 指定输出的模块格式。常见的格式有 esm(ES 模块)、cjs(CommonJS)、iife(立即执行函数表达式)等
        entry: ['./example/index.js'], // 指定项目的入口文件。可以是一个或多个文件路径
        outDir: 'lib', // 指定输出文件的目录
        platform: 'neutral', // 指定目标平台。常见的值有 neutral(中立平台,适用于所有环境)、browser(浏览器环境)、node(Node.js 环境)
        globalName: 'WebUtils', //当输出格式为 iife 时,指定全局变量的名称
        outExtension({ format }) { // 自定义输出文件的扩展名。接收一个对象参数,包含当前的格式信息
            if (format === 'iife') return { js: '.browser.js' };
            return { js: `.${format}.js` };
        },
        minify: true, // 是否启用代码压缩
        sourcemap: true, // 是否生成源映射文件
        shims: true, // 是否启用 polyfills 和 shims,以确保兼容性
        clean: true,  // 清理输出目录
        dts: true, // 是否生成 TypeScript 声明文件
    }
]);

我已经在后面都标注说明了,不要我在解释了吧

编写加解密代码

这里我使用的是crypto-jsjsencrypt,两个仓库,一个是对称加密,一个和做非对称加密,这个两个兼容浏览器端和Node.js环境

import CryptoJS from "crypto-js";
import JSEncrypt from "jsencrypt"
/**
 * 对称加密
 * @param word
 * @param iv
 * @param key
 * @returns {string}
 */
function aesEncrypt(word, iv, key) {
    let str = typeof word == "string" ? word : JSON.stringify(word);
    const data = CryptoJS.enc.Utf8.parse(str);
    const encrypted = CryptoJS.AES.encrypt(data, key, {
        iv: iv,
        mode: CryptoJS.mode.CBC,
        padding: CryptoJS.pad.Pkcs7
    });
    return encrypted.toString();
}


/**
 * 对称解密
 * @param word
 * @param iv
 * @param key
 * @returns {string}
 */
function aesDecrypt(word, iv, key) {
    const decrypt = CryptoJS.AES.decrypt(word, key, {
        iv: iv,
        mode: CryptoJS.mode.CBC,
        padding: CryptoJS.pad.Pkcs7
    });
    return CryptoJS.enc.Utf8.stringify(decrypt);
}


/**
 * 获取加密的密钥
 * @param iv
 * @param key
 */
function getCrypto({iv = '', key = ''} = {}) {
    return {
        CryptoJS,
        iv: CryptoJS.enc.Utf8.parse(iv),
        key: CryptoJS.enc.Utf8.parse(key), //16位
    }
}


/**
 * 非对称加密
 * @param str
 * @param publicKey
 * @returns {*}
 */
const rsaEncrypt = (str, publicKey) => {
    let encrypted = new JSEncrypt() // 创建加密对象实例
    encrypted.setPublicKey(publicKey) // 设置公钥
    return encrypted.encrypt(str) // 对内容进行加密
}


/**
 * 非对称解密
 * @param str
 * @param privateKey
 */
const rasDecrypt = (str, privateKey) => {
    const decrypted = new JSEncrypt() // 创建解密对象实例
    decrypted.setPrivateKey(privateKey) // 设置私钥
    return decrypted.decrypt(str) // 拿私钥解密内容
}

/**
 * 非对称生成Key
 * @param keySize
 */
const getJSEncrypt = (keySize = '512') => {
    const crypt = new JSEncrypt({default_key_size: keySize});
    return new Promise((resolve) => {
        crypt.getKey(function () {
            return resolve({
                privateKey: crypt.getPrivateKey(),
                publicKey: crypt.getPublicKey()
            })
        })
    })
}

export {
    aesEncrypt,
    aesDecrypt,
    getCrypto,
    rsaEncrypt,
    rasDecrypt,
    getJSEncrypt
}

打包构建

执行npx tsup

image.png

构建成功,并且我也生成了lib目录下的文件

测试脚本

我写了个列子进行测试

import {aesEncrypt,aesDecrypt, getCrypto,rasDecrypt,rsaEncrypt,getJSEncrypt} from "../packages/index";

const {iv,key} = getCrypto({
    iv: '1234567890123456',
    key: '1234567890123456'
})

getJSEncrypt().then((res)=>{
    console.log(res)
})

使用node进行测试

node ./lib/index.cjs.js

image.png

发现jsencrypt出现了window,这肯定就不行了哇,node环境那来的window的,如是我逛了下百度,找到了答案,也就是在代码的前面加上window=this

这是打包出来的代码,需要在前面加上window=this,我先手动加上进行测试

image.png

测试正常,这里我生成了一个非对称密钥对

image.png

自动加window=this

当实现自动化的时候,我就想到了gulp, Gulp 是一个流式构建系统,用于自动化前端工作流程。它使用 JavaScript 和 Node.js,通过一系列插件和任务来处理文件和资源,它的特点如下

  1. 流式处理:Gulp 使用 Node.js 流来处理文件,这意味着文件可以在内存中被处理,而不需要多次读写磁盘,从而提高性能。
  2. 简洁的 API:Gulp 的 API 非常简洁,易于理解和使用。
  3. 丰富的插件生态系统:Gulp 拥有庞大的插件生态系统,可以轻松找到你需要的插件,如编译 LESS/SASS、压缩 CSS/JS、图像优化等。
  4. 任务自动化:Gulp 可以自动化常见的开发任务,如代码检查、文件合并、代码压缩、文件监听等。

使用gulp

在根目录下新建文件gulpfile.js,内容如下

const {src, dest} = require('gulp');
const insert = require('gulp-insert');

function defaultTask(cb) {
    src('lib/index.cjs.js') // 指定要编辑的文件路径
        .pipe(insert.prepend('window = this;')) // 向文件开头插入指定的字符串
        .pipe(dest('lib')); // 指定输出目录
    cb();
}

exports.default = defaultTask

注意gulp的写法,gulp一直在升级,写法和使用方式一直在变化

执行gulp

测试成功
image.png

回归功能,完整加解密代码

import CryptoJS from "crypto-js";
import JSEncrypt from "jsencrypt"
/**
 * 对称加密
 * @param word
 * @param iv
 * @param key
 * @returns {string}
 */
function aesEncrypt(word, iv, key) {
    let str = typeof word == "string" ? word : JSON.stringify(word);
    const data = CryptoJS.enc.Utf8.parse(str);
    const encrypted = CryptoJS.AES.encrypt(data, key, {
        iv: iv,
        mode: CryptoJS.mode.CBC,
        padding: CryptoJS.pad.Pkcs7
    });
    return encrypted.toString();
}


/**
 * 对称解密
 * @param word
 * @param iv
 * @param key
 * @returns {string}
 */
function aesDecrypt(word, iv, key) {
    const decrypt = CryptoJS.AES.decrypt(word, key, {
        iv: iv,
        mode: CryptoJS.mode.CBC,
        padding: CryptoJS.pad.Pkcs7
    });
    return CryptoJS.enc.Utf8.stringify(decrypt);
}


/**
 * 获取加密的密钥
 * @param iv
 * @param key
 */
function getCrypto({iv = '', key = ''} = {}) {
    return {
        CryptoJS,
        iv: CryptoJS.enc.Utf8.parse(iv),
        key: CryptoJS.enc.Utf8.parse(key), //16位
    }
}


/**
 * 非对称加密
 * @param str
 * @param publicKey
 * @returns {*}
 */
const rsaEncrypt = (str, publicKey) => {
    let encrypted = new JSEncrypt() // 创建加密对象实例
    encrypted.setPublicKey(publicKey) // 设置公钥
    return encrypted.encrypt(str) // 对内容进行加密
}


/**
 * 非对称解密
 * @param str
 * @param privateKey
 */
const rasDecrypt = (str, privateKey) => {
    const decrypted = new JSEncrypt() // 创建解密对象实例
    decrypted.setPrivateKey(privateKey) // 设置私钥
    return decrypted.decrypt(str) // 拿私钥解密内容
}

/**
 * 非对称生成Key
 * @param keySize
 */
const getJSEncrypt = (keySize = '512') => {
    const crypt = new JSEncrypt({default_key_size: keySize});
    return new Promise((resolve) => {
        crypt.getKey(function () {
            return resolve({
                privateKey: crypt.getPrivateKey(),
                publicKey: crypt.getPublicKey()
            })
        })
    })
}

export {
    aesEncrypt,
    aesDecrypt,
    getCrypto,
    rsaEncrypt,
    rasDecrypt,
    getJSEncrypt
}

测试代码

import {aesEncrypt,aesDecrypt, getCrypto,rasDecrypt,rsaEncrypt,getJSEncrypt} from "../packages/index";

const {iv,key} = getCrypto({
    iv: '1234567890123456',
    key: '1234567890123456'
})

// getJSEncrypt().then((res)=>{
//     console.log(res)
// })

//
const privateKey = '-----BEGIN RSA PRIVATE KEY-----\n' +
    'MIIBOAIBAAJASj9QjNul1xu4Bpq6MByZJePADyBsoLvoGj+sSLuaPEy4pdJ6lEqW\n' +
    '0EjpT1nakDzlwXB1IDHQeeHlga31KkSUKwIDAQABAkAxWlLFvr9G9ELoCPOYRXo7\n' +
    'aF9i7q+mTCFlSUvQ8Pr9915Aot8qwjW3tcH0HhRbytikEmZ2esplPd832ie5qRKZ\n' +
    'AiEAigM6NID/wtv01bGBbmOgUePeD5UnHbD2IiwnAKcJ6/cCIQCJuLmkVNrOcVNe\n' +
    'Fz4vFRqvjOd95XBwlFkI4nfTVC7EbQIgYGPYpwrhlmqhGQ6cY0jZk9geI6v8YdRS\n' +
    'U5Oaue3wFAkCIDXE9F3Pb1oYbrcWlgWl1LRja+IAWUTq9lP8r1HH1TaFAiBSZ8oJ\n' +
    'Obty329SSgnl7ZICHome91o1BoxwWU5IBRKNaQ==\n' +
    '-----END RSA PRIVATE KEY-----'

const publicKey = '-----BEGIN PUBLIC KEY-----\n' +
    'MFswDQYJKoZIhvcNAQEBBQADSgAwRwJASj9QjNul1xu4Bpq6MByZJePADyBsoLvo\n' +
    'Gj+sSLuaPEy4pdJ6lEqW0EjpT1nakDzlwXB1IDHQeeHlga31KkSUKwIDAQAB\n' +
    '-----END PUBLIC KEY-----'


const str1  = aesEncrypt('123456', iv, key)
console.log(str1)
console.log(aesDecrypt(str1, iv, key))
console.log('------')

const str2 = rsaEncrypt('abcdefg', publicKey)
console.log(str2)
console.log(rasDecrypt(str2, privateKey))

执行结果,均没有问题

image.png

源码我放在了github上面有兴趣的看一看https://github.com/hangjob/web-utils


羊先生
1.9k 声望821 粉丝