react+node实现打包后静态资源自动上传到cdn

前言

为了加速网站首次访问的速度,我通过一顿操作+node脚本,以后网站每次部署都会自动将所有静态资源(css、js、图片等)上传我的cdn域名上,大大加快了网站访问速度。写篇文章记录下

可以访问我的个人网站,查看效果https://hyl999.co

1. 对象存储

对象存储类似云盘,可以将一些小文件存储进去,并暴露出来外链,配合cdn之后访问非常快。我们的目标就是把网站的css、js、图片等其他一些资源上传进去,再通过cdn来加速访问。

这里我使用到的是腾讯云的cos对象存储:https://console.cloud.tencent.com/cos

1.1 新建存储桶

首先新建一个存储桶

选个离自己近的地域,起个名称,先选择公有读私有写。然后一路下一步就行。

在这里插入图片描述

在这里插入图片描述

1.2 上传文件

点进刚刚建好的存储桶,随便上传一个文件,我传了一个图片

1.3 查看域名

存储桶列表,找到刚刚建好的存储桶,点配置管理,可以看到我们的访问域名

访问域名+文件路径 就可以访问到我们上传到存储桶的资源

可以直接访问测试一下

2. node自动上传

我们可以在存储桶上传我们的js、css之类的文件、不过我们的文件那么多,一个一个上传明显不合理。要你你也不干。

这时候,这些批量又重复的操作应该由我们的node出马,让我们来通过 node来批量上传我们的资源文件

2.1 获取密钥

在密钥管理下可以新建一个密钥,一会要用

]

2.2 遍历目录

既然要上传所有静态文件,那么就要先拿到所有静态文件的绝对路径。这里我写了个方法文件,可以遍历指定目录,返回一个数组。

注意,遍历目录的方法是异步的,所以这里使用promise,大概一秒足够遍历完所有文件

// node fs模块
const fs = require("fs");
// node path模块
const path = require("path");

