【插件系列】为了愉快的薅羊毛,小羽专门写了一个使用免费CDN的插件

如果生活有奇迹,那一定是努力的轨迹!

前言

Hello,大家好,我是小羽同学,一个平凡而又不甘于平凡的前端开发工程师~

前段时间,小羽复习了下 webpack 相关的知识,然后突然发现自己好像还没写过webpack插件的,手就有那么一点儿痒痒的,想动手自己撸一个webpack插件出来耍耍。

正当小羽在绞尽脑汁,想到底写个啥插件出来耍耍的时候,某个前端吹水群里讨论起cdn以及前段时间jsdelivr挂掉的事情。哎,这不正好吗?我给它整一个webpack插件,专门薅jsdelivr的羊毛,以后还可以使用。看这想法不是挺棒的嘛~

因此,本篇文章也是围绕该webpack插件展开的。

通过本篇文章你可能可以学到如下知识:

  • github+jsdelivr使用免费的cdn
  • 撰写一个简单的webpack插件(再也不怕面试官问我webpack插件了!!!)
  • 利用github api上传/修改文件
  • 利用html-webpack-plugin修改输出的文件内容
  • jsdelivr挂掉了的降级处理方案
  • 利用github-jsdelivr-upload直接使用cdn

1.如何使用免费cdn?

首先咱们想使用免费的cdn,就得先知道jsdelivr是怎么样使用滴~

jsdelivr官网中我们可以看到jsdelivr是通过npmgithubwordpress三种途径进行加速的。

现在我们主要讲的是github这种途径。

使用github的方式,咱们是可以通过版本或者直接使用路径的方式来进行加速的。

image-20220105210208984

这两种的区别就是版本的方式他会是将文件进行锁定,而直接使用路径的话则会根据你文件的变化而随之变化。

emmm,既然是使用github的方式,那咱们先创建一个仓库吧。

ps:

这里建议小伙伴们新开一个github账号,

这里建议小伙伴们新开一个github账号

这里建议小伙伴们新开一个github账号

重要的事情说三遍

因为后面的插件会使用到github的token,而拥有该token的用户则可以对你的仓库进行各种操作,懂得都懂

在创建的时候记得将仓库设置为public,这样子jsdelivr才可以读取到咱们github中的文件,然后顺便勾上add a readme file。这个是给咱们的仓库默认添加一个readme.md的文件,方便咱们测试jsdelivr。

image-20220105211428798

image-20220105211540996

ok,现在仓库建好了,咱们先测试一下是否可以通过jsdelivr来读取咱们的readme.md文件

这里就直接使用通过路径的方式了。

然后可以看到刚刚新建的README.md可以被正常读取了。

jsdelivr链接中的参数如下图所示,小伙伴这么聪明应该一看就懂吧?

image-20220105211800924

image-20220105212143903

2.通过github-jsdelivr-upload免费使用cdn

这里的话,小羽就直接使用基于vue-cli创建的开源项目——小羽直播平台,进行演示。(经测试vuereact都是可以正常使用的,angular的小伙伴就不好意思了,小羽不懂angular,但理论上也是可以使用的,毕竟是一个webpack的插件)

使用一个npm包的第一步就是查看相关的文档

image-20220105214918182

image-20220105220034683

emmm,然后发现咱们有这么两个问题需要处理,否则可能无法使用插件。

  • vue-cli创建的项目中html-webpack-plugin版本较低,为3.x版本
  • 需要一个github token

img

第一个问题比较简单,直播平台中的webpack4.x版本,因此直接升级html-webpack-plugin的版本即可

npm i [email protected]
复制代码

第一个问题解决了,那咱们的github token怎么获取呢?

跟着下面几幅图来操作就好,最后生成的token记得保存下来,因为关闭后就不会再显示这个token了~

再次声明,这个token是可以用来修改你的个人仓库的,所以为了避免token泄露可能造成不必要的损失。强烈建议小伙伴们新申请一个github账号。

image.png

image.png

image.png

image.png

好了,准备工作都完成了。咱们就开始使用github-jsdelivr-upload这个插件吧。

首先安装

npm i github-jsdelivr-upload
复制代码

然后根据npm中的文档,在vue.config.js中进行相应的配置

注意,vue-cli创建的项目这里需要手动引入html-webpack-plugin,否则会使用默认的html-wepback-plugin3.x版本。

image-20220105224632357

然后npm run build。查看一下咱们的打包结果,格式化一下。

emmm,可以发现咱们的链接全部换成带jsdelivr域名下的链接,很nice,说明咱们的cdn插件已经生效。

image-20220105224539225

ok,到这里就可以够小伙伴们的日常开发和使用了,如果想了解如何开发一个webpcak插件以及github-jsdelivr-upload实现原理的小伙伴们,请继续往下看~

img

3.撰写一个简单的webpack插件

咱们先来写一个最简单webpack插件

在跟目录下新建myWebpackPlugin.js,内容如下:

class MyPlugin {
  constructor(data) {
    const {
      name,
    } = data;
    this.name = name
    this.pluginName = 'MyPlugin'
  }

