webpack编译流程漫谈
前言
weback在web构建工具的激烈竞争中逐渐脱引而出。 无论是编译速度、报错提示、可扩展性等都给前端开发者耳目一新的感觉。本篇文章是个人对webpack的一点小研究总结。
webpack在开发者社区的反馈
类似gulp把自己定位为stream building tools一样,webpack把自己定位为module building system。
在webpack看来,所有的文件都是模块,只是处理的方式依赖不同的工具而已。webpack同时也把node的IO和module system发挥的淋漓尽致。 webpack在配合
babel(ES6/7)和tsc(typescript)等DSL语言预编译工具的时候,驾轻就熟,为开发者带来了几乎完美的体验。
webpack整体架构(以webpack.config主要部分进行划分)
entry:定义整个编译过程的起点output:定义整个编译过程的终点module:定义模块module的处理方式plugin对编译完成后的内容进行二度加工resolve.alias定义模块的别名
webpack的核心module
无论你是jsx,tsx,html,css,scss,less,png文件,webpack一视同仁为module。并且每个文件[module]都会经过相同的编译工序 loader==> plugin。
关于以上这点,以如下一个简单的webpack.config文件为例。看下webpack会做什么
module.exports = {
watch: true,
entry: './index.js',
devtool: 'source-map',
output: {
path: path.resolve(process.cwd(),'dist/'),
filename: '[name].js'
},
resolve: {
alias:{ jquery: 'src/lib/jquery.js', }
},
plugins: [
new webpack.ProvidePlugin({
$: 'jquery',
_: 'underscore',
React: 'react'
}),
new WebpackNotifierPlugin()
],
module: {
loaders: [{
test: /\.js[x]?$/,
exclude: /node_modules/,
loader: 'babel-loader'
}, {
test: /\.less$/,
loaders:['style-loader', 'css-loader','less-loader']
}, {
test: /\.(png|jpg|gif|woff|woff2|ttf|eot|svg|swf)$/,
loader: "file-loader?name=[name]_[sha512:hash:base64:7].[ext]"
}, {
test: /\.html/,
loader: "html-loader?" + JSON.stringify({minimize: false })
} ]
}
};
webpack是如何处理如上webpack.config文件解析
1. 确定webpack编译上下文context
默认情况下就是node启动的工作目录process.cwd(),当然也可以在配置中手动指定context。
webpack在确定webpack.config中entry的路径依赖时,会根据这个context确定每个要编译的文件(assets)的绝对路径。
2.entry和output 确定webpack的编译起点和终点
顾名思义,entry定义webpack编译起点,入口模块。 对应的结果为
compolation.assetsoutput定义webpack编译的终点,导出目录
3. module.loaders 和 module.test 确定模块预编译处理方式
以babel为例,当webpack发现模块名称匹配test中的正则/js[x]?的时候。
它会将当前模块作为参数传入babel函数处理,
babel([当前模块资源的引用])。函数执行的结果将会缓存在webpack的compilation对象上,并分配唯一的
id。以上的这一步,非常非常关键。唯一的id值决定了webpack在最后的编译结果中,是否会存在重复代码。
而缓存在compilation对象上,则决定了webpack可以在plugin阶段直接拿取模块资源进行二度加工。
4. plugin阶段发生在webpack的module.loader处理之后,一般用来做一些优化操作。
比如
webpack.ProvidePlugin,它会在对编译结果再加工的操作过程中进行自定义的变量注入,当模块中碰到比如_这个变量的时候,webpack将从缓存的module中取出underscore模块加载进引用_的文件(compilation.assets)。
比如WebpackNotifierPlugin,它会在编译结果ready的时通知开发者,output已经就绪。
5.resolve.alias的作用就是对module模块提供别名,并没有什么特殊的。
【副作用】 webpack编译过程中的电脑卡慢?
在weback经历以上流程的时候,查看你的内存,你会发现,内存飙升!!!
这一般都是loader阶段,对DSL进行AST抽象语法树分析的时候,由于大量应用递归,内存溢出的情
况也是非常常见。output目录不是一个渐进的编译目录,只有在最后compilation结果ready的时候,才会写入,造成开发者等待的时候,output目录始终为空。
【大招】 webpack将编译结果导出到output是怎么做到的,为啥output不是渐进的写入文件
如上,webpack在plugin结束前,将会在内存中生成了棵巨大的
文件模块tree。这个阶段就是ready阶段,webpack写入output目录的分割点。
这棵树的枝叶节点就是所有的module[由import或者require为标志,并配备唯一moduleId],
这棵树的主枝干就是所有的assets,也就是我们entry中的东西。
这棵树也是webpackPlugin的处理的时候的arguments。
总结
好吧,对于开发者来说,整体而言webpack的编译过程细节比较多,但是大体的框架还是比较直观。
里面涉及到的类似DSL,AST的概念及模块缓存等等,在构建工具中还是比较常见的。
一切文件皆为模块也和react的一切都可以变为JS一样,对前端世界带来了新的开发理念。
anyway,写webpackPlugin相对于loader而言还是比较简单的。
在写plugin的过程可以对webpack有个更加直观的认识,鼓励多多尝试。
最后,案例一个之前写的一个 repowebpackPlugin编写
webpack官方文档
webpack编译流程漫谈的更多相关文章
- 细说 webpack 之流程篇
摘自: http://taobaofed.org/blog/2016/09/09/webpack-flow/ 引言 目前,几乎所有业务的开发构建都会用到 webpack .的确,作为模块加载和打包神器 ...
- 细说webpack之流程篇
引言 目前,几乎所有业务的开发构建都会用到 webpack .的确,作为模块加载和打包神器,只需配置几个文件,加载各种 loader 就可以享受无痛流程化开发.但对于 webpack 这样一个复杂度较 ...
- vue项目实战, webpack 配置流程记录
vue项目实战记录,地址在这 购物车单界面 npm install npm run dev 跑起来可以看到界面效果 这里简单记录一下webpack的编译流程 入口 package.json " ...
- [Erlang 0113] Elixir 编译流程梳理
注意:目前Elixir版本还不稳定,代码调整较大,本文随时失效 之前简单演示过如何从elixir ex代码生成并运行Erlang代码,下面仔细梳理一遍elixir文件的编译过程,书接上文,从 ...
- 关于webpack编译scss文件
css加载器文件通常和extract-text-webpack-plugin一块使用,我们可以在源文件src目录下写scss文件,然后通过webpack编译成css文件到输出目录public,这个目录 ...
- WebPack系列:Webpack编译的代码如何在tomcat中使用时静态资源路径不对的问题如何解决
问题: 使用webpack+vue做前端,使用tomcat提供api,然后npm run build之后需要将编译,生成如下文件: | index.html \---appserver ...
- Gcc的编译流程分为了四个步骤:
http://blog.csdn.net/xiaohouye/article/details/52084770(转) Gcc的编译流程分为了四个步骤: 1.预处理,生成预编译文件(.文件): Gcc ...
- 编译流程,C开发常见文件类型名
编译流程 我们常说的编译是一个整体的概念,是指从源程序到可执行程序的整个过程,实际上,C语言编译的过程可以进一步细分为预编译->编译->汇编->链接 预编译是把include关键字所 ...
- Nginx模块开发1_明白自定义模块的编译流程
自定义模块的编译流程 --add-module参数 configure使用--add-module参数指定添加模块目录. config脚本 由--add-module指定的目录保存为$ngx-addo ...
随机推荐
- Android Spinner值不显示,选择列表正常
你在给adapter设置数据时,如果你是静态数据,也就是死数据,那么spinner显示没有问题,但是你如果异步进行网络请求,或者使用Volley请求的时候就要注意,你的adapter设置要在onRes ...
- ImportError: No module named 'request'
使用系统自带的Python 2.7执行python时出现ImportError: No module named 'request'这样的报错,这是系统自带的Python没有requests库,这里可 ...
- ubuntu16.04 查询ip,网关,dns信息
用ifconfig命令只能查询ip,子网掩码信息,不能获取dns和网关信息 用下面命令即可查询 nmcli dev show
- bzoj 4765: 普通计算姬
Description "奋战三星期,造台计算机".小G响应号召,花了三小时造了台普通计算姬.普通计算姬比普通计算机要厉害一些 .普通计算机能计算数列区间和,而普通计算姬能计算树中 ...
- Golang中的坑二
Golang中的坑二 for ...range 最近两周用Golang做项目,编写web服务,两周时间写了大概五千行代码(业务代码加单元测试用例代码).用Go的感觉很爽,编码效率高,运行效率也不错,用 ...
- 冲顶大会APP技术选型及架构设计
我在1月4日看到虎嗅推送"王思聪撒币"的消息,然后开始推敲背后技术.其中涉及直播流.实时弹幕.OAuth2.0开放授权.SMS api.Push网关.支付接口等业务,其技术实现并不 ...
- java RTTI笔记 之Class学习笔记(摘自java编程思想)
1.java 使用Class对象来执行其RTTI.java 中每个类在编译后都会对应产生一个Class对象(更恰当地说是被保存在一个同名的.class文件中),甚至void和基本类型也都对应一个cla ...
- KVO键值观察的具体实现
1.KVO简介 KVO是Objective-C对观察者设计模式的一种实现,它提供一种机制,指定一个被观察对象(如A类),当对象中的某个属性发生变化的时候,对象就会接收到通知,并作出相应的处理.在MVC ...
- JDK中AbstractQueuedSynchronizer应用解析
这个类首先是一个抽象类,定义了一个模板,很多java同步相关的类(ReetrantLock.Semaphore.CountDownLatch等)都是基于AbstractQueuedSynchroniz ...
- Spark 学习笔记大纲
Spark 内核 第28课:Spark天堂之门解密 (点击进入博客)从 SparkContext 创建3大核心对象开始到注册给 Master 这个过程中的源码鉴赏 第29课:Master HA彻底解密 ...