前言
前端性能优化是一个陈词滥调的话题,对于性能优化的技术文档和书籍都特地多。如果大家想深刻学习前端性能优化相干内容,有以下举荐
- 雅虎军规 35 条
- 某东上搜“前端性能优化”,书籍也特地多。
然而前端性能优化做的所有工作,都和一个灵魂拷问有极大的关系:
在浏览器输出 url 后,产生了什么? - 首先 url 是一个域名,首先它要被解析成 ip 地址。如果你的设施之前拜访过该 url,那么本地可能会缓存 ip 地址。如果没有缓存过,那么就向 dns 服务器进行解析。
- 依据 IP 地址和默认端口建设 TCP 连贯,三次握手。
- 浏览器收回 HTTP 申请;
- 服务器对申请作出响应;此时兴许会有一些 304 之类的返回后果。会波及到 http 缓存机制。
- 开释 TCP 连贯;
- 浏览器将该 html 文本并显示内容。
所以咱们能够从这个过程里去思考,服务器如何把文件尽快发送到客户浏览器。
- 第一点,就是文件尽可能要小,文件尽可能少,发送起来会更快
- 第二点,就是发送过程,在肯定条件下,缩小文件或申请的个数。
文件也并不是越少越好,假如文件内容少到极致,内容全副合并到一个文件,那么这个文件会是十分微小的,发送起来也会十分慢。如果文件个数太多,那么浏览器也会限度并发数量,在同一个域名下,浏览器的并发数量是 6 个。这样,尽管每个申请发送的文件很少,然而建设申请的过程也是耗时间的。很多申请都被阻塞了。
以上是针对第一次拜访网站时可用的计划,然而如果一个网站常常被反复拜访,还有以下办法 - 第三点,缓存机制 就是之前用到过的文件和内容,如果没有生效,就能够重复使用,不须要再从服务器拿。
以上是我大略能想到的一些思路。如果有不精确的中央,或者有其余好的思路,心愿大家留言帮我补充。
上面咱们进入正题,说一下我在开发我的项目时遇到的一个问题,以及解决思路
开发过程遇到的一个理论问题
在 vue 我的项目打包后,会在我的项目的根目录下生成一个 dist(你也能够扭转该名称)文件夹。一个单页面利用的 dist 文件夹通常蕴含一个 index.html 和 一个 js 文件夹 和一些其余资源文件。
而后咱们把 dist 文件夹公布到服务器上,在浏览器下来拜访咱们的我的项目,刚开始可能会特地慢。关上 chrome 调试工具,查看一下资源加载状况。
太惊人了,一个要害的 js 文件,在 nginx 服务器上曾经做了压缩解决,从 800k 压缩到 270k 左右。然而加载工夫仍然达到了惊人的 22.89s。这个对于任何一个我的项目来说都是不可承受的。
初步解决思路
问题曾经出现了。打包后的文件,呈现了特地大的 js,而且就是这个 js 文件阻塞了整个我的项目的加载。
因为最近正在钻研 webpack 相干内容。
webpack 大家应该都应用过。webpack 是一个打包编译工具,它做的事件,就是把你开发的整个我的项目,编译成一个浏览器可间接辨认的我的项目。它蕴含以下一些根底概念:
- 1,入口文件
入口文件,就是 webpack 工作的终点,从入口文件开始,咱们通常会 import 很多其余模块,import 等模块化的开发方法,就把整个我的项目给串联起来了。依据这些依赖信息,webpack 把整个我的项目解析为一个 ast(形象语法树),这个树记录了所有的文件依赖门路。 - 2,进口文件
就是我的项目打包后寄存的目录,所有资源文件都会输入到这个文件夹 - 3,loader
webpack 只能辨认 es5 的语法,对于 es6 等更新的语法,是不能辨认的,对于一些图片,css 文件,jsx 文件等各种不同后缀名的文件,都是须要 loader 进行解析的。loader 做的事件也就是这些。 - 4,plugin
依据 webpack 官网文档,咱们晓得 webpack 在整个打包和编译的过程中,有几十个工夫节点。具体的内容能够看这个链接,在 plugins 目录下:webpack.docschina.org/api/compile…
那么我做的一点小尝试,就是在文件打包并且输出到 output 文件夹后,找到要害的 js 文件(上图划红线的那个文件),上传到公司的阿里云 oss。而后 index.html 文件本来是援用了 output 外面的 js 文件,改为援用 oss 外面的链接。这也是待会儿实现 webpack 自定义插件的次要思路。
最初的试验成果
本来须要 20 多秒加载的文件,放到阿里云 oss 后,只须要 0.5s 的加载速度,是不是十分惊人呢。
而后发现,影响页面加载的次要因素,曾经不是这个要害 js 了。咱们好能够在此基础根底上做其余优化。
插件代码 和 应用办法
先看次要代码:
在 src 目录下新建 plugins 文件夹,而后新建了一个 UploadJsToCDNPlugin.js 文件。这也是咱们的插件文件。##### 参考 webpack 视频解说:进入学习
src/plugins/UploadJsToCDNPlugin.js 文件内容如下:
// const globby = require('globby');
const path = require('path');
const fs = require('fs');
const axios = require('axios')
var FormData = require('form-data')
let replaceFile = function(filePath,sourceRegx,targetStr){fs.readFile(filePath,function(err,data){if(err){return err;}
let str = data.toString();
str = str.replace(sourceRegx,targetStr);
fs.writeFile(filePath, str, function (err) {if (err) return err;
});
});
}
class UploadJsToCDNPlugin {constructor(options = {}) {this.options = options;}
apply(compiler) {console.log(compiler.options.mode)
compiler.hooks.afterEmit.tap('UploadJsToCDNPlugin', async (params) => {
try {const js_path = Object.keys(params.assets).find(item => item.includes('js/chunk-libs.'))// 请自行调整文件名称
const html_path = path.resolve(compiler.options.output.path, 'index.html')
const file_path = path.resolve(compiler.options.output.path, js_path)
// 因为是公司我的项目,已做脱敏解决,道歉
const url = 'https://wwwxxxxxx/file/upload'
const form = FormData()
form.append('file', fs.createReadStream(file_path), {filename: 'app.js'})
const res = await axios.create({headers: form.getHeaders()
})
.post(url,form)
const cdn_path = res.data.data
// 这行代码是本插件的外围代码
await replaceFile(html_path, /js\/chunk-libs.\w*.js/g, cdn_path)// 请自行调整文件名称
} catch (e) {e}
})
}
}
module.exports = UploadJsToCDNPlugin;
最初在 vue.config.js 外面应用 webpack 自定义 webpack 插件:
vue.config.js 文件结尾:
const UploadJsToCDNPlugin = require('./src/plugins/UploadJsToCDNPlugin')