Skip to content
文章目录

使用vite开发组件并发布到npm

步骤

  1. 新建项目并开发组件
  2. 编写 index.ts 文件,指明入口
  3. 配置 vite 库模式
  4. 打包
  5. 配置 package.json
  6. 测试
  7. 申请/登录 npm 账号
  8. 发布组件

新建项目

pnpm add @types/node vite-plugin-dts -D

  • 使用 pnpm 新建一个空项目,并使用 pnpm 的 monorepo 功能,使这个项目作为总的工作空间
  • 使用 vite 在 这个工作空间创建一个 vue 项目
  • 编写组件,并导出组件
  • 打包,并测试

启用 pnpm 的 monorepo 功能,只需要在项目根目录创建pnpm-workspace.yaml文件,并指定包含的目录

pnpm-workspace.yaml

yaml
packages:
  # 包含的目录
  - 'projects/**'
  # 排除的目录
  - '!**/test/**'

vite 配置库模式

ts
// vite.config.js
import { resolve } from 'path'
import { defineConfig } from 'vite'

export default defineConfig({
  build: {
    lib: {
      entry: resolve(__dirname, 'lib/main.js'),
      name: 'MyLib',
      // the proper extensions will be added
      fileName: 'my-lib',
    },
    rollupOptions: {
      // 确保外部化处理那些你不想打包进库的依赖
      external: ['vue'],
      output: {
        // 在 UMD 构建模式下为这些外部化的依赖提供一个全局变量
        globals: {
          vue: 'Vue',
        },
      },
    },
  },
})

package.json 配置说明

json
{
  /*
   1. 用于定义package.json文件和该文件所在目录根目录中.js文件和无拓展名文件的处理方式。值为'moduel'则当作es模块处理;值为'commonjs'则被当作commonJs模块处理
   2. 目前node默认的是如果pacakage.json没有定义type字段,则按照commonJs规范处理
   3. node官方建议包的开发者明确指定package.json中type字段的值
   4. 无论package.json中的type字段为何值,.mjs的文件都按照es模块来处理,.cjs的文件都按照commonJs模块来处理
    */
  "type": "module",
  /*
   如果需要避免这个包被发布到公共仓库上去,则可以设置为true,如果需要对外发布,则需要设置为false
   */
  "private": false,
  /*
  执行 npm pub 命令时哪些文件会被发布到npm仓库
   */
  "files": ["dist"],
  // 使用 require('xxx') 方式引入时, 引入的是这个文件
  "main": "./dist/my-button.umd.cjs",
  // 使用 import x from 'xxx' 方式引入组件时,引入的是这个文件
  "module": "./dist/my-button.js",
  // 组件ts类型声明文件的入口文件
  "types": "./dist/index.d.ts",
  /*
  定义外部可访问的资源。
  如果不定义,那么整个发布目录下的资源都是可以访问的。
  如果定义了,那只能访问定义的资源。
  ".": {
      "import": "./dist/my-button.js",
      "require": "./dist/my-button.umd.cjs"
    }
    上面这个配置表示当使用 import 和 require 方式引入时,分别引入的是哪个具体的js
   
   "./dist/style.css": "./dist/style.css"
   上面这个配置表示当使用 import 'xxx/dist/style.css'时访问的是 dist 目录下的 style.css文件

   定义了exports之后,如果想访问 import 'xx/dist/scss/index.scss' 会报错。 因为exports中未声明这个资源
   要么就添加这个资源的定义. 要么就删除exports定义,删除了exports定义之后,发布目录下的所有文件就都可以直接访问了
  */
  "exports": {
    ".": {
      "import": "./dist/my-button.js",
      "require": "./dist/my-button.umd.cjs"
    },
    "./dist/style.css": "./dist/style.css"
  },
  // 如果是打包成了一个可执行cli,那这里就指定这个cli的名称和cli文件的路径
  "bin": { "npm": "./cli.js" },
  // 提交bug的url和(或)邮件地址
  "bugs": {
    "url": "http://github.com/owner/project/issues",
    "email": "project@hostname.com"
  },
  // 指定执行publish命令时,会发布到哪个仓库. 该方式可以用于避免代码不小心被发布到公共仓库
  "publishConfig": {
    "registry": "http://localhost:2000"
  }
}

关于 pnpm 的 monorepo 的注意点

当你 pnpm 工作空间中有demo-comp项目,其他项目需要引用该项目,你通常是直接pnpm add进来,但如果外部registry中存在同名的包时,默认情况下会优先下载和使用外部registry中存在的包,此时有必要给项目加个前缀@xx/yyy之类的,但如果加了之后外部包还有同名包呢? 此时可以在工作空间根目录创建.npmrc文件,并设置prefer-workspace-packagestrue, 那么此时工作空间中的包将会优先于外部registry中的包。配置详见官网 prefer-workspace-packages, 那么实际上就是做两点

  • 给工作空间的项目加上特殊前缀。如: @xxx/yyy
  • 在工作空间根目录创建.npmrc文件,并指定prefer-workspace-packagestrue

更新一种添加 workspace 包的方式

shell
pnpm add workspace:npm-my-button@* -F web

这种方式能够在不修改配置的情况下,也能明确的让 pnpm 知道,你要添加的是 pnpm 中 workspace 里面的包,而非外部 npm 库中的包.

npm-my-button替换成你 workspace 中的包名即可

个人关于monorepo分包命名建议

yaml
packages:
  # 存放实际的项目
  - 'projects/**'
  # 存放公共的ui组件和util组件
  - 'packages/**'
  # 存放ui组件和util组件的使用文档
  - 'packages-docs/**'
  # 存放公共ui组件和util组件的使用示例
  - 'examples/**'
  # 排除目录
  - '!**/test/**'

补充

打包之后的组件,调用时有时会出现process is not defined的异常,这是因为浏览器环境是没有process对象的。而打包后的源代码中有使用process对象,根本原因不知道。解决方案就是

vite.config.ts

define:{
  'process.env': {}
}

参考资料

设置 NPM Registry 的 4 种姿势

https://vitejs.cn/vite3-cn/guide/build.html#library-mode

pnpm 官网 prefer-workspace-packages 配置属性说明

vue3 + vite 出现 process is not defined 解决办法