likes
comments
collection
share

用 Unbuild 和 mkdist 打造你的第一个 Vue.js 组件库本文将带您探索构建 Vue.js 组件库的简化

作者站长头像
站长
· 阅读数 47

TLDR: 本文将带您探索构建 Vue.js 组件库的简化流程,以及背后的设计理念。vue-library 示例库可供参考。

组件库是一组可重复使用的组件,可以用于多个项目。它可以帮助不同项目和团队共享资源,这些组件可以是低级通用组件(例如按钮、输入框和模态框),也可以是特定业务模块。简而言之,组件库是跨项目共享代码的有效方法,能够显著节省时间。

然而,使用 Vue.js 构建组件库并不像看起来那样容易,因为 Vue.js 的单文件组件 (SFC) 带来了挑战。在标准 TypeScript 项目中,通常使用 tsup 或 Vite 将代码转译为 JavaScript,并进行打包。

关键原则: 尽可能以原生方式交付包代码,让用户工具负责转译和优化。这是构建库时应牢记的原则,能极大地简化流程。

Vue.js SFC 的挑战:

让我们以一个使用可组合函数的组件为例:

<script lang="ts" setup>
import { useUser } from '../composables'
const { user } = useUser()
</script>
<template>
 <div v-if="user">
 {{ user.name }}
 </div>
</template>

可组合函数代码如下:

import { ref } from 'vue'
export function useUser() {
 const user = ref({ name: 'John Doe' })
 return {
 user
 }
}

这个组件使用了另一个文件中的可组合函数,这看似简单,但它带来了一个显著的挑战。

项目的结构如下:

src/
 components/
 User.vue
 composables/
 useUser.ts
 index.ts

index.ts 是库的入口文件,内容如下:

import User from './components/User.vue'
export { User }
export { useUser } from './composables/useUser'

package.json 包含一些 exports 配置:

{
 "type": "module",
 "exports": {
 ".": {
 "types": "./dist/index.d.ts",
 "import": "./dist/index.mjs"
 }
 },
 "main": "dist/index.mjs",
 "types": "dist/index.d.ts"
}

类似标准 TypeScript 项目

注意: 包是一个包含所有项目代码的单个文件。它通过减少需要加载的文件数量来优化项目的加载速度。在创建 npm 包时,这个包不会进行转译(除了 TypeScript 到 JavaScript)或压缩。

如果尝试打包这个项目,dist 文件夹的结构如下:

dist/
 index.cjs

检查 index.cjs 文件后,你会发现可组合函数 useUser 被内联了,但组件却被完全忽略了。如果打包工具运行成功,可能会出现类似 No loader is configured for ".vue" files 的错误。这意味着像 esbuild 或 tsc 这样的工具不知道如何处理 Vue 文件,这是正常的,因为 Vue 文件不是 JavaScript 文件。

问题很明显:我们需要一些配置来处理 Vue 文件。在网上搜索 "vue loader",因为我们使用了 Vue 文件,需要将它们转译为 JavaScript。

搜索结果中最顶端的是 Vue Loader,它是一个 Webpack 加载器。但是,我不打算使用 Webpack,因为 Vite 已经成为行业标准,在这种情况下没有理由使用 Webpack。

不过,在我们深入之前,让我们回顾一下我们的口号:尽可能以原生方式交付包代码,并遵循 KISS 原则。 使用 Webpack 来转译 Vue SFC 文件似乎违反了这个原则。

忽略 Vue 文件

为了不转译 .vue 文件,我们可以指示打包工具忽略它们。这可以使用 UnJS 生态系统中的 unbuild 工具来实现。

Unbuild 是一个简单但高度可配置的工具,因为它构建在 rollup 之上。

对于我们的小项目,我们可以直接进行尝试:

npx unbuild

不幸的是,它会因为与之前相同的原因而失败:

src/components/ShowGitHubUser.vue (1:0): Expression expected (Note that you need plugins to import files that are not JavaScript)

但 unbuild 的潜力远不止此。

