前端优化 ---- 从编码、缓存、打包与兼容性几个方面讨论

我们在做项目交付时,不仅要实现业务逻辑还要注重用户体验,当项目规格越来越大、浏览器不断的升级、越来越严峻的市场竞争,我们最初的设计可能会存在页面加载缓慢、白屏、低版本浏览器的兼容性等问题。
针对这些问题我们总结出一系列前端优化方案。

1. 编码层面

1.1 注重代码规范

  • 写好注释!
  • 使用ESLint代码检测工具,规范代码编写。
  • 变量、函数命名时使用小驼峰,能够见名知意。
  • 避免地狱回调,可使用函数循环调用方式。
  • 避免使用大函数,减少耦合。

1.2 避免造成内存泄漏

避免意外的全局变量 ,可以使用严格模式 ‘use strict’ 避免。
被遗忘的计时器或回调函数,没有被及时清除。
未被释放的闭包。

2. 缓存

当页面渲染的数据过多时,为了减轻对内存的占用,对初次接收且会用到的数据进行本地缓存,是有着大好处的.
受网速等各种因素的影响,当渲染数据过多时,若存在频繁的切换页面,用户体验效果不佳。

2.1 http缓存

缓存就是首次请求之后保留一个响应副本,待到下次请求时检查缓存,直接读取缓存数据。

  • 可以有效的艰难少冗余数据的传输
  • 缓解服务器压力,提高网站的性能
  • 加快客户端加载页面的速度

工程代码详见cacheTest工程代码

2.1.1 强缓存

强缓存是指,在缓存生命周期内,不走服务端,只走本地缓存,返回状态码为200.
由下面两个参数之一决定

  • expires 单位是毫秒 ms
  • cache-control(优先级更高) 单位是秒 s

2.1.2 协商缓存

协商缓存是在发起请求后,判断是否命中了缓存,命中缓存则直接返回304,未命中则返回所请求的资源。
由下面两个参数之一决定

  • Last-ModifiedIf-Modified-Since 对比的是文件修改时间
  • EtagIf-None-Match(优先级更高) 对比的是文件资源

2.2 本地缓存

可以将数据通过sessionStorage、localStorage、Cookie存储,方便使用。

sessionStoragelocalStorageCookie
存储大小5MB5MB4KB
生命周期重启浏览器、关闭页面或新开页面时失效永久存储,不过期,除非手动删除有过期时间

3 打包与兼容性优化

通过打包可以压缩文件大小,进而实现优化,本文主要介绍webpack打包。
初始化一个vue+webpack工程

vue init webpack vue-webpack-project

初始化一个vue+webpack工程
默认生成的package.json文件如下

