npm开发套件-上篇

背景

因为业务需求需要开发一个npm包,但没有一个npm开发规范,也没有一个开发npm的模板,看了已有的npm包。是一种百花齐放的状态,所以这里想完成一个npm开发套件,让开发者可以开箱即用。

目标

完成一个npm套件,让开发者开箱即用。那么这个套件应有包含以下功能:

  • 统一的代码规范
  • 统一的协作规范
  • 零配置
  • 自动化npm包创建【下篇实现】
  • 一键发布发布
  • 发布套件-cli 【下篇实现】

根据上面目标,这里给出了整个套件的架构

image.png

其实看到这里,你可能发现,npm和web或者其他应用其实类似,这里看完了你都了解了,配置其他类型的应用也很容易了。

认识NPM

虽然天天用这个,但是不是真的都完全了解了呢,不是吧!哈哈,这里有一篇很好的文章,还有这篇

包管理 – lerna

因为要开发一系列相关npm包, 这里用的是lerna,作为包管理工具。这里有篇文章介绍lerna最佳实践

初始化项目

yarn add global lerna
mkdir <dir-name>
cd dir-name
lerna init
复制代码

经过上面步骤,会在自定义目录里生成,以下目录和文件

packages/
lerna.json
package.json
复制代码

安装依赖

对于新项目,安装包,独立模式下都需要加上 -W

lerna add husky # 给所有包都安装husky
lerna add husky -D --scope=@xxxx/package-name # 指定给 @xxxx/package-name 包安装husky
# 更多信息, 查看 lerna add -h
复制代码

对于老项目

lerna bootstrap # 安装所有包的依赖
lerna bootstrap --scope @xxxx/package-name # 安装自定包下面的所有依赖
# 更多信息,查看 lerna bootstrap -h
复制代码

由于包之间可能存在共同的包,不需要我们重复安装,我们可以这样

lerna bootstrap --hoist # 把公共包装在根目录下的node_modules,这样降低依赖安装、管理成本
复制代码

还可以简化使用成本,修改配置文件

// lerna.json  这样 lerna bootstrap 等价于 lerna bootstrap --hoist
{
  "command": {
     "bootstrap": {
        "hoist": true
     }
  }
}
复制代码

统一代码规范

因为项目中可能用到TS 或 JS,所以 eslint 需要支持两种语法的lint检查。而这些检查是针对所有项目的,所以在根目录安装ESlint相关包

ESlint 检查JS

安装依赖

yarn add -D eslint
复制代码

新增配置.eslintrc.js, 完成eslint 对JS的语法检查

// .eslintrc.js
module.exports = {
  extends: ['eslint:recommended'],
  env: {
    browser: true,
    node: true,
  },
  parserOptions: {
    ecmaVersion: 2019,
    sourceType: 'module',
  }
};
复制代码

ESLint 检查TS

安装依赖

yarn add -D typescript @typescript-eslint/eslint-plugin @typescript-eslint/parser
复制代码

配置.eslintrc.js, 完成对eslint对TS的检查

// .eslintrc.js
module.exports = {
  parser: '@typescript-eslint/parser',
  extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended'],
  plugins: ['@typescript-eslint'],
  parserOptions: {
    ecmaVersion: 2019,
    sourceType: 'module',
  },
  env: {
    browser: true,
    node: true,
  }
};
复制代码

Prittier

安装依赖

yarn add -D prettier eslint-config-prettier eslint-plugin-prettier
复制代码

修改.eslintrc.js

// .eslintrc.js
module.exports = {
  parser: '@typescript-eslint/parser',
  extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended', 'plugin:prettier/recommended'],
  plugins: ['@typescript-eslint', 'prettier'],
  parserOptions: {
    ecmaVersion: 2019,
    sourceType: 'module',
  },
  env: {
    browser: true,
    node: true,
  }
};
复制代码

需要注意的是:由于eslint和prettier 都会对代码的格式做校验。那么就会有冲突

  • eslint-config-prettier 插件,可以让eslint使用prettier规则进行检查,并使用–fix选项。
  • eslint-config-prettier 插件,之前说了eslint也会检查代码的格式,这个插件就是关闭所有不必要或可能跟prettier产生冲突的规则。

新增.prettierrc

{
  "singleQuote": true,
  "trailingComma": "es5",
  "printWidth": 120,
  "tabWidth": 2,
  "useTabs": false,
  "semi": true,
  "overrides": [
    {
      "files": ".prettierrc",
      "options": { "parser": "json" }
    }
  ]
}
复制代码

统一协作规范

对改动文件做ESLint检查

首先安装可以提供各种git钩子的husky

yarn add -D husky
复制代码

注意默认你安装的应该是V6,husky配置发生了很大的改变,现在市面大都是V6以下的配置方式,所以你的husky配置不生效

npx husky install # 会在根目录生成 .husky文件夹,里面存放 githook 文件
复制代码

安装lint-staged, 顾名思义,他使用来对git add后的代码做lint检查。

yarn add -D lint-staged
复制代码

修改package.json

{
  // other config
  "lint-staged": {
    "*.{js,ts}": [
      "eslint --fix",
    ]
  }
}
复制代码

新增pre-commit hook,对staged代码做eslint校验

npx husky add .husky/pre-commit "npx lint-staged"
复制代码

Commit 信息规范化

这里要对每个人提交信息规范化,同时也方便后续自动化生成changelog

安装规范化commit的依赖

yarn add -D @commitlint/cli @commitlint/config-conventional 
复制代码

