当前位置: 首页 > news >正文

根据webpack设计原理手写一个简版webpack

文章目录

  • 根据webpack设计原理手写一个简版webpack
    • 模块解析:
    • 依赖图构建:
    • 代码打包:
    • 上代码

根据webpack设计原理手写一个简版webpack

模块解析:

读取文件内容
使用 Babel 将 ES6 + 代码转换为 ES5
提取模块中的依赖关系(通过正则匹配 require 语句)

依赖图构建:

从入口文件开始递归解析所有依赖
为每个模块创建唯一标识(使用文件绝对路径)
记录模块间的依赖关系映射

代码打包:

将所有模块打包到一个文件中
模拟 CommonJS 模块系统(实现 require、module、exports)
处理相对路径到模块 ID 的映射
生成可在浏览器环境运行的代码

上代码

const fs = require('fs');
const path = require('path');
const { transform } = require('@babel/core');
const babelPresetEnv = require('@babel/preset-env');/*** 解析模块内容,提取依赖关系* @param {string} filePath - 模块文件路径* @returns {object} 包含模块ID、依赖和转换后代码的对象*/
function parseModule(filePath) {// 1. 读取文件内容const sourceCode = fs.readFileSync(filePath, 'utf-8');// 2. 使用Babel将ES6+代码转换为ES5const { code } = transform(sourceCode, {presets: [babelPresetEnv]});// 3. 正则匹配require语句,提取依赖模块路径const dependencies = [];const requireRegex = /require\(['"](.*?)['"]\)/g;const transformedCode = code.replace(requireRegex, (match, dependencyPath) => {// 记录依赖dependencies.push(dependencyPath);// 替换为相对路径标识,后续会处理为绝对路径IDreturn `require('${dependencyPath}')`;});// 4. 返回模块信息return {id: filePath, // 用文件绝对路径作为模块IDdependencies, // 依赖的模块路径列表code: transformedCode // 转换后的代码};
}/*** 构建模块依赖图* @param {string} entry - 入口文件路径* @returns {array} 包含所有模块信息的依赖图*/
function buildDependencyGraph(entry) {// 解析入口模块const entryModule = parseModule(entry);// 用队列来处理所有模块(广度优先遍历)const queue = [entryModule];// 遍历队列,处理每个模块的依赖for (const module of queue) {// 模块所在目录const moduleDir = path.dirname(module.id);// 为每个依赖创建映射关系,并解析依赖模块module.dependencies.forEach(dependencyPath => {// 计算依赖模块的绝对路径const absolutePath = path.join(moduleDir, dependencyPath);// 解析依赖模块const dependencyModule = parseModule(absolutePath);// 将相对路径映射到绝对路径ID,方便后续查找module.mapping = module.mapping || {};module.mapping[dependencyPath] = dependencyModule.id;// 将依赖模块加入队列,继续处理其依赖queue.push(dependencyModule);});}// 返回完整的依赖图return queue;
}/*** 将依赖图打包成单个可执行文件* @param {array} graph - 模块依赖图* @returns {string} 打包后的代码*/
function bundle(graph) {// 1. 构建模块ID到模块代码的映射const modules = {};graph.forEach(module => {modules[module.id] = {code: module.code,mapping: module.mapping};});// 2. 生成可在浏览器运行的代码// 使用自执行函数包裹,模拟模块系统return `(function(modules) {// 模拟require函数function require(moduleId) {// 模拟module和exports对象const module = { exports: {} };// 执行模块代码modules[moduleId].code.call(module.exports, require, module, module.exports,function(path) {// 处理相对路径到模块ID的映射return require(modules[moduleId].mapping[path]);});// 返回模块导出return module.exports;}// 从入口模块开始执行require('${graph[0].id}');})({// 将模块信息注入到自执行函数中${graph.map(module => {return `'${module.id}': {code: function(require, module, exports, requireRelative) {// 替换require为我们的相对路径处理版本${module.code.replace(/require\(['"](.*?)['"]\)/g, (match, path) => {return `requireRelative('${path}')`;})}},mapping: ${JSON.stringify(module.mapping || {})}}`;}).join(',\n    ')}})`;
}/*** 简版Webpack的主函数* @param {object} options - 配置选项,包含entry和output*/
function webpack(options) {// 1. 解析入口文件路径const entryPath = path.resolve(options.entry);// 2. 构建依赖图const dependencyGraph = buildDependencyGraph(entryPath);// 3. 打包代码const outputCode = bundle(dependencyGraph);// 4. 确保输出目录存在const outputDir = path.dirname(options.output.path);if (!fs.existsSync(outputDir)) {fs.mkdirSync(outputDir, { recursive: true });}// 5. 写入输出文件fs.writeFileSync(options.output.path, outputCode, 'utf-8');console.log(`打包完成!输出至: ${options.output.path}`);
}// 使用示例
webpack({entry: './src/index.js',output: {path: './dist/bundle.js'}
});
http://www.dtcms.com/a/344954.html

相关文章:

  • 亚马逊广告优化新逻辑:从人工苦力到AI智能的进化之路
  • K8S的部署与常用管理
  • http请求有哪些?
  • 文件相关操作的函数和文件操作
  • 使用tensorRT8部署yolov5目标检测模型(1)
  • 深入解析 Docker 镜像构建与性能优化实践指南
  • SSM从入门到实战: 2.6 MyBatis缓存机制与性能优化
  • 双发 ARP 测试与实践:从原理到生产验证
  • PHP 函数的参数顺序,它们是随机的吗?
  • 数学建模论文注意点
  • 华盛顿大学GeoAI本土化实践:五大实验贯穿预测、检测、生成、推理与偏差审视
  • 碧海琴魂,孤独与纯粹的永恒绝唱——《海上钢琴师》鉴赏
  • 双摄工业相机镜头切换与同步曝光技术方案
  • 11,FreeRTOS延时函数
  • 微算法科技(NASDAQ:MLGO)基于人工智能优化构建混合ARIMA模型,提高比特币价格预测准确性
  • 日志的配置
  • nvm 更新到最新版本
  • C++ 数组:从底层原理到实战应用的深度解析
  • UE5 将纯蓝图项目转为 C++ 项目
  • 探索Thompson Shell:Unix初代Shell的智慧
  • 线性回归入门学习:从原理到代码实现
  • 南溪智融双碳示范基地建筑设备管理系统 + 智能照明系统调试完成:筑牢 “绿色智能” 运营基石
  • 2025年9月5090工作站、
  • APP Usage『安卓』:比系统自带强10倍!手机应用使用时长精确到秒
  • 无穿戴AI动捕实训室:多专业融合实训的创新实践
  • KWDB 分布式架构探究——数据分布与特性
  • 机器学习在量化中的应用
  • 自动驾驶感知——BEV感知(学习笔记)
  • osgEarth 图像融合正片叠底
  • 爬楼梯变式