{
  "name": "vue-webpack-project",
  "version": "1.0.0",
  "description": "vue+webpack project",
  "author": "",
  "private": true,
  "scripts": {
    "dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
    "start": "npm run dev",
    "lint": "eslint --ext .js,.vue src",
    "build": "node build/build.js"
  },
  //生产模式的依赖插件
  "dependencies": {
    "vue": "^2.5.2",
    "vue-router": "^3.0.1"
  },
  //开发模式的依赖插件
  "devDependencies": {
    "autoprefixer": "^7.1.2",// 自动补全css代码前缀 配置在.postcssrc.js
    "babel-core": "^6.22.1",// 转译核心文件 babel-cli、babel-node都依赖这个包
    "babel-eslint": "^8.2.1", // 配置在.eslintrc.js
    "babel-helper-vue-jsx-merge-props": "^2.0.3",//转译jsx语法
    "babel-loader": "^7.1.1", // 构建时JS代码进行转译 配置在 build/webpack.base.conf.js 
    "babel-plugin-syntax-jsx": "^6.18.0",//转译jsx语法
    "babel-plugin-transform-runtime": "^6.22.0",//api(函数or方法)的转译
    "babel-plugin-transform-vue-jsx": "^3.5.0",//转译jsx语法
    "babel-preset-env": "^1.3.2", // 根据开发者的配置,按需加载插件 配置于.babelrc
    "babel-preset-stage-2": "^6.22.0", // stage-2转译规则
    "chalk": "^2.0.1",// 修改终端输出字符样式的 npm 包
    "copy-webpack-plugin": "^4.0.1",// 用来复制文件,将打包过程中没用到的图片或音视频文件输出到指定文件目录
    "css-loader": "^0.28.0",// 解析CSS文件,以字符串的形式打包到JS文件中。可配合style-loader使用,由style-loader帮我们直接将css-loader解析后的内容挂载到html页面当中
    "eslint": "^4.15.0", //一些eslint插件,用于代码格式校验
    "eslint-config-standard": "^10.2.1",
    "eslint-friendly-formatter": "^3.0.0",
    "eslint-loader": "^1.7.1",
    "eslint-plugin-import": "^2.7.0",
    "eslint-plugin-node": "^5.2.0",
    "eslint-plugin-promise": "^3.4.0",
    "eslint-plugin-standard": "^3.0.1",
    "eslint-plugin-vue": "^4.0.0",
    "extract-text-webpack-plugin": "^3.0.0",//与style-loader作用类似,将样式文件单独打包,打包输出的文件由配置文件中的output属性指定。然后我们在入口HTML页面写个link标签引入这个打包后的样式文件。
    "file-loader": "^1.1.4",// 复制资源文件并替换访问地址
    "friendly-errors-webpack-plugin": "^1.6.1",// webpack友好错误提示
    "html-webpack-plugin": "^2.30.1",// 生成html文件
    "node-notifier": "^5.1.2",// 使用Node.js发送跨平台本地通知。 
    "optimize-css-assets-webpack-plugin": "^3.2.0",// webpack构建过程中搜索css文件,并压缩优化
    "ora": "^1.2.0",// 用于在控制台显示加载中的效果,类似于前端页面的loading效果
    "portfinder": "^1.0.13",// 自动获取端口,避免端口号冲突
    "postcss-import": "^11.0.0",// 配置在.postcssrc.js
    "postcss-loader": "^2.0.8",//处理CSS的loader,自动生成浏览器兼容性前缀,配置在 build/utils.js
    "postcss-url": "^7.2.1", // 配置在.postcssrc.js
    "rimraf": "^2.6.0",// 用来删除文件和文件夹的,不管文件夹是否存在,都可以进行删除。
    "semver": "^5.3.0",// 获取npm版本 
    "shelljs": "^0.7.6", // 实现js文件中执行shell命令
    "uglifyjs-webpack-plugin": "^1.1.1",// 压缩js代码
    "url-loader": "^0.5.8",// 支持file-loader的所有功能,此外可以计算出文件的base64编码,在文件体积小于我们指定的值(单位 byte)的时候,可以返回一个base64编码的DataURL来代替访问地址。使用base64编码的好处是可以减少一次网络请求,提升页面加载速度。
    "vue-loader": "^13.3.0",// 解析和转换.vue文件。提取出其中的逻辑代码 script,样式代码style,以及HTML 模板template,再分别把他们交给对应的loader去处理
    "vue-style-loader": "^3.0.1",// 转译css样式,类似于style-loader,区别在于 vue-style-loader 支持 vue 中的 ssr(服务端渲染),style-loader 支持的功能更丰富些,比如可以懒注入、可以指定位置插入标签等。
    "vue-template-compiler": "^2.5.2",// 将 Vue 2.0 模板预编译为渲染函数(template => ast => render)
    "webpack": "^3.6.0",
    "webpack-bundle-analyzer": "^2.9.0",// 生成代码分析报告,帮助提升代码质量和网站性能。
    "webpack-dev-server": "^2.9.1",// 提供热更新的开发服务器,旨在帮助开发者在开发阶段快速进行环境搭建。支持反向代理。
    "webpack-merge": "^4.1.0"// 区分打包环境dev、prod与公共的base,将不同环境的配置与base合并。
  },
  "engines": {
    "node": ">= 6.0.0",
    "npm": ">= 3.0.0"
  },
  "browserslist": [
    "> 1%",
    "last 2 versions",
    "not ie <= 8"
  ]
}

