前端为什么要工程化

前端为什么要工程化

文章目录

  • 前端为什么要工程化
    • 传统开发的弊端
      • 一个常见的案例
      • 更多问题
    • 工程化带来的优势
      • 开发层面的优势
      • 团队协作的优势
        • 统一的项目结构
        • 统一的代码风格
        • 可复用的模块和组件
        • 代码健壮性有保障
        • 团队开发效率高
      • 求职竞争上的优势

现在前端的工作与以前的前端开发已经完全不同了。

刚接触前端的时候,做一个页面,是先创建 HTML 页面文件写页面结构,再在里面写 CSS 代码美化页面,再根据需要写一些 JavaScript 代码增加交互功能,需要几个页面就创建几个页面,相信大家的前端起步都是从这个模式开始的。

而实际上的前端开发工作,早已进入了前端工程化开发的时代,已经充满了各种现代化框架、预处理器、代码编译…

最终的产物也不再单纯是多个 HTML 页面,经常能看到 SPA / SSR / SSG 等词汇的身影。

传统开发的弊端

在了解什么是前端工程化之前,先回顾一下传统开发存在的一些弊端,这样更能知道为什么需要它。

在传统的前端开发模式下,前端工程师大部分只需要单纯的写写页面,都是在 HTML 文件里直接编写代码,所需要的 JavaScript 代码是通过 script 标签以内联或者文件引用的形式放到 HTML 代码里的,当然 CSS 代码也是一样的处理方式。

例如这样:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <!-- 引入 JS 文件 -->
    <script src="./js/lib-1.js"></script>
    <script src="./js/lib-2.js"></script>
    <!-- 引入 JS 文件 -->
  </body>
</html>

如演示代码,虽然可以把代码分成多个文件来维护,这样可以有效降低代码维护成本,但在实际开发过程中,还是会存在代码运行时的一些问题。

一个常见的案例

继续用上面的演示代码,来看一个最简单的一个例子。

先在 lib-1.js 文件里,声明一个变量:

js

var foo = 1

再在 lib-2.js 文件里,也声明一个变量(没错,也是 foo ):

js

var foo = 2

然后在 HTML 代码里追加一个 script ,打印这个值:

html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>

  <!-- 引入 JS 文件 -->
  <script src="./js/lib-1.js"></script>
  <script src="./js/lib-2.js"></script>
  <!-- 引入 JS 文件 -->

  <!-- 假设这里是实际的业务代码 -->
  <script>
    console.log(foo)
  </script>
  <!-- 假设这里是实际的业务代码 -->

</body>
</html>

先猜猜会输出什么? —— 答案是 2

如果在开发的过程中,不知道在 lib-2.js 文件里也声明了一个 foo 变量,一旦在后面的代码里预期了 foo + 2 === 3 ,那么这样就得不到想要的结果(因为 lib-1.js 里的 foo11 + 2 等于 3 ) 。

原因是 JavaScript 的加载顺序是从上到下,当使用 var 声明变量时,如果命名有重复,那么后加载的变量会覆盖掉先加载的变量。

这是使用 var 声明的情况,它允许使用相同的名称来重复声明,那么换成 let 或者 const 呢?

虽然不会出现重复声明的情况,但同样会收到一段报错:

bash

Uncaught SyntaxError: Identifier 'foo' has already been declared (at lib-2.js:1:1)

这次程序直接崩溃了,因为 letconst 无法重复声明,从而抛出这个错误,程序依然无法正确运行。

更多问题

以上只是一个最简单的案例,就暴露出了传统开发很大的弊端,然而并不止于此,实际上,存在了诸如以下这些的问题:

  1. 如本案例,可能存在同名的变量声明,引起变量冲突
  2. 引入多个资源文件时,比如有多个 JS 文件,在其中一个 JS 文件里面使用了在别处声明的变量,无法快速找到是在哪里声明的,大型项目难以维护
  3. 类似第 1 、 2 点提到的问题无法轻松预先感知,很依赖开发人员人工定位原因
  4. 大部分代码缺乏分割,比如一个工具函数库,很多时候需要整包引入到 HTML 里,文件很大,然而实际上只需要用到其中一两个方法
  5. 由第 4 点大文件延伸出的问题, script 的加载从上到下,容易阻塞页面渲染
  6. 不同页面的资源引用都需要手动管理,容易造成依赖混乱,难以维护
  7. 如果要压缩 CSS 、混淆 JS 代码,也是要人力操作使用工具去一个个处理后替换,容易出错

