【自用】从模块化背起的前端工程化

博主有一天向ai问了一个神金的问题:是谁先发现代码需要打包的?^^ 博主没有经过知识污染的大脑就是这样的干净。作为学生,在自己做项目练手的时候,从来都是在开发环境下,很少有接触到生产环境。打包/构建/工程化/模块化/...,这种概念从来没有出现在博主的脑子里。然而八股文要考,于是博主只能硬着头皮理解了。

所以这是一个博主在阅读了部分八股文,拷打ai,加上个人理解之后的一篇关于前端工程化的自用总结文章。

一、模块化——代码组织的基本法

关于前端工程化,我想从模块化讲起。

1.1 早期方案

早期前端项目规模小,代码直接通过<script>标签引入浏览器。

<!-- 传统的开发方式 -->
<script src="jquery.js"></script>
<script src="utils.js"></script>
<script src="module1.js"></script>
<script src="module2.js"></script>
<script src="app.js"></script> 

但由于所有变量都在全局作用域,造成全局命名空间污染的问题。并且,脚本加载顺序必须手动管理,依赖关系十分混乱。早期通过IIFE(立即执行函数)、命名空间等手动隔离作用域。

慢慢地,社区提出一些模块化理念以及规范。

1.2 社区规范

CommonJS 规范:同步加载,Node.js的默认模块系统,不适合浏览器。使用`require()` 和 `module.exports`。

2010年 Node.js 开始使用 CommonJS。2011 年 Browserify 将 CommonJS 转换后可在浏览器使用;2012 年 webpack 出现。

// math.js
exports.add = function(a, b) {
  return a + b;
};

// app.js
const math = require('./math');
console.log(math.add(1, 2));

// 在浏览器中使用 require
const $ = require('jquery');
const utils = require('./utils'); 

AMD规范(Asynchronous Module Definition):异步加载,适合浏览器。

// 使用 RequireJS
define(['jquery', 'underscore'], function($, _) {
  return {
    init: function() {
      // 模块逻辑
    }
  };
});

1.3 标准统一

一直到2015年,官方正式规定了ES6模块标准化ESM。2017年,浏览器开始支持ESM。2020年,Node开始支持ESM。

// math.js
export const add = (a, b) => a + b;
export const subtract = (a, b) => a - b;
export default class Calculator {
  // ...
}

// app.js
import Calculator, { add, subtract } from './math.js';

二、包管理器——依赖管理自动化

刚刚说到模块化,包就是模块的进一步集合。模块化后,项目依赖大量第三方模块。而各类模版可能会迭代更新,如果手动下载、更新、管理,效率极低且容易出现版本冲突。

包管理器的核心价值就是通过自动化工具解决上述痛点,实现依赖的 “安装、更新、卸载、版本控制” 全流程自动化。

2.1 主要功能

  • 自动安装依赖:根据 package.json 中的依赖声明,一键下载所需模块及其子依赖,无需手动寻找资源地址。
  • 版本控制与冲突解决:通过语义化版本规则(SemVer)管理版本范围,自动处理依赖间的版本兼容问题。
  • 维护依赖树快照:生成 lock 文件(如 package-lock.json、yarn.lock),记录每个依赖的精确版本和依赖关系,确保不同环境安装的依赖完全一致。
  • 脚本执行:通过 package.json 的 scripts 字段定义快捷命令(如 npm run dev、yarn build),简化开发流程(如启动开发服务器、执行构建)。

2.2 主流包管理器对比

npm

yarn

pnpm

简介

最早的前端包管理器,随 Node.js 普及

解决了早期 npm 的性能和一致性问题

基于硬链接和符号链接

特点

嵌套树——>扁平树

扁平树

并行安装、全局缓存机制、依赖树预解析、原子安装

基于内容寻址的存储 + 硬链接/符号链接

优点

生态最成熟

兼容性强

无需额外安装

早期性能优于 npm

支持离线缓存

语法更简洁

速度极快

磁盘空间利用率高

对monorepo友好

缺点

安装速度较慢

磁盘空间利用率较低

需额外安装

性能被追赶

可能有兼容问题

概念学习成本较高

社区支持略差

lock 文件

package-lock.json

yarn.lock

pnpm-lock.yaml

适用场景

中小型项目、追求兼容性和生态稳定性的场景

习惯简洁语法、需要离线安装支持的团队

大型项目(如 monorepo 多包)

