一次前端性能优化的过程(多图)

性能优化听多了,又是各个注意点,又是监控什么的,如《JS性能优化探讨》《前端性能监控》,真正遇到了还是得具体场景具体分析。

一直觉得我的个人网站首页(现在不会了)很慢,进去后背景和熊猫头渲染得特别慢。当然这个慢是相对的,就我做过的 TO B 系统单单是前置接口的获取都要几秒了,只是有 loading 效果看起来不难受。但是我这个网页啥都没有,就那么几个图片和动画,着实不该。那就实际一步步看看吧。

一. 服务器连接速度

直接百度搜网站访问速度测试就有很多工具网站。一看都没啥问题,除了极个别的比较远的省份(我这是买的阿里云深圳的服务器)其他都在一秒以内。再 ping 一下,也可以看到并无延迟。也就是 DNS 解析和访问并没有问题。

二. 减小图片体积

那首先考虑资源图片过大,因为确实用了比较高清的图片,那就在不糊的情况下尽量缩小体积。兴冲冲地更新一看,没啥变化。还是有那个等待过程。那好吧,一不做而不休,我尝试把其他图片都去掉,只留下一个熊猫头,还是很慢,就证明不该是图片背锅。当然缩小体积是没有问题的。省流量嘛。

三. 使用 Devtool Performance

那就直接用工具看吧,打开开发者工具,切到 Performance,启动录制看看效果。找一下,在 Timings 那里看到 FP FCP 等事件,这里就是影响视觉观看的主要节点了。当然前面还有 Parse HTML 或者 Function call 等等事件。主要看 Parse HTML,因为要解析了 html,才会加载一系列资源,可以看出这一步并没有什么问题,也是很快就响应了。但是到 FCP 却隔了好几秒。也就是中间有东西耽搁了。
看了一下,是必要的 js 文件加载。有两个,一个是 app.***.js,基础的业务 js, 一个是 chunk-vendor.***.js,vue 框架的打包产物。毫无疑问,这两者都是不可或缺的。appjs 比较小还好,很快就获取完了。chunk-vendorjs有 300+kb,耗时几秒。可以看到它加载完后,很快就 FCP 了。所以它的加载就是问题关键了。

四. js 文件太大?

讲道理,300+kb 的 js 文件不算小,但也不能叫很大啊。怎么要好几秒才能加载完?当然我的服务器没有加速功能,如果放到 CDN 服务,我想应该效果会好点。但是没有这条件,那只能另外想想办法。我代码里用了 Element-UI,测试了一下确实是按需引入,去掉几个组件后,体积变小了。
但,这些就是要用到的,减不了。路由页面用的也是 import() 动态引入,也就是到了真正访问那个页面组件,才会去加载相应的 js。再说了业务代码也不会打包到 vendor 去。那体积没法减了。然后在自己本地测试了一下,以及线上的缓存状态下,页面出现都很快,更加印证了我的猜测,就是这个 “大 js 文件” 导致了页面渲染慢。(当然最好有个 CDN 什么的加速可以验证…)

事情本到这里就结束了(啥都没干,555…),结果又看到一个神奇的网站,谷歌的性能分析网站,地址:https://pagespeed.web.dev (可能需要科学上网)

Read More

文件切片上传(断点续传)

上传文件体积一大,要等很久。如果只是水管小,等一会也就算了。但是如果网络差,上传到 99% 突然断网了又重新开始,就比较难受了。所以又有了文件切片进行断点上传的方法。

上传的文件对象是一个 File 对象,然后它是 Blob 对象的一个子类。再然后它有一个 slice 方法,用这个方法就可以对文件进行切片,就和数组的这个方法一样。用法如示例。

话不多说直接上代码(里面代码是问了 chatgpt 然后改的,哈哈)。把下面两份代码分别保存为 index.htmlserver.js,安装好依赖,然后启动执行 node server.js,访问 http://localhost:3000

前端也大概美化了一下上传组件,支持点击选择文件或者拖拽文件上传。原生的 <input type="file" ></input> 组件的样式应该没人用吧,那么丑…。其中的 loading 效果出自网上大佬的《纯css实现117个Loading效果》,里面挺多效果不错的。

Read More

nginx 的基础用法 & linux(centos)下支持 https 和 http2

其实之前写过一篇相关的《记录下 nginx 使用配置》,关于 nginx 的一些稍微复杂的场景。然后发现日常的基础用法,反而记不住。这里就记录一下。

安装,mac 可以用 brew 下载。windows 的也很简单,去官网下载个压缩包就行了。至于 linux 的,就网上搜搜啦,我记得也很简单。

基础用法

# 安装
brew install nginx