当然,实际上还会有更多的问题会遇到。

工程化带来的优势

为了解决传统开发的弊端,前端也开始引入工程化开发的概念,借助工具来解决人工层面的烦琐事情。

开发层面的优势

在 传统开发的弊端 里,主要列举的是开发层面的问题,工程化首要解决的当然也是在开发层面遇到的问题。

在开发层面,前端工程化有以下这些好处:

  1. 引入了模块化和包的概念,作用域隔离,解决了代码冲突的问题
  2. 按需导出和导入机制,让编码过程更容易定位问题
  3. 自动化的代码检测流程,有问题的代码在开发过程中就可以被发现
  4. 编译打包机制可以让使用开发效率更高的编码方式,比如 Vue 组件、 CSS 的各种预处理器
  5. 引入了代码兼容处理的方案( e.g. Babel ),可以让自由使用更先进的 JavaScript 语句,而无需顾忌浏览器兼容性,因为最终会帮转换为浏览器兼容的实现版本
  6. 引入了 Tree Shaking 机制,清理没有用到的代码,减少项目构建后的体积

还有非常多的体验提升,列举不完。而对应的工具,根据用途也会有非常多的选择,在后面的学习过程中,会一步一步体验到工程化带来的好处。

团队协作的优势

除了对开发者有更好的开发体验和效率提升,对于团队协作,前端工程化也带来了更多的便利,例如下面这些场景:

统一的项目结构

以前的项目结构比较看写代码的人的喜好,虽然一般在研发部门里都有 “团队规范” 这种东西,但靠自觉性去配合的事情,还是比较难做到统一,特别是项目很赶的时候。

工程化后的项目结构非常清晰和统一,以 Vue 项目来说,通过脚手架创建一个新项目之后,它除了提供能直接运行 Hello World 的基础代码之外,还具备了如下的统一目录结构:

  • src 是源码目录
  • src/main.ts 是入口文件
  • src/views 是路由组件目录
  • src/components 是子组件目录
  • src/router 是路由目录

虽然也可以自行调整成别的结构,但根据笔者在多年的工作实际接触下来,以及从很多开源项目的代码里看到的,都是沿用脚手架创建的项目结构(不同脚手架创建的结构会有所不同,但基于同一技术栈的项目基本上都具备相同的结构)。

统一的代码风格

不管是接手其他人的代码或者是修改自己不同时期的代码,可能都会遇到这样的情况,例如一个模板语句,上面包含了很多属性,有的人喜欢写成一行,属性多了维护起来很麻烦,需要花费较多时间辨认:

vue

<template>
  <div class="list">
    <!-- 这个循环模板有很多属性 -->
    <div class="item" :class="{ `top-${index + 1}`: index < 3 }" v-for="(item, index)
    in list" :key="item.id" @click="handleClick(item.id)">
      <span>{{ item.text }}</span>
    </div>
    <!-- 这个循环模板有很多属性 -->
  </div>
</template>

而工程化配合统一的代码格式化规范,可以让不同人维护的代码,最终提交到 Git 上的时候,风格都保持一致,并且类似这种很多属性的地方,都会自动帮格式化为一个属性一行,维护起来就很方便:

vue

<template>
  <div class="list">
    <!-- 这个循环模板有很多属性 -->
    <div
      class="item"
      :class="{ `top-${index + 1}`: index < 3 }"
      v-for="(item, index) in list"
      :key="item.id"
      @click="handleClick(item.id)"
    >
      <span>{{ item.text }}</span>
    </div>
    <!-- 这个循环模板有很多属性 -->
  </div>