为了解决这个问题,让我们尝试显而易见的解决方案。在 index.ts 文件中,移除组件导出,只导出 TypeScript 文件:

export { useUser } from './composables/useUser'

现在,npx unbuild 命令可以正常运行:

➜ npx unbuild
ℹ Automatically detected entries: src/index [esm] [dts]
ℹ Building vue-library
ℹ Cleaning dist directory: ./dist
✔ Build succeeded for vue-library
 dist/index.mjs (total size: 139 B, chunk size: 139 B, exports: useUser)
Σ Total dist size (byte size): 531 B

这是一个好的开始,但我们的组件仍然在 src 文件夹中,无论你如何仔细搜索,它们都不会出现在 dist 文件夹中。

复制 Vue 文件

现在 .ts 文件已经正确处理了,我们可以尝试使用简单的 cp 命令将 .vue 文件复制到 dist 文件夹中。

cp -r src/components/ dist/components/

然后,我们在 package.json 中添加一个 exports 字段,告诉用户在哪里可以找到这些组件:

{
 "type": "module",
 "exports": {
 ".": {
 "types": "./dist/index.d.ts",
 "import": "./dist/index.mjs"
 },
 "./components/*": {
 "import": "./dist/components/*.vue"
 }
 },
 "main": "dist/index.mjs",
 "types": "dist/index.d.ts"
}

看起来很有希望,不是吗?但事实并非如此。 😔

导入路径的困境

在我们的 Vue 组件中,useUser 可组合函数的导入方式如下:

<script lang="ts" setup>
import { useUser } from '../composables'
</script>

而我们的 dist 文件夹的结构如下:

dist/
 components/
 User.vue
 index.d.mts
 index.d.ts
 index.mjs

你能找出问题所在吗?👀

组件无法使用,并会产生 Cannot find module '../composables' or its corresponding type declarations 错误,因为路径指向错误的位置。我们已经将所有 TypeScript 文件打包到一个名为 index.mjs 的文件中,完全丢失了项目的结构。

打包还是不打包?

从这里,我们有两个选择:

  1. 使用 Vite、插件和复杂的配置来打包 Vue 文件。
  2. 保留目录结构,并使用 mkdist 等工具对 TypeScript 文件进行文件到文件的转译(无包构建)。

最终的决定取决于你的具体需求,但我相信简洁是最好的方法。因此,让我们探索第二个选项。

目标是将 TypeScript 文件转换为 JavaScript 文件,同时保留 src 文件夹在 dist 文件夹中的原始结构,并且忽略 Vue 文件。

注意: 使用 <script setup lang="ts"> 块,mkdist 会忽略 Vue 文件,以便 Vue 编译器生成运行时 props。否则,它会生成一个 .vue.d.ts 文件,为 Vue 组件提供类型。请记住,@vitejs/plugin-vue 和 Vite 本身就理解 TypeScript 脚本块。有关更多详细信息,请参阅mkdist#14 问题

配置 Unbuild

没错,我们将配置 unbuild,因为它集成了 mkdist,使其非常易于使用。

首先,在项目的根目录中创建一个 build.config.ts 文件。Unbuild 会读取此配置文件,了解如何处理项目。它假设了一些默认值,并从 package.json 中推断出许多方面,但我们需要告诉它使用 mkdist。

import { defineBuildConfig } from 'unbuild'
export default defineBuildConfig({
 entries: ['./src/'],
 declaration: true,
})

这是一个非常简单的配置文件。我很喜欢它。 entries 键告诉 unbuild 从哪个文件开始转译。但是,./src/ 是一个目录,由末尾的 / 表示。有了这个提示,unbuild 会放弃默认的打包工具 rollup,转而使用 mkdist。declaration 键提示 unbuild 创建 TypeScript 声明文件(.d.ts)。

我们也可以移除 package.json 中的 exports 字段,因为我们不再打包文件,并恢复 index.ts 文件中的组件导出。

让我们重新运行 npx unbuild 命令,见证奇迹。

