本文首发于微信公众号:大迁世界, 我的微信:qq449245884,我会第一工夫和你分享前端行业趋势,学习路径等等。
更多开源作品请看 GitHub https://github.com/qq449245884/xiaozhi ,蕴含一线大厂面试残缺考点、材料以及我的系列文章。

技术始终在变动,咱们的流程和做法也须要跟上这些变动。因而,尽管npm曾经有12年的历史了,但围绕 npm 包创立的做法应该更古代。

在这节课中,咱们应用古代最佳实际(截至2022年)一步一步地创立一个npm包。首先学习如何创立一个npm包,这样你就能够相熟构建和公布一个包到 npm 注册表。

而后,再学习如何通过建设测试框架、继续集成和部署管道、安全检查以及公布的主动语义版本治理,来制作一个更强壮、可用于生产的npm包。

简略的npm包示例

咱们先通过一个简略的例子来相熟创立和公布npm包的过程。

创立我的项目

  1. 创立一个 GitHub 仓库: https://github.com/new
  2. 克隆本地的 repo。
    例如:git clone https://github.com/snyk-labs/simple-npm-package.git
  3. 关上你的终端,进入到克隆的我的项目文件夹。
    例如:cd simple-npm-package
  4. 运行 npm init -y 来创立 package.json 文件。留神:如果克隆了示例仓库,就不须要做这一步。
  5. 在package.json 取一个名称,对应 name 字段
  6. 为该包编写你的代码

创立 npm 账户

为了可能让咱们的 npm 包供别人应用,须要一个npm账户。

  • 通过 https://www.npmjs.com/signup 注册
  • 为了进步安全性,请在您的npm账户上启用2FA:https://docs.npmjs.com/configuring-two-factor-authentication
  • 应用 npm login 命令在终端中用你的 npm账户登录,并依照屏幕上的批示操作。
> npm loginnpm notice Log in on https://registry.npmjs.org/Username: clarkioPassword:Email: (this IS public) <email address>npm notice Please use the one-time password (OTP) from your authenticator applicationEnter one-time password from our authenticator app: <OTP>Logged in as clarkio on https://registry.npmjs.org/.

如何公布 npm 包

一旦你有了一个npm我的项目和一个npm账户,你就能够把你的npm包公布到公开的官网npmjs注册表上,让其他人能够应用。以下是你要遵循的步骤,在执行之前查看将公布的内容,而后运行理论的公布过程。

  1. 在终端,运行 npx npm-packlist 来查看将被蕴含在公布版本的软件包中的内容。

这能够确保咱们没有脱漏任何源代码文件,这些文件是软件包失常运行所须要的。这也是一个好的做法,以确保咱们不会意外地将敏感信息泄露给公众,如带有数据库凭证或API密钥的本地配置文件。

> npx npm-packlistLICENSEindex.jspackage.jsonREADME.md

在终端,运行npm publish --dry-run,看看理论运行命令时将会做什么。

> npm publish --dry-runnpm noticenpm notice @clarkio/simple-npm-package@0.0.1npm notice === Tarball Contents ===npm notice 1.1kB LICENSEnpm notice 1.2kB README.mdnpm notice 95B index.jsnpm notice 690B package.jsonnpm notice === Tarball Details===npm notice name: @clarkio/simple-npm-packagenpm notice version: 0.0.1npm notice filename:@clarkio/simple-npm-package-0.0.1.tgznpm notice package size:1.7 kBnpm notice unpacked size: 3.1 kBnpm notice shasum:40ede3ed630fa8857c0c9b8d4c81664374aa811cnpm notice integrity:sha512-QZCyWZTspkcUXL... ]L60ZKBOOBRLTg==npm notice total files:4npm notice+ @clarkio/simple-npm-package@0.0.1
  1. 在终端,运行 npm publish --access=public 来公布软件包到npm。

留神:--access=public对于作用哉内的包(@clarkio/modern-npm-package)是须要的,因为它们默认是公有的。如果它不是作用哉内的,并且在你的 package.json 中没有将private 字段设置为 true,它也将是公开的。

> npm publish --access=publicnpm noticenpm notice @clarkio/simple-npm-package@0.0.1npm notice === Tarball Contents ===npm notice 1.1kB LICENSEnpm notice 1.2kB README.mdnpm notice 95B index.jsnpm notice 690B package.jsonnpm notice === Tarball Details===npm notice name: @clarkio/simple-npm-packagenpm notice version: 0.0.1npm notice filename:@clarkio/simple-npm-package-0.0.1.tgznpm notice package size:2.1 kBnpm notice unpacked size: 4.1 kBnpm notice shasum:6f335d6254ebb77a5a24ee729650052a69994594npm notice integrity:sha512-VZ1K1eMFOKeJW[...]7ZjKFVAxLcpdQ==npm notice total files:4npm noticeThis operation requires a one-time password.Enter OTP: <OTP>+ @clarkio/simple-npm-package@0.0.1