对安装速度和磁盘空间敏感的场景

2.3 依赖树方案对比

包管理器的依赖管理方案经历了从嵌套树、扁平树到 pnpm 的硬链接 + 符号链接的演进,具体对比如下:

① 嵌套树(npm v2 及之前)

严格按照依赖声明的层级关系,在node_modules中嵌套存储。例如,A 依赖 B,B 依赖 C,则A/node_modules/B/node_modules/C。

  • 优点:

每个依赖独立拥有自己的子依赖,依赖结构清晰。

无 “幽灵依赖” 问题(只能访问项目声明的依赖)。

  • 缺点:

磁盘空间浪费严重,同一包的不同版本可能在多个嵌套层级中重复存储,尤其深层依赖时体积爆炸。

性能问题,嵌套层级过深可能导致文件系统访问效率低(尤其 Windows )。重复下载相同包,耗时更长。

② 扁平树(npm v3+、Yarn)

将嵌套依赖 “提升” 到顶层node_modules,复用相同版本的包,减少重复。例如,A 依赖 **********,C 依赖 **********,则 ********** 会被提升到顶层,供 A 和 C 共享。

  • 优点:

减少重复依赖,节省部分磁盘空间。

安装速度比嵌套树快。

  • 缺点:

依赖结构不稳定,提升规则受安装顺序、版本范围影响,可能生成不同的依赖树,导致不一致问题。

幽灵依赖,可能访问项目声明外的依赖。

③ pnpm 的硬链接 + 符号链接方案

全局存储:所有下载的包会被存入一个全局store共享存储,不同项目通过硬链接复用,避免重复存储。

依赖树:使用符号链接(软链接)指向全局存储中的包,并严格按照依赖声明构建层级关系,但实际文件不重复。

硬链接类似文件分身,和源文件共享一个inode和数据块。软连接则像一个快捷方式。

  • 优点:

节省磁盘空间,同一版本的包仅存储一次,通过硬链接共享,空间利用率远高于前两者。

安装速度快,无需重复下载和存储,依赖解析逻辑简单,效率高于扁平树。

依赖结构稳定,无提升逻辑,严格遵循声明的依赖关系,无幽灵依赖。

  • 缺点:

对符号链接支持较差的环境可能存在兼容性问题(部分旧系统)。

学习成本略高,需熟悉硬链接和符号链接的工作原理。

三、构建与打包——从源码到可部署的资源

3.1 构建

开发时为了方便编写,我们的文件很分散;我们的语法很便捷,很易读;我们的依赖错综复杂;我们的资源类型五花八门。但当我们需要给其他人使用时,需要申请域名,需要把代码放在服务器上。有其他人访问网站,我们的业务逻辑谁来隐藏?部署到服务器后,没有了开发工具的 “实时翻译” ,我们写的高级语法谁转换后再给浏览器?谁考虑繁多的文件资源造成的网络请求?总而言之,开发环境下的代码是无法直接部署到生产环境的,那么就需要构建来进行转换。

构建是连接 “开发友好” 与 “生产可用” 的核心桥梁。在项目的开发和部署流程中,为了达到“某些目的”(如下),需要将文件转化成适合生产环境运行的资源,这就叫构建(build)。

而具体的目的是什么呢,将构建的目的作以下归纳整理:

  • 压缩体积:打包可以减少文件体积和数量,比如合并零散文件为chunk(可减少浏览器的HTTP请求次数),减少冗余资源(tree-shaking:剔除条数代码、注释、未使用的变量),压缩算法(对于css,js,图片等)等可以优化加载性能。
  • 适配运行环境:开发环境可能使用ES6+语法,Sass/Less 等预处理语言或 TypeScript 等,而部分旧浏览器或运行环境不支持这些语法,转换可将其编译为兼容的代码(如 ES5)。
  • 提升代码安全性:通过混淆、压缩等处理,除了html元素外(浏览器的 DOM 解析与渲染机制),源代码不易被解读。

从具体的流程讲讲构建和打包。

构建的详细流程:

1、检查:如 ESLint ,TS校验

2、解析依赖:从文件入口开始解析模块依赖,如import/require

3、分割合并:代码分割成chunk,再合并成最终的bundle

4、转译:如 ES6,TS,Sass,PostCSS

5、优化:Tree-Shaking、资源优化(图片、字体)

6、输出:到dist 目录

