如何构建 Vue CLI 插件

2025-06-10

如何构建 Vue CLI 插件

本文转载自ITNEXT

如果你正在使用 Vue 框架,你可能已经知道什么是 Vue CLI。它是一个用于快速开发 Vue.js 的完整系统,提供项目脚手架和原型设计。

CLI 的一个重要组成部分是 cli-plugins。它们可以修改内部 webpack 配置并将命令注入到vue-cli-service。一个很好的例子是@vue/cli-plugin-typescript:当你调用它时,它会将 添加tsconfig.json到你的项目中,并更改App.vue为 类型,因此你无需手动执行此操作。

插件非常有用,如今市面上有很多插件,适用于各种场景——GraphQL + Apollo支持、Electron 构建器、添加 UI 库(例如VuetifyElementUI)等等。但是,如果你想为某个特定的库添加插件,而它又不存在,该怎么办呢?嗯,我就是这种情况😅……所以我决定自己动手做一个。

在本文中,我们将构建一个vue-cli-plugin-rx 插件vue-rx。它允许我们在项目中添加一个库,并在 Vue 应用程序中获得 RxJS 支持。

🎛️ Vue-cli 插件结构

首先,什么是 CLI 插件?它只是一个具有特定结构的 npm 包。关于docs,它必须以服务插件作为主要导出,并且可以包含其他功能,例如生成器和提示文件。

目前还不清楚什么是服务插件或生成器,但不用担心 - 稍后会解释!

当然,与任何 npm 包一样,CLI 插件必须package.json在其根文件夹中有一个,并且最好有一个README.md带有一些描述的。

那么,让我们从以下结构开始:

.
├── README.md
├── index.js      # service plugin
└── package.json

现在我们来看看可选部分。生成器package.json可以向项目注入额外的依赖项或字段,并添加文件。我们需要它吗?当然,我们想添加rxjsvue-rx作为依赖项!更确切地说,我们希望创建一些示例组件,以便用户在插件安装过程中添加它。因此,我们需要添加generator.jsgenerator/index.js。我更喜欢第二种方式。现在的结构如下所示:

.
├── README.md
├── index.js      # service plugin
├── generator
│   └── index.js  # generator
└── package.json

还有一件事需要添加,那就是一个提示文件:我希望我的插件能够询问用户是否需要示例组件。我们需要prompts.js在根文件夹中创建一个文件来实现这个功能。所以,目前的结构如下:

├── README.md
├── index.js      # service plugin
├── generator
│   └── index.js  # generator
├── prompts.js    # prompts file
└── package.json

⚙️ 服务插件

服务插件应该导出一个函数,该函数接收两个参数:一个 PluginAPI 实例和一个包含项目本地选项的对象。它可以扩展/修改内部 webpack 配置以适应不同的环境,并注入额外的命令vue-cli-service。让我们想一想:我们是否想以某种方式更改 webpack 配置或创建一个额外的 npm 任务?答案是否定的,我们只想在必要时添加一些依赖项和示例组件。因此,我们需要做的更改如下index.js

module.exports = (api, opts) => {}

如果您的插件需要更改 webpack 配置,请阅读官方 Vue CLI 文档中的此部分。

🛠️ 通过生成器添加依赖项

如上所述,CLI 插件生成器可以帮助我们添加依赖项并更改项目文件。因此,我们需要做的第一步是为插件添加两个依赖rxjsvue-rx

module.exports = (api, options, rootOptions) => {
  api.extendPackage({
    dependencies: {
      'rxjs': '^6.3.3',
      'vue-rx': '^6.0.1',
    },
  });
}

生成器应该导出一个接收三个参数的函数:GeneratorAPI 实例、生成器选项以及 - 如果用户使用某个预设创建项目 - 则整个预设将作为第三个参数传递。

api.extendPackage方法扩展了项目的。除非您将其作为参数package.json传递,否则嵌套字段将深度合并。在我们的例子中,我们向部分添加了两个依赖项。{ merge: false }dependencies

现在我们需要修改一个main.js文件。为了让 RxJS 在 Vue 组件中工作,我们需要导入VueRx并调用Vue.use(VueRx)

首先,让我们创建一个想要添加到主文件的字符串:

let rxLines = `\nimport VueRx from 'vue-rx';\n\nVue.use(VueRx);`;

现在我们要使用api.onCreateComplete钩子。当文件写入磁盘时,它会被调用。

  api.onCreateComplete(() => {
    // inject to main.js
    const fs = require('fs');
    const ext = api.hasPlugin('typescript') ? 'ts' : 'js';
    const mainPath = api.resolve(`./src/main.${ext}`);
};

这里我们正在寻找主文件:如果它是一个 TypeScript 项目,它将是一个main.ts,否则它将是一个main.js文件。fs这是一个文件系统。

现在让我们更改文件内容

  api.onCreateComplete(() => {
    // inject to main.js
    const fs = require('fs');
    const ext = api.hasPlugin('typescript') ? 'ts' : 'js';
    const mainPath = api.resolve(`./src/main.${ext}`);

    // get content
    let contentMain = fs.readFileSync(mainPath, { encoding: 'utf-8' });
    const lines = contentMain.split(/\r?\n/g).reverse();

    // inject import
    const lastImportIndex = lines.findIndex(line => line.match(/^import/));
    lines[lastImportIndex] += rxLines;

    // modify app
    contentMain = lines.reverse().join('\n');
    fs.writeFileSync(mainPath, contentMain, { encoding: 'utf-8' });
  });
};

