Skip to content

开发一个 vite-plugin-terminal 插件

介绍

插件功能:在开发时,将服务器的 url 转换为二维码,实现手机扫码就能访问的功能。

写在项目里

插件实现:plugin/index.ts

ts
import {
  Plugin,
  ResolvedConfig,
  ResolvedServerOptions,
  ServerOptions
} from 'vite'
import qrcode from 'qrcode-terminal'
import { getAllHost } from './util.js'

export interface PluginOption {
  content?: string;
  small?: boolean;
}

import chalk from 'chalk'

const allHost = getAllHost()

export function vitePluginQrcodeTerminal(params: PluginOption = {}): Plugin {
  let config: ResolvedConfig
  return {
    name: 'vite-plugin-qrcode-terminal',
    apply: 'serve',
    enforce: 'post',
    configResolved(resolvedConfig) { 
      config = resolvedConfig 
    }, 
    configureServer(server) { 
      server.middlewares.use((req, res, next) => { 
        createQrcode(params, config.server); 
        next(); 
      }); 
    } 
  } 
}

function createQrcode(
  params: PluginOption,
  server: ServerOptions & ResolvedServerOptions
) {
  const { small } = params;
  const content = getInputContent(params, server);
  const urls = renderUrl(content, server);
  urls.forEach((each) => {
    qrcode.generate(each, { small: small ?? true }, (qrcode) => {
      console.log(('------------qrcode------------'));
      console.log(`${chalk.green('[url]')} ${chalk.blue(each)} `);
      console.log(qrcode);
    });
  });
}

function getInputContent(
  params: PluginOption,
  server: ServerOptions & ResolvedServerOptions
): string[] {
  const { content } = params;
  const { host } = server;

  let input: string[] = [];

  if (content) {
    input = [content];
  } else {
    if (typeof host === 'boolean') {
      input = host ? allHost : ['localhost'];
    }

    if (typeof host === 'string') {
      input = host === '0.0.0.0' ? allHost : [host];
    }

    if (host === undefined) {
      input = ['localhost'];
    }
  }
  return input;
}

function renderUrl(
  input: string[],
  server: ServerOptions & ResolvedServerOptions
) {
  const { https, port, open } = server;
  const protocol = https ? 'https://' : 'http://';
  const postUrl = typeof open === 'string' ? open : '';
  return input.map((item) => {
    return postUrl.startsWith('/')
      ? `${protocol}${item}:${port}${postUrl}`
      : `${protocol}${item}:${port}/${postUrl}`;
  });
}

工具函数:

ts
import os from 'os';
const network = os.networkInterfaces();

export function getAllHost() {
  const keys = Object.keys(network);
  return keys.reduce<string[]>((prev, curr) => {
    const element = network[curr] ?? [];
    const IPv4Item = element?.filter((item) => item.family === 'IPv4');
    prev.push(IPv4Item?.[0]?.address);
    return prev;
  }, []);
}

作为插件上传到 npm 包

下载依赖:

js
pnpm i tsup typescript vite -D

创建 tsconfig.json 文件:

shell
tsc --init

执行脚本:

json
{
  "build": "rm -rf dist/ && tsup src/main.ts --dts --no-splitting"
}

修改 package.json:

json
{
  "types": "dist/main.d.ts",
  "main": "dist/main.js",
  "files": [
    "dist"
  ],
}

最后,可以使用 pnpm link <dir> 在本地进行调试。如果无误,再 npm publish 上传到 npm 上。

Released under the MIT License.