  apply(compiler) {
    compiler.hooks.emit.tap(this.pluginName, () => {
      console.log("这是小羽的个人webpack插件")
      console.log("this.name", this.name)
    })
  }
}
module.exports = MyPlugin
复制代码

然后在vue.config.js中引入该plugin,然后再npm run build

此时我们会发现咱们的控制台中输出了咱们在插件中撰写的内容

好了,一个简单的插件这样子就完成了。

img

而一个复杂的插件无非就是在合适的时候调用合适的compilercomplation钩子,然后进行相应的操作。

image-20220105230046541

image-20220105225944900

4.利用github api上传/修改文件

小伙伴们还记得咱们平时是怎么将咱们的文件推送到github上不?

git add *
git commit -m 'xxx'
git push origin master
复制代码

一般都是这样命令行或者使用可视化工具进行操作的,对吧?

那咱们的github-jsdelivr-upload也是这样子操作的吗?

emmm,刚开始小羽的确有想过这么处理,因为这样子的逻辑是最简单的,直接添加一个命令行npm包即可。但是这样子的话会存在一些问题。比如咱们所有可以打包的机器都必须带有github仓库允许提交密钥,这样一来就不是很方便了。

因此,小羽就另辟蹊径,看看能不能直接将文件上传到github。然后就发现了原来github是有给咱们提供了api接口,利用这些api接口,咱们就可以完成了上传。而这些接口就需要到github token。这也是为啥github-jsdelivr-upload需要github token的原因.

upload(path, content, message = 'update cdn') {
    return this.octokit.request('PUT /repos/{owner}/{repo}/contents/{path}', {
      owner: this.owner,
      repo: this.repo,
      path,
      message,
      content
    }).catch(err => {
      console.log(JSON.parse(JSON.stringify(err)))
    })
  }
复制代码

5.利用html-webpack-plugin修改输出的文件内容

还记得咱们在第二小节时候,使用了github-jsdelivr-upload这个插件。然后这个插件会自动帮咱们将文件路径替换为jsdelivr中的路径。emmm,这个是怎么处理的呢?

这里是利用了html-webpack-plugin 提供的 getHooks方法,获取html中的内容,并进行修改。

伪代码如下:

compiler.hooks.compilation.tap(this.pluginName, (compilation) => {
      HtmlWebpackPlugin.getHooks(compilation).beforeEmit.tapAsync(this.pluginName, async (data, cb) => {
        const assets = getAssets(compilation) // 获取文件路径
        const cdnUrl = `${this.baseCdnUrl}/${this.owner}/${this.repo}${this.cdnType === 'staticaly'?'/main':''}/${this.basePath}`
        const newAssetJson = ['/']
        for(let i in assets){
          for(let item of assets[i]){
            // 正则替换对应的文件路径
          }
        }
        data.plugin.assetJson = newAssetJson
        cb(null, data)
      })
    })
复制代码

6.jsdelivr挂掉的降级处理方案

emmm,前段时间jsdelivr在全国范围内,大面积挂掉。导致很多使用jsdelivr的小伙伴们苦不堪言

既然咱们写了这么一个薅羊毛的插件,那咱们是不是也需要考虑到这种情况

当文件加载异常的时候,script、link这些标签都会触发一个onerror的事件。

ok,那咱们就利用这个onerror事件来搞事情。

封装一个errorCDN的方法,在所有替换链接为jsdelivr的同时,添加data-cdn以及errorCDN方法。

当咱们的jsdelivr对应的文件加载异常的时候就会触发errorCDN方法,而errorCDN将会将咱们加载异常的标签进行替换本地路径(部署的服务器),即降级为使用本地的文件。

这时候咱们的页面只会出现文件加载异常的报错,但是并不会影响到咱们页面的运行。

function errorCDN(e) {
    var target = e.getAttribute("data-cdn");
    var tagName = e.tagName
    var cdnDOM = document.createElement(tagName);
    if(tagName === 'SCRIPT'){
        cdnDOM.src = "./" + target;
    }else{
        cdnDOM.href = "./" + target;
    }
    document.head.appendChild(cdnDOM);
    e.remove();
}
复制代码

后语

本文小羽和小伙伴们分享了怎样使用免费的cdn,并且对github-jsdelivr-upload这个webpack插件的原理进行了简单的分析,并且聊了下github-jsdelivr-upload是怎么对jsdelivr挂掉进行降级处理。

如果看这篇文章后,感觉有收获的小伙伴们可以点赞+关注哦~

img

如果想和小羽交流技术可以加下wx,然后小羽最近建立了一个技术交流群(有很多大佬在群里哦~),想进群的小伙伴们可以扫码,嘿嘿~

ps:本文原创,转载请标明出处。

最后奉上github-jsdelivr-upload的相关连接

npm链接:www.npmjs.com/package/git…

GitHub链接:github.com/sulgweb/git…

如果条件允许的话,希望小伙伴们给小羽的github添加一颗小星星哦~

img

おすすめ

転載: juejin.im/post/7050257265877581832
おすすめ