这里发生了什么?我们读取主文件的内容,将其分成几行并还原它们的顺序。然后,我们搜索包含import语句的第一行(第二次还原后,它将是最后一行),并rxLines在那里添加我们的语句。之后,我们反转行数组并保存文件。

💻 本地测试 cli-plugin

让我们添加一些关于插件的信息package.json,并尝试在本地安装进行测试。最重要的信息通常是插件名称和版本(这些字段在将插件发布到 npm 时是必需的),但您可以随意添加更多信息!完整的package.json字段列表可以在这里找到。以下是我的文件:

{
  "name": "vue-cli-plugin-rx",
  "version": "0.1.5",
  "description": "Vue-cli 3 plugin for adding RxJS support to project using vue-rx",
  "main": "index.js",
  "repository": {
    "type": "git",
    "url": "git+https://github.com/NataliaTepluhina/vue-cli-plugin-rx.git"
  },
  "keywords": [
    "vue",
    "vue-cli",
    "rxjs",
    "vue-rx"
  ],
  "author": "Natalia Tepluhina <my@mail.com>",
  "license": "MIT",
  "homepage": "https://github.com/NataliaTepluhina/vue-cli-plugin-rx#readme"
}

现在是时候检查我们的插件是如何工作的了!为此,让我们创建一个简单的 vue-cli 项目:

vue create test-app

转到项目文件夹并安装我们新创建的插件:

cd test-app
npm install --save-dev file:/full/path/to/your/plugin

插件安装完成后,需要调用它:

vue invoke vue-cli-plugin-rx

现在,如果您尝试检查该main.js文件,您会发现它已更改:

import Vue from 'vue'
import App from './App.vue'
import VueRx from 'vue-rx';

Vue.use(VueRx);

devDependencies此外,您还可以在测试应用程序部分找到您的插件package.json

📂 使用生成器创建新组件

太棒了,插件成功了!现在是时候扩展一下它的功能,让它能够创建一个示例组件了。Generator API 使用了一个render方法来实现这个目的。

首先,让我们创建这个示例组件。它应该.vue位于项目文件夹中。在组件src/components创建一个文件夹,然后在其中模拟以下整个结构:templategenerator

树截图

你的示例组件应该……嗯,只是一个 Vue 单文件组件!我不会在本文中深入讲解 RxJS,但我创建了一个由 RxJS 驱动的简单点击计数器,其中包含两个按钮:

Rx 示例

它的源代码可以在这里找到

现在我们需要指示我们的插件在调用时渲染这个组件。为此,我们将以下代码添加到generator/index.js

api.render('./template', {
  ...options,
});

这将渲染整个template文件夹。现在,当插件被调用时,一个新的文件RxExample.vue将被添加到src/components文件夹中。

我决定不覆盖原有的组件,App.vue而是让用户自行添加示例组件。不过,您可以替换现有文件的部分内容,请参阅文档中的示例。

⌨️ 通过提示处理用户选择

如果用户不想使用示例组件怎么办?让用户在插件安装过程中自行决定,岂不是明智之举?这就是提示存在的原因!

之前,我们prompts.js在插件根文件夹中创建了一个文件。该文件包含一个问题数组:每个问题都是一个对象,包含一组特定的字段,例如namemessagechoicestype

名称很重要:我们稍后会在生成器中使用它来创建渲染示例组件的条件!

提示符可以有不同的类型,但在 CLI 中最广泛使用的有checkboxconfirm。我们将使用后者来创建一个有是/否答案的问题。

因此,让我们将提示代码添加到prompts.js

module.exports = [
  {
    name: `addExample`,
    type: 'confirm',
    message: 'Add example component to components folder?',
    default: false,
  },
];

我们有一个addExample提示,询问用户是否要将组件添加到组件文件夹。默认答案是No

让我们回到生成器文件并进行一些修复。将 out api.rendercall 替换为

if (options.addExample) {
    api.render('./template', {
      ...options,
    });
}

我们正在检查是否addExample有肯定的答案,如果是,则渲染该组件。

每次更改后,请不要忘记重新安装并测试插件!

📦 公开!

重要提示:在发布插件之前,请检查其名称是否符合模式vue-cli-plugin-<YOUR-PLUGIN-NAME>。这样您的插件才能被 发现@vue/cli-service并通过 进行安装vue add

我还希望我的插件在 Vue CLI UI 中看起来美观,所以我添加了描述、标签和仓库名称,package.json并创建了一个 logo。logo 图片应该命名logo.png并放置在插件根文件夹中。最终,我的插件在 UI 插件列表中显示如下:

UI 中的 vue-rx

现在我们可以发布了。你需要注册一个npmjs.com,并且显然你应该已经安装了 npm。

要发布插件,请转到插件根文件夹并npm publish在终端中输入。瞧,您刚刚发布了一个 npm 包!

现在你应该可以使用vue add命令安装插件了。试试看!

当然,本文中描述的插件非常基础,但我希望我的说明能够帮助某人开始 cli-plugins 开发。

你缺少哪种 CLI 插件?欢迎在评论区分享你的想法🤗

鏂囩珷鏉ユ簮锛�https://dev.to/n_tepluhina/how-to-build-a-vue-cli-plugin-3b6b
PREV
提高代码审查技能的六个技巧
NEXT
Git 中的撤消:如何修复常见错误