likes
comments
collection
share

手把手带你实现一个多页签umi插件

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

前言

前段时间实现了普通多页签功能,和微前端多页签功能,不过都是在项目中实现的,如果别人想用,还要把代码复制到项目里,太麻烦了。所以这一篇就来实现一个umi插件,让别人更快的使用你开发的功能。本来我以为实现这个很简单,没想到遇到了个问题,下面会和大家分享。在文章开始之前还是建议大家先看下我前面关于多页签实现的文章。

手把手带你基于ant design pro 5实现多tab页(路由keepalive)

手把手带你在微前端(qiankun)中实现多页签功能(路由keepalive)

实现思路

通过插件把我们写好的几个文件复制到项目中,然后调用umi插件提供的addLayouts方法把路由添加进去就行了。

具体实现

初始化项目

创建pnpm-workspace

找一个合适的目录,执行下面命令

pnpm init

在项目根目录下创建pnpm-workspace.yaml文件

packages:
  - "package/*"

初始化插件项目

在项目根目录下创建package文件夹,然后在package目录下创建plugin文件夹,然后在plugin目录下执行命令

pnpm create umi

选择Umi Plugin 手把手带你实现一个多页签umi插件 选择pnpm 手把手带你实现一个多页签umi插件 选择taobao镜像 手把手带你实现一个多页签umi插件 输入组件名称,然后回车就行了 手把手带你实现一个多页签umi插件

初始化测试项目

到package目录下执行下面命令,创建ant design pro项目

pro create example

修改项目中package.json文件中name字段,改成example,然后执行下面命令,安装刚初始化的插件项目,umi-plugin-keepalive-tabs是刚才插件项目中package.json的name值。

pnpm --filter "example" add umi-plugin-keepalive-tabs

安装完成后,example项目中package.json依赖中,会多了一个像下图一样的依赖,如果没有则说明上面某一步出错了,检查一下。 手把手带你实现一个多页签umi插件 改造example/config.ts文件,增加plugins属性,值是刚才初始化插件名称 手把手带你实现一个多页签umi插件 改造pulgin/src/index.ts文件,添加一个打印测试一下。 手把手带你实现一个多页签umi插件 改造根目录下packge.json文件,添加两个start命令。

"start:plugin": "pnpm -C ./package/plugin dev",
"start:test": "pnpm -C ./package/example start"

手把手带你实现一个多页签umi插件 然后开两个终端分别运行这两个命令,start:plugin要先执行

npm run start:plugin
npm run start:test

运行start:test命令的时候,发现有keepalive-tabs输出就行了。 手把手带你实现一个多页签umi插件 到此我们项目框架搭建成功了

umi插件api说明

关于umi插件的api文档,官网说的很详细,我这边找几个常用的,给大家实战演示一下。

describe

文档链接:umijs.org/docs/api/pl… 手把手带你实现一个多页签umi插件 这个函数的主要作用是给自己的插件定义一个配置key,并且可以限制值的类型。

实战一下:

import type { IApi } from 'umi';

export default (api: IApi) => {
  // See https://umijs.org/docs/guides/plugins
  const config = api.userConfig;

  api.describe({
    key: 'keepaliveTabs',
    config: {
      schema(joi) {
        return joi.string().required();
      },
      onChange: api.ConfigChangeType.regenerateTmpFiles,
    },
    enableBy: api.EnableBy.config,
  });

  console.log(config.keepaliveTabs);
};

上面代码定义一个keepaliveTabs可配置变量,使用joi限制了类型为string并且是必填的,然后必须通过config配置开启。 通过api.userConfig可以获取用户的所有配置,config.keepaliveTabs就是当前插件的配置。

writeTmpFile

手把手带你实现一个多页签umi插件 这个函数的主要作用是往src/.umi文件夹下生成文件,我们插件会用到这个api。一般这个api都是在onGenerateFiles这个生命周期中使用。