当初,咱们曾经实现了构建和部署本人的npm包。接下来,咱们来看一下如何制作一个更弱小的包,为生产环境做好筹备,并失去更宽泛的应用。

生产就绪的npm包

尽管后面的例子的包能够在生产中应用,但它波及到人工成本来放弃其长期的保护。应用工具和自动化以及适当的测试和安全检查将有助于最大限度地缩小放弃软件包顺利运行的总工作量。让咱们深刻理解一下这其中的内容。

  1. 构建CommonJS(CJS)和ECMAScript(ESM)模块
  2. 设置和编写单元测试
  3. 施行安全检查
  4. 实现版本治理和公布的自动化

构建 CommonJS(CJS)和ECMAScript(ESM)模块

尽管ECMAScript模块格局当初在Node.js的12+版本中被原生反对,但它还没有被社区宽泛采纳。为了面向未来并反对这两种格局,咱们来看下应用 TypeScript怎么来配置。

首先,创立一个根本的 TypeScript 配置文件 tsconfig.base.json。这是通用的编译设置,无论你的指标是哪种模块格局,都能够应用。

{  "compilerOptions": {    "strict": true,    "esModuleInterop": true,    "forceConsistentCasingInFileNames": true,    "skipLibCheck": true,    "checkJs": true,    "allowJs": true,    "declaration": true,    "declarationMap": true,    "allowSyntheticDefaultImports": true  },  "files": ["../src/index.ts"]}

而后为 CommonJS 格局创立一个TypeScript配置文件,命名为tsconfig.cjs.json

  • lib 属性向TypeScript指出它应该参考哪些类型。
  • target 属性向TypeScript指出要编译的我的项目代码的JavaScript版本。
  • module 属性向 TypeScript 指出在编译的我的项目代码时应该应用哪种JavaScript模块格局。
  • moduleResolution 属性帮忙 TypeScript 弄清 "import"语句应该如何被提及。
  • outDirdeclarationDir 属性向TypeScript指出了将编译的代码和定义其中应用的类型的后果放在哪里。
{  "extends": "./tsconfig.base.json",  "compilerOptions": {    "lib": ["ES6", "DOM"],    "target": "ES6",    "module": "CommonJS",    "moduleResolution": "Node",    "outDir": "../lib/cjs",    "declarationDir": "../lib/cjs/types"  }}

之后,为 ECMAScript 格局创立一个TypeScript配置文件,命名为tsconfig.esm.json。这里的属性与你在 CommonJS 配置中看到的雷同,但当初针对古代ECMAScript模块格局作为其输入。

{  "extends": "./tsconfig.base.json",  "compilerOptions": {    "lib": ["ES2022", "DOM"],    "target": "ES2022",    "module": "ESNext",    "moduleResolution": "NodeNext",    "outDir": "../lib/esm",    "declarationDir": "../lib/esm/types"  }}

更新 package.json 文件,减少一个 files 字段,指向lib文件夹,外面有 TypeScript为你构建软件包的后果。

更新 package.json 文件中的 exports 字段,以定义如何依据应用的模块加载器(CJS vs. ESM)查找源文件。

"exports": {    ".": {      "import": {        "types": "./lib/esm/types/index.d.ts",        "default": "./lib/esm/index.mjs"      },      "require": {        "types": "./lib/cjs/types/index.d.ts",        "default": "./lib/cjs/index.js"      }    }  },

更新 package.json 文件的 maintypes 字段,以指向软件包的CJS版本。这将作为一个默认的、后备的选项。

“types": "./lib/cjs/types/index.d.ts","main": "./lib/cjs/index.js",

package.json 文件中增加一个 files 字段,以表明当 npm 打包你的代码进行公布时,应该包含哪些文件。

"files": [   "lib/**/*"],

通过 package.json 中的 scripts 字段创立命令,应用 tsc 并编译包的 CJS 和 ESM 格局,并生成 lib 文件。

clean 命令是用来删除过来构建的输入,并从一个洁净的中央开始。

build:esm命令开端的 mv lib/esm/index.js lib/esm/index.mjs 重命名了文件扩展名,这样Node.js模块加载器就晓得它是一个ESM模块。

