当我需要动态生成 graphql 的 template 时,做了一个骚操作

1,868 阅读1分钟

成立背景

在一个项目中,一个请求的结构,里面包含三种权限,权限可以任意组合

一开始我的想法

这个操作有点骚,我提前准备好各种权限组合的 template ?想了下我可能需要准备如下情况

权限 A 权限 B 权限 C
X X X
X X️ ✔️
X ✔️ ✔️
✔️
X
X X
X X
X

有这 8 种,如果到时候再我加一个权限,岂不是要原地去世。然后就考虑了下 gql 函数直接传模板,通过对模板的过滤来生成我们想要的模板,于是就看了下用法,

// 这样的
import gql from 'graphql-tag'

const t = gql`
   query Demo {
       
   }
`
// 支持传 fragment 的
const t2 = gql`
   query Demo {
       ...Fragment
   }
   ${Fragment}
`

看了半天没找到我要的结果,于是我就到 graphql-tag 源码里面看了下,如下图

这里我们看到一个 literals 变量,他就是 gql 函数的第一个参数传进来的 template,但是如果我们直接如下使用

gql(`
    query Demo {
        ...Fragment
    }
 `, Fragment)

literals 这个值就是一个纯字符串,到下面的拼接 args,我们可以想一下 result 肯定会被加上一些莫名其妙的字符,结局就是 parseDocument 报错,到这里我们要先停一下,这个时候,我们就需要去了解普通的函数调用和字符串模板函数调用的区别

函数调用的区别

在这里我只是简单的打印下两种函数调用的 arguments 给大家看下

我们可以看到区别就是第一个参数 arguments[0] 是不同的,普通函数是字符串,模板字符串函数是一个数组,这个数组包含一个原始模板和一个传入的占位符

结果

所以到此我们就有了动态模板的思路了,我们只需要构造一个和模板字符串第一个参数一样结构的参数传入 gql 就 ok 了

export function stringRaw(template, args = 0) {
  const r = new Array(args)
  if (r.length !== 0) {
    r.fill('')
  }
  r.unshift(template)
  return r
}

const t = gql(stringRaw(`
    query Demo{
        field1
        ${permissionA ? 'field2' : ''}
        ${permissionB ? 'field3' : ''}
        ${permissionC ? 'field4' : ''}
        field5 {
            ...Fragment
        }
    }
`, 1), Fragment)

至此我们就完成了传入动态字符串了