前端为什么要工程化
前端为什么要工程化
文章目录
- 前端为什么要工程化
- 传统开发的弊端
- 一个常见的案例
- 更多问题
- 工程化带来的优势
- 开发层面的优势
- 团队协作的优势
- 统一的项目结构
- 统一的代码风格
- 可复用的模块和组件
- 代码健壮性有保障
- 团队开发效率高
- 求职竞争上的优势
现在前端的工作与以前的前端开发已经完全不同了。
刚接触前端的时候,做一个页面,是先创建 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 里的 foo 是 1 , 1 + 2 等于 3 ) 。
原因是 JavaScript 的加载顺序是从上到下,当使用 var 声明变量时,如果命名有重复,那么后加载的变量会覆盖掉先加载的变量。
这是使用 var 声明的情况,它允许使用相同的名称来重复声明,那么换成 let 或者 const 呢?
虽然不会出现重复声明的情况,但同样会收到一段报错:
bash
Uncaught SyntaxError: Identifier 'foo' has already been declared (at lib-2.js:1:1)
这次程序直接崩溃了,因为 let 和 const 无法重复声明,从而抛出这个错误,程序依然无法正确运行。
更多问题
以上只是一个最简单的案例,就暴露出了传统开发很大的弊端,然而并不止于此,实际上,存在了诸如以下这些的问题:
- 如本案例,可能存在同名的变量声明,引起变量冲突
- 引入多个资源文件时,比如有多个 JS 文件,在其中一个 JS 文件里面使用了在别处声明的变量,无法快速找到是在哪里声明的,大型项目难以维护
- 类似第 1 、 2 点提到的问题无法轻松预先感知,很依赖开发人员人工定位原因
- 大部分代码缺乏分割,比如一个工具函数库,很多时候需要整包引入到 HTML 里,文件很大,然而实际上只需要用到其中一两个方法
- 由第 4 点大文件延伸出的问题,
script的加载从上到下,容易阻塞页面渲染 - 不同页面的资源引用都需要手动管理,容易造成依赖混乱,难以维护
- 如果要压缩 CSS 、混淆 JS 代码,也是要人力操作使用工具去一个个处理后替换,容易出错
当然,实际上还会有更多的问题会遇到。
工程化带来的优势
为了解决传统开发的弊端,前端也开始引入工程化开发的概念,借助工具来解决人工层面的烦琐事情。
开发层面的优势
在 传统开发的弊端 里,主要列举的是开发层面的问题,工程化首要解决的当然也是在开发层面遇到的问题。
在开发层面,前端工程化有以下这些好处:
- 引入了模块化和包的概念,作用域隔离,解决了代码冲突的问题
- 按需导出和导入机制,让编码过程更容易定位问题
- 自动化的代码检测流程,有问题的代码在开发过程中就可以被发现
- 编译打包机制可以让使用开发效率更高的编码方式,比如 Vue 组件、 CSS 的各种预处理器
- 引入了代码兼容处理的方案( e.g. Babel ),可以让自由使用更先进的 JavaScript 语句,而无需顾忌浏览器兼容性,因为最终会帮转换为浏览器兼容的实现版本
- 引入了 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"><!-- 这个循环模板有很多属性 --><divclass="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 开发… 这些技能都属于前端工程化开发的知识范畴,不仅在面试的时候会提问,入职后新人接触的项目通常也是直接指派前端工程化项目,如果能够提前掌握相关的知识点,对求职也是非常有帮助的!
相关文章:
前端为什么要工程化
前端为什么要工程化 文章目录 前端为什么要工程化传统开发的弊端一个常见的案例更多问题 工程化带来的优势开发层面的优势团队协作的优势统一的项目结构统一的代码风格可复用的模块和组件代码健壮性有保障团队开发效率高 求职竞争上的优势 现在前端的工作与以前的前端开发已经完…...
软件测试/测试开发/人工智能丨视觉与图像识别自动化测试
视觉与图像识别在软件自动化测试领域中的应用是越来越重要的一项技术,它使得测试可以更全面、准确地模拟用户对图形用户界面(GUI)的交互。以下是视觉与图像识别在软件自动化测试中的主要应用: 1. 自动化 GUI 测试 视觉与图像识别…...
nvm的下载与使用
1.如果已经安装nodejs , 先卸载nodejs; 从控制面板中 卸载程序 卸载nodejs win r打开cmd ,管理员运行 where node 查看是否删除干净nodejs 2.下载nvm 从github 下载nvm , 下载nvm 3.nvm 和node安装路径最好写在同一个路径下 ,如D盘 ,D\a\nvm , D\a\nodejs 4.…...
拼多多官方开放平台接口app商品详情接口获取实时商品详情数据演示
拼多多开放平台提供了一种名为“商品详情接口”的API接口,它允许卖家从自己的系统中快速获取商品信息,如商品标题、描述、价格、库存等,并将这些信息展示在自己的店铺中。通过该接口,卖家可以更好地管理自己的商品库存和销售&…...
STM32F4系列单片机GPIO概述和寄存器分析
第2章 STM32-GPIO口 2.1 GPIO口概述 通用输入/输出口 2.1.1 GPIO口作用 GPIO是单片机与外界进行数据交流的窗口。 2.1.2 STM32的GPIO口 在51单片机中,IO口,以数字进行分组(P0~P3),每一组里面又有8个IO口。 在ST…...
【LeetCode刷题】--9.回文数
9.回文数 class Solution {public boolean isPalindrome(int x) {if(x < 0){return false;}int tmp x, sum 0;boolean flag false;while(x ! 0){sum sum * 10 x % 10;x / 10;}if(sum tmp){flag true;}return flag;} }...
大数据-之LibrA数据库系统告警处理(ALM-12057 元数据未配置周期备份到第三方服务器的任务)
告警解释 系统安装完成后会检查元数据是否有周期备份到第三方服务器的任务,然后每1小时会检查一次。如果元数据未配置周期备份到第三方服务器的任务,将发送严重告警。 在用户创建元数据周期备份到第三方服务器的任务后,告警消除。 告警属性…...
毅速丨嫁接打印在模具制造中应用广泛
在模具行业中,3D打印随形水路已经被广泛认可,它可以提高冷却效率,从而提高产品良率。然而,全打印模具制造的成本相对较高,因为需要使用金属3D打印机和专用材料。为了节省打印成本,同时利用3D打印的优势&…...
『亚马逊云科技产品测评』活动征文|基于next.js搭建一个企业官网
『亚马逊云科技产品测评』活动征文|基于next.js搭建一个企业官网 授权声明:本篇文章授权活动官方亚马逊云科技文章转发、改写权,包括不限于在 Developer Centre, 知乎,自媒体平台,第三方开发者媒体等亚马逊云科技官方…...
C# Winform围棋棋盘
C# Winform简单的围棋棋盘vs2008winform小游戏C#vs2010winform棋盘C#窗体小游戏 这是一个简单的围棋棋盘小游戏,使用C# Winform编写棋盘界面,玩家可以在空白的交叉点上下棋子 项目获取: 项目获取:typora: typora/img (gitee.co…...
vue使用本地图片设置为默认图
一、引用 import imgSrc /assets/common/image/xxx.png 二、赋值给变量 defaultImg:imgSrc, 三、将变量给img标签 <img :src"defaultImg:imgSrc" alt"icon"> 注意:这里直接使用路径给变量是无法实现的哟...
day17-高速缓冲区的管理机制
1.目的 用户与磁盘进行文件交互时的流程 磁盘与高速缓冲区的关系 加深块设备驱动的理解 hash 循环链表 单链表的使用方法 2.高速缓冲区的工作流程 高速缓冲区中存储这对应的块设备驱动的数据 当从块设备中读取数据的时候,OS首先会从高速缓冲区中进行检索࿰…...
文心一言 VS 讯飞星火 VS chatgpt (139)-- 算法导论11.4 3题
三、用go语言,考虑一个采用均匀散列的开放寻址散列表。当装载因子为 3/4 和 7/8 时,试分别给出一次不成功查找和一次成功查找的探查期望数上界。 文心一言: 在开放寻址法中,当散列表的装载因子超过其阈值时,会触发重…...
Java 解压文件
maven库: <!--FileUtil、ZipUtil 依赖--> <dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.3.1</version> </dependency><!--IOUtils 依赖--> <depen…...
SASS/SCSS精华干货教程
目录 介绍 基本说明 特点 sass语法格式sass的语法格式一共有两种,一种是以".scss"作为拓展名,一种是以".sass"作为拓展名,这里我们只讲拓展名: 编译环境安装 Vscode安装编译插件 简单使用 sass语法扩张…...
8.jib-maven-plugin构建springboot项目镜像,docker部署配置
目录 1.构建、推送镜像 1.1 执行脚本 2.2 pom.xml配置 2.部署镜像服务 2.1 执行脚本 2.2 compose文件 3.docker stack常用命令 介绍:使用goole jib插件构建镜像,docker stack启动部署服务; 通过执行两个脚本既可以实现构建镜像、部…...
海康威视综合安防管理平台任意文件上传
系统介绍 HIKVISION iSecure Center综合安防管理平台是一套“集成化”、“智能化”的平台,通过接入视频监控、一卡通、停车场、报警检测等系统的设备,获取边缘节点数据,实现安防信息化集成与联动,公众号:web安全工具库…...
Linux环境下C++ 接入OpenSSL
接上一篇:Windows环境下C 安装OpenSSL库 源码编译及使用(VS2019)_vs2019安装openssl_肥宝Fable的博客-CSDN博客 解决完本地windows环境,想赶紧在外网环境看看是否也正常。毕竟现在只是HelloWorld级别的,等东西多了&am…...
美国网站服务器SSL证书介绍
美国网站服务器的SSL证书也是一种数字证书,由权威数字证书机构CA验证网站的身份后所颁发,可实现浏览器与网站主机之间的数据传输加密。美国网站服务器搭建的网站在安装SSL证书后会在浏览器显示安全锁标志,数据传输协议则从HTTP传统协议升级为…...
JSP命令标签 静态包含/动态包含
好 下面我们聊聊JSP中的指令标签 这边 我们来说两个 分别是 静态包含 和 动态包含 我们可以将重用性代码包含起来 更好的使用 比如 我们界面上中下 分别有三个导航栏 那么 如果你写三份 就会出现很多重复代码 而且 改起来 也很不方便 要一次改三份 口说无凭 我们来做一个小案…...
python打卡day49
知识点回顾: 通道注意力模块复习空间注意力模块CBAM的定义 作业:尝试对今天的模型检查参数数目,并用tensorboard查看训练过程 import torch import torch.nn as nn# 定义通道注意力 class ChannelAttention(nn.Module):def __init__(self,…...
SpringBoot+uniapp 的 Champion 俱乐部微信小程序设计与实现,论文初版实现
摘要 本论文旨在设计并实现基于 SpringBoot 和 uniapp 的 Champion 俱乐部微信小程序,以满足俱乐部线上活动推广、会员管理、社交互动等需求。通过 SpringBoot 搭建后端服务,提供稳定高效的数据处理与业务逻辑支持;利用 uniapp 实现跨平台前…...
基于Docker Compose部署Java微服务项目
一. 创建根项目 根项目(父项目)主要用于依赖管理 一些需要注意的点: 打包方式需要为 pom<modules>里需要注册子模块不要引入maven的打包插件,否则打包时会出问题 <?xml version"1.0" encoding"UTF-8…...
【论文阅读28】-CNN-BiLSTM-Attention-(2024)
本文把滑坡位移序列拆开、筛优质因子,再用 CNN-BiLSTM-Attention 来动态预测每个子序列,最后重构出总位移,预测效果超越传统模型。 文章目录 1 引言2 方法2.1 位移时间序列加性模型2.2 变分模态分解 (VMD) 具体步骤2.3.1 样本熵(S…...
k8s从入门到放弃之HPA控制器
k8s从入门到放弃之HPA控制器 Kubernetes中的Horizontal Pod Autoscaler (HPA)控制器是一种用于自动扩展部署、副本集或复制控制器中Pod数量的机制。它可以根据观察到的CPU利用率(或其他自定义指标)来调整这些对象的规模,从而帮助应用程序在负…...
ThreadLocal 源码
ThreadLocal 源码 此类提供线程局部变量。这些变量不同于它们的普通对应物,因为每个访问一个线程局部变量的线程(通过其 get 或 set 方法)都有自己独立初始化的变量副本。ThreadLocal 实例通常是类中的私有静态字段,这些类希望将…...
接口 RESTful 中的超媒体:REST 架构的灵魂驱动
在 RESTful 架构中,** 超媒体(Hypermedia)** 是一个核心概念,它体现了 REST 的 “表述性状态转移(Representational State Transfer)” 的本质,也是区分 “真 RESTful API” 与 “伪 RESTful AP…...
PostgreSQL 与 SQL 基础:为 Fast API 打下数据基础
在构建任何动态、数据驱动的Web API时,一个稳定高效的数据存储方案是不可或缺的。对于使用Python FastAPI的开发者来说,深入理解关系型数据库的工作原理、掌握SQL这门与数据库“对话”的语言,以及学会如何在Python中操作数据库,是…...
C#调用Rust动态链接库DLL的案例
C#调用Rust动态链接库DLL的案例 项目概述 这是一个演示C#调用Rust动态链接库DLL的项目,包含: C#主程序 (Program.cs)Rust动态链接库 (rust_to_csharp目录) 使用C#创建一个net9的控制台项目,不使用顶级语句 dotnet new console --framewo…...
C++.OpenGL (4/64)纹理(Texture)
纹理(Texture) 纹理映射核心流程 #mermaid-svg-XxVbt4fizulzb5H3 {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-XxVbt4fizulzb5H3 .error-icon{fill:#552222;}#mermaid-svg-XxVbt4fizulzb5H3 .error-text{fill:…...
