前端工程化
为什么会出现前端工程化?
前端工程化的出现,究其根本,是前端项目复杂度的提升与开发环境与生产环境不一致的矛盾。
以往的前端项目,只需要编写少许的HTML,CSS,JS文件,随着应用的发展,项目的复杂度在迅速提升,一些古早的问题也开始浮现: 全局变量污染、依赖关系混乱、代码冗余造成了生产环境性能低下。
为此,前端工程化主要分三个大方向: 工程化、模块化、组件化。
组件化解决HTML、CSS、JS复用问题,减少代码冗余
模块化解决依赖关系混乱问题和全局变量污染
工程化解决开发环境与生产环境不一致问题,在开发环境,我们要求代码更加规范更加模块化,在书写前端项目的时候,可能会涉及到使用其他的语言,typescript、less/sass这涉及到编译,在部署的时候,还需要对代码进行丑化、压缩,分片等一些优化措施来提升生产环境的性能。
对前端工程化,模块化,组件化的理解?
这三者中,模块化是基础,没有模块化,就没有组件化和工程化
模块化的出现,解决了困扰前端的两大难题:全局污染问题和依赖混乱问题,从而让精细的拆分前端工程成为了可能。
工程化的出现,解决了前端开发环境和生产环境要求不一致的矛盾。在开发环境中,我们希望代码使用尽可能的细分,代码格式尽可能的统一和规范,而在生产环境中,我们希望代码尽可能的被压缩、混淆,尽可能的优化体积。工程化的出现,就是为了解决这一矛盾,它可以让我们舒服的在开发环境中书写代码,然后经过打包,生成最合适的生产环境代码,这样就解放了开发者的精力,让开发者把更多的注意力集中在开发环境上即可。
组件化开发是一些前端框架带来的概念,它把一个网页,划分为多个小的组件,组件是一个可以复用的单元,它包含了一个某个区域的完整功能。这样一来,前端便具备了开发复杂应用的能力。
为什么要打包呢?
为了解决前端项目复杂度的提升与开发环境与生产环境不一致的矛盾。在开发环境中,我们使用增强开发体验的编译工具和新的特性,例如TypeScript、less/sass/Tailwindcss、ES6等来提升我们开发环境的体验,但是这些工具在生产环境是不支持的,所以需要打包成浏览器可以识别的代码。
模块化有什么好处
高复用性
高维护性
按需加载
避免变量全局污染
对比ES6和CommonJS
- CMJ是社区标准,ES6是官方标准
CommonJS是社区模块化标准,node环境支持该标准。它不产生新的语法,是使用API实现的,本质是把要加载的模块放到一个闭包中执行。因此,node环境中的所有JS文件在执行的时候,都是放到一个函数环境中执行的,这对使得模块内部可以访问函数的参数,如exports、module、__dirname等,而且对this的指向也会有影响。 ESM是后来的官方标准,在各种环境都支持,它引入了新的书写语法import/export - CMJ是动态依赖,ES6同时支持静态和动态
ES Module是静态的模块化标准,在模块执行前,会递归确定所有依赖关系,然后加载所有文件,加载完成后再运行,这在浏览器环境下会产生多次请求。由于使用的是静态依赖,因此,它要求导入导出的代码必须放置到顶层,因为只有这样才能在代码运行前就确定依赖关系。ES也可以使用import()函数来实现动态加载 - CMJ 模块输出的是一个值的拷贝,ES6 模块输出的是值的引用
CommonJS 模块输出的是值的拷贝(浅拷贝),也就是说,一旦输出一个值,模块内部的变化就影响不到这个值。
ES6 模块中,JS 引擎对脚本静态分析,遇到模块加载命令import,就会生成一个只读引用。等到脚本真正执行时,再根据这个只读引用,到被加载的那个模块里面去取值。原始值变了,import加载的值也会跟着变。因此,ES6 模块是动态引用,并且不会缓存值,模块里面的变量绑定其所在的模块。由于是只读引用,导入变量也无法修改。
ES6 中如何实现模块化的异步加载?
使用import()动态导入即可,导入后,得到的是一个 Promise,完成后,得到一个模块对象,其中包含了所有的导出结果。
什么是 babel,有什么作用
babel 是一个 JS 编译器,主要用于将下一代的 JS 语言代码编译成兼容性更好的代码。 它其实本身做的事情并不多,它负责将 JS 代码编译成为 AST,然后依托其生态中的各种插件对 AST 中的语法和 API 进行处理