关于next.js:cssvarsponyfill-在ie环境下使用问题nextjs-构建

60次阅读

共计 2388 个字符,预计需要花费 6 分钟才能阅读完成。

css-vars-ponyfill

通过 css 变量来实现网页换肤的过程中,会呈现兼容性问题。

为了解决 ie,qq,百度浏览器等兼容性问题,引入 css-vars-ponyfill,然而在 ie 浏览器下,css-vars-ponyfill 的在 nextjs 下体现不佳,次要缺点是因为页面是服务端渲染,因而用户在看到界面后,动静主题色等款式不能很快渲染好,而是有一个过渡的工夫(css-vars-ponyfill 仅反对 client-side),色彩会存在显著替换的过程用户体验差。通过浏览源码能够看到,cssVars 须要等到浏览器 contentLoaded 之后,才会触发,否则始终监听 dom 的 data content 事件,这就导致了体验上的问题。

解决方案

1. 解析速度

通过把间接去除 document.readyState !== 'loading' 这样的限度条件使得浏览器在解析到,而后更改 css-vars-ponyfill 的引入形式(旧的引入形式是在 nextjs 中的 mainjs 中引入 module,而后间接调用 cssVars(),这样在调用到 ponyfill 的脚本前还会解析其余不相干的 chunk,为了更快的解析 css 变量,须要手动抉择插入地位),更改之后的 css-vars-ponyfill 通过找到 css 变量的地位(nextjs 通过将不同组件下的 style,对立打包在 header 外面),而后将更改后的 ponyfill 插入到 style 之后进行调用,这一步抉择在服务端渲染的 _document.tsx 文件中更改。

2. 解析稳定性

通过手动更改文件解析地位,以及对源码的条件触发机制进行相干更改,首页色彩渲染速度有了肯定晋升。然而仍存在一个问题,即通过路由跳转的界面,如果有新的 style chunk,插入时不能进行无效的 css 变量解析(已尝试配置 cssVars 的 option 关上 MutationObserver)。
因而,解决方案是通过判断 UA,来让 ie 等浏览器下所有的路由通过 a 标签跳转,触发 css-ponyfill 的从新解析执行。

export function browser() {
  const UA = window.navigator.userAgent
  if (UA.includes("qqbrowser")) return "qqbrowser"
  if (UA.includes("baidu")) return "baidu"
  if (UA.includes("Opera")) return "Opera"
  if (UA.includes("Edge")) return "Edge"
  if (UA.includes("MSIE") || (UA.includes("Trident") && UA.includes("rv:11.0")))
    return "IE"
  if (UA.includes("Firefox")) return "Firefox"
  if (UA.includes("Chrome")) return "Chrome"
  if (UA.includes("Safari")) return "Safari"
}
type CommonLinkProps = {
    children: ReactElement
    href?: string
    target?: string
    outerLink?: boolean
    styles?: unknown
}
export default function CustomLink(props: CommonLinkProps) {const { children, href, target, as, outerLink, styles = emptyStyles} = props
  const [isIE, setIE] = useState<boolean>(false)
  const cloneEl = (c: ReactElement, props?: any) =>
    React.cloneElement(c, { href: as ?? href, target, ...props})
  useEffect(() => {if (["IE", "qqbrowser", "baidu"].includes(browser())) {setIE(true)
    }
  }, [])
  function renderLink() {if (Children.only(children).type === "a") {const node = cloneEl(children as ReactElement)
      return node
    } else {let fn: () => void | null = null
      if (outerLink) {fn = () => {window.open(as ?? href)
        }
      } else {fn = () => {window.location.href = as ?? href}
      }
      const node = cloneEl(children as ReactElement, {onClick: () => {fn()
        },
      })
      return node
    }
  }

  return (
    <>
      {!href ? (children) : isIE ? (renderLink()
      ) : (<Link {...props}>{children}</Link>
      )}
      <style jsx>{styles}</style>
    </>
  )
}

这里 children 的 type 抉择了 ReactElement,而不是插槽中通常反对的 ReactNode 次要是不想思考直接插入字符串这种状况,会减少问题的复杂度,因而间接在 type 这层做限度。还有 Fragments 也没有思考,且没有找到无效的 Fragments 类型,没法在 ReactNode 中把它 Omit 掉,nextjs 外面的 Link 如果首层插入了 Fragments 后,也无奈失常跳转,可能起因也是无奈再 Fragments 下面绑定无效的事件吧,目前 Fragments(16.13.1)只反对 key 属性,心愿后续能够优化。

正文完
 0