// 收集所有的文件路径
const arr = [];
const fileDisplay = (filePath) => {
  //根据文件路径读取文件,返回文件列表
  return new Promise((resolve) => {
    fs.readdir(filePath, function (err, files) {
      if (err) return console.error("Error:(spec)", err);
      files.forEach((filename) => {
        //获取当前文件的绝对路径
        const filedir = path.join(filePath, filename);
        // fs.stat(path)执行后,会将stats类的实例返回给其回调函数。
        fs.stat(filedir, (eror, stats) => {
          if (eror) return console.error("Error:(spec)", err);
          // 是否是文件
          const isFile = stats.isFile();
          // 是否是文件夹
          const isDir = stats.isDirectory();
          if (isFile) {
            // 这块我自己处理了多余的绝对路径,第一个 replace 是替换掉那个路径,第二个是所有满足的直接替换掉
            arr.push(
              filedir
                .replace(
                  "D:lhstudyjiaoshoujiavuegenerator-lh-vuegeneratorsapp",
                  ""
                )
                .replace(//gim, "/")
            );
          }
          // 如果是文件夹
          if (isDir) fileDisplay(filedir);
        });
      });
    });

    setTimeout(() => {
      resolve(arr);
    }, 1000);
  });
};
module.exports = fileDisplay;

2.3 编写上传脚本

脚本思路就是,先把cdn上原来旧的文件清理,然后再将新文件逐一上传。 这里封装了两个方法

const fs = require("fs");
const path = require("path");
const COS = require("cos-nodejs-sdk-v5");
//上面封装的遍历目录方法
const fileDisplay = require("./fileDispaly");
//2.1拿到的密钥
const cos = new COS({
  SecretId: "xxxxxxxxxxxx",
  SecretKey: "xxxxxxxxxxxxxxx",
});
/* 存储桶名称 */
const bucket = "hylcdn-1305519392";
/* 存储桶所在地域 */
const region = "ap-beijing";

// 需要上传的文件夹地址
const filePath = path.resolve("build/");

// 批量删除文件,先查后删
const deleteOldFile = () => {
  return new Promise((resolve) => {
    cos.getBucket(
      {
        Bucket: bucket,
        Region: region,
        Prefix: "static/", //要清理的目录
        Marker: "static/", //要清理的目录
        MaxKeys: 1000,
      },
      function (listError, listResult) {
        if (listError) return console.log("list error:", listError);
        var objects = listResult.Contents.map(function (item) {
          return { Key: item.Key };
        });
        if (objects.length) {
          cos.deleteMultipleObject(
            {
              Bucket: bucket,
              Region: region,
              Objects: objects,
            },
            function (delError, deleteResult) {
              if (delError) {
                console.log(delError);
              }
              if (deleteResult?.statusCode === 200) {
                console.log("清理原static目录成功!");
                resolve();
              }
            }
          );
        } else {
          console.log("目录下无资源,无需删除!");
          resolve();
        }
      }
    );
  });
};

//单个上传文件
const uploadFile = (pathItem) => {
  cos.putObject(
    {
      Bucket: bucket,
      Region: region,
      Key: `static/${pathItem.split("static/")[1]}`, //上传到 存储桶 的路径 *
      StorageClass: "STANDARD",
      Body: fs.createReadStream(pathItem), // 被上传的 文件对象
    },
    function (err, data) {
      if (data?.statusCode === 200) {
        console.log(`上传${pathItem.split("/").pop()}到cdn成功!`);
      }
    }
  );
};

const playUpload = async () => {
  // 先删除原来的static
  await deleteOldFile();
  // 获取即将上传的所有文件路径
  const fileData = await fileDisplay(filePath);
  // 开始逐一上传
  fileData.forEach((item) => {
    uploadFile(item);
  });
};

playUpload();

2.4 效果

运行脚本

3. 修改项目的静态文件指向

项目默认一般是指向根目录,我们把它改成我们的存储桶cdn链接(这里我使用了自定义域名,1.3那个访问域名也可以)

以creat-react-app为例

效果,使用了cdn链接后资源加载的非常快

4. 自动化部署

修改package.json scripts配置

将打包,上传cdn,上传服务器 三个脚本合成一个指令

一条龙服务

附上我上传项目到服务器的脚本配置

const scpClient = require("scp2")
const ora = require("ora")
const server = {
    host:"xx.xx.xx.xx",//服务器IP
    port:22,//服务器端口
    username:"root",//服务器ssh登录用户名
    password:"xxx",//服务器ssh登录密码
    path:"/www/wwwroot/my-blog"//服务器web目录
}
const loading = ora("正在部署至 " + server.host )
loading.start()
scpClient.scp("build/", server ,(err)=>{
loading.stop()
    if(err) {
        console.log("部署失败")
        throw err
    }else {
        console.log("部署成功")
    }
})

可能遇到的问题

1、产生了额外的流量费,欠费。

因为这个存储桶会产生四种流量费,建议都购买一下

  • 标准存储容量费用:这个开始会自动送你50个G
  • CDN 回源流量费用:这个需要买,一年十块左右
  • 标准存储请求费用:一年一块钱
  • 外网下行流量费用:一个月三块左右

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
基于ReactNode的云课堂系统设计与实现如下: 设计方案: 1.前端部分使用React进行开发,通过组件化的方式搭建系统各个页面,包括学生和教师的登录页面、课程列表页面、课程详情页面等。前端使用React的虚拟DOM和状态管理机制,提高页面渲染效率和用户交互体验。 2.后端部分使用Node作为服务器端语言,搭建服务端应用,提供数据接口和业务逻辑处理。使用Express框架处理HTTP请求,通过路由控制不同请求的处理逻辑。同时,使用MongoDB数据库存储用户信息、课程信息等。 3.系统采用前后端分离的架构,前后端通过接口进行数据交互。前端发送请求到后端获取数据,后端经过处理后返回相应的数据给前端进行展示。 实现步骤: 1.创建React项目,搭建基本的项目架构和路由配置,实现用户登录页面和注册页面。 2.在后端使用Express创建服务器,配置路由,实现用户注册和登录接口,将用户信息存储在MongoDB中。 3.开发课程列表页面,通过前端请求后端接口获取课程列表数据,并进行展示。 4.实现课程详情页面,通过前端发送请求获取具体的课程详情数据,包括课程名称、教师信息、课程介绍等。 5.开发学生选课功能,前端通过请求后端接口获取可选课程列表,用户选择后将选课信息存储到数据库中。 6.开发教师端功能,教师可以管理课程信息,包括创建课程、编辑课程、删除课程等。 7.完善系统功能,如学生查看已选课程、教师查看已开课程等。 总结: 基于ReactNode的云课堂系统设计与实现需要充分发挥React的组件化和状态管理特性,同时利用Node的高效处理请求和Express的简洁路由配置,通过前后端分离架构实现系统的功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值