➜ npx unbuild
ℹ Building vue-library
ℹ Cleaning dist directory: ./dist
✔ Build succeeded for vue-library
 dist (total size: 600 B)
 └─ dist/index.d.ts (108 B)
 └─ dist/index.mjs (112 B)
 └─ dist/composables/useUser.d.ts (79 B)
 └─ dist/composables/useUser.mjs (124 B)
 └─ dist/components/User.vue (177 B)
Σ Total dist size (byte size): 600 B

现在,dist 文件夹的结构如下:

dist/
 components/
 User.vue
 composables/
 useUser.d.ts
 useUser.mjs
 index.d.ts
 index.mjs

这与 src 文件夹的结构一致,User.vue 组件现在可以在 dist 文件夹中使用。相对导入路径仍然有效,组件可以在任何 Vue 项目中使用。🥳

本地开发

许多教程到此为止,建议你已经准备好将包发布到 npm 了。但是,如果你看不到工作成果,如果你不能在构建过程中进行测试,如何才能创建一个复杂的库呢?

基本上,你无法做到。

让我们看看如何在本地项目中使用该库,为了简单起见,我们将使用同一个仓库。

我将展示使用 pnpm workspace 的最简单方法。

首先,在项目的根目录中创建一个 pnpm-workspace.yaml 文件:

packages:
 - .
 - playground

然后,在 playground 文件夹中创建一个新的 Vite 项目:

npx create-vite playground --template vue-ts

因为我们使用的是 pnpm workspace,所以要从项目的根目录安装依赖项:

pnpm install

注意: 此步骤不是必需的。你可以创建一个新的 Vite 项目并在其中安装依赖项。Pnpm 通过在根目录中安装所有工作区的依赖项来简化这个过程。一个简单的 pnpm install 命令会安装所有工作区的依赖项。

现在,我们可以在一个 "真实" 项目中使用这个 playground 库来测试我们的库。

例如,打开 src/App.vue 文件,导入 User 组件:

<script setup lang="ts">
import { User } from '../../src'
</script>
<template>
 <User />
</template>

然后运行项目:

cd playground && pnpm dev

你将在浏览器中看到 User 组件显示出来。🎉 如此简单,却又如此强大。我几乎在构建的每个库中都使用这种方法,它非常有效。

发布到 npm

这一部分很简单,只要你理解了工作流程。

首先,给你的库命名。在本例中,我将使用 @barbapapazes/vue-library

接下来,在 npm 上创建一个帐户,并使用 npm login 命令登录。

然后,安装 changelogen 来生成变更日志,按照语义化版本控制和提交规范更新版本号,并预先填写 GitHub 版本发布信息。

pnpm i -D changeloggen

接下来,在 package.json 中添加两个脚本:

{
 "scripts": {
 "prepack": "unbuild",
 "release": "changelogen --release && npm publish --access public && git push --follow-tags"
 }
}

prepack 脚本在将包发布到 npm 之前运行 unbuild 命令。release 脚本生成变更日志,将包发布到 npm,并将标签推送到 GitHub。

注意: 你的项目应该在 GitHub 上才能使用 --release 选项。如果没有,请省略它,并在仓库中手动创建发布。

现在,使用以下命令将包发布到 npm:

npm run release

就这样!你已经将你的第一个 Vue.js 组件库发布到 npm 了。🚀

准备就绪

今天就到这里。我们已经涵盖了许多主题:

  • 如何使用 TypeScript 构建 Vue.js 组件库。
  • 如何在 TypeScript 项目中管理 Vue 文件。
  • 如何使用 unbuild 来转译 TypeScript 文件,而不打包 Vue 文件。
  • 如何使用 mkdist 来保留项目结构。
  • 如何使用 pnpm workspace 在本地项目中测试库。
  • 如何将库发布到 npm。

有关更详细和更复杂的示例,请查看 GitHub: vue-library,但这篇文章中解释的所有内容都来自我的实际经验。

我希望你喜欢本教程,并希望它能帮助你构建自己的 Vue.js 组件库。

转载自:https://juejin.cn/post/7426558944103055396
评论
请登录