Stories

Detail Return Return

關於tsup工具構建項目庫使用過程 - Stories Detail

最近一直在寫前端項目、然後又使用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

user avatar haoqidewukong Avatar guixiangyyds Avatar kongsq Avatar geeklab Avatar zhaodawan Avatar nzbin Avatar esunr Avatar code500g Avatar mandy_597086799bac8 Avatar tizuqiudehongcha Avatar hightopo Avatar hsr2022 Avatar
Favorites 49 users favorite the story!
Favorites

Add a new Comments

Some HTML is okay.