前端工程化——Livereload和HMR、本地开发服务器

目录

本地开发服务器解决的问题

动态构建

Mock服务

动态构建

源码改动之后,浏览器应该在何时获取重新编译后的资源?

Livereload和HMR


有了构建系统的支持,前端开发人员可以使用诸多有利于开发和维护的技术进行源代码编写。然而如果在开发过程中源码的每次修改都需要执行一次构建才可以在浏览器中调试,这显然非常影响工作效率。要解决这个问题,可以将本地开发服务器与构建系统结合,对源码进行监听并在其修改之后触发动态构建,以自动的方式取代人工。此外,构建系统将源码转化为生产环境可用的文件,主要解决了开发层面的问题。Web开发过程中除开发层面的问题以外,协作同样是影响工作效率的重要因素,最典型的是前端逻辑依赖服务器端异步接口完成情况的串行工作流程。本地开发服务器的另一个主要功能是提供Mock服务以实现前后端并行开发。

本地开发服务器解决的问题

动态构建和Mock服务是本地开发服务器的主要功能。动态构建解决的问题是面向开发层面的,通过监听→修改→触发→构建的流程避免了源码的每次修改都需要人为地执行一次构建,便于开发过程中的即时调试。Mock服务解决的问题是面向前后端协作层面的,以提前约定好的规范为前提,通过本地服务容器提供的Mock数据接口辅助前端逻辑的编写。此外,如果项目需要SSR(服务器端渲染),本地开发服务器还需要具备解析HTML模板的功能,同时Mock服务提供SSR所需的初始数据。

动态构建

动态构建存在的必要性是为了方便前端工程师在开发期间进行即时的调试。我们不妨设想一下没有动态构建场景下的开发流程。

【1】前端工程师编写了一段源码之后,手动执行构建产出目标文件,然后在浏览器中查看效果。

【2】目标文件在浏览器中运行时发现某个CSS属性存在问题。

【3】工程师在浏览器调试面板中修正了问题,然后将修正后的代码写入源代码中,执行构建后再次打开浏览器查看效果。

【4】然而此次构建后的目标文件仍然存在问题,工程师不得不重复着调试→修改源码→手动构建→调试的工作。

前端开发过程中需要非常频繁的调试,尤其是CSS效果的实现,每次修改源码后手动执行构建势必会拖慢工作效率。动态构建的作用是通过自动构建取代人工,减少前端工程师开发之外的精力消耗。如果把构建比喻为将宿主环境不识别的源码加工成可运行代码的加工机器,那么动态构建就是连接源码与加工机器的管道。这条管道有两个功能模块:监听和触发。管道开启期间,源码的任何修改行为都会被监听模块侦测到,然后触发模块唤起构建这台加工机器对改动后的源码进行加工。

Mock服务

动态构建为前端工程师单方面开发提供了便利,Mock服务针对的是前后端开发人员协作过程中,部分前端逻辑开发必须以服务器端数据接口完成为前提,造成整体团队开发周期翻倍的问题。前端工程师使用本地服务器提供的Mock数据接口,在服务器端开发的同时进行前端逻辑的并行开发,待服务器端接口开发完成之后将接口的请求地址从Mock服务迁移至服务器端环境即可。Mock服务能够发挥作用的必要前提是前后端开发人员在正式进入开发之前协商好数据接口的规范,这不仅仅是技术层面的问题。前面章节我们也提到过,前端工程体系不仅仅需要技术的支持,同样也包括人员沟通上的规范。

如果你的项目不是完全前后端分离的,则仍然需要依赖服务器端渲染HTML,并且本地开发服务器使用与服务器端同样的编程语言,那么Mock服务还需要具备SSR功能,包括以下两点。【1】支持与服务器端相同的HTML模板引擎。【2】SSR所需的Mock数据。

综上所述,Mock服务等同于正式服务器的一个替代品,但是仅具备前端所需的基本功能(异步接口和SSR),与前端逻辑无关的功能(比如数据库操作、缓存层、Session管理等)不在Mock服务的范畴内。与构建系统相比,本地开发服务器要解决的问题非常明确。

动态构建

动态构建,或者叫作动态编译(Dynamic compilation),最早来源于Self语言,使用此技术最广为人知的是Java。前端工程体系中所谓的动态编译与Java中的同名概念并不相同,应用于Java的动态编译最普遍的是即时编译(JIT),将部分代码的编译行为推迟到运行时执行,目的是为了提高性能。而我们在此讨论的动态编译并没有那么复杂,按前文所述,本地开发服务器动态编译功能的目的是为了节省人力、方便前端开发和调试,本质原理是监听+触发。webpack-dev-server是官方提供的用于搭建本地开发环境的一个微型Node.js服务框架,并且提供动态编译、HMR(热更新)等功能。如果你的项目不需要Mock服务,webpack-dev-server完全可以满足需求。但是Mock服务是本地开发服务器不可或缺甚至可以说是最重要的功能,不能舍弃。幸运的是,webpack同时提供了webpack-dev-middleware,它是Express框架的一个中间件,结合一些必要的功能模块可以实现动态编译以及热更新等功能。