prepack命令是npm在打包npm包筹备公布到注册表之前应用的。

    "clean": "rm -rf ./lib",    "build": "npm run clean && npm run build:esm && npm run build:cjs",    "build:esm": "tsc -p ./configs/tsconfig.esm.json && mv lib/esm/index.js lib/esm/index.mjs",    "build:cjs": "tsc -p ./configs/tsconfig.cjs.json",    "prepack": "npm run build"

当初能够在终端运行 npm run build,让TypeScript构建你的我的项目,为应用和公布做筹备

这就是应用 TypeScript 构建 npm 包所须要做的所有设置,它同时反对 CommonJS 和ECMAScript模块格局。

设置和增加测试

为了对代码的行为和后果有信念,咱们须要有一个测试过程。测试迫使在第一次创立代码时,在happy-path 之外,以不同的形式思考代码的性能。举个例子,能够想方法突破一个函数,使它抛出一个谬误或产生一个非预期的后果。这样做将使你的应用程序更有弹性和可持续性,并确保在增加更多内容时不会呈现问题。

单元测试

要确保库以咱们想要的形式运行,须要针对代码编写测试。咱们须要一些工具来帮忙设置咱们我的项目来运行单元测试并显示后果。

这些工具有 Mocha.jsChai.jsts-node。Mocha.js 是一个测试运行器,Chai.js是一个断言库,帮忙确定你是否从你的代码中失去你所冀望的后果,而 ts-node 帮忙咱们在TypeScript我的项目中应用这些工具。依照上面的步骤,为 npm包设置和运行测试。

  • 在终端中应用以下命令装置开发者的依赖:
    npm i -D mocha @type/mocha chai @types/chai ts-node
  • 在我的项目的根目录下创立一个新文件 .mocharc.json,内容如下:

    {  "extension": ["ts"],  "spec": "./**/*.spec.ts",  "require": "ts-node/register"}
  • 在我的项目的根目录下创立一个 tests 文件夹。
  • index.spec.ts 文件中写单元测试来测试 index.ts 中的代码。
  • package.json 文件的 scripts 局部增加一个 test 属性,给它一个 mocha 的值。
  "scripts": {    "clean": "rm -rf ./lib",    "build": "npm run clean && npm run build:esm && npm run build:cjs",    "build:esm": "tsc -p ./configs/tsconfig.esm.json && mv lib/esm/index.js lib/esm/index.mjs",    "build:cjs": "tsc -p ./configs/tsconfig.cjs.json",    "prepack": "npm run build",    "test": "mocha"  },
  • 最初,在终端运行 npm test
bc@mbp-snyk modern-npm-package % npm test> @clarkio/modern-npm-package@0.0.0-development test> mocha  NPM Package    ✔️ should be an object    ✔️ should have a helloworld property  Hello World Function    ✔️  should be a function    ✔️ should return the hello world message4 passing (22ms)

管道中的测试

依照上面的步骤,创立一个测试工作流,作为我的项目管道的一部分。

  1. 为仓库创立一个新的GitHub Action :https://github.com/<your-account-or-organization>/<your-repo-name>/actions/new
  2. 将工作流程重命名为 test.yml
  3. 在工作流程文件中插入以下Snyk动作脚本:
name: Testson:  push:    branches: [ main ]  pull_request:    branches: [ main ]jobs:  build:    runs-on: ubuntu-latest    strategy:      matrix:        node-version: [12.x, 14.x, 16.x, 18.x]    steps:      - uses: actions/checkout@v3      - name: Use Node.js ${{ matrix.node-version }}        uses: actions/setup-node@v3        with:          node-version: ${{ matrix.node-version }}      - run: npm ci      - run: npm test

这个YAML脚本查看出你的最新代码,装置其依赖性,并运行 npm test命令来执行测试。它对node-version字段中列出的每一个Node.js版本都会这样做,所以能够确保代码在每次运行时都能按预期工作。

当初曾经实现了对我的项目的设置,以便对npm包的代码进行运行和评估测试。然而,你可能在想 "我如何在另一个我的项目中应用我的npm包进行测试?" 让咱们来看看。

包测试

包上传实现后,除了单元测试外,咱们还要测试在另一个我的项目引入咱们包应用的状况,看看是否像咱们所冀望那样。这里有五种能够测试的办法:

  1. 通过 npm pack 输入装置
  2. 通过相对路径装置
  3. 通过npm链接装置
  4. 通过注册表装置(如npmjs.com的npm公共注册表)。
  5. 应用Verdaccio(一个开源的npm公有npm注册我的项目)来运行端到端的软件包公布和装置步骤,作为你CI的一部分。

npm pack