#查看
brew info nginx

查看信息,可以看到配置文件在 /opt/homebrew/etc/nginx/nginx.conf

命令

# 启动
nginx

# 刷新,改了 nginx.conf 文件,要重新生效
nginx -s reload

# 关闭
nginx -s stop

默认端口是 8080。所以直接访问本地地址 http://localhost:8080/,看到有显示 Welcome to nginx! 字样就是启动成功了。

其实 nginx.conf 已经写了例子和注释,这里只是稍微补充点。

root:资源文件夹
index: 默认的 index 文件

location / {
  root   /电脑地址/nginx;
  index  index.html index.htm;
}

如果要配置不同路由访问不同的文件,root 要改成 alias,比如访问 http://localhost:8080/page

location /page {
  alias /电脑地址/nginx;
  index page.html;
}

当然最好是写个兜底返回。在 vue 或者 react 使用 router 时,兜底返回默认 index.html。不然每增加一个路由就要写多一个配置很麻烦。

location ~* ^/* {
  root   /电脑地址/nginx;
  try_files $uri $uri/ /index.html;
}

注意事项

注意 1
try_files $uri $uri/ /index.html; 兜底的写法,最后那个 /index.html 不是返回物理文件路径,而是发起重新的 url 请求,然后再来匹配规则返回。
比如以下这种不是根路径的配置,当我访问 /new 是 ok 的,但是访问 /new/abc 就不 ok。在使用 SPA 框架时候,我们知道有要求所有路由请求都需要返回 html,路由都是交由前端框架自己处理。

location /new {
  alias   /电脑地址/nginx;
  try_files $uri $uri/ /new/index.html; # 注意这里是 /new/index.html,不是 /index.html
}

匹配到最后的兜底是发起一个 http://域名/new/index.html 的请求,然后匹配到 /new 规则,返回相应的 index.html。
如果写成 try_files $uri $uri/ /index.html;,那么兜底是发起一个 http://域名/index.html 的请求,这样会导致匹配不到所有规则,导致 404。

注意 2
root 与 alias
两者区别在于 nginx 如何解释 location 后面的 url

root:
语法:root path
默认值:root html
配置段:http、server、location、if
处理结果:root 路径+ location 路径

alias:
语法:alias path
配置段:location
处理结果:使用 alias 路径替换 location 路径

所以用正则匹配写路径的要注意写好 root 或 alias,不然找不到资源就会出现 403!

注意 3

location ~ /api {
  proxy_pass   http://localhost:3000;
}

后面都没有斜杆,/api/user 会变成 http://localhost:3000/api/user 请求

location ~ /api/ {
  proxy_pass   http://localhost:3000/;
}

后面都有斜杆,/api/user 会变成 http://localhost:3000/user 请求

所以关键就是看后端接口要不要以 api 打头。

其它用法

可以写多个 server,启动多个服务

server {
  listen       3000;
  server_name  0.0.0.0;

  location / {
    root   /电脑地址/nginx;
    index  3000.html 3000.htm;
  }
}

代理 ~ 为区分大小写,~*为不区分大小写,其他符号则请查询官网啦。

location ~ /api/* {
  proxy_pass   http://localhost:3000;
}

https 服务,声明好证书即可。这里只是把其中证书配置列出来,实际上 nginx.conf 的例子还有挺多配置,一般我们不是运维,应该默认就够了。作为调试用,可能都不需要启动到 https server。

server {
  ssl_certificate      /电脑地址/nginx/cert/cert.pem;
  ssl_certificate_key  /电脑地址/nginx/cert/server.key;
}

开启文本压缩

http {
  gzip on;
  # 压缩比例,比例越大,压缩时间越长。默认是1
  gzip_comp_level 6;
  # 哪些文件可以被压缩
  gzip_types text/xml text/plain text/css application/javascript application/x-javascript application/rss+xml;
}

linux 下支持 https 和 http2,也是网上搜集的,实操了可以,这里记录一下。

# 安装依赖
yum -y install gcc zlib zlib-devel pcre-devel openssl openssl-devel
# 解压缩
tar -zxvf nginx-1.23.4.tar.gz
cd nginx-1.23.4
# 执行配置
./configure --with-http_ssl_module --with-http_v2_module
# 编译安装
make
make install
# 默认安装在
/usr/local/nginx
# 启动
/usr/local/nginx/sbin/nginx
# 刷新配置启动
/usr/local/nginx/sbin/nginx -s reload
# 关闭
/usr/local/nginx/sbin/nginx -s stop
# 修改配置
vim  /usr/local/nginx/conf/nginx.conf

从零搭建前端工程(下)

文章内容太多,分为上下两部分,这里是下半部分。上半部分在《从零搭建前端工程(上)》,此篇的内容有:
4. 使用 eslint + prettier 让代码健壮和优雅
5. 使用 husky + lint-staged 强制增量各类检查
6. 使用 @commitlint/cli 规范提交信息
7. 使用 埋点(性能 + 错误) 让项目运行更好



四、使用 eslint + prettier 让代码健壮和优雅

到 eslint 了,是不是让人又爱又恨。刚接的时候应该很不爽吧,动辄就来个错,这也错那也错。满屏尽是红 error。其实都是没有配好,也有处理好。eslint 是非常必要的,可以尽早发现一些错误及不合理,也可以统一一些写法,减少冲突等。比如,vue template 的属性顺序,import 的顺序等等。

循例先上代码示例,在项目根目录创建一份 .eslintrc.js,记得前面有个点的,上书代码:

module.exports = {
  env: {
    // 关键字指定你想启用的环境
    browser: true,
    es2021: true,
  },
  extends: [
    // 一个配置文件可以被基础配置中的已启用的规则继承
    'plugin:vue/essential',
    'plugin:vue/recommended',
    'standard',
    'plugin:prettier/recommended',
  ],
  parserOptions: {
    // 允许你指定你想要支持的 JavaScript 语言选项
    ecmaVersion: 12,
    sourceType: 'module',
  },
  plugins: [
    // 支持使用第三方插件,检查自定义的语法
    'vue', // 省略了 eslint-plugin- 前缀,插件全称为 eslint-plugin-vue
    'prettier',
  ],
  rules: {
    // 直接声明的 eslint 规则
    semi: ['error', 'always'], // 规则为:需要结束分号,优先级为 error,即抛错
    // 当最后一个元素或属性与闭括号 ] 或 } 在 不同的行时,要求使用拖尾逗号
    // 当在 同一行时,禁止使用拖尾逗号。https://eslint.bootcss.com/docs/rules/comma-dangle
    'comma-dangle': ['error', 'always-multiline'],
    'no-console': ['error', { allow: ['info', 'warn', 'error'] }],
    'no-unused-vars': ['error', { args: 'after-used' }],
    // "plugin1/rule1": "error" 配置定义在插件中的一个规则的时候,必须使用 插件名/规则ID 的形式
    'prettier/prettier': 'error',
  },
  globals: {
    var1: 'writable', // 对 var1 这个全局变量允许重写
    var2: 'readonly', // 对 var2 这个全局变量只允许读取
    var3: 'off', // 不支持 var3 这个全局变量
  },
};

说一下可能配置较多的。

Read More

从零搭建前端工程(上)

文章内容太多,分为上下两部分,这里是上半部分。下半部分在《从零搭建前端工程(下)》,此篇的内容有:
1. 使用 webpack 打包(编译)vue
2. 使用 babel 处理 js
3. 使用 webpack-dev-sever 做热调试开发



产生这个的想法来自于某天接手一个项目,eslint 没配好,想着弄好格式化一下,一时之前忘了 cli 命令。
想一下,现在我们用的各种框架,都自带了脚手架工具,初始化后基本上不用怎么改造就可以上手开发。导致很多工程化的东西被人忽视了,就容易遇到问题时被卡住或者东找西找翻资料。
所以就想着自己从头搭建一个项目看看,遇到的一些配置、工具、命令都给记录下来,方便后面再遇到时候就不会生手了。

这里我就用 vue 来做基础框架,用 react 也一样,就一些编译工具的差别,大部分是一样的。要做的事有:

  1. 使用 webpack 打包(编译)vue
  2. 使用 babel 处理 js
  3. 使用 webpack-dev-sever 做热调试开发
  4. 使用 eslint + prettier 让代码健壮和优雅
  5. 使用 husky + lint-staged 强制增量各类检查
  6. 使用 @commitlint/cli 规范提交信息
  7. 使用 埋点(性能 + 错误) 让项目运行更好

零、文件初始化

准备一个和 vue 脚手架创建出来的初始工程一样。有:

src:项目源代码
src/main.js:工程入口文件,在这里做 vue 初始化,也是 webpack 的entry
src/App.vue:一个主页面
src/components/HelloWorld.vue:一个子组件
src/assets/logo.png:一张图片资源
src/public:公共资源文件夹,这里放的东西依样拷贝进打包里(除了index.html)
src/public/index.html:用来做单页面工程入口 html 的基础模板

然后初始化一下 npm 环境:

npm init -y

-y 就是创建一份默认的,不需要一步步问要填什么。直接生成空信息,有需要自己再去填就好了。

Read More