前端交接文档_前端工程化实践

本文回顾了前端技术的发展,从JSP时代的前后端不分离,到Ajax的出现推动了jQuery等框架的兴起,再到移动端发展催生了Bootstrap和新一代前端三大框架React、Vue和Angular。文章重点介绍了前端工程化实践,包括命名规范、代码检测、分支管理和组件化,旨在提升代码质量和开发效率。
摘要由CSDN通过智能技术生成

大家好又见面了cba5129327fbf43e947df40e18007919.png,过去几个月我们探讨了JAVA的方方面面,今天我们终于把目光转向了前端,带来前端技术的第一篇文章,讨论前端开发的工程化问题c9bde46726e3b515c1db7e0987b71e88.png

前言 前端的发展虽说历史不如后端时间更长,但也经历了很多年一代代程序员的努力。预计当前入行的很多小伙伴并不了解前端技术是如何发展到今天的,我们先来通俗的讲一下历史。

1 从前后不分离时期,后端MVC的V层,到画页面,切图仔

我们绝大多数程序员可能认为,BS架构的网站起始于JSP。这种观点某种意义上没有太大问题。但是网页开发与前端技术的发起,要远远早于这个时期。Macromedia,估计没有多少人听过这个公司,但当时的“网页三剑客”可是顶顶大名。

dfdbf7bb02103a1d3797baa77c4b8fc5.png

特别幸运的是我在97年,十几岁的时候就已经接触到了电脑,也开心了买了一本在家里那台586上捣鼓过。Dreamweaver,Fireworks,Flash三剑客陪伴了我很长时间,当时甚至能在电脑上写出网页来掉起本地应用程序。可惜后来Macromedia公司兵败如山倒,2005年被Adobe公司收购,一代传奇惨淡收场。这三剑客现在网上依旧能查到,不过都变成了Adobe家的宝宝。这段时间属于静态独霸天下的太古时代。

接下来的故事大家应该都听过,程序猿们不满足与静态页面提供的简单逻辑,开始要求在页面端开发动态代码,于是JAVA强势介入,JSP横空出世。那时候,我们的程序猿大虾们是不分前后端开发的,好像几乎人人都是全栈工程师。页面怎么写?JSP就完事了。JSP在2000年后的第一个十年非常流行,还经历了1.2,2.0多个版本,也衍生出SimpleTag,FreeMarker等技术。但总的来说这段时期属于前后不分离的远古时代。

随着技术的更迭,业务场景的增加,前后端不分离的软件开发模式慢慢演变成界限清晰,分工精细的前后分离模式。这时的前端岗输出的工作,更多的是为后台MVC架构层面的View层,以html和css为主,不涉及业务逻辑。“切图仔”,“画页面的”也就成了当时前端的称呼代号。

以下代码是典型的示例:

首页    险种信息页

2 Ajax来了

Ajax 即“Asynchronous Javascript And XML”(异步 JavaScript 和 XML),是指一种创建交互式网页应用的网页开发技术。
  • Ajax = 异步 JavaScript 和 XML 或者是 HTML(标准通用标记语言的子集)。
  • Ajax 是一种用于创建快速动态网页的技术。
  • Ajax 是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术。