新建commitlint.config.js文件。

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

新增commit-msg hook

npx husky add .husky/commit-msg 'npx --no-install commitlint --edit "$1"'
复制代码

自动生成changelog

前面我们规范化了我们的提交信息,这里我们希望利用我们的提交信息,在发布版本后,能自动生成changelog

安装依赖

yarn add -D commitizen cz-lerna-changelog
复制代码

修改package.json

// package.json 新增config 配置
{
  "config": {
    "commitizen": {
      "path": "./node_modules/cz-lerna-changelog"
    }
  }
}
复制代码

至此我们完成了,所有代码规范和协作规范上的配置。我们可以正常开发npm包了。

打包工具 – rollup

我们一般都是用TS,或者ES6来开发npm包,但大部分应用都还是需要es5才能正常运行,所以我们需要一款打包工具。这里是为了从来没用过rollup,所以选择了rollup

看社区还有个基于rollup的、零配置的Bili,看起来更香

a word on Bili. Bili is just a nice, Rollup-based and zero-config (by default) bundler with built-in support for ES-Next and CSS

进入子包,安装依赖

 cd packages/your-subpackage
 yarn add -D bili rollup-plugin-typescript2
复制代码

在子包根目录下新建配置文件,点击了解更多 Bili 官网

// config/bili.base.js
module.exports = {
  input: 'src/index.ts',
  output: {
    moduleName: 'Package',
    fileName: '[name][ext]',
  },
  plugins: {
    typescript2: {
      useTsconfigDeclarationDir: true,
    },
    // 这里是fix @rollup/plugin-replace 剔出的warning
    replace: {
      preventAssignment: true,
    },
  },
};

// config/bili.dev.js
import merge from 'rollup-merge-config';
import baseConfig from './bili.base';

module.exports = merge(baseConfig, {
  output: {
    // 这里输入dev 模式下配置
  },
  env: {
    ENV: 'development',
  },
});


// config/bili.prod.js
import merge from 'rollup-merge-config';
import baseConfig from './bili.base';

module.exports = merge(baseConfig, {
  output: {
    // 这里输入prod 模式下配置
    minify: true,
    sourceMap: false,
  },
  env: {
    ENV: 'production',
  },
});

复制代码

开发生产模式的配置都在这了,是不是炒鸡简单。

修改子包package.json

{
  "scripts": {
    // other npm scripts
    "build": "rm -rf dist/ && bili --config config/bili.prod.js",
    "start": "bili --watch --config config/bili.dev.js"
  },
}
复制代码

至此,所有项目配置完成。可以尽情的开发npm包了。

发布

配置发布脚本

由于bili或者rollup只是负责打包,如果我们需要发布npm包,需要做以下几件事:

  • 将包目录下package.json拷贝到dist
  • changelog.mdreadme.md 拷贝到dist

ok,很容易,子包根目录新建build.sh文件。


cp package.json dist/
cp CHANGELOG.md dist/
cp README.md dist/

# 如果npm是ts项目,则将typings拷到dist
tsconfig=$(cd `dirname $0`; pwd)"/tsconfig.json"
typingsDir=$(cd `dirname $0`; pwd)"/typings/"
if [ -f "$tsconfig" ] && [ -d "$typingsDir" ]; then
  cp -r typings dist/
fi
复制代码

这里typings是啥?

这里存放npm自己的声明文件。

根目录下增加命令行

// package.json

// 这里要做三件事:
// 1. 更新版本号
// 2. 执行子包下面的build.sh,【因为这里要是最终的版本号,所以要在lerna version 后】
// 3. 发布

{
  "scripts": {
    // other npm scripts
    "prePublish": "npx lerna exec ./build.sh",
    "pub:test": "npx lerna version prerelease --preid=beta --yes && npm run prePublish && npx lerna publish from-git --yes", // 发beta包
    "pub:patch": "npx lerna version patch --yes && npm run prePublish && npx lerna publish from-git --yes", // 发 patch 包
    "pub:minor": "npx lerna version minor --yes && npm run prePublish && npx lerna publish from-git --yes", // 发 minor 包
    "pub:major": "npx lerna version major --yes && npm run prePublish && npx lerna publish from-git --yes" // 发 major 包
  },
}
复制代码

执行发布命令

npm run pub:test # 发beta
npm run pub:xxx # 发其他正式包
复制代码

补充

lerna.json

这里给出lerna.json完整代码

{
  "packages": [
    "packages/*"
  ],
  "command": {
    "bootstrap": {
      "hoist": true
    },
    "version": {
      "conventionalCommits": true,
      "noCommitHooks": true
    },
    "publish": {
      "conventionalCommits": true,
      "message": "chore(release): publish %s"
    }
  },
  "ignoreChanges": ["**/__tests__/**", "**/*.md"],
  "version": "independent"
}
复制代码

提取ts相同配置

根目录配置一份tsconfig.base.json

{
  "compilerOptions": {
    "module": "esnext",
    "lib": ["esnext", "dom"],
    "strict": true,
    "declaration": true,
    "esModuleInterop": true,
    "moduleResolution": "Node"
  },
  "files": []
}
复制代码

子包根目录配置子包的tsconfig

{
  "extends": "../../tsconfig.base.json",
  "compilerOptions": {
    "outDir": "dist",
    "rootDir": "src",
    "baseUrl": "./",
    "declarationDir": "./typings"
  },
  "include": ["src/**/*"],
  "exclude": [
    "node_modules",
    "**/__tests__/*",
    "**/__e2e__/*"
  ],
}
复制代码
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享