7、部署:部署到生产环境

最终生成的生产文件通常存放在dist目录下:入口文件为index.html(部分项目可能有多个入口);assets子目录中则包含经过处理的 JS、CSS、图片、字体等资源文件,文件名常带有哈希值(如app.8f2d7.js),能实现缓存控制。

常用的构建(打包)工具

Webpack:功能全面,支持处理多种资源。loader 转换非 JS 资源,plugin 扩展功能。适合大型复杂项目

Vite:基于 ES Modules 和esbuild的新一代构建工具,开发环境无需打包,生产环境用 Rollup 打包。

Rollup:专注于 js 打包,输出更简洁的代码(Tree-Shaking 支持更好),适合如 UI 组件库、工具库等项目。

esbuild: 由 Go 语言编写的超快 JavaScript 打包器、转译器和压缩器。

Parcel:零配置打包工具,自动处理依赖和资源,适合快速原型开发。

下面根据刚刚整理的构建流程,列举每个流程常用的工具(随便举举):

1️⃣ 代码检查

Prettier:代码格式化。

ESlint:js/ts的语法检查。

Stylelint:css/sass/less的语法检查。如是否符合BEM

TypeScript:类型检查。

2️⃣ 解析依赖

webpack-resolve:webpack 内置的依赖解析机制,处理模块查找规则。

enhanced-resolve:webpack底层使用的依赖解析库,支持自定义解析逻辑。

esbuild:Vite 等工具使用的快速依赖解析器,处理 ES 模块导入导出关系。

resolve:Node.js 生态中常用的依赖路径解析库,可用于自定义脚手架或构建工具的依赖查找。

3️⃣ 分割合并

Webpack: optimization.splitChunks

Vite: build.rollupOptions.output.manualChunks

Rollup: output.manualChunks

4️⃣ 语法转译

Babel:通过插件(Plugins)和预设(Presets)处理语法转换。

TypeScript Compiler/tsc:TypeScript 官方编译器

Sass/Less:CSS预处理器

PostCSS:CSS后处理器

5️⃣ 优化

webpack

babel-loader (Loader) - JS/TS 转译

css-loader (Loader)+style-loader (Loader) - CSS 处理、注入

file-loader (Loader) - 文件处理

HtmlWebpackPlugin (Plugin) - HTML 生成

MiniCssExtractPlugin (Plugin) - CSS 提取

CleanWebpackPlugin (Plugin) - 清理输出

vite(都是plugin)

vitejs/plugin-vue - Vue 支持

vite-plugin-eslint - ESLint 集成

vite-plugin-compression - 资源压缩

rollup(都是plugin)

rollup/plugin-babel - Babel 转译

rollup/plugin-terser - 代码压缩

rollup-plugin-postcss - CSS 处理

6️⃣ 输出

Source Maps:源码映射文件生成

Manifest 文件:资源清单生成,版本号

7️⃣部署

Docker:容器化部署

CDN 上传:静态资源 CDN 部署

3.2 打包

打包:转译、解析依赖、分割合并、优化

流程:建立依赖树后,根据代码分割策略将依赖树拆分为多个chunk。对每个chunk应用loader处理(如转译),和plugin优化(如压缩)。最终生成多个分割后的bundle文件。

Bundle(包):最终输出的文件包,包含应用的所有代码和资源。

Chunk(块):Bundle 的组成部分,可以按需加载的代码片段,用于代码分割和优化。

分包策略最佳实践

1️⃣ 按功能分包

manualChunks: {
  'auth': ['./src/pages/login', './src/pages/register'],
  'dashboard': ['./src/pages/dashboard'],
  'profile': ['./src/pages/profile']
} 

2️⃣ 按依赖大小分包

manualChunks(id) {
  if (id.includes('node_modules')) {
    // 大型库单独分包
    if (id.includes('echarts')) return 'echarts';
    if (id.includes('moment')) return 'moment';
    if (id.includes('antd')) return 'antd';
    // 小型库合并
    return 'vendor';
  }
} 

3️⃣ 按加载优先级分包

manualChunks: {
  'critical': ['react', 'react-dom'], // 关键依赖
  'common': ['lodash', 'dayjs'],      // 通用工具
  'features': ['./src/features']       // 业务功能
} 

四、其他

测试

单元测试:Jest、Vitest、Mocha 等

集成测试:Testing Library、Enzyme 等