源码改动之后,浏览器应该在何时获取重新编译后的资源?

这似乎是一个显而易见的问题,你可能会不假思索地回答:当然是在重新编译行为完成之后。那么我们如何知道重新编译何时完成呢?难道一直盯着命令行窗口直到获得输出编译完成的日志吗?前端工程体系的原则之一是能够自动化的工作就不要消耗人力,这种人工“盯梢”的方式显然违背了这条原则。在webpack发布之前,业界大多数工具对此问题的解决方案是:在动态编译完成之后立即触发浏览器自动刷新,从而让浏览器及时获取重新编译之后的资源,这种方案被称为Livereload。webpack使用了一种效率更高且更利于调试的解决方案:Hot Module Replacement,简称HMR。接下来,我们一起探讨Livereload和HMR的区别以及如何在本地开发服务器中综合HMR和Livereload以保证浏览器即时获取动态编译资源。

Livereload和HMR

Livereload

Livereload的原理是在浏览器和服务器(本地开发服务器)之间创建WebSocket连接,服务器端在执行完动态编译之后发送reload事件至浏览器,浏览器接收到此事件之后刷新整个页面,流程如图所示。

Livereload虽然能够保证动态构建的资源被浏览器即时获取,但是它有一个致命的缺陷:无法保存页面状态。举个例子,调试是编写CSS最重要的一个环节,因为CSS没有逻辑性可言,即使是专家级的CSS开发者也不能保证不经调试编写的CSS在浏览器中得到预期的效果。所以几乎所有的CSS编写工作都是先通过浏览器调试面板查看效果,然后将代码写入源文件中的。此外,复杂的CSS效果可能并不是一个HTML元素便可以实现的,往往是需要多个元素配合的综合方案。那么请设想下面这样的场景。

【1】通过浏览器调试面板实现一个复杂的CSS效果,涉及的HTML元素个数为5个。

【2】在将CSS代码写入源文件的过程中,在写入第4个元素的CSS代码之后不小心保存了源文件,或者干脆就遗漏了一个元素的代码。

【3】源文件修改保存之后立即触发了动态构建,构建完成之后触发Livereload。

【4】页面刷新之后由于源文件中缺少了一个元素的CSS代码,导致UI乱作一团。

之所以出现上述场景的原因有两个,一是因为浏览器调试面板中的代码是临时性的,页面刷新之后便被清空;二是由于开发人员的马虎大意。你可能会说人为的失误完全可以避免,然而在实际开发中,这种“低级错误”反而是严重影响工作效率的因素之一。之所以建立前端工程体系的原因之一,便是在开发阶段允许一定的容错空间,在产出阶段对质量严格把控。所以,我们在搭建工程体系各个功能模块期间不能因为人为失误是技术层面外的因素而忽略了它对工程效率的影响。

即便不考虑人为失误,Livereload对于一些需要复杂的操作流程才可展示的组件同样有影响。比如一个弹窗组件需要操作三四步才会展示,浏览器刷新之后必须重复完整的操作流程才可以看到修改后的效果。HMR以局部更新取代整体页面刷新,有效地弥补了Livereload无法保存页面状态的缺陷。

HMR

HMR工作流程在开启webpack-dev-server模式下,webpack向构建输出的文件中注入了一项额外的功能模块——HMR Runtime。同时在服务器端也注入了对应的服务模块——HMR Server。两者是客户端与服务器端的关系,与Livereload的实现方式类似的是,两者之间也是通过WebSocket进行通信的。HMR热更新的流程如图所示。

【1】修改源文件并保存后,webpack监听到Filesystem Event事件并触发了重新构建行为。

【2】构建完成之后,webpack将模块变动信息传递给HMR Server。

【3】HMR Server通过WebSocket发送Push信息告知HMR Runtime需要更新客户端模块,HMR Runtime随后通过HTTP获取待更新模块的内容详情。

【4】最终,HMR Runtime将更新的模块进行替换,在此过程中浏览器不会进行刷新

以上流程虽然看上去非常清晰明了,但其中有许多技术细节值得品味,比如HMR Server以何种形式的文件将信息传递给Runtime, Runtime又是如何替换模块内容并且立即生效等。其中涉及webpack内部细节以及浏览器原理的部分知识,可以自行查阅相关资料

Express集成HMR功能
webpack-hot-middleware是可实现HMR的中间件,用于Express服务器端集成,集成方式很简单,只需在webpack-dev-middleware之后接入HMR中间件即可。

猜你喜欢

转载自blog.csdn.net/Octopus21/article/details/127828648