这种办法将利用npm pack命令将 npm 包打包并压缩成一个文件(<package-name>.tgz)。而后你能够到你想应用该包的我的项目中,通过这个文件装置它。这样做的步骤如下。

  • 终端运行 npm pack。留神它产生的.tgz文件和它的地位。
  • 扭转目录到你想应用 npm 包的我的项目目录。例如:cd /path/to/project
  • 运行npm install /path/to/package.tgz
  • 而后就能够在我的项目中应用该包来测试货色了

npm link

利用 npm link 命令来装置本地包:

  1. 在以后包目录中,在终端运行 npm link
  2. 扭转目录到你想应用npm包的我的项目目录。例如:cd /path/to/project
  3. 在我的项目中运行 npm link <name-of-your-package>

这样在我的项目中就能够应用咱们的包。

相对路径

这种相似于npm link。

  • 在终端运行 npm install /path/to/your/package

npm link 的办法相似,这容许咱们在我的项目中疾速测试包的性能,但不会给你残缺的相似生产的体验。这是因为它指向残缺的软件包源代码目录,而不是你在npm注册表中找到的软件包的构建版本。

npm registry

这种办法利用了npm包的公共(或你本人)注册表。它波及到公布的包,并像你通常对任何其余npm包那样进行装置。

  • 应用本文后面概述的步骤,通过 npm publish 命令公布npm包
  • 扭转目录到想应用npm包的我的项目目录。例如:cd /path/to/project
  • 在我的项目目录中运行 npm install <name-of-your-package>

施行安全检查

就像你不心愿在本人的我的项目中呈现安全漏洞一样,你也不心愿在其他人的我的项目中引入破绽。构建一个预计会在许多其余我的项目中应用的npm包,这就减少了确保事件平安的责任。你须要有安全检查,以帮忙监测、揭示和提供帮忙来缩小破绽。这就是像Snyk这样的工具能够简化实现这些需要所需的工作的中央。

对于这个例子中的npm包,你应用GitHub作为你的源码管制管理工具,所以利用它的GitHub Actions性能将Snyk整合到工作流程中。Snyk 有一个GitHub Actions参考我的项目,能够帮忙启动这方面的工作,并为你的我的项目可能应用的其余编程语言和工具提供例子。

  1. Snyk是收费的,这里能够进行注册。
  2. 在GitHub上将你的Snyk API令牌增加为仓库机密: https://github.com/<your-account-or-organization>/<your-repo-name>/settings/secrets/actions/new
  3. 仓库创立一个新的GitHub Action: https://github.com/<your-account-or-organization>/<your-repo-name>/actions/new
  4. 将workflow 重命名为 snyk.yml
  5. 在 workflow 文件中插入以下Snyk Action 脚本:
name: Snyk Security Checkon: [push,pull_request]jobs:  security:    runs-on: ubuntu-latest    steps:      - uses: actions/checkout@main      - name: Run Snyk to check for vulnerabilities        uses: snyk/actions/node@master        env:          SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
  1. 提交你的批改。
  2. 验证Action 胜利运行: https://github.com/<your-account-or-organization>/<your-repo-name>/actions

有了这个设置,任何时候任何人推送到你的版本库或针对它关上一个拉动申请,都会进行安全检查,以确保它不会在软件包中引入任何破绽。如果发现了问题,口头将失败,并揭示你发现的平安问题的细节。接下来,你将围绕版本治理和公布你的npm包进行自动化解决。

对于目前的设置,须要留神的一点是,它只利用了Snyk开源(SCA)产品,而不是Snyk代码(SAST)。Snyk Code是咱们的代码平安产品,你须要首先通过你的Snyk账户启用它(收费),而后在这里增加到你的工作流程脚本中,以充分利用它。

实现版本治理和公布的自动化

每当在主分支中合并变动时,咱们不想每次都手动更新npm包的版本并公布它。相同,会想让这个过程主动产生。如果你还记得本篇文章后面那个简略的npm包的例子,用以下命令来更新npm包的版本,而后公布它。

npm version <major|minor|patch>npm publish

什么是语义版本治理?

语义版本治理规定,版本要用三个占位符进行编号。第一个是次要版本,第二个是主要版本,而最初一个是补丁版本。

Semantic Release的工具能够与 GitHub Actions 整合来帮忙咱们主动批改版本并公布。实现这一过程自动化的要害是,你在向我的项目提交变更时应用所谓的惯例提交。这使得自动化可能相应地更新所有,并晓得如何为你筹备我的项目的下一个版本。

  1. 运行:npm i -D semantic-release
  2. npx semantic-release-cli setup
  3. 依照终端的提醒,提供所需的令牌

    • 须要一个来自 GitHub 的集体拜访令牌。要创立一个,请到 https://github.com/<your-name-or-github-organization>/<your-repo-name>/settings/secrets/actions/new
    • 在创立此令牌时,请应用以下作用域

  1. 还须要一个来自npm的自动化类型的拜访令牌,只在CI环境中应用,这样它就能绕过你的账户的2FA。要创立一个,请到https://www.npmjs.com/settings/<your-npm-account>/tokens。请确保抉择 "Automation"类型,因为这将用于CI/CD工作流程中。