实战一下

假如我有一个公共方法想让用户直接从umi中导出使用,我们可以用这个api实现。

import type { IApi } from 'umi';

export default (api: IApi) => {
  api.onGenerateFiles(() => {
    api.writeTmpFile({
      content: `export const add = (num1: number, num2: number): number => num1 + num2`,
      path: 'index.tsx',
    })
  })
};

代码很简单,我就不解释了。 手把手带你实现一个多页签umi插件 example项目src/.umi生成了这个文件,并把内容也写了进去 手把手带你实现一个多页签umi插件 然后我们在业务组件中就可以从umi或umi/max中导出使用了 手把手带你实现一个多页签umi插件 因为用了ts,所以还有代码提示。

addRuntimePlugin

手把手带你实现一个多页签umi插件 这个插件文档很简单,但是umi大部分内置组件都用到了。他的作用是可以让你的插件支持动态修改,也就是umi支持的运行时配置。umi项目中app.ts导出的那些变量和属性都是给一个个插件使用的,如果想让你的插件也支持这个,可以用这个api。注意这个api一般和addRuntimePluginKey一起使用。

实战一下

import type { IApi } from 'umi';
import path from 'path';

export default (api: IApi) => {
  // See https://umijs.org/docs/guides/plugins

  api.describe({
    key: 'keepaliveTabs',
    config: {
      schema(joi) {
        return joi.string().required();
      },
      onChange: api.ConfigChangeType.regenerateTmpFiles,
    },
  });

  api.addRuntimePluginKey(() => 'keepaliveTabs');

  api.onGenerateFiles(() => {

    api.writeTmpFile({
      content: `import React, { useEffect } from 'react';
      import { ApplyPluginsType } from 'umi';
      import { getPluginManager } from '../core/plugin';
      
      function Layout(props) {
      
        async function getRuntime() {
          const config = await getPluginManager().applyPlugins({
            key: 'keepaliveTabs',
            type: ApplyPluginsType.modify,
            initialValue: '',
            async: true,
          });
          setTimeout(() => {
          document.title = config || "${api.userConfig.keepaliveTabs}";
          }, 1000);
        }
      
        useEffect(() => {
          getRuntime();
        }, [])
      
        return (
          <div>{props.children}</div>
        )
      }
      export function rootContainer(container) {
        return React.createElement(Layout, null, container);
      }      
      `,
      path: 'runtime.tsx',
    });

  });

  api.addRuntimePlugin(() => path.join(api.paths.absTmpPath!, `plugin-keepaliveTabs/runtime.tsx`),)
};

app.ts中,导出keepaliveTabs函数 手把手带你实现一个多页签umi插件 启动项目后,一会就发现tab的标题变成了999。 手把手带你实现一个多页签umi插件 如果把app.ts中keepaliveTabs函数删掉后,title值就变成了config中配置的hello了。 手把手带你实现一个多页签umi插件

上面代码实现了可以通过config或app.ts导出配置页面title,使用getPluginManager().applyPlugins获取app.ts导出的值,其他基本是固定写法,这一块官方没有详细文档,我看了一些内置插件的源码自己总结出来的。

插件实战

下面我们就开始实现我们的插件 首先把我们以前写的几个文件复制到插件项目里,当文件模版。 手把手带你实现一个多页签umi插件

然后写我们的插件,代码很简单,我们只要把上面几个文件复制到.umi临时文件中,然后注册一个全局layout就行了。 上面我说的坑就是官方给的添加全局layout的addLayouts方法,使用这个方法会导致项目中所有的路由的上级都会变成你当前添加的layout,还没办法配置,把umi插件源码看了一下,然后才找到解决方,需要使用register注册addLayouts方法。

import type { IApi } from 'umi';
import * as fs from 'fs'
import * as path from 'path'

