如何实现一个自己的 vue-cli 插件

357 阅读3分钟

tools.png

什么是cli工具?

  • 基于 @vue/cli 实现的交互式的项目脚手架
  • 基于 webpack 构建,并带有一些默认配置并且可扩展

实现了什么?

  • 定义自己的命令行
  • 使用对应的命令行执行对应的插件脚本
  • 尽量做到开箱即用,也就是独立性要高

开撸

1. 首先我们建一个自己的插件目录比如说叫 dd

dd.png

2. 然后在bin/index.js中添加如下代码

#!/usr/bin/env node 
// 上面这段的意思是让使用 node 进行脚本的解释程序,那下面的就可以使用 node 的语法了
const webpack = require('webpack');
const builtInWebpackConfig = require('../webpack.config');

webpack(builtInWebpackConfig, (err, stats) => {
    if (err || stats.hasErrors()) {
        return console.log('build failed.')
    }
    console.log('build success.');
})

并在package.json中添加上:"bin": "bin/index.js",就是添加可执行js文件,然后执行 npm link (将npm 模块链接到对应的运行项目中去,方便地对模块进行调试和测试)

然后我们建一个临时的测试项目demo,在demo项目下执行 npm link demo 将dd模块 链接到demo项目中, 会在demo项目的 node_modules 中复制一份dd模块的内容 并且在demo的package.json中添加自定义的 srcipts : { "build": "dd" },我们来执行 npm run build 打印结果符合我们的预期

build.png

3. 接下来搞一个自定义的插件,首先在demo中建一个插件配置文件 config.js

const CleanPluginForCommand = require('./plugins/clean');
module.exports = {
  plugins: {
     // hello options 相当于可预置的默认配置参数
    commands: [ CleanPluginForCommand('hello options') ],
    webpackPlugins: [],
    webapckLoader: []
  }
}

在/plugins中加一个 比如自定义的 clean.js

// 假设用户要支持自定义的 clean 的命令
// module.exports = (api) => {}
module.exports = (options) => (api) => {
  // 打印一下预置的参数
  console.log('options: ', options);
  api.registerCommands('clean', (...args) => {
    // 我们自定义的 clean 命令的逻辑
    console.log('exec clean script success!');
  })
}

在 scripts中添加一个命令 "clean": "dd clean",后面执行 npm run clean来执行我们的插件

4. 最后一步完善一下我们的 dd/bin/index.js,困了,直接上代码,兄弟们自己看🥱🥱😴😴

#!/usr/bin/env node 
// 这段话的意思是让使用 node 进行脚本的解释程序,那下面的就可以使用 node 的语法了

const webpack = require('webpack');
const minimist = require('minimist');
const builtInWebpackConfig = require('../webpack.config');
const path = require('path');
const args = minimist(process.argv.slice(2)); // 获取命令行的参数

// class PluginManager extends Plugin {} <- 优雅的方式是 内聚到一个模块实现
const __commands = {};
// const __plugins = {};
const fname = 'config.js'; // 上面建好的插件配置文件

const runWebpackBuild = () => {
  webpack(builtInWebpackConfig, (err, stats) => {
    if (err || stats.hasErrors()) {
      return console.log('build failed.')
    }
    console.log('build success.');
  })
}

// 封装 api,这个是作为参数塞到自定义插件函数中的,通过这个 api 往外暴露能力
// 优雅的方式是要写一个 class Api extends BaseApi {}
const api = {
  registerCommands(name, impl) {
    const command = __commands[name];
    if (!command) {
      __commands[name] = impl
    }
  },
}

// 读取用户本地的配置文件 config.js
const readLocalOption = () => new Promise((resolve) => {
  // 读取到配置文件 config.js 的内容
  const config = require(path.join(process.cwd(), fname)) || {};
  // 取出对应的配置参数
  const { plugins: { commands = [] } = {} } = config;
  if (commands.length) {
    commands.forEach(command => {
      command(api);
    })
  }
  console.log('__commands', __commands)
  resolve(__commands);
})

readLocalOption().then((commands) => {
  const command = args._[0]; // 取执行命令  dd clean
  console.log('command', command)
  // 有对应的插件就直接执行
  if (commands[command]) {
    commands[command]();
  }
  else {
    runWebpackBuild();
  }
})

执行 npm run clean 看下执行结果

clean.png

到这里我们就实现了一个最简单的 cli机制和 plugin, 是否对你有帮助呢

记得留个赞哦🤞🤞🤞