webpack打包原理分析

  • 基础配置,webpack会读取配置 (找到入口模块)

    • 如:读取webpack.config.js配置文件:
      const path = require("path")
      module.exports = {
      entry:"./src/index.js"
      mode:"development"
      output:{
      path:path.resolve(__dirname,"./dist"),
      filename:"main.js"
      }
      }//读取这里面的入口文件,和导出文件夹等
  • 入口分析

    • 分析依赖模块(分析这个入口文件依赖了哪些模块,并且拿到模块的路径)
    • 分析内容(并对内容进行处理)
    • 编译内容
  • 依赖模块(怎么分析了入口模块以同样的方式分析依赖模块:递归)

    • 分析依赖模块是否有其他模块
    • 分析内容(并对内容处理)
    • 编译内容
  • 生成bundle.js (这个js可以直接在浏览器中执行)

    • 基础结构为一个自执行函数
      (function(){ })({})
      并且传入了一个对象属性,
      对象属性的键为入口出口文件和依赖文件的路径
      对象属性的值为webpack实现他具体功能的函数

实现

index.js入口文件   webpack.config.js配置文件  webpack文件  bundle.js 中间执行文件
index.js文件的依赖文件expo.js webpack.js文件:
const fs = require("fs")
const parser = require("bable/parser")
const traverse = require('@babel/traverse').default;
const path = require("path");
const {tarnsformFromAst} = require('@babel/core');
//因为webpack是基于node的,而node是遵循common.js规范的,所以不能用import,export导入导出
module.exports = class Webpack{
constructor(options){ //接收传入参数
console.log(options) //读取作为参数传入的webpack配置文件
//将参数保存下来
const {entry ,output} = options;
this.entry = entry;
this.output = output; //我们已经编写好了解析入口模块的方法,只需要用这个方法,去处理依赖模块,依赖中的依赖模块即可
this.moudles = [] ;
}
run(){
console.log('hello webpack')
this.parse(this.entry)
//处理其他依赖模块,做一个信息汇总
this.modules.push(info);
for(let i=0 ; i<this.modules.length ;i++){
const item = this.modules[i];
const { dependencies} = item;
if(dependencies){
for(let j in dependencies ){
//递归,处理所有模块的信息
this.modules.push(this.parse(dependencies[j]))
}
}
}
//将这个数组结构转换成对象
console.log(this.moudles)
const obj = {}
this.modules.forEach((item)=>{
obj[item.entryFile] = {
dependencies:item.dependencies
code:item.code
}
})
}
//解析模块函数
parse(entryFile){
//解析入口函数
//运用nodejs的文件模块,读取模块内容
const content = fs.readFileSync(entryFile,"utf-8") //他会将入口模块的内容给返回 //分析出哪些是依赖?以及依赖的路径
//推荐使用@bable/parser,这是bable7的工具,来帮助我们分析内部的语法,包括es6,返回一个ast抽象语法树,便于分析提取
//安装插件 npm install @bable/parser --save
const ast = parser.parse(content,{
sourceType:"module"
}); const dependencies = {} //存储import模块
//此时,ast中就有所有的节点信息,并且分类为import为import模块名,即依赖的文件名模块和表达式节点
//可以用bable下的traverse模块 npm installl @bable/traverse --save
traverse(ast, {
//根据ast中type类型作为函数名的函数来提取
ImportDeclaration({ node }) {
const dirname = path.dirname(filename);
//node.source.value为import模块名,即依赖的文件名
const newFile = './' + path.join(dirname, node.source.value);
//依赖的文件文件名为key,原始路径为值保存下来
dependencies[node.source.value] = newFile;
}
});
//然后再利用@bable/core和@bable/preset-env,把ast语法树转换成合适的代码
//处理内容
const {code} = tarnsformFromAst(ast,null,{
presets:["@bable/preset-env"]
});
//处理完毕
return {
entryFile,//分析的哪个模块
dependencies,//依赖是什么
code //代码是什么
};
}
//生成最后的合成文件函数
file(code){
//根据之前解析出来的参数,生成一个自执行函数,然后内部完成对require以及import的处理
//生成bundle.js =>./dist/main.js (路径为配置文件当中的路径+文件名)
const filePath = path.join(this.output.path,this.output.filename)
const newcode = JSON.stringify(code)
const bundle = `(function(graph){
function require(module){
function localRequire(relativePath){
return require(graph[module].dependencies[relativePath])
}
var exports = {};
(function(exports,code){
eval(code)
})(localRequire,graph[module].code)
}
require(exports,'$this.entry')
})(${newcode})`;
fs.writeFileSync(filePath,bundle,"utf-8")
}
} bundle.js文件:
//拿到webpack配置文件 (配置文件本身就是导出一个对象,将配置导出)
const options = require("./webpack.config.js");
//创建一个webpack实例,接收配置参数,然后根据参数,完成构建
const Webpack = require("./lib/webpack.js");
new Webpack(options).run(); //打印 hello webpack index.js文件:
imports {add,minus} from "./expo,js"
add(1,2); expo.js文件:
export const add =function(a,b){
return a+b;
}
export const minus = function(a,b){
return a-b;
}

总结

  • 理解webpack打包流程
  • AST基础知识
  • 分析模块之间的依赖图谱(借助bable的几个模块,和递归,解析所有的依赖文件)
  • 动手实现一个简易webpack