export default (api: IApi) => {
  // See https://umijs.org/docs/guides/plugins

  // 获取tpl文件夹下的所有文件路径
  const filePaths = fs.readdirSync(path.join(__dirname, './tpl/'));

  api.onGenerateFiles(() => {
    // 把tpl文件全部复制到项目临时文件中
    filePaths.forEach((filePath: string) => {
      api.writeTmpFile({
        path: `plugin-keepalive-tabs/${filePath.replace('tpl', 'tsx')}`,
        noPluginDir: true,
        content: fs.readFileSync(path.join(__dirname, `./tpl/${filePath}`)).toString(),
      })
    });

    api.writeTmpFile({
      content: `export { KeepAliveTabContext } from './context'`,
      path: `plugin-keepalive-tabs/index.tsx`,
      noPluginDir: true,
    });
  });

  // 注册layout
  api.register({
    key: 'addLayouts',
    fn() {
      return [{
        id: 'keepalive-tabs',
        file: path.join(api.paths.absTmpPath, './plugin-keepalive-tabs/layout.tsx'),
        test: (route: any) => {
          return route.layout !== false;
        },
      }];
    },
    stage: -1, // 这里给-1,想让我们写的layout注册到全局layout之前
  });
};

然后启动example项目测试一下,没有任何问题 手把手带你实现一个多页签umi插件 也可以从umi/max里面导出KeepAliveTabContext使用 手把手带你实现一个多页签umi插件

发布npm包

这个使用github action自动发布npm包,只需要往main分支推送代码就行了。关于github action这篇文章写的很详细,大家可以去看下。

作为前端,要学会用Github Action给自己的项目加上CICD

我们首先到npm 生成一个Access Token,需要先登录。 手把手带你实现一个多页签umi插件 手把手带你实现一个多页签umi插件 手把手带你实现一个多页签umi插件 生成完token复制一下,后面有用 创建github仓库,这个大家应该都会,我就不说了,打开仓库设置,改一下action的权限。 手把手带你实现一个多页签umi插件 手把手带你实现一个多页签umi插件 添加npm token 手把手带你实现一个多页签umi插件 手把手带你实现一个多页签umi插件 手把手带你实现一个多页签umi插件 然后项目里增加github action配置,在根目录创建.github/workflows/main.yml文件

name: CI Github Pages
on:
  push:
    branches:
      - main 

env:
  NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

jobs:
  build-and-deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: pnpm/action-setup@v2.1.0
        with:
          version: 7.2.1
      - name: Install   
        run: cd package/plugin && npm install --no-frozen-lockfile
      - name: Build
        run: cd package/plugin && npm run build
      - name: Login to NPM registry
        run: echo "//registry.npmjs.org/:_authToken=\${NODE_AUTH_TOKEN}" > ~/.npmrc
      - name: Deploy 
        run: cd package/plugin && npm publish

改一下项目中package/plugin/package.json里面的插件版本号,然后在main分支把代码push上去,这里注意一下每次在main分支推代码,必须要改版本号,不然发布npm包会报错,因为版本号不能重复。 手把手带你实现一个多页签umi插件 推送完代码,可以github action查看cicd执行情况 手把手带你实现一个多页签umi插件 发布成功后,我们初始化一个pro项目测试一下 项目初始化后,安装插件

pnpm i umi-plugin-keepalive-tabs

在config.ts文件中使用插件 手把手带你实现一个多页签umi插件 启动项目,可以正常使用了。 手把手带你实现一个多页签umi插件

总结

到此插件开发完成了,大家可以跟着教程自己开发一个插件,也可以使用我刚开发的插件。支持微前端的多页签插件,我下篇写,感兴趣的可以自己写一下练一下手。

如果这篇文章对你有帮助,麻烦给个赞,谢谢。

插件仓库地址:github.com/dbfu/umi-pl…

antd pro 5多页签仓库地址:github.com/dbfu/antd-p…

微前端多页签仓库地址:github.com/dbfu/antd-p…

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