首页 技术 正文
技术 2022年11月15日
0 收藏 402 点赞 2,731 浏览 3326 个字

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.jswebpack.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 webpackindex.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
相关推荐
python开发_常用的python模块及安装方法
adodb:我们领导推荐的数据库连接组件bsddb3:BerkeleyDB的连接组件Cheetah-1.0:我比较喜欢这个版本的cheeta…
日期:2022-11-24 点赞:878 阅读:9,026
Educational Codeforces Round 11 C. Hard Process 二分
C. Hard Process题目连接:http://www.codeforces.com/contest/660/problem/CDes…
日期:2022-11-24 点赞:807 阅读:5,516
下载Ubuntn 17.04 内核源代码
zengkefu@server1:/usr/src$ uname -aLinux server1 4.10.0-19-generic #21…
日期:2022-11-24 点赞:569 阅读:6,364
可用Active Desktop Calendar V7.86 注册码序列号
可用Active Desktop Calendar V7.86 注册码序列号Name: www.greendown.cn Code: &nb…
日期:2022-11-24 点赞:733 阅读:6,145
Android调用系统相机、自定义相机、处理大图片
Android调用系统相机和自定义相机实例本博文主要是介绍了android上使用相机进行拍照并显示的两种方式,并且由于涉及到要把拍到的照片显…
日期:2022-11-24 点赞:512 阅读:7,778
Struts的使用
一、Struts2的获取  Struts的官方网站为:http://struts.apache.org/  下载完Struts2的jar包,…
日期:2022-11-24 点赞:671 阅读:4,856