最近一直在寫前端專案、然後又使用strapi在寫後端服務,在使用到加解密這快內容,相同的程式碼需要複製貼上,索性寫一個工具吧,於是帶著研究,百度了一番,目前常見的工具有webpack、vite、rollup,相對主流的vite和rollup目前比較流行,webpack實在是卡頓
於是我又找找看看,又翻翻看,看到了tsup,構建方式簡單,不用繁瑣的配置,這不正是我想要的嘛
介紹一下tsup
tsup 是一個用於打包web指令碼的輕量級工具,它基於 esbuild,旨在提供快速且簡單的打包體驗。tsup 支援多種輸出格式,如 CommonJS、ES 模組、UMD 等
特點
- 快速打包:利用 esbuild 的高效能,tsup 能夠非常快速地打包 TypeScript 專案
- 多格式輸出:支援多種輸出格式,包括 CommonJS (cjs)、ES 模組 (esm)、UMD 等
- 零配置:預設情況下,tsup 可以自動檢測專案配置並進行打包,無需複雜的配置檔案
- 靈活配置:可以透過命令列引數或配置檔案進行靈活配置
- 樹搖最佳化:自動進行樹搖最佳化,減少最終包的大小
- 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-js
、jsencrypt
,兩個倉庫,一個是對稱加密,一個和做非對稱加密,這個兩個相容瀏覽器端和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
構建成功,並且我也生成了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
發現jsencrypt
出現了window,這肯定就不行了哇,node環境那來的window的,如是我逛了下百度,找到了答案,也就是在程式碼的前面加上window=this
這是打包出來的程式碼,需要在前面加上window=this
,我先手動加上進行測試
測試正常,這裡我生成了一個非對稱金鑰對
自動加window=this
當實現自動化的時候,我就想到了gulp
, Gulp 是一個流式構建系統,用於自動化前端工作流程。它使用 JavaScript 和 Node.js,透過一系列外掛和任務來處理檔案和資源,它的特點如下
- 流式處理:Gulp 使用 Node.js 流來處理檔案,這意味著檔案可以在記憶體中被處理,而不需要多次讀寫磁碟,從而提高效能。
- 簡潔的 API:Gulp 的 API 非常簡潔,易於理解和使用。
- 豐富的外掛生態系統:Gulp 擁有龐大的外掛生態系統,可以輕鬆找到你需要的外掛,如編譯 LESS/SASS、壓縮 CSS/JS、影像最佳化等。
- 任務自動化: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
測試成功
迴歸功能,完整加解密程式碼
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))
執行結果,均沒有問題
原始碼我放在了github上面有興趣的看一看https://github.com/hangjob/web-utils