npm link和webpack流程
最近在学习webpack的流程,因为很多都问过webpack的流程,随便不知道问的人知不知道,自己还是想去了解一下。说webpack流程之前先说一下npm link,方便调试npm包的小技巧。
我们先初始化一个项目,我这边是wadepack:npm init -y,然后在package.json里面配置bin:
bin对应的路径可以随便,只要是能找到这个js就可以,这个js里面代码:
#! /usr/bin/env node(固定的,指定用node去执行)
console.log('wadepack')(随便写点代码)
然后初始化另外一个项目demo,要先安装webpack和webpack-cli,接着在wadepack项目下执行npm link,结果:
npm link 将当前目录临时放到全局,指向wadepaxk.js,然后可以在npm的目录下找到wadepaxk.cmd,node_modules下也有wadepack文件。
回到demo项目,执行npm link wadepack,这时候这个项目就把我们写的wadepack链接到这个项目下,可以在node_modules下看见wadepack这个文件夹,接着执行npx wadepack:
可以执行。这就是npm link的使用,方便调试你的npm包。如果demo项目不用了要解绑可以用npm unlink wadepack,但是我发现执行之后,原来的依赖会有一些问题,就是node_nodules里面好像被删除了,需要删除这文件夹重新初始化。如果要全局移除就在wadepack下执行npm unlink就可以。
接着说webpack大概流程,通过配置文件找到入口文件,解析入口文件生成ast语法树,ast语法树有个字段name判断语法是否是require,大概是下面这样(删除了很多其他字段):
Node {
callee: Node {
name: 'require'
},
]
}
如果有新的依赖先放入一个依赖数组dependencies(引入地址):
[ './src\a.js', './src\b.js' ]
[]
[]
然后循环dependencies继续解析成ast,继续判断是否有依赖,递归把所有的依赖都找到。期间需要用path解析拼接地址,用fs读取文件内容:
fs.readFileSync(modulePath, 'utf-8');
这期间,获取到文件内容之后要获取配置文件的loader,看是否有rules数组,通过配置的正则test(/.js/)判断当前内容的引入地址modulePath是否是以这个test为结尾,然后倒叙的把内容传递到loader里面处理:
let content = fs.readFileSync(modulePath, 'utf-8');
let rules = this.config.module.rules;
if(Array.isArray(rules)){
for (let i = 0; i < rules.length; i++) {
let rule = rules[i];
let {test, use} = rule;
let len = use.length - 1;
if(test.test(modulePath)){
function normalLoader() {
let loader = require(use[len - 1]);
content = loader(content);
if(len >= 0){
normalLoader();
}
}
normalLoader();
}
}
}
return content;
loader之前有分享过大概怎么手写,所以就很清楚这边为什么这样执行了。
把每个文件的内容都缓存到modules对象,key就是每个引入依赖的地址:
this.modules[moduleName] = sourceCode;
当递归把所有依赖解析出来之后,把内容写入配置文件的出口地址和文件名,这边直接写是不对的,如果找不到文件夹和文件会报错,我是提前建好文件和文件夹。
fs.writeFileSync(output, code);
插件的注入更简单了,只要在不同过程调用tapable的回调就可以了,比如在编译之前和文件发射之后:
this.hooks.compile.call();
this.buildModule(path.resolve(this.root, this.entry), true);
this.hooks.afterCompile.call();
this.emitFile();
this.hooks.emit.call();
this.hooks.done.call();
hooks在constructor的时候就声明了,之前分享怎么手写插件,所以这个应该也不难理解。
随便看看,自己也只是理解到这种程度,比较重要的其实是知道解析成ast之后怎么递归加载依赖,然后loader怎么注入的,至于插件的注入,知道了tapable应该不难理解,就是发布订阅,然后在不同运行阶段调用。
可以使用npm link调试自己手写一个简易的webpack打包过程,网上还蛮多的,运行一遍对这个流程就挺好理解的了。
(完)
- hdu----(1257)最少拦截系统(dp/LIS)
- nginx安装Fancy美化索引目录
- hdu---(3779)Railroad(记忆化搜索/dfs)
- RHEL下KVM虚拟化部署-安装虚拟化
- hdu--(1025)Constructing Roads In JGShining's Kingdom(dp/LIS+二分)
- kafka权威指南 第二章第6节 Kafka集群配置与调优
- hdu----(1677)Nested Dolls(DP/LIS(二维))
- hdu----(1950)Bridging signals(最长递增子序列 (LIS) )
- hdu------(1757)A Simple Math Problem(简单矩阵快速幂)
- python实现Tab自动补全功能
- hdu-----(2807)The Shortest Path(矩阵+Floyd)
- hdu----(4686)Arc of Dream(矩阵快速幂)
- HDU----(4549)M斐波那契数列(小费马引理+快速矩阵幂)
- Centos系统修改时区
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 安全通告 | Apache SkyWalking SQL注入漏洞安全风险公告(CVE-2020-13921)
- Cmd Markdown 迁移备份的流程
- PyTorch3:计算图torch.autograph
- spark shell 配置 Kryo 序列化
- Mac里捣腾Kerberos(一)
- Spark on K8S 访问 Kerberized HDFS
- Apache Beam的Docker Demo
- docker login 报错了...
- Spark-Submit 和 K8S Operation For Spark
- Spark的Dockerfile分析
- Spark on Kubernetes在Mac的Demo
- Python的Wand模块
- 机器学习第4天:预测1立方米混凝土抗压强度
- 硬件笔记之GP106-90 3GB GTX1060 3GB魔改
- Java BigDecimal 的舍入模式(RoundingMode)详解