</template>

同样的,写 JavaScript 时也会有诸如字符串用双引号还是单引号,缩进是 Tab 还是空格,如果用空格到底是要 4 个空格还是 2 个空格等一堆 “没有什么实际意义” 、但是不统一的话协作起来又很难受的问题……

在工程化项目这些问题都可以交给程序去处理,在书写代码的时候,开发者可以先按照自己的习惯书写,然后再执行命令进行格式化,或者是在提交代码的时候配合 Git Hooks 自动格式化,都可以做到统一风格。

可复用的模块和组件

传统项目比较容易被复用的只有 JavaScript 代码和 CSS 代码,会抽离公共函数文件上传到 CDN ,然后在 HTML 页面里引入这些远程资源, HTML 代码部分通常只有由 JS 创建的比较小段的 DOM 结构。

并且通过 CDN 引入的资源,很多时候都是完整引入,可能有时候只需要用到里面的一两个功能,却要把很大的完整文件都引用进来。

这种情况下,在前端工程化里,就可以抽离成一个开箱即用的 npm 组件包,并且很多包都提供了模块化导出,配合构建工具的 Tree Shaking ,可以抽离用到的代码,没有用到的其他功能都会被抛弃,不会一起发布到生产环境。

TIP

在 依赖包和插件 一节可以学习如何查找和使用开箱即用的 npm 包。

代码健壮性有保障

传统的开发模式里,只能够写 JavaScript ,而在工程项目里,可以在开发环境编写带有类型系统的 TypeScript ,然后再编译为浏览器能认识的 JavaScript 。

在开发过程中,编译器会检查代码是否有问题,比如在 TypeScript 里声明了一个布尔值的变量,然后不小心将它赋值为数值:

ts

// 声明一个布尔值变量
let bool: boolean = true

// 在 TypeScript ,不允许随意改变类型,这里会报错
bool = 3

编译器检测到这个行为的时候就会抛出错误:

bash

# ...
return new TSError(diagnosticText, diagnosticCodes);
           ^
TSError: ⨯ Unable to compile TypeScript:
src/index.ts:2:1 - error TS2322: Type 'number' is not assignable to type 'boolean'.

2 bool = 3
  ~~~~
# ...

从而得以及时发现问题并修复,减少线上事故的发生。

团队开发效率高

在前后端合作环节,可以提前 Mock 接口与后端工程师同步开发,如果遇到跨域等安全限制,也可以进行本地代理,不受跨域困扰。

前端工程在开发过程中,还有很多可以交给程序处理的环节,像前面提到的代码格式化、代码检查,还有在部署上线的时候也可以配合 CI/CD 完成自动化流水线,不像以前改个字都要找服务端工程师去更新,可以把非常多的人力操作剥离出来交给程序。

求职竞争上的优势

近几年前端开发领域的相关岗位,都会在招聘详情里出现类似的描述:

熟悉 Vue / React 等主流框架,对前端组件化和模块化有深入的理解和实践
熟悉面向组件的开发模式,熟悉 Webpack / Vite 等构建工具
熟练掌握微信小程序开发,熟悉 Taro 框架或 uni-app 框架优先
熟悉 Scss / Less / Stylus 等预处理器的使用
熟练掌握 TypeScript 者优先
有良好的代码风格,结构设计与程序架构者优先
了解或熟悉后端开发者优先(如 Java / Go / Node.js )

知名企业对 1-3 年工作经验的初中级工程师,更是明确要求具备前端工程化开发的能力:

在这里插入图片描述

知名企业对 1-3 年经验的前端工程师招聘要求

组件化开发、模块化开发、 Webpack / Vite 构建工具、 Node.js 开发… 这些技能都属于前端工程化开发的知识范畴,不仅在面试的时候会提问,入职后新人接触的项目通常也是直接指派前端工程化项目,如果能够提前掌握相关的知识点,对求职也是非常有帮助的!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/163944.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【计算机毕业设计】Springboot 社区助老志愿服务系统-96682, 免费送源码,【开题选题+程序定制+论文书写+答辩ppt书写-原创定制程序】