3.1 babel

主要用于语法降级,向后兼容低版本浏览器。编译流程分为 parse、transform、generate 3 步。

3.2 ESLint

用于静态检查代码的语法和风格,提高代码可读性可维护性等。

3.3 postcss-autoprefixer

配置autoprefixer,自动增加样式前缀,兼容不同浏览器。

3.4 postcss-pxtorem 移动端适配

配置pxtorem可以实现移动端适配,原理就是修改根节点的字体大小。对应的入口index.html的 meta 标签设置viewport参考

<meta 
  name="viewport" 
  content="
    width=device-width,  // 设置viewport的宽等于屏幕宽
    initial-scale=1.0,  // 初始缩放为1
    maximum-scale=1.0, 
    user-scalable=no,  // 不允许用户手动缩放
    viewport-fit=cover // 缩放以填充满屏幕
    " 
>

viewport-fit=cover: 可实现网页内容完全覆盖可视窗口。
env:向 CSS 插入用户代理定义的变量设定安全区域与边界的距离,有四个预定义的变量:

  • safe-area-inset-left:安全区域距离左边边界距离
  • safe-area-inset-right:安全区域距离右边边界距离
  • safe-area-inset-top:安全区域距离顶部边界距离
  • safe-area-inset-bottom:安全区域距离底部边界距离
    padding-bottom: env(safe-area-inset-bottom);//不被小黑条遮挡的安全距离

3.5 移动端1px兼容

1px像素在iPhone视网膜屏上显示不出来,在安卓可以正常显示,这是由于移动设备屏幕的像素密度越来越高,同样大小的屏幕有了更多的物理像素点。原来的1px像素对应了2个或3个物理像素参考

  • 使用伪元素 + CSS3缩放的方式
  • 使用动态 viewport + rem 布局 的方式

3.6 uglifyjs-webpack-plugin

压缩JS代码,可以配置打包时清除console、debugger。

3.7 webpack-bundle-analyzer

查看打包文件的大小,进而进行相应的体积优化。

3.8 url-loader

可以设置一个limit值,小于该值的资源可被压缩为base64编码格式,可以减少一次网络请求,提升加载速度,但是可能会导致文件变大,是一种以空间换时间的办法。

3.9 Tree Shaking

移除 JavaScript 上下文中的未引用代码 。参考

3.10 cdn加载资源

首开时需要加载很多的js和css文件,加速首开可以通过配置webpack的externals将引用的外部js、css文件剥离开来,生成公共资源包。以cdn的形式加载。如果cdn加载缓慢可以参考

3.11 模块懒加载 待补充

如果不进行模块懒加载的话,最后整个项目代码都会被打包到一个js文件里,单个js文件体积非常大,那么当用户网页请求的时候,首屏加载时间会比较长,使用模块懒加载之后,大js文件会分成多个小js文件,网页加载时会按需加载,大大提升首屏加载速度。

import login from '../views/login/login.vue'
const routes = [
  {
    path: '/login',
    name: 'login',
    component: login
  },
  {
    path: '/home',
    name: 'home',
    // 懒加载
    component: () => import('../views/home/home.vue'),
  },
]

3.12 合理配置hash

如果使用了hash,并不是每次都会重新生成新的hash,需要看具体使用的哪种hash策略。

  • hash:粒度整个项目
  • chunkhash:粒度每个模块
  • contenthash:粒度每个文件的内容

改过的文件需要更新hash值,而没改过的文件依然保持原本的hash值,这样才能保证在上线后,浏览器访问时没有改变的文件会命中缓存,从而达到性能优化的目的。参考

  output: {
    path: path.resolve(__dirname, '../dist'),
    filename: 'chunk-[contenthash].js',
    clean: true,
  },

3.13 图片懒加载

待补充

3.14 工程多入口分包

待补充

3.15 ES Modules

前端模块化。待补充

参考文章1
参考文章2
参考文章3
参考文章4
参考文章5

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值