不得不说,确实是Ajax改变了B/S开发的格局。在Ajax出现后,前端才渐渐成为了一个独立的工种。
function ajax(url,fn){                //创建xhr对象                var xhr = new XMLHttpRequest()                //设置发送的服务器地址和方法                xhr.open("GET",url)                //发送                xhr.send()                  //xhr状态改变的事件进行监听                xhr.onreadystatechange = function(){                    console.log("readyState:"+xhr.readyState)                    console.log("status"+xhr.status)                    if(xhr.readyState==4&&xhr.status==200){                        fn(xhr)                    }                }            }

上面的代码不清楚是否还有小伙伴记得cba5129327fbf43e947df40e18007919.png,估计这老古董大家都没看过了。其实就是js原生,没用任何框架写的Ajax原生代码。重点就是:

  1. 建立xmlHttpRequest对象

  2. 设置回调函数

  3. 使用OPEN方法与服务器建立连接

  4. 向服务器端发送数据

  5. 在回调函数中针对不同的响应状态进行处理

这5个步骤。那么Ajax最关键的作用,是让页面有了部分刷新的功能,避免了每次后台请求都需要刷新页面的差体验,同时也让前端页面能够通过js构写复杂的页面数据逻辑。

随着Ajax技术的越来越普及,很多基于这项技术为核心功能的前端js框架也纷纷出世。这些框架基本上实际上是分为两个大类:

  • 功能强大,从界面到功能具有完整解决方案的大型框架,典型例子:早期的Ext JS,现在的Sencha
  • 体积很小,但适用性很强的轻量级框架,典型例子:jquery

当然现在看来,jquery的统治力要远远高于其他的框架,统治了前端领域好多年。当然在这个过程中也出现了adobe flex的搅局,微软microsoft silverLight的试水,但最终软件开发的领域,个人的理解还是免费大于收费,开源大于产品。直到移动化浪潮的来临,jquery对于移动端支持和移动端体验的保障慢慢出现了疲态,虽然也推出了jquerymobile,但对响应式布局的支持确实不够看。于是后来又有了Bootstrap等新生的支持两端的框架,但真正的新变化,还是来自移动端的发展。

3 前端三大框架与node的出现 时间推进到2015年以后,移动开发已慢慢变为整个互联网开发的核心,随着整体开发工作领域的细分,前端的工作也越来越重要。

新一代的前端三大框架听说过吗?什么,没有?那你就out了b14b3e0c1f43782dd32847399a138101.png

当前,三大主流前端框架分别是React、Vue、Angular这三个框架。
  • React起源于Facebook的内部项目,用来架设Instagram的网站,于2013年5月开源。
  • Vue是尤雨溪编写的一个构建数据驱动的Web界面的库,准确来说不是一个框架,它聚焦在V(view)视图层。
  • Angular是一款优秀的前端JS框架,google出品。已经被用于Google的多款产品当中。
那么为啥我们原先已经有了jquery,为啥还要新框架?

36ff28c20c6b29e44e8577d80d6a8ac0.png

d5954d3c902f19370b64c67a7618a38b.png

根本的原因可以说就是以上两个图,我们前端的开发思路从上图的MVC模式,转化为了下图的MVVM模式。 何为MVVM模式?MVVM最早由微软提出来,它借鉴了桌面应用程序的MVC思想,在前端页面中,把Model用纯JavaScript对象表示,View负责显示,两者做到了最大限度的分离。也就是我们常说的,前后分离,真正在这里得以实现。所以前后分离,先做到的其实是前端的自我分离。 有神马不一样? 它采用双向绑定(data-binding):View的变动,自动反映在ViewModel,反之亦然,model数据的变动,也自动展示给页面显示。把Model和View关联起来的就是ViewModel。ViewModel负责把Model的数据同步到View显示出来,还负责把View的修改同步回Model。 而我们上文提到的三大前端框架则均为MVVM的落地。新入坑的前端同学们可要好好的掌握这些框架哦a416f555505bb3d1eadc910c7ca2a149.png。 最后说说我觉得走的最远的,还是非node.js莫属了。node是第一个将js的手伸到服务器端的框架。 Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境。Node.js 使用了一个事件驱动、非阻塞式 I/O 的模型,使其轻量又高效。  Node.js能让一个前端工程师变成全栈工程师cc763cb1a20db30762f54bc9f1f0f90f.png。 我们会在后续章节里介绍node的其他细节。规范

说完前端发展简史,下面我们开始我们的重点内容,前端工程化实践。

工欲善其事必先利其器,coding 未起,规范先行。

1. 样式还原 页面的还原,尤其是在移动端上,不同屏幕尺寸下,如何做适配,我们的原则是,基准机型下100%还原,其他机型做相对比例适配(pc 端,基于设计稿px 值对应还原)。 有些同学,被问及移动端如何适配,大多能答上来用rem, 再细问的话,就说不出一二,这里就解释下,rem 是html 根目录字体大小, 例html标签的字体大小为100px,则1rem==100px, 当前页面下所有涉及到rem 的长度,都是这个关系,说回适配,通过获取屏幕的宽度,然后按比例动态设定html 的 font-size, 此时的rem 即是适配的, 对应的样式也就适配了,代码如下:
/** * rem 动态设置函数 * @param {*} pxToRem 设置px转换rem 比例,默认100 * @param {*} baseWidth 设置基准设计稿宽, 默认750px 基准机型iPhone6/7/8 * @returns */function htmlSizeCalculation(pxToRem, baseWidth) {  pxToRem = pxToRem || 100;  baseWidth = baseWidth || 750;  // 获取根节点元素  var docEl = document.documentElement;  // 屏幕变化监听event  var resizeEvt = 'orientationchange' in window ? 'orientationchange' : 'resize';  // 核心方法,计算关系,并赋值根节点font size  var recalc = function () {      // 获取当前设备屏幕宽      var clientWidth = docEl.clientWidth;      if (!clientWidth) return;      // 根据当前设备屏幕宽,计算相应的根节点字体大小      docEl.style.fontSize = pxToRem * (clientWidth / baseWidth) + 'px';    };  recalc();  if (!document.addEventListener) return;  // 屏幕变化,重新计算  window.addEventListener(resizeEvt, recalc, false);  // 文档加载后,执行计算  document.addEventListener('DOMContentLoaded', recalc, false);}

2. 内容逻辑还原

严格按照需求文档,做逻辑还原。按需求行事,本来讲没什么需要强调的,但工作中发现,有些伙伴喜欢自己加成,自行添加页面上的文字话术,更有甚交付的成品与最终的需求南辕北辙,这些问题到测试环节,都会按bug处理。当然,也有可能是需求文档本身的纰漏,如有发现,需及时与需求人员沟通调整。

以上,不管是样式层面还是逻辑层面,我们坚持的原则一言以蔽之,尊重上游环节和专业人员的工作。

3. 命名规范

讲求见名知意,通常约定英文语义化命名,多单词可用中横线、小驼峰、大驼峰等格式,这个可以根据团队习惯,统一约定。语义化命名,对代码可读性的保障,笔者发现工作中,有小伙伴命名变量,百思不得意,有甚至反意命名,混淆逻辑,造成后期难以维护、项目交接困难等一系列问题。

例:

样式 中横线 some-name

变量/方法 小驼峰someName

图片名 下划线 some_name.png

常量 全大写下划线  SOME_NAME

组件名  大驼峰 SomeName

4. 代码检测

代码检测,通过一定的工具对项目代码做书写规范、冗余等方面检测,提示开发者对应代码行位置存在的 error、warning,以便修正;检测的目的是,一方面规范化的代码对其他开发者友好的可读性、可维护性,二是可以加强代码质量、规避潜在风险;工具有多种,比较常用的eslint,我们一般选用其standard规范,并稍加修改,团队也可以根据内部习惯,选择合适的工具。各家IDE也有一些相关格式化的工具,方便开发者做代码书写规范的格式化 。如有团队人员对此意识不足,可以使用git hook 进行提交分支时代码检测,有任何error则阻塞提交。

eslint可以在package.json、 .eslintrc 和 webpack中进行配置,具体可参考官网https://eslint.org/docs/developer-guide/nodejs-api#cliengine,以下是eslint 在webpack.config.js中的配置示例。

{        test: /\.js$/,        exclude: /node_modules/,        loader: 'eslint-loader',        options: {          // community formatter          formatter: require('eslint-friendly-formatter'),          // This option will enable ESLint autofix feature.          fix: true,          // This option will enable caching of the linting results into a file.          cache: true,        },      },

5. 分支规范

约定分支的意义,是保证关键节点的快速相应,生产的稳定性,开发的灵活性;我们选用git做版本控制,在分支规范上,master 稳定生产版本,develop 为主开发分支,feature/xxxx 功能模块的分支,hotfix紧急修复分支。

master分支,是从其他分支合并,存放的是供生产部署的稳定代码,每次合并是一次版本更迭,可打标签tag。

develop分支存放开发的阶段性成果,从fetaure分支合并,是可以提供测试部署的代码,做人工测试部署,或执行自动化测试的代码源。

feature分支,是做具体功能块开发的分支,项目开发常用敏捷开发,敏捷开发中的用户故事,拆分成多个1-2天的功能模块,分配到开发者,开发者可在本地基于develop建立对用模块分支feature/xxxx,本地开发完成后,并入develop,并入后该特性分支可删除 。

hotfix分支,是针对生产版遇到异常或严重问题必须及时修复的场景,此时要基于master分支,建立hotfix/xxxx 分支,用作修正生产bug,而不影响develop分支其他迭代开发工作,修复后的hotfix分支,验证无误则及时合并至master并tag,及时发版,同时合并至develop,保证后续迭代的正常开发,并入后该hotfix 分支可删除。

模块化 模块化是将大体量功能块拆分至小的可维护单元块,以便分治和复用,是大型复杂应用快速开发和维护的必要基础。
  • css 模块化
css预处理的变量机制、嵌套关系等语法促进了css样式的书写清晰及便利,为样式模块化提供了基础,加之像webpack配置css-loader来统一加hash 属性,利用属性选择器的特性,避免样式的全局污染,实现其模块化,而对共有样式、属性值,则提取至global模块,其他相应模块引入使用,global模块在主题切换上有很高效的体现。 
// webpack.config.js{  test: /\.css$/,  use: [    {      loader: 'css-loader',      options: {        modules: true,        localIdentName: '[path][name]__[local]--[hash:base64:5]'      }    }  ]}
市面上优秀的css预处理有less、sass、stylus等,各有优缺,选择一个适合团队的即可。
  • js 模块化

js  模块化,目前常用的是commonjs 规范和es6 的modules, nodejs在commonjs范式基础上制定的模块API,用于node 包的管理,例 modules.export = somePackage / require('somePackage');es6是ECMA2015版本规定的module机制, 通过 export / import 导出引入模块。 node模块
// log.jsmodule.exports = function (mes) {  console.log(mes)}// print.jsconst log = require('./log.js')log('hello world')
node 模块按出处分为两大类,一类是内置模块,一类是自定义模块。 内置模块是node API中涉及的模块,由官方提供,如文件系统fs、协议http/https、路径path等。 自定义模块,非官方出品,来自社区或私有自研自用,通常开源的模块都会发布到npm上,开发者可以通过npm install,下载安装(npm install xxxx)。 node 模块按功能分为两大类,一类是开发依赖模块,一类是线上生产依赖模块。 开发依赖模块是开发过程中使用到的,增加开发效率和友好性为主(如代码改动实时更新到页面的热加载模块、dev运行时shell输出文字美化的chalk模块等),通过install时加参数 --save-dev, 备录在package.json 的devdependencies下;生产依赖,为线上运行时,所依赖的模块(如日期格式化模块、px2rem转换模块等),同样install时加参数--save,备录在package.json的dependencies下。 通过 require引入模块有一定机制,如果是直接名字,例 require('path'),则首先看是是否在cash中缓存过,即缓存优先级最高(require入参不一样,但索引的资源是同一个,则视为同一个入缓存),没有则判断是不是内置模块,没有的话则去项目node_modules文件夹下查找;如果是路径索引,绝对路径"/"、或相对路径"./""../",例 require('./a');则按路径位置查找对应模块,如果文件没有指定格式,nodejs会试图加载a.js、a.json,a.node,如果以上都不存在,则按照a文件夹依次索引其下的package.json(main字段配置的文件)、index.js、index.json、index.node。 es6模块
// 2. es6 module// log.jsexport default function (mes) {  console.log(mes)}// print.jsimport print from './log.js'print('hello world')
export语法规定是对外的出口,必须跟内部变量建立一一对应的关系。如果模块出口只有一个,可以用export default来导出一个没有名字的变量, export 也可以暴露多个出口,但不可以出现在块级作用域内,否则会出错。
// export.js// 报错export 9// 报错var num = 9export num// 正例一export var num = 9//正例二var age = 15export { age }//正例三 通过as关键词 重命名对外出口var color = 'red'export {color as pigment }// 正例四 default export default function sayHello () {  console.log('hello')}
import引入包,语法合export,可以全包引入,可以部分引入,对default 形式的可自定义名引入,import后的from指定文件位置,用法类似require,示例代码如下:
// import.js// 引入的对象可以结构, 对应变量为import 里定义的变量名// from的文件格式后缀可省了import { num } from './export.js' // 重命名引入import { age as year } from './export.js'// 整体引入import * as obj from './export.js' // default 引入import anyName from './export.js'
js 模块化,不管是公共方法还是业务逻辑都分治处理,为便利开发和后期维护,同时也很好的解决了全局变量污染、混乱开发的局面,对大型工程项目开发来讲,尤为重要。组件化

对一个应用来讲,单样式和js模块化,还是不够,需要按照UI用户交互层面进行细颗粒度的组件划分抽离,讲一个页面中不同块分治为不同的组件,其应包含该组件的样式和逻辑数据层块。组件相对独立,组件与组件可自由组合,页面是组件的容器,在不同的业务需求下,快速响应组合。理论上分块后的组件间无时间顺序的依赖,可保证开发的同步进行,在分工中无障碍伸缩,提高生产力。

组件统一放在components下,如下图,每一个组件的样式、标签内容、逻辑归类一起,高内聚,功能明确,目录清晰,使得构建可靠的组件,自然也就可复用。

a49c9e4071d86c21b826010f07c20306.png

header.html
header
 

header.css

.header{    background: black,    color: red}
header.js
const title = document.querySelector('.title')title.innerHTML = 'newTitle'

开发中一般不会直接上述原生方式写组件,以目前框架为主的开发方式下,各家框架都有很好配合工程化组件的实现。比如vue 的组件,一个文件构建组件,template标签内dom节点,script里放置js 数据和逻辑,style里样式,通过props定义组件被父级调用时的属性,通过emit实现组件向父级传递数据。

title组件vue示例:

  
{{title}} {{color}}
export default { data() { title: 'title' }, props: { color: { default: 'red', type: String } }} .header{ background: #f0f }

市面上,各大厂商基于主流框架开源了不少的优秀UI组件库,如基于vue的element-ui、muse-ui等, 基于react 的ant-design 、material-ui等,详细文档可去相应官网查看。

编译构建

前端工程化,围绕在如何提高开发效率,而最终的发布,则依赖于宿主环境浏览器,当下的主流浏览器,可支持的html5、css3、es5,少数es6语法支持,那上述所提及的 css预处理器、原生es6+、js框架、模块机制等需要进行一步编译构建工作,将开发者友好的语言转译成浏览器可识别的资源,目前市面上用的最多的是 webpack。

1cfc38694851b0e0fe91ff47eca42eaa.png

本质上,webpack 是一个现代 JavaScript 应用程序的静态模块打包器(module bundler)。当 webpack 处理应用程序时,它会递归地构建一个依赖关系图(dependency graph),其中包含应用程序需要的每个模块,然后将所有这些模块打包成一个或多个 bundlehttps://www.webpackjs.com/concepts/

从webpackv4.0.0 的开始,可以无配置化编译打包,默认的入口文件是src/index.js,打包后的文件为dist/main.js。当然webpack依然可高度配置。

webpack有四个核心配置项,entry、output、loader、plugin,webpack就如上图中的box, 通过入口entry 文件,输入资源,box 通过loader 和 plugin,然后output出资源。入口出口比较容易理解,下面说下loader和plugin。

loader是用来处理各种类型资源转化成webpack可理解的模块,loader配置中有两个要点,test 和 use。test 正则匹配文件类型,use 配置所要用到的对应loader。当链式调用多个 loader 的时候,请记住它们会以相反的顺序执行。取决于数组写法格式,从右向左或者从下向上执行。

// webpack.config.jsconst path = require('path');const config = {  entry: 'index.js',  output: {    filename: 'bundle.js'  },  module: {    rules: [      { test: /\.less$/, use: ['style-loader', 'css-loader', 'less-loader'] }          ]  }};module.exports = config;

这里就是告诉webpack在遇到require()/import 对应.less文件类型的资源时,先使用less-loader将less文件转换成css文件,css-loader去解析css文件,遇到"@import"、"url()"这类语句就将相应的样式资源引入,最后由style-loader生成一个包含最终解析完的css代码的style标签,并追加到head标签里。

loader处理特定文件的转换,而plugin则可以处理更广泛的任务,如打包优化、代码压缩、自动插入打包好的js到模板html、环境变量定义等。插件的用法,通过require过来,实例化放入plugins数组中。

const HtmlWebpackPlugin = require('html-webpack-plugin'); // 通过 npm 安装const config = {  plugins: [    new HtmlWebpackPlugin({template: './src/index.html'})  ]};module.exports = config;
webpack 配置中使用插件是简单直接的,多数可以通过文档介绍直接配置使用。自动化再谈提高效率,编译之后我们有了浏览器可识别的代码,那后续工作是否可以缩短到用户的距离,答案是肯定的,如切换测试生产环境、测试、部署等环节,以自动化为方向,在越来越多的项目中,解放人力。  切换环境通过npm run build 指令,先set env后build,代码中通过env走分流逻辑处理不同环境下的代码走向。
// 命令行cross-env NODE_ENV=production webpack --config build/webpack.config.js// 逻辑代码块const  env = process.env.envif (env === 'production') {  // doSomething in production} else {  // doSomething in test}

环境变量设置,因为操作系统不通过而设置上有差异,此处推荐使用cross-env, 免除不同操作系统下来回切换命令的烦恼。

测试

常用的单元测试和验收测试。单元测试是直接测试代码单元,可以一个模块或函数,常用工具mocha。验收测试是用脚本控制浏览器来触发web程序的功能,来测试界面和功能是否完好。目前公司内部测试团队已经开始着手这方面的工作。 部署    生产服务器,如果多台,手工上传代码,将是一件低效且容易出错的;重复性的事情交给机器,自动化部署,可使用Jenkins,它 是开源CI&CD软件领导者, 提供超过1000个插件来支持构建、部署、自动化, 满足任何项目的需要。总结:稳定高效的交付产品,是前端工程化的意义所在,前端发展这么多年,从最初的原始蛮荒,一步一步走到现在高度工具化产线链,不断创新,来满足日益增长的移动化应用场景和多维度客户更高的体验诉求。

A B O U T   I N S T R U C T O R

讲 师 速 递

袁森,泰康集团数据信息中心移动互联部前端高级工程师,在前端领域浸润多年。基础扎实,无论在H5,CSS,JS三大框架,或微信小程序weex,还是node等领域均有深入研究。更关键的是小伙人很帅cee70c6962f1b48f82df5f6a1696e44b.png

cab980f340a7bcaea664b8c9276b17f2.png

deb7c1d545c26993b9701bc4a6f83777.png

d09ef58d0636ea51b3fc55d813cc7949.png

科技鱼系列

第一期 编码有故事

第二期 计算精度与Java编译问题探究

第三期 流量防卫兵Sentinel

第四期 科普区块链

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值