🔥一个能满足我对CDN所有幻想的插件

1,053 阅读6分钟

目前市面上服务器带宽都挺贵的,为了节省服务器的带宽,咱们通常都会使用cdn的方式进行分流,从而降低带宽的压力。

但是目前市面上的公共cdn这么多,有选择困难症,怎么办?

想用公共cdn,还得自己去找对应的cdn链接,很麻烦的,有什么好的办法吗?

找到链接后,还需要自己手动添加html文件中,有更好的解决方案吗?

前段时间jsdeliver大范围挂掉,导致不少网站白屏,面对这种问题,该如何处理?

如果说,现在有一个可以解决如上问题的cdn插件,你想不想试一下?

基本使用

这个cdn插件就是白泽团队开源的vite-add-cdn-script,咱们先看看如何使用吧?

ps:使用webpack or 其他打包工具的小伙伴们,别着急,核心包正在抽离中,很快就可以完成适配啦~

快速上手

// 安装
pnpm install vite-add-cdn-script rollup-plugin-external-globals -D

在vite中进行配置(这里使用react+react-dom,作为最简单的例子)

import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import externalGlobals from "rollup-plugin-external-globals";
import viteAddCdnScript from "vite-add-cdn-script";

const externals = {
  react: "React",
  "react-dom": "ReactDOM",
};

export default defineConfig({
  base: "./",
  plugins: [react(), viteAddCdnScript({})],
  build: {
    rollupOptions: {
      external: [...Object.keys(externals)],
      plugins: [externalGlobals(externals)],
    },
  },
});

然后执行打包(pnpm run build),就会发现咱们得打包产物中,已经自动添加了cdn。对的,你已经掌握了cdn插件的使用,是不是非常简单呢?

对比一下使用cdn插件前后的打包,可以发现

首先咱们打包的速度和体积都有所下降,这个主要是externalrollup-plugin-external-globals的原因。

其次,我们也不需要去纠结选择什么cdn,到哪里去找cdn的链接了,插件都帮咱们自动引入到打包的产物中啦。

再者就是这个插件好像帮咱们做了cdn的异常处理

咱们来试下cdn异常的时候是什么样的效果?

这里我们将src改掉,改成一个不存在的包,再通过live server打开看看。

可以看到咱们得页面中虽然有报错,但是还是可以正常运行的,这就非常棒~

自定义cdn

如果你觉得目前插件的公共cdn不符合你的要求,没关系,咱们也有自定义cdn的功能。

你可以通过customScript字段来进行定义,不过自定义cdn将会丢失异常处理方案,即需要保证自定义cdn的稳定性。

注意事项

当然使用这个cdn插件还是有一点点需要注意的事情,就是依赖的先后顺序问题,不过这个在你手动引入cdn的时候也是会有这个问题,因此插件层暂时也没有太好的解决方案。

比如react-router-dom需要依赖react、@remix-run/router、react-router,因此需要放在最后。

如下:

插件的实现

好了,前面就是插件的基本使用啦。

下面将会来介绍咱们插件的实现,想了解的小伙伴,咱们继续。

如果不了解vite插件的基本实现,可以看小羽的这篇文章《同事:唉,你写的代码有bug!》,这里就不讲了。

整体架构图

npm包地址:www.npmjs.com/package/vit…

github地址:github.com/baizeteam/b…

整体的架构图如下,目前我们主要完成了vite插件版本的开发。在后续的开发中,我们将会把工具层基建层数据持久层剥离出来成为一个核心包,从而可以轻松的适配各种打包工具插件。

image.png

cdn的获取

cdn的获取方式,刚开始时想自己维护一套键值对,后面经过咱们团队的新成员lgldl同学的提醒,发现各大开源的cdn都是有对应的api接口的。直接通过api接口来处理cdn的适配,可以有效的降低我们的工作量。

然后,我们只需要通过对应api接口,整理出cdn中文件的规则即可。

怎么插入到html文件中?

ok,现在cdn相关的链接咱们都可以获取到了,那script的拼接,相信难不倒大家了。那该如何在打包时自动把咱们的cdn拼接后的script插入到html页面中呢?

在vite插件中,有一个叫transformIndexHtml的钩子函数。

它可以用来对index.html进行处理,而单页面应用的时代,很少直接处理index.html了。所以,咱们可以直接用正则来替换

cdn的异常处理

前段时间jsdeliver大范围挂掉,导致不少网站白屏,面对这种问题,我们的插件是如何处理的?

我们定义了一个errorCDN的方法,当cdn加载异常的时候,就会触发onerror。而我们在cdn对应的script中绑定这个errorCDN的方法,就会自动去新建一个新的script,并且去加载新的cdn

这样子下来,虽然打开控制台会看到第一个cdn加载报错,但我们在后续又直接加载了新的cdn,所以不影响网站的使用了。

数据持久层

为啥需要这个数据持久层

别问,问就是性能优化【手动狗头】

嘿嘿,待小羽解析一下~

因为每次请求cdn接口都是需要耗费一定的时间

如果每次打包的时候都去请求一次接口,那么就可能会降低我们的打包效率,而且每次请求回来的内容都是一样的,所以添加这个数据持久层就变得十分有必要了。

我们新增了一个cache.ts,而在vite这些基于node的打包工具中,咱们是可以直接使用fs模块的,想了解数据持久层具体实现的小伙伴们可以直接去看代码

具体效果如下,打包时会自动在项目的根目录下新建了一个.cdn-cache.json。然后在后续的打包中,咱们的插件会先通过这个缓存文件来寻找cdn,如果没有再去通过cdn的接口来获取,这样子就可以有限的降低打包的cdn 接口请求耗时。

ps:建议不要通过.gitignore忽略该文件,否则每次打包都是需要通过api接口获取cdn路径。

加入我们

白泽大舞台,有胆你就来!

白泽开源团队持续向大家发出邀请,欢迎各位有志之士加入到咱们的开源团队中来,舞台很大,等的就是你!!!

ps:如果二维码失效了,也可以加小羽的微信(注明来意哦~)