一、背景介绍

在最新接手的一个项目中,在通过webpack打包项目后,将静态资源托管到CDN平台,但是有一个问题就是,当项目中文件内容改动后,重新构建并上传至CDN平台,无法实时更新最新上传的文件内容,原因是CDN平台对托管的 这些文件有缓存,如果我们希望每次构建后托管的资源文件不被缓存的话,往往通过配置webpack 的output,为输出的文件名动态配置一段hash,就可以避免这个缓存问题,但是由于项目架构设计的问题,有些文件打包后需要输出静态文件名,不能为文件名添加动态的hash,所以需要解决一个问题 “把当项目托管到 CDN 平台,每次重新上传文件后希望刷新这个文件不被CDN缓存”。

二、解决思路

因为项目中构建完成后上传cdn 这个功能是通过webpack插件实现了,思考一阵后发现刷新cdn上文件这个功能也可以通过插件这种方式,实现自动化的cdn文件刷新功能。

三、插件开发基本流程

webpack打包是一种事件流的机制,它的原理是将各个插件串联起来。核心就是tapable,它可以暴露出挂载plugin的方法。可以让我们能将plugin控制在webpack事件流上运行.

在官网的描述中,一个webpack 插件由以下组成:

  • 一个 JavaScript 命名函数。
  • 在插件函数的 prototype 上定义一个 apply 方法。
  • 指定一个绑定到 webpack 自身的事件钩子
  • 处理 webpack 内部实例的特定数据。
  • 功能完成后调用 webpack 提供的回调。


1、注册一个www.npmjs.com 网的账号以便开发完成后发布到npm中

  • npm login 登录授权
  • npm publish 发布插件

    2、创建webpack插件结构

  • 创建一个cdn-cache-refresh目录

  • 进入目录 cd cdn-cache-refresh
  • npm初始化 npm init ``` package name: (vue-toast-demo) // 插件名 version: (1.0.0) // 插件版本 description: a toast plugin for mobile // 插件的作用描述 entry point: (index.js) // 插件入口 test command: // 测试脚本 git repository: // 大家把插件做完以后,可以上传到自己的github仓库,最后把github的地址贴近来,这样别人在下载你的插件的时候,就可以直接驱读你源码了,可以先留空,等代码上传github仓库之后把地址再拷贝下来 keywords: toast vue-toast 关键词 author: JackBean 作者 license: (ISC)

{ “name”: “cdn-cache-refresh”, // 插件名 “version”: “1.0.2”, // 插件版本 “description”: “刷新项目中托管到cdn上的资源,保证不被缓存”,// 插件的作用描述 “main”: “index.js”,// 插件入口 “scripts”: { “test”: “echo \”Error: no test specified\” && exit 1” }, “repository”: { // 插件做完以后,可以上传到自己的github仓库,最后把github的地址贴近来,别人在下载你的插件的时候,就可以直接读你源码。 “type”: “git”, “url”: “git+https://github.com/ccwyn/cdn-cache-refresh.git“ }, “bugs”: { “url”: “https://github.com/ccwyn/cdn-cache-refresh/issues“ }, “homepage”: “https://github.com/ccwyn/cdn-cache-refresh#readme“, “keywords”: [ // 关键词 “cdn-cache-refresh”, “ali-oss”, “qiniu”, “webpack”, “plugin” ], “dependencies”: { “@alicloud/pop-core”: “^1.7.10”, “ora”: “^3.2.0”, “qiniu”: “^7.2.1” }, “author”: “wyn”,// 作者 “license”: “ISC” }

  1. - 创建一个index.js

“use strict”; // 一个 JavaScript 命名函数。 class CdnCacheRefresh { constructor(options = {}) {

} // 在插件函数的 prototype 上定义一个 apply 方法。 apply(compiler) {

}

}

module.exports = CdnCacheRefresh;

<br />
<a name="1dHu5"></a>
## 四、编写插件逻辑

- 在index.js文件中实现插件功能(在静态资源上传到CDN后,清除CDN上的文件缓存)
- 实现思路
   - cdn刷新文件需要下载cdn平台提供的sdk,刷新的文件url 由 cdn加速域名/存放目录/文件名 组成。分析需求可知,我们需要拿到当前编译后output输出的文件名称,并在编译完成后执行刷新操作。
   - 从[compiler-hooks](https://www.webpackjs.com/api/compiler-hooks/)中找出相关事件钩子
      -  assetEmitted(每个文件完成写入)时触发
      -  done(编译完成)时触发

“use strict”; // 一个 JavaScript 命名函数。 class CdnCacheRefresh { constructor(options = {}) {

} // 在插件函数的 prototype 上定义一个 apply 方法。 apply(compiler) { // 生成文件的时候执行,提供访问产出文件信息的入口 compiler.hooks.assetEmitted.tapPromise(“CdnCacheRefresh”, (file) => { // 获取文件名,并保存起来,刷新文件时组装URL return Promise.resolve(); }); // 编译完成后执行 compiler.hooks.done.tapAsync( “CdnCacheRefresh”, async (compilation, callback) => { // 调用cdn 刷新文件接口 callback(); } ); } }

module.exports = CdnCacheRefresh; ```