bc@mbp-snyk modern-npm-package % npx semantic-release-cli setup? What is your npm registry? https://registry.npmjs.org/? What is vour nom username? clarkio? What is your pm password? [hidden]? What is your NPM two-factor authentication code? <2FA code>Provide a GitHub Personal Access Token (create a token at https://github.com/settings/tokens/new?scopes=repo<token>? What CI are you using? Github Actionsbc@mbp-snyk modern-npm-package %
  1. 将npm令牌作为仓库机密增加到GitHub仓库中:https://github.com/<your-name-or-organization/<your-repository>/settings/secrets/actions/new。将机密的名称设置为NPM_TOKEN,其值是你在后面步骤中检索到的

  1. 回到我的项目中,进入package.json文件,像上面这样增加一个release键。如果你的版本库的主分支依然叫master而不是main,那么就相应地更新上述分支的值。
"release": {    "branches": ["main"]  }
  1. package.json 文件中也增加一个publishConfig键。
"publishConfig": {    "access": "public" }
  1. 通过应用semantic-release npm脚本进行模仿运行来测试所有。采纳以下命令,并将NPM_TOKEN=GH_TOKEN=值设置为应用您各自的令牌值。而后在你的终端中复制并运行残缺的命令,看看所有是否运行失常。你会看到过程被记录在终端的输入中。如果呈现任何问题,它们会在这里显示进去,并提供解决这些问题的细节。
  2. 在确认试运行胜利后,能够为GitHub仓库设置一个新的GitHub动作来为你解决公布过程。转到你在GitHub上的仓库,点击 "Actions"。
  3. 点击新建工作流程选项。
  4. 将工作流程重命名为release.yml。
  5. 在新的工作流程文件中退出以下YAML脚本。这个脚本次要是说,一旦Snyk安全检查工作胜利实现,就运行公布工作。公布作业会查看代码,设置Node.js环境,装置你的依赖项,而后应用你的GitHub和npm令牌运行语义公布。
name: Releaseon:  workflow_run:    workflows: ['Snyk Security Check', 'Tests']    branches: [main]    types:      - completedjobs:  release:    name: Release    runs-on: ubuntu-latest    steps:      - name: Checkout        uses: actions/checkout@v2        with:          fetch-depth: 0      - name: Setup Node.js        uses: actions/setup-node@v2        with:          node-version: 'lts/*'      - name: Install dependencies        run: npm ci      - name: Release        env:          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}          NPM_TOKEN: ${{ secrets.NPM_TOKEN }}        run: npx semantic-release

13.提交你的本地批改并推送到你的GitHub仓库

  • 能够通过在终端运行命令 git commit -am '<your commit message>',而后git push来实现。
  • 也能够在VS Code中通过其版本控制性能做到这一点。
  1. 在所有这些设置实现后,当初能够应用传统的提交形式将批改推送到你的主分支(或通过合并拉动申请),而后公布工作流就会运行(当然是在Snyk安全检查之后)。你能够在modern-npm-package版本库工作流程的例子中看到这种状况。

总结

咱们总结一下在本文中学到的所有。首先,相熟了设置、创立和部署一个简略的npm包。这对于相熟首次公布本人的npm包来说是很好的。然而,如果想制作一个供生产应用的npm包,这样做是相当费劲的,也是不可继续的。

为了实现制作一个可用于生产的包,随后学会了如何为CommonJS(CJS)和ECMAScript(ESM)模块格局进行构建,设置和编写单元测试,实现安全检查,并主动进行版本治理和公布。有了这些常识,当初曾经筹备好制作更多属于你本人的npm包了,这些包很容易被社区或你的公司所应用。

起源:https://snyk.io/blog/best-practices-create-modern-npm-package/

代码部署后可能存在的BUG没法实时晓得,预先为了解决这些BUG,花了大量的工夫进行log 调试,这边顺便给大家举荐一个好用的BUG监控工具 Fundebug。

交换

有幻想,有干货,微信搜寻 【大迁世界】 关注这个在凌晨还在刷碗的刷碗智。

本文 GitHub https://github.com/qq449245884/xiaozhi 已收录,有一线大厂面试残缺考点、材料以及我的系列文章。