Springboot 社区助老志愿服务系统 摘要 大数据时代下&#xff0c;数据呈爆炸式地增长。为了迎合信息化时代的潮流和信息化安全的要求&#xff0c;利用互联网服务于其他行业&#xff0c;促进生产&#xff0c;已经是成为一种势不可挡的趋势。在图书馆管理的要求下&#xff0c;开发…

Vue3-readonly(深只读) 与 shallowReadonly(浅只读)

Vue3-readonly(深只读) 与 shallowReadonly&#xff08;浅只读&#xff09; readonly(深只读)&#xff1a;具有响应式对象中所有的属性&#xff0c;其所有值都是只读且不可修改的。shallowReadonly(浅只读)&#xff1a;具有响应式对象的第一层属性值是只读且不可修改的&#x…

数据库的三范式(Normalization)

数据库的三范式&#xff08;Normalization&#xff09;是关系数据库设计中的基本理论原则&#xff0c;旨在减少数据冗余和提高数据库的数据组织结构。三范式通过将数据分解为更小的表&#xff0c;并通过关系建立连接&#xff0c;使得数据库设计更加灵活、规范和容易维护。在这篇…

同花顺,通达信,东方财富股票竞价,早盘板块、概念、题材竞价数据接口

早盘板块、概念、题材竞价数据接口 量化接口地址&#xff1a;https://stockapi.com.cn 通过分析每天早盘的板块竞价&#xff0c;从而判断出今日主力资金的看好方向 地址&#xff1a; https://stockapi.com.cn/v1/base/bkjjzq?tradeDate2023-11-08再结合个股竞价数据筛选出自…

数据库索引详解

数据库索引是一种用于提高数据库查询性能的关键技术。索引是一种数据结构&#xff0c;可以加速数据库中数据的检索过程。在本文中&#xff0c;我们将详细讨论数据库索引的定义、类型、优缺点以及如何选择和优化索引。 1. 什么是数据库索引&#xff1f; 数据库索引是一种数据结…

Rocket如何实现顺序消费

RocketMQ 支持两种消息模式 集群消费&#xff08; Clustering &#xff09;和广播消费&#xff08; Broadcasting &#xff09;。 集群消费&#xff1a;同一 Topic 下的一条消息只会被同一消费组中的一个消费者消费。也就是说&#xff0c;消息被负载均衡到了同一个消费组的多…

Janus: 基于eBPF的5G实时AI控制器

O-RAN定义的RIC模型并不能很好支持对实时性有很高要求的用例&#xff0c;本文定义了一套基于eBPF的内联执行架构&#xff0c;从而可以将RIC的支持扩展到实时场景。原文: Taking 5G RAN Analytics and Control to a New Level[1] 摘要 Open RAN为5G无线接入网(RAN)引入了模块化和…

LangChain 代理 Agent(学习笔记)

原文&#xff1a;LangChain 代理 Agent(学习笔记) - 尘叶心繁的专栏 - TNBLOG LangChain 代理 Agent(学习笔记) LangChain 代理 Agent(学习笔记) 简介Agent Zero-shot ReActStructured Input ReActOpenAI FunctionsConversationalSelf ask with searchReAct document storePlan…

机器学习---初识贝叶斯分类器

1. 引入问题 有两个可选的假设&#xff1a;病人有癌症、病人无癌症&#xff0c;可用数据来自化验结果&#xff1a;正和负- 有先验知识&#xff1a;在所有人口中&#xff0c;患病率是0.008&#xff0c;对确实有病的患者的化验准确率为98%&#xff0c;对确实无 病的患者的化验…

记录一次较为完整的服务打包发布流程

文章目录 1. Spring Boot编程2. 打包成jar服务3. 使用Docker Compose发布服务 1. Spring Boot编程 使用Spring Initializr 选择基本工具 导入常用工具 配置多环境 参考https://blog.csdn.net/qq_37992410/article/details/121008415&#xff0c; https://blog.csdn.net/xiao…