端到端测试:Cypress、Playwright、Puppeteer 等

视觉回归测试:Chromatic、Percy 等

测试覆盖率:Istanbul、c8 等

部署

持续集成/持续部署 (CI/CD):GitHub Actions、GitLab CI、Jenkins 等

自动化构建:多环境构建、版本管理

自动化测试:测试流水线、自动化回归测试

自动化部署:蓝绿部署、滚动更新等

版本控制与协作

Git 工作流:GitFlow、GitHub Flow 等

分支管理策略:功能分支、发布分支管理

提交规范:Conventional Commits、Commitizen

变更日志:自动生成 CHANGELOG

先背诵到这,uu们如果有收藏过前端工程化相关的好的文章,评论区贴贴

#前端八股文##自用##八股文##前端工程化##前端#
全部评论
Mark
点赞 回复 分享
发布于 昨天 02:02 四川
mark
点赞 回复 分享
发布于 08-23 12:18 重庆

相关推荐

08-23 10:28
已编辑
北京交通大学 C++
有个哥们跟我说,他在拼多多干了三年,晚上十点之后基本没加过班。我当时就不信,互联网公司晚上十点走?你是在逗我吗?这家伙就笑,说你不信是吧,我给你看看我们的日常。早上想几点到就几点到,反正是弹性工作制。中午吃完饭能躺一个半小时,下午还有一个半小时的休息时间,晚上十点准时走人,公司还给报销打车费。我心想,这不会是在什么野鸡公司混日子吧?结果这货告诉我,他们组叫拼多多跨境基础平台,专门负责支撑全球业务的核心技术。什么概念?就是全球几亿用户,海量的交易数据,都要经过他们的系统。RPC中间件、存储、K8s、CI/CD、大模型,这些最硬核的技术全是他们在搞。我就更不理解了,这种核心业务不应该是最累的吗?怎么可能这么轻松?他跟我解释说,关键就在于技术驱动。别的公司遇到问题就堆人,他们这里是用最牛逼的架构去解决最复杂的问题。高并发?用技术手段优化。复杂架构?设计更合理的系统。极致高可用?提前预防而不是事后救火。这就是第一性原理啊兄弟,从根本上解决问题,而不是用战术上的勤奋掩盖战略上的懒惰。更让我震惊的是,他说他们组的离职率低得可怕。我问为什么,他说你想想,一个地方技术氛围好,待遇还行,谁特么愿意走啊?组里一堆三十多岁的技术大牛,这些人如果真的不爽,早就跳槽了。他还跟我说了个细节,让我特别感动。他们开发完全以数据指标和业务逻辑为准,没有那些乱七八糟的形式主义流程。作为一个校招生,你只要把事情做好,就能得到认可。不用拍马屁,不用搞人际关系,就是纯粹的技术导向。我突然想起乔布斯说过的话,伟大的产品来自于对细节的执着和对本质的追求。这个团队就是这样,他们不搞那些花里胡哨的东西,就是专注于把技术做到极致。package高不高我不知道具体数字,但是每年固定涨薪这一点就很说明问题了。现在这个环境,能保证涨薪的公司有几个?而且四餐全包,这细节也体现了公司对员工的重视。现在他们要2026届的校招生,要求其实挺实在的:本科以上学历,对计算机和互联网技术有兴趣,扎实的数据结构和算法能力。没有那些虚头巴脑的什么领导力、沟通能力、团队合作,就是硬核技术要求。我觉得这才是对的。技术这东西,要么你有天赋,要么你够努力,要么你运气好进了一个能让你成长的地方。其他的都是扯淡。你想想,现在这个市场环境下,能找到一个真正重视技术的地方有多难?大部分公司都在裁员,都在压缩成本,都在搞形式主义。而这个团队还在招人,还在投入核心技术,说明什么?说明他们是真的在做事情,不是在混日子。我觉得对于校招生来说,第一份工作选择什么样的环境,基本上决定了你未来几年的技术路径。在一个重视技术、氛围好、不搞内卷的地方,你才能真正专心把技术学好,把基础打扎实。有兴趣的话真的可以了解一下,现在好的机会确实不多了。别等毕业了才后悔没抓住机会。​​​​​​​​​​​​​​​​
ResourceUt...:开头就有个哥们跟我说,这是什么传销话术
投递拼多多集团-PDD等公司10个岗位
点赞 评论 收藏
分享
评论
4
9
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务