前端发展浅谈
让我们回忆一下前端系列的文章:
- Vue 学习笔记(一) 初遇
- Node.js 教程(一) 基本概念与基本使用
- Vue学习笔记(二) 相识篇
- Vue学习笔记(三) 甚欢篇
- JavaScript学习笔记(一) promise和async/wait
- CSS学习笔记(一) 盒子模型
Node.js 让JavaScript代码可以在浏览器之外的地方运行,同时引入了模块化,提升了JavaScript的复用能力。而Vue则为我们带来的是快速构建大型Web系统的能力:
- 响应式:Vue会自动化跟踪JavaScript状态并在其发生变化时响应式地更新DOM
- 声明式渲染: Vue基于标准HTML拓展了一套模板语法,使我们可以声明式地描述最终输出的HTML和JavaScript之间的关系。
- 组件化: 提升的是Web工程的复用能力, 将JavaScript、CSS、HTML封装在一起,按需引入。
那开发Web应用,我们可以将Node.js和Vue.js结合在一起,将Vue.js当做依赖引入, 同时也享受npm带来的便利。那最终的产物呢,我们可以类比服务端应用程序Java,Java最终交付的是一个jar或war,这个jar或者war被JVM或者Servelt容器(Tomcat)所解析,对外提供服务。那Node.js和Vue.js结合之后呢,最终交付的应该是什么呢?对于Java的服务端应用程序来说,一般用Spring Boot来搭建,对于Spring Boot程序搭建的Web应用都会有一个入口。那对于对于Web前端呢,是否也需要一个入口呢? 我们当前掌握的有:
- Vue.js (基本特性的使用)
- Node.js (会用npm、简单的启动一个web服务器)
- 基本的JavaScript、HTML、CSS
- Sass: CSS的扩展语言
我没学系统的学习前端的时候觉得这些就足够了,但我忽略的一点就是我是在以服务端的程序在看前端,所以会存在一些盲点。用Java写服务端应用程序的时候,开发的JDK版本和生产的版本是一致的,也就是说你用JDK 8开发的代码,实际应用的JDK版本也只会是JDK 8,不会是JDK 7,JDK 8的部分代码在JDK 7上可能是运行不了的。如果你用了JDK 8的新特性,仅仅是语法层面的,比如Lambda,但是你又想这套代码在JDK 7上运行,那其实可以用retrolambda来进行转换。那如果我用JDK 8 添加的新类库呢? 比如Stream,这个JDK 8才引入的类,那其实可以试着用streamSupport以及ThreeThen来进行转换。如果你只用了JDK 7的语法特性和库,那在编译的时候可以加上-source 1.7 -target来指定编译到JDK 7版本的class文件。如果不这么做可能就会出现下面的异常:
java.lang.UnsupportedClassVersionError
那我们用JavaScript、CSS、HTML构建的页面呢? 这些是被浏览器所解析的,这就意味着我们无法确定用户浏览器的版本,也就是说高版本的JavaScript特性可能在用户浏览器上市无法被支持的,但高版本的JavaScript特性又实在好用,总不能在开发的时候,低版本的写一套,高版本的写一套吧。有没有像Java那样的转换工具,将高版本的代码等价转换成效果一样的低版本代码呢? 当然是有的,这也就是Babel,那什么是Babel:
Babel是一个工具链,主要用于将采用ECMAScript 2015+语法编写的代码转换为向后兼容的JavaScript语法,以便能够运行在当前和旧版本的浏览器或其他环境中。
- 语法转换
- 通过Polyfill(我个人倾向于将其翻译为适配)方式在目标环境中添加缺失的特性(通过引入第三方polyfill模块,例如core-js)
- 源码转换
下面是babel的语法转换示例:
// Babel 输入: ES2015 箭头函数
[1, 2, 3].map(n => n + 1);
// Babel 输出: ES5 语法实现的同等功能
[1, 2, 3].map(function(n) {
return n + 1;
});
我们不打算在这一篇完全介绍babel,我们本篇的主题是前端工程化。让我们回到最终的问题,Web前端页面最终应该交付成一个什么样的形式? 我们在回顾一下前后端不分离的时代,即前端代码都在一个项目下的场景,这样项目在如今已经不多见了,但是我想这样的项目会让我们有所启发。一般用maven构建的项目,会有一个resources文件夹,这个文件夹我们用来放配置文件,在这个文件夹下面我们一般有两个文件夹: static、templates:
templates 放html,static放css、js。一般templates里面会直接放一个index.html,这也是首页,进入首页之后来跳对应的页面。那我最后用Vue.js、Node.js、CSS、Sass、Babel开发的浏览器页面也被做成这样的形式呢? 即js 文件夹里放js文件,css文件夹放css文件,图片放在jpg文件夹,字体放在font文件夹呢。这也就是webpack做的工作,下面这张图来自webpack官网:
Webpack将我们构建前端页面所用的各种文件按类别放入对应的文件夹,所以Webpack也被称为打包工具,本质上webpack是一个用于现代JavaScript应用程序的静态打包工具,当webpack处理应用程序时,它会在内部从一个或多个入口点构建一个依赖图,然后将你项目所需的每个模块组合成一个或多个bundles,它们均为静态资源,用于展示你的内容。
bundle的对应的中文为: 捆, (一)包,(一)扎,一批(同类事物或出售的货品);风趣的人; 笑料;一大笔钱。
下面是表达这个词的图片:
那该怎么理解这个bundle, 或者什么是module bundle?
## module bundling 简介
什么是模块捆绑? 宏观上说,模块捆绑只是将一组模块(及其依赖项)以正确的顺序拼接成一个文件(或一组文件)的过程。在JavaScript中,一个模块就是一个文件。一个脚本就是一个模块。模块之间可以相互加载,并可以使用特殊的指令export和import来交换功能,从另一个模块调用一个模块的函数。
那为什么需要合并模块(bundle module)呢? 原因在于我们将程序划分为模块时,通常会将这些模块组织到不同的文件和文件夹中,一般情况下,还会引入其他库的模块,比如Underscore.js或React。
因此页面需要的模块都必须包含在主html文件的script标签中,然后在用户访问您的主页时由浏览器加载,一个文件一个script标签意味着浏览器必须一个一个的加载文件,一个一个的加载也就意味着会花一定的时间,一个加载就对应一个HTTP请求,
为了解决这个问题,我们将所有的文件捆绑或链接成一个 大文件(或几个文件,视情况而定)以减少请求数量。另一种加速的方式是减小代码体积,从源代码中删除不必要的字符, 例如空格、注释、换行符等。
由于JavaScript的原生模块化来的比较晚,JavaScript社区有几种不同的模块系统,如果你现在使用的是非原生模块系统,如CommonJS或者AMD,则需要使用专门的工具将这些模块转换为对浏览器来说更加友好的代码,这也就是Browserify、RequireJS、WebPack等其他打包工具发挥作用的地方。除了合并模块之外,模块打包工具还提供了其他大量附加功能,例如在更改代码的时候自动重新编译代码。
前端工程化
说了这么多,前端工程化在哪里呢? 或者我们换种方式来理解前端工程化,前端工程化是一个组合词,前端 + 工程化,那什么是工程化? 或者让我们回顾下软件工程的发展简史:
1970年代和1980年代的软件危机。在那个时代,许多软件最后都得到了一个悲惨的结局,软件项目开发时间大大超出了规划的时间表。一些项目导致了财产的流失,甚至某些软件导致了人员伤亡。同时软件开发人员也发现软体开发的难度越来越大。在软件工程界被大量引用的案例是Therac-25的意外:在1985年六月到1987年一月之间,六个已知的医疗事故来自于Therac-25错误地超过剂量,导致患者死亡或严重辐射灼伤。
鉴于软件开发时所遭遇困境,北大西洋公约组织在1968年举办了首次软件工程学术会议,并于会中提出"软件工程"来界定软件开发所需相关知识,并建议"软件开发应该是类似工程的活动"。软件工程自1968年正式提出至今,这段时间累积了大量的研究成功,广泛地进行大量的技术实践,借由学术界和产业界的共同努力,软件工程正逐渐发展成为一门专业学科。
关于软件工程的定义,在GB/T11457-2006《消息技术 软件工程术语》中将其定义为"应用计算机科学理论和技术以及工程管理原则和方法,按预算和进度,实现满足用户要求的软件产品的定义、开发、和维护的工程或进行研究的学科"。
Therac-25: 是加拿大原子能有限公司(AECL) 在 Therac-6 和 Therac-20 装置之后于 1982 年生产的一种计算机控制的放射治疗机。它有时会给患者带来比正常情况高数百倍的辐射剂量,导致死亡或重伤
软件的复杂让项目时间超出了规划时间,导致了一定程度的财产损失,软件在变得复杂的过程中,出现了质量的不可控,造成了人员的伤亡。由此引出了软件工程,软件工程的目标就在于进度与质量的把控。而对于软件开发难度越来越大,也是软件工程需要解决的问题,这对应代码的复用,版本管理,开发协作。这也就是软件工程化。我想前端工程化也是因为出现了类似这样的问题,才会引入工程化的方法来去解决对应的问题, 对于页面变的不断复杂的情况下,加快开发进度同时保证质量,这是前端工程和软件工程共同追求的,那如何加快开发进度呢? 那就是引入工具,自动化,将一些重复的需求变成工具,减少对于程序员的依赖,这也就是打包工具出现的原因,像webpack、Babel。另一种加快开发进度的原因就是增强代码的可复用性,这也就是模块化,将功能封装进模块,不需要在重复开发。以此来实现质量和进度的把控,无论前端怎么边,或者需求怎么变,工程化追求的始终就是速度与质量,而开发速度则让我想到了工具,越是大型的项目工具就越多,会有更多的标准流程。所以随着软件的发展,应当会有越来越多工具进入软件开发,需求也会倾向于被拆分,便于分工。
写在最后
老实说本文最初的思路是从软件工程的定义引出打包工具这些,但关于工程化来说这方面并没有明确的定义,所以没有办法想做数学证明一样,给定某些条件证明某个结论的正确性。后面觉得工程化更像是代码量变多之后的一个自然选择,即实现自动化、避免做重复操作、可复用性高,质量好、进度快。为了实现这些前端引入了各种各样的工具和概念。关于模块合并的部分主要参考自: 《JavaScript Modules: A beginner’s guide》。最后放的有链接,非常值得一看。
参考资料
- 什么是前端工程化?https://juejin.cn/post/691744...
- 使用JDK7编写的代码:是否可以用JDK8编译,用JRE7来运行呢? https://www.zhihu.com/questio...
- 我对前端工程化的理解 https://juejin.cn/post/684490...
- Babel 是什么? https://www.babeljs.cn/docs/
- JavaScript Modules: A beginner’s guide https://www.preethikasireddy....
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。