webpack构建原理和实现简单webpack
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的更多相关文章
- 从0构建webpack开发环境(一) 一个简单webpack.config.js
本文基于webpack4.X,使用的包管理工具是yarn 概念相关就不搬运了,直接开始 首先项目初始化 mkdir webpack-demo && cd webpack-demo ya ...
- 手写webpack核心原理,再也不怕面试官问我webpack原理
手写webpack核心原理 目录 手写webpack核心原理 一.核心打包原理 1.1 打包的主要流程如下 1.2 具体细节 二.基本准备工作 三.获取模块内容 四.分析模块 五.收集依赖 六.ES6 ...
- Webpack探索【16】--- 懒加载构建原理详解(模块如何被组建&如何加载)&源码解读
本文主要说明Webpack懒加载构建和加载的原理,对构建后的源码进行分析. 一 说明 本文以一个简单的示例,通过对构建好的bundle.js源码进行分析,说明Webpack懒加载构建原理. 本文使用的 ...
- Webpack探索【15】--- 基础构建原理详解(模块如何被组建&如何加载)&源码解读
本文主要说明Webpack模块构建和加载的原理,对构建后的源码进行分析. 一 说明 本文以一个简单的示例,通过对构建好的bundle.js源码进行分析,说明Webpack的基础构建原理. 本文使用的W ...
- 使用webstorm+webpack构建简单入门级“HelloWorld”的应用&&引用jquery来实现alert
使用webstorm+webpack构建简单入门级"HelloWorld"的应用&&构建使用jquery来实现 1.首先你自己把webstorm安装完成. 请参考这 ...
- 使用webstorm+webpack构建简单入门级“HelloWorld”的应用&&构建使用jquery来实现
使用webstorm+webpack构建简单入门级“HelloWorld”的应用&&构建使用jquery来实现 1.首先你自己把webstorm安装完成. 请参考这篇文章进行安装和破解 ...
- webpack构建工具初始化并运行简单的demo
webpack官网:https://webpack.js.org/ webpack是构建工具 安装webpack的前提:node,npm要安装 初始化项目 首先是初始化项目,创建一个文件夹,并且进入文 ...
- gulp + webpack 构建多页面前端项目
修改增加了demo地址 gulp-webpack-demo 之前在使用gulp和webpack对项目进行构建的时候遇到了一些问题,最终算是搭建了一套比较完整的解决方案,接下来这篇文章以一个实际项目为例 ...
- 深入浅出的webpack构建工具---webpack基本配置(一)
深入浅出的webpack构建工具---webpack基本配置(一) 阅读目录 一:webpack入门构建: 1. 安装webpack到全局 2. 安装webpack到本项目. 3. 如何使用webpa ...
随机推荐
- Vue.js大屏数字滚动翻转效果
================================ 大屏数字滚动翻转效果来源于最近工作中element后台管理页面一张大屏的UI图,该UI图上有一个模块需要有数字往上翻动的效果,以下是最 ...
- Java数组深入
Java数组深入 内存中的数组 前边提到:数组是一种引用类型,数组引用变量只是一个引用,当它指向有效内存的时候才可以通过数组变量来访问数组元素,也就是说数组变量和数组元素在内存中是分开放的. 可以这么 ...
- es5设置属性不能修改
/*es5*/ { var Person ={ name:'es5', age:19 } Object.defineProperty(Person,'sex',{ writable:false, va ...
- 【02】对象的Getter and Setter
java和C#非常相似,它们大部分的语法是一样的,但尽管如此,也有一些地方是不同的. 为了更好地学习java或C#,有必要分清它们两者到底在哪里不同. 我们这次要来探讨对象的Getter and Se ...
- 源码分析— java读写锁ReentrantReadWriteLock
前言 今天看Jraft的时候发现了很多地方都用到了读写锁,所以心血来潮想要分析以下读写锁是怎么实现的. 先上一个doc里面的例子: class CachedData { Object data; vo ...
- 安装iris框架
1.导语 目前Go语言已经为大多数人所熟知,越来越多的开发人员选择使用Go语言来进行开发,但是如何使用 Go来进行web开发,在其他编程语言中都有对应的开发框架,当然在Go中也有,就是即将要介绍的-- ...
- UVA439 骑士的移动 Knight Moves
#include<bits/stdc++.h> using namespace std; char a,c; int b,d; ][]; ]={,,,-,,-,-,-}; ]={,-,,, ...
- java数据类型(大小等),变量定义,各进制书写方法
1. java中字符占两个字节,因为char类型占两个字节(16位),而C,C++中占1字节(8位). 2. 变量定义 第一步:声明(Declaration) 第二步:赋值(Assignment) 这 ...
- 华为鲁勇:5G+云+AI三大核心引擎将驱动广州数字经济发展
[摘要] 华为云将携手广州政企,全面释放 5G+云+AI新动能,推动广州步入高质量发展新阶段. [中国,广州] 广州是一座多样化的城市,在历史上被誉为千年的商都,现在,广州也在持续的开放.融合.与时俱 ...
- Dict.setdefault()
""" setdefault方法参数输入已有键,返回对应值,找不到已有键,创建新键,值为None """ >>> dict ...