webpack构建原理和实现简单webpack的更多相关文章

  1. 从0构建webpack开发环境(一) 一个简单webpack.config.js

    本文基于webpack4.X,使用的包管理工具是yarn 概念相关就不搬运了,直接开始 首先项目初始化 mkdir webpack-demo && cd webpack-demo ya ...

  2. 手写webpack核心原理,再也不怕面试官问我webpack原理

    手写webpack核心原理 目录 手写webpack核心原理 一.核心打包原理 1.1 打包的主要流程如下 1.2 具体细节 二.基本准备工作 三.获取模块内容 四.分析模块 五.收集依赖 六.ES6 ...

  3. Webpack探索【16】--- 懒加载构建原理详解(模块如何被组建&如何加载)&源码解读

    本文主要说明Webpack懒加载构建和加载的原理,对构建后的源码进行分析. 一 说明 本文以一个简单的示例,通过对构建好的bundle.js源码进行分析,说明Webpack懒加载构建原理. 本文使用的 ...

  4. Webpack探索【15】--- 基础构建原理详解(模块如何被组建&如何加载)&源码解读

    本文主要说明Webpack模块构建和加载的原理,对构建后的源码进行分析. 一 说明 本文以一个简单的示例,通过对构建好的bundle.js源码进行分析,说明Webpack的基础构建原理. 本文使用的W ...

  5. 使用webstorm+webpack构建简单入门级“HelloWorld”的应用&&引用jquery来实现alert

    使用webstorm+webpack构建简单入门级"HelloWorld"的应用&&构建使用jquery来实现 1.首先你自己把webstorm安装完成. 请参考这 ...

  6. 使用webstorm+webpack构建简单入门级“HelloWorld”的应用&&构建使用jquery来实现

    使用webstorm+webpack构建简单入门级“HelloWorld”的应用&&构建使用jquery来实现 1.首先你自己把webstorm安装完成. 请参考这篇文章进行安装和破解 ...

  7. webpack构建工具初始化并运行简单的demo

    webpack官网:https://webpack.js.org/ webpack是构建工具 安装webpack的前提:node,npm要安装 初始化项目 首先是初始化项目,创建一个文件夹,并且进入文 ...

  8. gulp + webpack 构建多页面前端项目

    修改增加了demo地址 gulp-webpack-demo 之前在使用gulp和webpack对项目进行构建的时候遇到了一些问题,最终算是搭建了一套比较完整的解决方案,接下来这篇文章以一个实际项目为例 ...

  9. 深入浅出的webpack构建工具---webpack基本配置(一)

    深入浅出的webpack构建工具---webpack基本配置(一) 阅读目录 一:webpack入门构建: 1. 安装webpack到全局 2. 安装webpack到本项目. 3. 如何使用webpa ...

随机推荐

  1. 2019-11-4:渗透测试,bypass学习,笔记

    编码方式过wafurl编码,针对特殊情况可以两次URL编码十六进制编码,针对某些数据,如特殊字符,特殊字符串等unicode编码,使用两个字节编码一个字符,高位不足使用0填充单引号:%u0027.%u ...

  2. Spring Boot2 系列教程(二十七)Nginx 极简扫盲入门

    上篇文章和大家聊了 Spring Session 实现 Session 共享的问题,有的小伙伴看了后表示对 Nginx 还是很懵,因此有了这篇文章,算是一个 Nginx 扫盲入门吧! 基本介绍 Ngi ...

  3. SpringBoot学习(六)—— springboot快速整合RabbitMQ

    目录 Rabbit MQ消息队列 简介 Rabbit MQ工作模式 交换机模式 引入RabbitMQ队列 代码实战 Rabbit MQ消息队列 @ 简介 优点 erlang开发,并发能力强. 社区活跃 ...

  4. 最全 HTTP 安全响应头设置指南

    销售“安全记分卡”的公司正在崛起,并已开始成为企业销售的一个因素.这些公司组合使用 HTTP 安全报头和 IP 信誉来进行评级.不过,在很大程度上,公司的得分取决于对外开放网站上设置的安全响应报头.本 ...

  5. 数据降维-NMF非负矩阵分解

    1.什么是非负矩阵分解? NMF的基本思想可以简单描述为:对于任意给定的一个非负矩阵V,NMF算法能够寻找到一个非负矩阵W和一个非负矩阵H,使得满足 ,从而将一个非负的矩阵分解为左右两个非负矩阵的乘积 ...

  6. 【JavaEE】之MyBatis查询缓存

    为了减轻数据压力,提高数据库的性能,我们往往会需要使用缓存.MyBatis为我们提供了一级缓存和二级缓存. (1)一级缓存是SqlSession级别的缓存,在操作数据库的时候需要创建一个SqlSess ...

  7. OSI-传输层

    OSI-传输层 端口号(2字节 SYN(1bit) ACK(1bit) 会话多路复用(为什么一个IP地址可以做很多事情?) 源端口地址可以不同 五元组(世界上没有相同的2个五元组) 源IP地址-目的I ...

  8. 大白话OSI七层协议

    目录 一.物理层 二.数据链路层 2.1 以太网协议 2.2 Mac地址 2.3 广播地址 三.网络层 3.1 IP协议详解 3.1.1 IP地址的两部分 3.2 子网掩码详解 3.3 IP数据包详解 ...

  9. 特殊权限set_uid、set_gid、stick_bit、软链接、硬链接文件 使用介绍

    第2周第4次课(3月29日) 课程内容:2.18 特殊权限set_uid2.19 特殊权限set_gid2.20 特殊权限stick_bit2.21 软链接文件2.22 硬链接文件     2.18  ...

  10. num += num 与 num = num+ num

    a = 100def test(num): num += num print(num) test(a)print(a) 200100 这里 num += num 与 num = num+ num 不能 ...