Linux系统编程 day02 vim、gcc、库的制作与使用

Linux系统编程 day02 vim、gcc、库的制作与使用 01. vim0101. 命令模式下的操作0102. 切换到文本输入模式0103. 末行模式下的操作0104. vim的配置文件 02. gcc03. 库的制作与使用0301. 静态库的制作与使用0302. 动态库(共享库)的制作与使用 01. vim vim是一个编辑器&#xff0…

go-zero微服务的使用

一、入门案例 1、使用goland创建一个工程 2、新建一个user.proto syntax "proto3";package user; // 这个地方表示生成的go的包名叫user option go_package "./user";message UserInfoRequest {int64 userId 1; }message UserInfoResponse {int64 user…

300. 最长递增子序列

题目 题解 class Solution:def lengthOfLIS(self, nums: List[int]) -> int:# 定义状态dp [1 for i in range(len(nums))]# 状态转移for i in range(len(nums)):for j in range(i):if nums[i] > nums[j]:dp[i] max(dp[i], dp[j] 1)# 返回结果res 0for i in range(le…

如何查看 class 文件的编译器版本

文章目录 原理分析解决方案其它解决方案javap 命令行工具 在平时的 Java 开发中&#xff0c;有时候我们需要知道某个 class 文件是由哪个版本的 Java 编译器编译生成的 原理分析 class 文件&#xff0c;即字节码文件&#xff0c;它有特定的二进制格式&#xff0c;这种格式是由…

vulhub redis-4-unacc

环境搭建 cd vulhub/redis/4-unacc docker-compose up -d 漏洞复现 检测 redis-cli -h ip 使用redis工具 工具地址&#xff1a;https://github.com/vulhub/redis-rogue-getshell 下载完成后&#xff0c;先进入RedisModulesSDK/exp/ 目录进行make操作 获得exp.so后可以进行…

memcacheredis构建缓存服务器

一、缓存服务器&#xff1a; 1、简介&#xff1a; ① 许多Web应用都将数据保存到RDBMS中&#xff0c;应用服务器从中读取数据并在浏览器中显示。 但随着数据量的增大、访问的集中&#xff0c;就会出现RDBMS的负担加重、数据库响应恶化、 网站显示延迟等重大影响。 ● RDBMS&…

【Go学习之 go mod】gomod小白入门,在github上发布自己的项目(项目初始化、项目发布、项目版本升级等)

参考 Go语言基础之包 | 李文周的博客Go mod的使用、发布、升级 | weiGo Module如何发布v2及以上版本1.2.7. go mod命令 — 新溪-gordon V1.7.9 文档golang go 包管理工具 go mod的详细介绍-腾讯云开发者社区-腾讯云Go Mod 常见错误的原因 | walker的博客 项目案例 oceanweav…

LoRA低秩微调技术详解

在当今快节奏的技术环境中&#xff0c;大型AI模型正在推动不同领域的突破。 然而&#xff0c;根据特定任务或数据集定制这些模型可能是一项计算和资源密集型工作。 LoRA是一种突破性且高效的微调技术&#xff0c;它利用这些高级模型的强大功能来执行自定义任务和数据集&#xf…

注解【元数据,自定义注解等概念详解】(超简单的好吧)

注解的理解与使用 注解的释义元数据的含义基础阶段常见的注解注解的作用&#xff08;包括但不限于&#xff09;教你读懂注解内部代码内容五种元注解尝试解读简单注解我当时的疑惑点 自定义注解自定义注解举例 注解的原理总结 注解的释义 我们都知道注释是拿来给程序员看的&…

fopen/fwrite/fread 对UNICODE字符写入的总结

windows对fopen函数进行了升级&#xff0c;可以支持指定文件的编码格式&#xff08;ccs参数指定&#xff09;。 例如&#xff1a; FILE *fp fopen("newfile.txt", "rt, ccsUTF-8"); 当以 ccs 模式打开文件时&#xff0c;进行读写操作的数据应为 UTF-16…