认识Webpack
认识Webpack
网上已经有不少Webpack教程入门教程了。 本文记录了我以我的方式方法、思路认识了解Webpack。从官方的Tutorial入手,不断提出问题、解决,一步一步认识Webpack。
从早期的自己写脚本,到现在的各种构建工具,前端工程化已经发展到新的阶段了。
早先在百度地图的时候,地图代码用PHP进行简单粗放的处理。这个阶段算是最原始的自己写脚本处理。后来我用Ruby写了一套集合了开发、动态合并、mock数据、一键build的工具。这算是更进了一步。
现在基于Nodejs的任务管理工具Grunt、Glup都提供了代码合并、压缩、各种JS Transpiler、CSS预处理、各种前端模板的处理。
在Grunt、Gulp中是通过第三方库进行编译的。 在Webpack中也是类似的,只不过是增加了Loader的概念。通过一系列“Loader”完成处理。 处理之后统一输出为JS代码。
初步认识
在深入之前,你需要先照着官方教程实践一下。有个感性的认识。 完成教程的getting started部分后,你可以初步得出以下结论:
- Webpack是一个用来打包js工程的工具。官方定义为
Module bundler
- Webpack命令行参数可以配置到名为
webpack.config.js
(或webpackfile
)的配置文件中 - Webpack提供一个可以检测文件变化并编译然后刷新浏览器的
webpack-dev-server
那么问题来了: 对于如Grunt、Webpack这种通过配置工作的工具来说,有哪些配置可用,配置的行为、配置的可选值,需要完备的文档才好会用。 幸好Webpack官网提供了详尽的文档
下面是主要配置项的简要说明
context 工程目录,必须是绝对路径
entry 打包生成的bundle。可以是多个
output 生成的文件配置选项
output.filename 生成的文件名模板,比如 "[name].bundle.js"
output.path 生成的文件目录,绝对路径
output.publicPath 线上静态资源目录
output.chunkFilename 代码块文件名模板
output.sourceMapFilename source-map文件名模板。默认是[file].map
output.devtoolModuleFilenameTemplate
output.devtoolFallbackModuleFilenameTemplate
output.devtoolLineToLine
output.hotUpdateChunkFilename
output.hotUpdateMainFilename
output.jsonpFunction JSONP异步加载代码块(chunk)时JSONP函数名,默认是webpackJsonp
output.hotUpdateFunction JSONP异步热更新代码块时JSONP函数名,默认是webpackHotUpdate
output.pathinfo 是否以注释形式在require中增加模块path信息
output.library bundle作为库输出,值为库名
output.libraryTarget 输出库的格式。比如可选amd,umd,commonjs等
output.umdNamedDefine
output.sourcePrefix
output.crossOriginLoading
module
module.loaders Loader配置
module.preLoaders, module.postLoaders preLoader和postLoader配置
module.noParse 不需要loader编译的文件
resolve 模块决议配置
resolve.alias 模块别名
resolve.root 模块根目录,绝对路径
resolve.modulesDirectories 模块目录,工作方式类似node_modules。默认值是["web_modules", "node_modules"]
resolve.fallback 如果在root和modulesDirectories都找不到,会在这里搜索
resolve.extensions 用于模块查找的扩展名。
resolve.packageMains
resolve.packageAlias
resolve.unsafeCache
resolveLoader 与resolve类似,不过是给loader模块决议使用的配置
resolveLoader.moduleTemplates
externals
target 目标环境,代码是用于web还是node还是electron环境等等
bail
profile 每个模块的时间打点信息
cache 是否开启编译缓存以提高性能。watch模式默认开启
debug 设置loaders为debug模式
devtool 用于方便调试的开发工具选项。比如source-map方便调试混淆后的代码
devServer 传给webpack-dev-server的参数
node 传递给node作为polyfills和mocks的参数
amd require.mad和define.amd对应的值。比如{jQuery:true}
loader 提供给loader的额外信息
recordsPath, recordsInputPath, recordsOutputPath
plugins 插件配置
Loaders
我们最关心的是有哪些loader可以用呢? 通过在 https://github.com/webpack 搜索项目名中包含-loader
。我找到了这些官方提供的loader:
#裸数据
raw-loader
#脚本代码
coffee-loader
script-loader
#样式相关
css-loader
style-loader
less-loader
#html相关
html-loader
jade-loader
#json相关
json-loader
json5-loader
#其他
worker-loader-loader imports-loader exports-loader source-map-loader coffee-redux-loader multi-loader react-proxy-loader expose-loader url-loader node-loader bundle-loader val-loader transform-loader jshint-loader null-loader coverjs-loader
咦,为什么有一个css-loader还有一个style-loader?css-loader是用来加载css文件的 style-loader是用来应用已经加载的css中的样式的。
在配置文件中,配置需要使用的loader。test
用来对文件名进行匹配测试,匹配成功的文件会用对应的loader处理。
module: {
loaders: [
{ test: /\.coffee$/, loader: "coffee-loader" },
{ test: /\.js$/, loader: "jsx-loader" }
]
},
每个loader都有自己独特的配置,需要参考对应文档。 所有loader都可以配置一下项目:
test 用来对文件名进行匹配测试
exclude 被排除的文件名
include 包含的文件名
loader 叹号分割的loaders
loaders loader数组
比如babel的配置就有query、cacheDirectory配置项。
可以想象,loader要做的工作无非就是拿到源码,根据参数配置进行变换,返回变换后的结果。看一下less-loder
的源代码:
/**
* 简化后的伪代码
*/
var less = require("less");
var loaderUtils = require("loader-utils");
module.exports = function(source){
//解析loader的query string
var query = loaderUtils.parseQuery(this.query);
//默认less编译配置
var config = {
filename: this.resource,
compress: !!this.minimize
};
//将query中的配置merge到默认配置中
Object.keys(query).forEach(function(attr){
config[attr] = query[attr]
});
//编译less
var cb = this.callback;
less.render(source, config, function(e, result){
cb(null, result.css, result.map);
});
};
基本上就是从query读取配置,调用less编译器编译源码。
官网编写loader的教程验证了上述想法。同时也指出了编写loader时要注意的一些问题。
参考:官方给出的已有loader列表
Plugins
有哪些plugin呢? 通过在 https://github.com/webpack 搜索项目名中包含-plugin
我找到了这些官方提供的plugin:
extract-text-webpack-plugin
compression-webpack-plugin
i18n-webpack-plugin
component-webpack-plugin
感觉不对啊,那个很多教程中常见的UglifyJsPlugin
都没有看到啊!那么只有一个可能,这些plugin都是内置的。在源代码中一定能找到。clone下来webpack的代码。打开lib,满眼都是XXXPlugin。在optimize目录下可以找到UglifyJsPlugin
。大致看一下这些代码可以发现,每个Plugin的原型上都有一个apply函数:
/**
* 从UglifyJsPlugin.js简化而来的伪代码
*/
...
var uglify = require("uglify-js");
...
UglifyJsPlugin.prototype.apply = function(compiler) {
...
compiler.plugin("compilation", function (module) {
...
var input = asset.source();
var ast = uglify.parse(input);
//压缩
if (options.compress !== false) {
var compress = uglify.Compressor(options.comrpess);
ast = ast.transform(compress);
}
//混淆
if (options.mangle !== false) {
ast.mangle_names();
uglify.mangle_properties(ast);
}
//重新从ast生成代码
var result = uglify.OutputStream();
ast.print(result);
});
};
可以想象,webpack会根据配置文件中plugins数组中的插件实例,调用其apply函数。 在apply函数中,插件对感兴趣的事件(官方叫做stage)注册处理函数(plugin
)。比如UglifyJsPlugin
就是在compilation
事件触发时,对源代码进行压缩混淆。
通过官网阅读how-to-write-a-plugin可以验证了上面的想法。
既然有compilation
事件,那肯定还有其他事件喽。在lib目录下搜索源代码中的compile.plugin
调用
$ ack -Q compiler.plugin( | grep plugin|gawk "{print($2)}"|sort|uniq
compiler.plugin("additional-pass",
compiler.plugin("after-compile",
compiler.plugin("after-environment",
compiler.plugin("after-resolvers",
compiler.plugin("compilation",
compiler.plugin("compile",
compiler.plugin("context-module-factory",
compiler.plugin("done",
compiler.plugin("emit",
compiler.plugin("entry-option",
compiler.plugin("environment",
compiler.plugin("invalid",
compiler.plugin("make",
compiler.plugin("normal-module-factory",
compiler.plugin("run",
compiler.plugin("should-emit",
compiler.plugin("this-compilation",
compiler.plugin("watch-run",
一共有18个事件。官方教程中只介绍了done,compilation,emit
三个。 用同样的方法,我们还可以查出compilation
支持的事件:
$ ack -Q compilation.plugin( | grep plugin|gawk "{print($2,$3)}"|sort|uniq
compilation.plugin("additional-assets", function(callback)
compilation.plugin("additional-chunk-assets", function()
compilation.plugin("after-hash", function()
compilation.plugin("after-optimize-chunk-assets", function(chunks)
compilation.plugin("after-optimize-tree", function(chunks,
compilation.plugin("before-module-ids", function(modules)
compilation.plugin("build-module", function(module)
compilation.plugin("chunk-hash", function(chunk,
compilation.plugin("failed-module", moduleDone);
compilation.plugin("need-additional-pass", function()
compilation.plugin("normal-module-loader", function(context,
compilation.plugin("normal-module-loader", function(loaderContext)
compilation.plugin("normal-module-loader", function(loaderContext,
compilation.plugin("optimize-assets", function(assets,
compilation.plugin("optimize-chunk-assets", function(chunks,
compilation.plugin("optimize-chunk-ids", function(chunks)
compilation.plugin("optimize-chunk-order", function(chunks)
compilation.plugin("optimize-chunks-advanced", function(chunks)
compilation.plugin("optimize-chunks-basic", function(chunks)
compilation.plugin("optimize-module-order", function(modules)
compilation.plugin("optimize-modules-advanced", function(modules)
compilation.plugin("optimize-tree", function(chunks,
compilation.plugin("record", function(compilation,
compilation.plugin("record-chunks", function(chunks,
compilation.plugin("record-modules", function(modules,
compilation.plugin("revive-chunks", function(chunks,
compilation.plugin("revive-modules", function(modules,
compilation.plugin("seal", function()
compilation.plugin("should-generate-chunk-assets", function()
compilation.plugin("should-record", function()
compilation.plugin("succeed-module", moduleDone);
compilation.plugin(["optimize-chunks", "optimize-extracted-chunks"],
compilation.plugin(["optimize-chunks-basic", "optimize-extracted-chunks-basic"],
有了这两个列表,在自己编写插件就可以有的放矢地参考源代码了。
参考:官方给出的已有plugin的列表
Webpack-dev-server
Webpack提供一个小巧的基于express的开发服务器。支持自动刷新、模块热替换。还有代理。具体如何配置在这里。
代理(proxy
)在开发是还是很有用的。你可以将动态请求映射到后端的开发机,方便联调。
总结
现在照着官方教程你已经可以简单地使用Webpack了。下一步要做的是
- 了解webpack.config.js中如何配置,有哪些要注意的(比如路径)
- 实践常用的Loader和Plugin
- 实践webpack的众多配置项
- 实践使用webpack-dev-server进行开发
需要时可以更进一步:
- 学习如何编写Loader和Plugin
- 阅读已有Loader和Plugin的源码
- 在源码中了解上面列出的stages的含义
更新:Webpack、Browserify和Gulp三者之间到底是怎样的关系?
下面是我在知乎的回答:
Task Runner
Gulp、Grunt和Make(常见于c/cpp)、Ant、Maven、Gradle(Java/Android)、Rake、Thor(Ruby)一样,都是是Task Runner。用来将一些繁琐的task自动化并处理任务的依赖关系。 其中有些是基于配置描述的,描述逻辑比较费劲,比如Ant基于xml。还有些就是代码,比较灵活,个人偏好这种。比如Rake、Thor、Gulp、Gradle。对于Gradle来说也有些蛋疼。因为它本身是Groovy的DSL。如果要深入使用,你还得学一下Groovy语言。其他就好多了Rake、Thor就是写Ruby;Gulp就是JavaScript。相对门槛低很多。
模块化解决方案
Browserify It provides a way to bundle CommonJS modules together, adheres to the Unix philosophy(小工具协作), is in fact a good alternative to Webpack. Webpack takes a more monolithic(整体解决、大而全) approach than Browserify... is relies on configuration.
上面这些工具在功能上有交集:代码的Minify、Concat;资源预处理等;
其实每个工具的官网上都有对工具的设计思想、要解决的问题、与其他工具的对比。自己摘抄下来,做个表格对比一下。高亮出每个工具独特的特性。这样你就知道什么时候需要用哪个工具了。 比如,你的工程模块依赖很简单,不需要把js或各种资源打包,只需要简单的合并、压缩,在页面中引用就好了。那就不需要Browserify、Webpack。Gulp就够用了。
反过来,如果你的工程庞大,页面中使用了很多库(SPA很容易出现这种情况),那就可以选择某种模块化方案。至于是用Browserify还是Webpack就需要根据其他因素来判断了。比如团队已经在使用了某种方案,大家都比较熟悉了。再比如,你喜欢Unix小工具协作的方式,那就Browserify。
充分了解各种工具、方案,选择合适的和自己需要的。没有绝对的好。优点换了场景也会变成缺点。
UPDATE
下面是闲耘™用Makefile管理前端工程任务的例子: https://github.com/hotoo/pinyin/blob/master/Makefile
更多资料:
认识Webpack的更多相关文章
- js学习笔记:webpack基础入门(一)
之前听说过webpack,今天想正式的接触一下,先跟着webpack的官方用户指南走: 在这里有: 如何安装webpack 如何使用webpack 如何使用loader 如何使用webpack的开发者 ...
- webpack之傻瓜式教程
接触webpack也有挺长一段时间了,公司的项目也是一直用着webpack在打包处理,但前几天在教新人的情况下,遇到了一个问题,那就是:尽管网上的webpack教程满天飞,但是却很难找到一个能让新人快 ...
- 细说前端自动化打包工具--webpack
背景 记得2004年的时候,互联网开发就是做网页,那时也没有前端和后端的区分,有时一个网站就是一些纯静态的html,通过链接组织在一起.用过Dreamweaver的都知道,做网页就像用word编辑文档 ...
- Webstorm+Webpack+echarts构建个性化定制的数据可视化图表&&两个echarts详细教程(柱状图,南丁格尔图)
Webstorm+Webpack+echarts ECharts 特性介绍 ECharts,一个纯 Javascript 的图表库,可以流畅的运行在 PC 和移动设备上,兼容当前绝大部分浏览器(I ...
- 使用webstorm+webpack构建简单入门级“HelloWorld”的应用&&引用jquery来实现alert
使用webstorm+webpack构建简单入门级"HelloWorld"的应用&&构建使用jquery来实现 1.首先你自己把webstorm安装完成. 请参考这 ...
- webpack入门教程之Hello webpack(一)
webpack入门教程系列为官网Tutorials的个人译文,旨在给予想要学习webpack的小伙伴一个另外的途径.如有不当之处,请大家指出. 看完入门教程系列后,你将会学习到如下内容: 1.如何安装 ...
- webpack的使用
1.webpack是什么? 打包前端项目的工具(为项目提高逼格的东西). 2.webpack的基本命令 webpack#最基本的启动webpack命令 webpack-w #提供watch方法,实时进 ...
- Webpack 配置摘要
open-browser-webpack-plugin 自动打开浏览器 html-webpack-plugin 通过 JS 生成 HTML webpack.optimize.UglifyJsPlugi ...
- Vue + Webpack + Vue-loader 系列教程(2)相关配置篇
原文地址:https://lvyongbo.gitbooks.io/vue-loader/content/ 使用预处理器 在 Webpack 中,所有的预处理器需要和一个相应的加载器一同使用.vue- ...
- Vue + Webpack + Vue-loader 系列教程(1)功能介绍篇
原文地址:https://lvyongbo.gitbooks.io/vue-loader/content/ Vue-loader 是什么? vue-loader 是一个加载器,能把如下格式的 Vue ...
随机推荐
- .net 平台下, Socket通讯协议中间件设计思路(附源码)
.net 平台下,实现通讯处理有很多方法(见下表),各有利弊: 序号 实现方式 特点 1 WCF 优点:封装好,方便.缺点:难学,不跨平台 2 RocketMQ,SuperSocket等中间件 优点: ...
- JAVA中的 static使用
主要内容: 1.静态变量 2.静态方法 3.静态代码块 静态变量 我们知道,可以基于一个类创建多个该类的对象,每个对象都拥有自己的成员,互相独立.然而在某些时候,我们更希望该类所有的对象共享同一个成员 ...
- 关于FPGA的一些你必须知道的概念
前仿真也称为功能仿真,主旨在于验证电路的功能是否符合设计要求,其特点是不考虑电路门延迟与线延迟,主要是验证电路与理想情况是否一致.可综合FPGA代码是用RTL级代码语言描述的,其输入为RTL级代码与T ...
- Jquery_基础(二) 包装集
包装集 <body> <div id="a01">1.包装集——length</div> <div id="a02"& ...
- Codeforces 888E Maximum Subsequence
原题传送门 E. Maximum Subsequence time limit per test 1 second memory limit per test 256 megabytes input ...
- [国嵌攻略][136][DM9000网卡驱动深度分析]
网卡初始化 1.分配描述结构,alloc_etherdev 2.获取平台资源,platform_get_resource 2.1.在s3c_dm9k_resource中有相关的资源 2.2.add地址 ...
- HDU 1979 Red and Black
题目: There is a rectangular room, covered with square tiles. Each tile is colored either red or black ...
- Oracle_字段数据类型
Oracle_字段数据类型 数据库表字段的数据类型 字符数据类型 CHAR:存储固定长度的字符串 VARCHAR2 :存储可变长度的字符串 数值数据类型 NUMBER:存储整数和浮点数,格式为NUMB ...
- bat脚本设置系统环境变量即时生效
关于bat的资料多但零碎,记录一下. 1.设置环境变量即时生效:通过重启explorer来实现即时生效(亲测有效) @echo off set curPath=%cd% wmic ENVIRONMEN ...
- 关于STM32驱动DS1302实时时钟的一点思考
之前用51驱动过DS1302,没用多久就输出了正确的时间.当时以为这块芯片其实没啥,很简单.但是现在用STM32做项目,用到同样的芯片,以为这有何难,只要把那个程序拿过来复制黏贴改一下IO设置不就行了 ...