CDN优化

290 阅读3分钟

什么是CDN

介绍:CDN(内容分发网络)优化是一种用于加速网站或应用程序内容传输的技术策略。CDN将站点的静态资源(如图像、CSS文件、JavaScript文件等)分布在全球各个服务器节点上,使用户能够从离他们地理位置更近的服务器获取内容,从而提高加载速度和性能。

CDN优化的几个主要方面:

  • 静态资源缓存:CDN将静态资源缓存在离用户更近的服务器上,这样用户在请求资源时可以从离他们最近的服务器获取,减少网络延迟和带宽消耗。
  • 负载均衡:CDN使用负载均衡算法将用户的请求分配到最优的服务器节点上,以避免某些节点过载而影响性能。
  • 边缘缓存:CDN将静态资源缓存在分布在全球各地的边缘服务器上,这些服务器位于用户和源服务器之间,可以更快地响应用户请求,减少网络距离。
  • 动态内容加速:除了静态资源,CDN还可以缓存和加速动态生成的内容。CDN可以缓存动态内容的片段或完整页面,并使用高速缓存服务器提供快速响应。
  • 压缩和优化:CDN可以对静态资源进行压缩和优化,以减小文件大小并提高加载速度。例如,可以压缩CSS和JavaScript文件、对图像进行压缩和优化,以减少传输时间和带宽消耗。
  • 安全性增强:CDN可以提供一些安全功能,如防御DDoS攻击、提供SSL加密等,以保护网站或应用程序免受恶意行为的影响。

为什么要使用CDN

随着项目的功能增多,项目变大,而使用的第三方库也可能随之变多,最后通过打包会将这些第三方库都打包到一个js文件中,导致这个文件非常的大,加载时的速度慢。而使用CDN可以将这些第三方库缓存在离自己更近的服务器上,用户在请求资源时可以从离自己比较近的服务器上获取,减少了网络延时以及自己服务器宽带的消耗。

演示不使用CDN和使用CDN的区别

注意:下面的演示并没有用vue脚手架创建项目,而是用自己搭的webpack演示的,但也差不多。

测试使用的第三方库有:

npm install vue@2.6.14 vuex@3.5.1 vue-router@3.2.0 axios@1.3.6 element-ui@2.15.13
// src/index.js
import Vue from 'vue';
import App from './App.vue';
import VueRouter from 'vue-router';
import vuex from 'vuex';
import Element from 'element-ui';
import axios from 'axios';
  
console.log(VueRouter, vuex, Element, axios);

new Vue({
  render: (h) => h(App),
}).$mount('#app');

修改package.json

"scripts": {
  "build": "webpack --config ./webpack.config.js"
},

配置webpack

// webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const VueLoaderPlugin = require('vue-loader/lib/plugin');

module.exports = {
  entry: './src/index.js',
  output: {
    path: path.resolve(__dirname, 'build'),
    filename: '[name].[contenthash:4].js',
  },
  module: {
      rules: [
        {
            test: /\.vue$/,
            use: ['vue-loader']
        }
      ]
  },
  plugins: [
    new VueLoaderPlugin(),
    new HtmlWebpackPlugin({
      template: path.resolve(__dirname, './index.html'),
    }),
  ],
};

直接打包

npm run build

然后通过Live server运行打包后的index.html,并将浏览器的Disable cache开启并将网络切换到Fast 3G,运行结果如下图所示:

image.png

使用CDN首先需要对webpack进行修改,我的配置如下:

  • externals:防止将某些 import 的包(package)打包到 bundle 中,而是在运行时(runtime)再去从外部获取这些扩展依赖。
    • 注意externals对象中的键名对应包名值对应包的全局变量
  • 一般只有生产环境时才会用到CDN,开发环境一般不用
  • 免费开源的CDN网站:Bootcdnjsdelivr
// webpack.common.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const VueLoaderPlugin = require('vue-loader/lib/plugin');

// prettier-ignore
const externals = {
  'vue': 'Vue',
  'vue-router': 'VueRouter',
  'vuex': 'Vuex',
  'axios': 'axios',
  'element-ui': 'Element',
};

const cdn = {
  dev: {
    css: ['https://cdn.bootcdn.net/ajax/libs/element-ui/2.15.13/theme-chalk/index.min.css'],
    js: [],
  },
  build: {
    css: ['https://cdn.bootcdn.net/ajax/libs/element-ui/2.15.13/theme-chalk/index.min.css'],
    js: [
      'https://cdn.bootcdn.net/ajax/libs/element-ui/2.15.13/index.min.js',
      'https://cdn.bootcdn.net/ajax/libs/vue/2.6.14/vue.min.js',
      'https://cdn.bootcdn.net/ajax/libs/vue-router/3.2.0/vue-router.min.js',
      'https://cdn.bootcdn.net/ajax/libs/vuex/3.5.1/vuex.min.js',
      'https://cdn.bootcdn.net/ajax/libs/axios/1.3.6/axios.min.js',
    ],
  },
};

module.exports = {
  entry: './src/index.js',
  output: {
    path: path.resolve(__dirname, 'build'),
    filename: '[name].[contenthash:4].js',
  },
  module: {
    rules: [
      {
        test: /\.vue$/,
        use: ['vue-loader'],
      },
    ],
  },
  externals: externals,
  plugins: [
    new VueLoaderPlugin(),
    new HtmlWebpackPlugin({
      template: path.resolve(__dirname, './index.html'),
      cdn: cdn.build,
    }),
  ],
};

在准备的HTML文件中读取webpack中事前配置好的cdn,并使用EJS语法进行动态插入script标签引入外部资源。具体如下:

<!-- index.html -->
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
    <% for (var i in htmlWebpackPlugin.options.cdn.css) { %>
    <link href="<%= htmlWebpackPlugin.options.cdn.css[i] %>" rel="stylesheet" />
    <% } %> 
    <% for (var i in htmlWebpackPlugin.options.cdn.js) { %>
    <script src="<%= htmlWebpackPlugin.options.cdn.js[i] %>"></script>
    <% } %>
  </head>
  <body>
    <div id="app"></div>
    <div class="img-container"></div>
    <img class="img" />
  </body>
</html>

将安装到node_modules中的包移除

npm uninstall vue vuex vue-router axios element-ui

打包后运行index.html对比之前要快了不少

image.png