基于typescript、rollup工具搭建自己的开源库

515 阅读2分钟

1. 简介

这是基于typescript和rollup打包工具搭建的前端库开发框架,单元测试使用jest,文档插件使用typedoc, 还集成了commit提交规范,版本发布和版本号自动提升,changelog自动生成等。基于github的action,使用.github/workflows 自动构建文档。

2. 环境准备

  1. node环境
  2. git

3. 框架搭建

1. 新建空的代码仓库

2. clone这个仓库到本地

image.png

3.初始化node项目,得到packages

npm init

image.png

4.添加依赖

(1) 添加rollup 打包依赖

npm install @rollup/plugin-typescript rollup rollup-plugin-dts rollup-plugin-terser --save-dev

(2) 添加typescript依赖

npm install @types/node typescript tslib --save-dev

(3) 添加jest单元测试依赖

npm install jest @types/jest jest-config ts-jest --save-dev

(4) 添加代码格式化约束插件依赖

npm install @typescript-eslint/eslint-plugin @typescript-eslint/parser eslint eslint-config-airbnb-base eslint-config-prettier eslint-plugin-import eslint-plugin-prettier lint-staged prettier --save-dev

(5) 添加文档插件依赖

npm install typedoc --save-dev

(6) 添加提交规范插件和生成changelog插件

npm install @commitlint/cli @commitlint/config-conventional commitizen husky --save-dev

(6) 添加版本发布插件

npm install standard-version --save-dev

(7) 其他工具包省略~~~

(8) 完整依赖如下

"devDependencies": {
    "@commitlint/cli": "^17.0.3",
    "@commitlint/config-conventional": "^17.0.3",
    "@rollup/plugin-typescript": "^8.3.4",
    "@types/inquirer": "^9.0.1",
    "@types/jest": "^28.1.7",
    "@types/node": "^18.7.8",
    "@typescript-eslint/eslint-plugin": "^5.33.1",
    "@typescript-eslint/parser": "^5.33.1",
    "chalk": "^5.0.1",
    "commitizen": "^4.2.5",
    "cross-env": "^7.0.3",
    "eslint": "^8.22.0",
    "eslint-config-airbnb-base": "^15.0.0",
    "eslint-config-prettier": "^8.5.0",
    "eslint-plugin-import": "^2.26.0",
    "eslint-plugin-prettier": "^4.2.1",
    "esno": "^0.16.3",
    "husky": "^8.0.1",
    "inquirer": "^9.1.0",
    "jest": "^28.1.3",
    "jest-config": "^28.1.3",
    "lint-staged": "^13.0.3",
    "prettier": "^2.7.1",
    "rollup": "^2.78.1",
    "rollup-plugin-dts": "^4.2.2",
    "rollup-plugin-terser": "^7.0.2",
    "standard-version": "^9.5.0",
    "ts-jest": "^28.0.8",
    "tslib": "^2.4.0",
    "typedoc": "^0.23.10",
    "typescript": "^4.7.4"
  },

5. 插件配置

(1) 新建rollup.config.ts文件

import typescript from "@rollup/plugin-typescript";
import dts from "rollup-plugin-dts";
import { terser } from "rollup-plugin-terser";

const currentNodeEnv = process.env.NODE_ENV;
const isCompressLibrary =
  currentNodeEnv === "prod" ? terser({ module: true, toplevel: true }) : null;
const pkg = require("./package.json");

const libraryName = "ol-plugins";

export default [
  {
    input: "./src/index.ts",
    output: [
      {
        file: pkg.main,
        name: libraryName,
        format: "umd",
        sourcemap: true,
      },
      { file: pkg.module, format: "es", sourcemap: true },
    ],
    plugins: [
      typescript({ compilerOptions: { lib: ["esnext"] } }),
      isCompressLibrary,
    ],
    watch: {
      include: "src/**",
      exclude: "node_modules/**",
    },
  },
  {
    input: "./src/index.ts",
    output: [{ file: `dist/${libraryName}.d.ts`, format: "esm" }],
    plugins: [dts()],
  },
];

(2) 新建.prettierrc文件

{
  "printWidth": 80,
  "tabWidth": 2,
  "useTabs": false,
  "semi": true,
  "singleQuote": false,
  "trailingComma": "es5",
  "bracketSpacing": true,
  "arrowParens": "always",
  "htmlWhitespaceSensitivity": "css",
  "endOfLine": "lf"
}

(3) 新建.editorconfig文件

root = true

[*]
indent_style = space
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
max_line_length = 120
indent_size = 2

[*.md]
trim_trailing_whitespace = false

(3) 新建.eslintrc.js文件

module.exports = {
  env: {
    browser: true,
    es2021: true
  },
  extends: ['airbnb-base', 'plugin:prettier/recommended'],
  parser: '@typescript-eslint/parser',
  parserOptions: {
    ecmaVersion: 'latest',
    sourceType: 'module'
  },
  plugins: ['@typescript-eslint'],
  rules: {
    'import/no-extraneous-dependencies': 'off',
    'no-underscore-dangle': 'arrow'
  }
}

(4) 新建commitlint.config.js文件

module.exports = { extends: ['@commitlint/config-conventional'] }

(5) 新建tsconfig.json文件

