在日常開發中,經常會遇到一些通用的邏輯,導致每次都需要複製貼上。而我們作為coder,可以將一些常用業務邏輯封裝成通用的函式庫,併發布到npm中。
這樣,每次遇到新的專案時,只需要 install一下即可
這裡我們已經有了一個fe-utils 前端日常開發工具庫,也是本文最後的產物,並且後續也會持續更新。如果你有一個開源的心,但是沒信心去為大的專案提pr,不妨從這個封裝日常通用邏輯的專案做起,我們一起進步!!!
接下來我們就嘗試自己動手實現一個工具庫
建立專案
首先在自己的github上建立一個專案,然後拉取。進入到該倉庫中,執行yarn init
。一路enter下去。
主要目錄結構
- .github
- workflows
- xx.yml
- .husky
- src
- __test__
- index.ts
- sum.ts
- .editorconfig
- .gitignore
- .npmignore
- commitlint.config.js
- jest.config.mjs
- package.json
- rollup.config.js
- tsconfig.json
配置專案
1. 安裝rollup和ts
yarn add rollup typescript -D
2. 配置typescript配置檔案
yarn tsc --init
生成一個預設的配置檔案,然後根據我們的專案,改成如下:
{
"compilerOptions": {
"target": "es5" /* 編譯目標 */,
"module": "commonjs" /* 專案模組型別 */,
"lib": ["ES2018", "DOM"],
"allowJs": true /* 是否允許js程式碼 */,
"checkJs": true /* 檢查js程式碼錯誤 */,
"declaration": true /* 自動建立宣告檔案(.d.ts) */,
"declarationDir": "./lib" /* 宣告檔案目錄 */,
"sourceMap": true /* 自動生成sourcemap檔案 */,
"outDir": "lib" /* 編譯輸出目錄 */,
"rootDir": "./src" /* 專案原始碼根目錄,用來控制編譯輸出的目錄結構 */,
"strict": true /* 啟用嚴格模式 */
},
"include": ["src/index.ts"],
"exclude": ["node_modules", "lib"]
}
3. 配置rollup.config.js
在配置之前,我們需要安裝幾個rollup外掛yarn add @rollup/plugin-node-resolve @rollup/plugin-typescript @rollup/plugin-commonjs rollup-plugin-terser -D
這幾個分別是如下作用
- @rollup/plugin-node-resolve 處理路徑
- @rollup/plugin-typescript 支援ts
- @rollup/plugin-commonjs 處理commonjs
- rollup-plugin-terser 壓縮umd規範的輸出檔案
const resolve = require('@rollup/plugin-node-resolve');
const typescript = require('@rollup/plugin-typescript');
const commonjs = require('@rollup/plugin-commonjs');
const { terser } = require('rollup-plugin-terser')
module.exports = [
{
input: './src/index.ts',
output: [
{
dir: 'lib',
format: 'cjs',
entryFileNames: '[name].cjs.js',
sourcemap: false, // 是否輸出sourcemap
},
{
dir: 'lib',
format: 'esm',
entryFileNames: '[name].esm.js',
sourcemap: false, // 是否輸出sourcemap
},
{
dir: 'lib',
format: 'umd',
entryFileNames: '[name].umd.js',
name: 'FE_utils', // umd模組名稱,相當於一個名稱空間,會自動掛載到window下面
sourcemap: false,
plugins: [terser()],
},
],
plugins: [resolve(), commonjs(), typescript({ module: "ESNext"})],
}
]
4. 修改package.json
我們直接看完整的package.json
{
"name": "@lxnxbnq/utils",
"version": "0.0.2-alpha",
"main": "lib/index.cjs.js",
"module": "lib/index.esm.js",
"jsnext:main": "lib/index.esm.js",
"browser": "lib/index.umd.js",
"types": "lib/index.d.ts",
"files": [
"lib"
],
"repository": {
"type": "git",
"url": "git+https://github.com/SaebaRyoo/fe-utils.git"
},
"author": "SaebaRyoo <yuanddmail@163.com>",
"license": "MIT",
"scripts": {
"build": "rollup -c",
"test": "jest"
},
"devDependencies": {
"@rollup/plugin-babel": "^6.0.3",
"@rollup/plugin-commonjs": "^23.0.4",
"@rollup/plugin-node-resolve": "^15.0.1",
"@rollup/plugin-typescript": "^10.0.1",
"@types/jest": "^29.2.4",
"jest": "^29.3.1",
"rollup": "^3.7.2",
"rollup-plugin-terser": "^7.0.2",
"ts-jest": "^29.0.3",
"tslib": "^2.4.1",
"typescript": "^4.9.4"
},
"description": "前端業務程式碼工具庫",
"bugs": {
"url": "https://github.com/SaebaRyoo/fe-utils/issues"
},
"homepage": "https://github.com/SaebaRyoo/fe-utils#readme",
"dependencies": {}
}
其中需要注意的有如下幾個欄位
告知使用者不同的規範引用哪個檔案
- "main": "lib/index.cjs.js", // 當使用commonjs規範時會使用這個包
- "module": "lib/index.esm.js", // 使用esm時,會使用這個包
- "jsnext:main": "lib/index.esm.js", //這個同上,不過這個是社群規範,上面是官方規範
- "browser": "lib/index.umd.js", // umd規範,當直接在瀏覽器中開發時,可以直接下載release包並在瀏覽器中使用script匯入
ts型別檔案
- "types": "lib/index.d.ts",
使用yarn run build
打包專案
- "scripts": {
"build": "rollup -c",
},
files 欄位是用於約定在發包的時候NPM 會發布包含的檔案和資料夾。
"files": [
"lib"
],
5. 安裝jest + lint + prettier + husky + commit-msg對程式碼的質量進行約束
首先是安裝安裝測試框架jest,因為專案時基於ts寫的,所以需要配置jest來支援tsyarn add -D jest ts-jest @types/jest
- 建立配置檔案
yarn jest --init
- 修改配置檔案,完整如下
jest的預設環境是node,但是我們這個工具庫是面向前端的,肯定需要操作dom,所以需要安裝yarn add jest-environment-jsdom -D
來支援DOM和BOM操作
然後就是在使用到DOM或者BOM物件的測試檔案的頂部加上這一行註釋即可執行
/**
* @jest-environment jsdom
*/
或者在配置檔案中修改執行環境為testEnvironment: 'jsdom'
/*
* For a detailed explanation regarding each configuration property, visit:
* https://jestjs.io/docs/configuration
*/
export default {
clearMocks: true,
collectCoverage: true,
coverageDirectory: 'coverage',
coverageProvider: 'v8',
preset: 'ts-jest',
testEnvironment: 'jsdom', // 支援測試環境訪問dom
// 配置測試環境ua
testEnvironmentOptions: {
userAgent:
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/108.0.0.0 Safari/537.36',
},
};
在package.json的script中新增cli命令
{ "scripts": { "test": "jest", "coveralls": "jest --coverage", } }
- 最後按照這篇文章的步驟來配置規範程式碼的檔案
開發
我們先在src的目錄下寫一個簡單的sum方法以及一個單元測試
src/sum.ts
export function sum(...args: number[]): number {
return args.reduce((prev, total) => total + prev, 0);
}
在入口中匯入並匯出
src/index.ts
export { sum } from './sum';
寫一個sum的單元測試
src/__test__/sum.test.ts
import {sum} from '../index'
describe('sum', () => {
it('should work', () => {
expect(sum()).toEqual(0)
})
})
到這,基本上一個最簡單的npm包就開發完了,接下來就是需要釋出
npm包釋出
1. 手動釋出
首先需要準備一個賬號,然後進行登入,輸入你的npm賬號、密碼、郵箱npm login
可以用npm logout
退出當前賬號
npm who am i
查詢當前登入的賬號
登入成功就可以透過npm publish
將包推送到伺服器上
如果某版本的包有問題,可以使用npm unpublish [pkg]@[version]
將其撤回
注意:如果使用@[scope]/package
的命名形式,[scope]一定要寫你的賬號名,不然釋出的時候會提示404
2. 使用github action 釋出npm、建立release 以及處理一些工作流程
如果不瞭解github action的話, 建議先學習一下github actions的一些概念
在根目錄下建立.github/workflows/node.js.yml
CI配置檔案(這裡也可以在倉庫上的tab欄中找到Actions生成)
注意:如果你需要不同的actions,可以在Marketplace中查詢需要的action
目標
- 自動釋出npm包
- 建立release並上傳對應asset
- 跑單元測試,生成測試覆蓋率提交到coveralls
準備工作
- 在npm中生成token
- 然後複製token到github對應倉庫的秘鑰中
- 設定一個變數名,我們這裡設定的是
NPM_ACCESS_TOKEN
,後面可以在CI中透過secrets.NPM_ACCESS_TOKEN
獲取到
整體程式碼
有了以上的思路來看下面的整體程式碼
# This workflow will do a clean installation of node dependencies, cache/restore them, build the source code and run tests across different versions of node
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-nodejs
name: Node.js CI
on:
push:
branches: [ "main" ]
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [18.x]
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/
steps:
- uses: actions/checkout@v3
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
cache: 'yarn'
- run: yarn
# 測試,並生成測試覆蓋率檔案
- run: yarn run coveralls
- run: yarn run build
# 上報
- name: Coveralls
uses: coverallsapp/github-action@master
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
# publish-npm任務
publish-npm:
# 在ubuntu最新版本的虛擬機器執行
runs-on: ubuntu-latest
# 設定變數
strategy:
matrix:
node-version: [ 18.x ]
steps:
# 檢查並切換到main分支
- name: 檢查main分支
# 使用actions/checkout外掛
uses: actions/checkout@v3
# 初始化快取
- name: 快取
uses: actions/cache@v3
id: cache-dependencies
with:
path: node_modules
key: ${{runner.OS}}-${{hashFiles('**/yarn.lock')}}
# 安裝node
- name: 設定Node.js
# 使用actions/setup-node外掛
uses: actions/setup-node@v3
with:
# node版本
node-version: ${{ matrix.node-version }}
- run: yarn
- run: yarn run build
# 讀取當前版本號
- name: 讀取當前版本號
id: version
uses: notiz-dev/github-action-json-property@release
with:
# 讀取版本號
path: './package.json'
prop_path: 'version'
- run: echo ${{steps.version.outputs.prop}}
# 建立Release
- name: release
# 原本使用的 actions/create-release@latest來發版, actions/upload-release-asset@v1上傳release-asset
# 不過這兩個action官方已經停止維護了,所以換成如下
uses: softprops/action-gh-release@v1
with:
files: ./lib/index.umd.js
name: v${{steps.version.outputs.prop}}
tag_name: v${{steps.version.outputs.prop}}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
# 釋出NPM包
- name: 釋出NPM包
# 執行釋出程式碼
run: |
npm config set //registry.npmjs.org/:_authToken=$NPM_TOKEN
npm publish
env:
# 配置 npm access token 環境變數
NPM_TOKEN: ${{secrets.NPM_ACCESS_TOKEN}}
# 重新整理快取
- name: 重新整理快取
run: |
curl https://purge.jsdelivr.net/npm/iemotion-pic@latest/lib/name.json
為readme新增badge(徽章)
我們會發現在一個開源專案中,readme通常都會寫的很好,而且還有很多的badge,如ant-design的readme
那麼這一切都是怎麼完成的呢?一些簡單的badge可以直接在shields中輸入倉庫名即可生成。
比如:
workflow工作流狀態:
npm包版本:
license:
我們也可以根據自己需要來建立不同的badge
不過要新增測試覆蓋率的badge會稍稍有些麻煩。
- 首先進入coveralls官網,進去後需要透過github的授權
- 授權後點選左側側邊欄的 ADD REPOS 會進入如下頁面
然後我們將需要生成badge徽章的庫設定為on即可
- 後面的流程就是在CI中執行測試指令碼並生成測試覆蓋率的檔案然後上傳到coveralls就可以了