{
  "compilerOptions": {
    "moduleResolution": "node",
    "target": "es5",
    "module": "es2015",
    "lib": ["es2015", "es2016", "es2017", "dom"],
    "strict": true,
    "sourceMap": true,
    "declaration": true,
    "allowSyntheticDefaultImports": true,
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true,
    "declarationDir": "dist/types",
    "outDir": "dist/lib",
    "typeRoots": ["node_modules/@types"]
  },
  "include": ["src"],
  "typedocOptions": {
    "entryPoints": ["src/index.ts"],
    "out": "docs"
  }
}

(6) 新建typedoc.json文件

{
  "entryPoints": [
    "./src/index.ts"
  ],
  "includes": [
    "src/*.ts"
  ],
  "out": "docs",
  "readme": "none",
  "includeVersion": true,
  "disableSources": false
}

(7) 配置lint-staged。在packages 里面添加如下

  "devDependencies":{},
  ...
  "lint-staged": {
    "src/**/*.{js,ts}": [
      "prettier --write",
      "git add"
    ]
  },

(8) 配置commitizen。在packages 里面添加如下

  "devDependencies":{},
  ...
  "config": {
    "commitizen": {
      "path": "cz-conventional-changelog"
    }
  },

(9) 配置husky。在packages 里面添加如下

  "devDependencies":{},
  ...
  "husky": {
    "hooks": {
      "commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
    }
  },

(10) 配置jest。在packages 里面添加如下

  "devDependencies":{},
  ...
  "jest": {
    "transform": {
      ".(ts|tsx)": "ts-jest"
    },
    "testEnvironment": "node",
    "testRegex": "(/__tests__/.*|\\.(test|spec))\\.(ts|tsx|js)$",
    "moduleFileExtensions": [
      "ts",
      "tsx",
      "js"
    ],
    "coveragePathIgnorePatterns": [
      "/node_modules/",
      "/test/"
    ],
    "coverageThreshold": {
      "global": {
        "branches": 90,
        "functions": 95,
        "lines": 95,
        "statements": 95
      }
    },
    "collectCoverageFrom": [
      "src/*.{js,ts}"
    ]
  },

6. 打包脚本编写。

(1) toolkit/release.ts

import { execSync } from "child_process";
import chalk from "chalk";
import { inquireVersion } from "./inquirer";

// NPM 发包流程文件
// 0. 执行 npm run test 确保所有测试用例通过
// 1. 询问发什么版本的包 major:大版本 minor: 小版本 patch: 补丁,新特性,bug修复版本

async function initRelease() {
  execSync("jest --coverage --watch", { stdio: "inherit" });
  console.log(chalk.blueBright("所有测试用例通过!"));
  const version = await inquireVersion(); // 自动提升版本
  execSync(`standard-version --release-as ${version}`, { stdio: "inherit" });
  console.log(chalk.blueBright("版本更新完成!"));
  execSync("npm publish --access public", { stdio: "inherit" });
  console.log(chalk.blueBright("NPM发布完成!"));
  execSync("git push origin main", { stdio: "inherit" });
  execSync("git push origin --tags", { stdio: "inherit" });
  console.log(chalk.blueBright("代码提交到远程仓库中!"));
}

initRelease();

(2) toolkit/inquirer.ts

import inquirer from "inquirer";

export const inquireVersion = async () => {
  const { version } = await inquirer.prompt({
    type: "list",
    name: "version",
    message: "Please select the release version from list",
    default: "patch",
    choices: ["major", "minor", "patch"],
  });
  return version;
};

7. 脚本命令配置之

 "scripts": {
    "dev": "npm run build:entry && cross-env NODE_ENV=dev rollup --config rollup.config.ts --watch",
    "build": "npm run build:entry && cross-env NODE_ENV=prod rollup --config rollup.config.ts",
    "test": "jest --coverage",
    "test:watch": "jest --coverage --watch",
    "test:prod": "npm run lint && npm run test -- --no-cache",
    "doc": "typedoc --options typedoc.json",
    "release": "esno ./toolkit/release.ts",
    "commit": "git cz"
  },
  ...
  "devDependencies":{},
  ...

4. 文档发布

1. 在跟目录新建目录 ./github/workflows

2. 新建文件 eploy-docs.yml, dp监听了main分支的变化,会自动构建文档,新建或覆盖推送到gh-pages 分支。

name: Build and Deploy Docs
# 监听 main 分支的推送
on:
  push:
    branches:
      - main
  pull_request:
    branches:
      - main
jobs:
  # job 名
  build-and-deploy:
    # 运行环境
    runs-on: ubuntu-latest
    # 运行步骤
    steps:
      # 获取源码
      - name: Checkout
        uses: actions/checkout@v2.3.1
      # 下载依赖
      - name: Install dependencies
        run: npm install
      # Docs 安装依赖
      - name: Build Docs
        run: npm run doc
      # 发布
      # 发布在 gh-pages 分支,会自动创建
      # 将打包后的 dist 目录放到 gh-pages 分支
      - name: Deploy
        uses: peaceiris/actions-gh-pages@v3
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}
          publish_dir: docs

3. 使用github page 显示自己的文档。

(1) 新建仓库,命名为自己的github账号名+'github.io',例如:# little-qiu.github.io。

(2) 进入本仓库,如下图:点击save 保存。

1661351152135.jpg

(3) 等待1分钟即可,此时就可以用自己的github page 访问自己的文档。

@little_q/ol_plugins - v1.0.0 (little-qiu.github.io)

image.png

5. 参考源码

github.com/Little-Qiu/…