Open lcxfs1991 opened 8 years ago
讲得不错,对新开发一个webpack插件有启发
:) 。第二篇得探索一下如何利用webpack的缓存机制。
mark
多谢博主分享,刚刚开始学webpack,先mark下
博主,能概括说下,loader 和 plugin 有什么区别吗,或者他们能力范围有什么不同?
loader一般是用来处理文件语言的编译,例如sass -> css, babel转es6->es5。plugin的功能则强大的得多,能调用许多webpack提供的能力,如果处理构建流程中的事件,例如丑化代码、去重、code splitting都是通过plugin去处理。
@e-cloud 暂时没有,后续加上
@e-cloud 可以参考一下官方的 extract text plugin
请教一个问题,我现在需要吧每个chunk上传到公司CDN静床,上传之后会返回一个没有规则但唯一的URL。请问如何load这些chunk? webpack的output.publicPath是指定chunk的根目录,但我们的CDN静床没有目录的概念。
@JonneyYan 能给具体例子吗
比如说:用Code Split分出来chunk.1.js、chunk.2.js两个包,output.publicPath = 'http://cdn.a.com/',bundle.js会在app运行时异步加载http://cdn.a.com/chunk.1.js和http://cdn.a.com/chunk.2.js
但是我需要的是把chunk.1.js、chunk.2.js上传到一个网站上,这个网站会返回这两个文件的URL(http://abc.com/sajdhkjhf.js和http://abc.com/askjdhj12kj32.j,文件名没有规则),如何设置才能让bundle.js加载这两个地址的文件?
这样子的 话,可能你得在拿到url之后,通过插件将加载地址写进去
请问编写webpack 插件,如何更好的断点调试,请问有什么好的办法?
调试工具吗?node-inspector, webstorm, vscode 还是其他因素?
marks,read it when needed
@lcxfs1991 你好,我最近也遇到一个比较难于处理的问题。
简单来说,在我的项目中,前端需要输出 .pug 模板文件给后端,由后端传入一些变量去动态渲染出html。 并且,前端输出的 .pug 文件需要替换好 webpack 编译输出的 js/css 文件的访问路径,同时保持整个模板文件目录的结构。
这一点我通过在emit事件中读取 .pug 文件,匹配相应的js/css文件,复制加入到assets当中,勉强解决了。
不过还有的问题就是,模板文件实际上并没有经过 webpack 去处理资源的依赖,这就导致了模板文件中存在的图片资源的依赖无法解析并交由 webpack 去内联或者添加 hash
我想请教一下,要出如何编写插件,才能在编译之前将 .pug 文件加入到 webpack 的处理流程中,图片资源的依赖关系,然后在编译之后读取出来?或者说有什么更好的处理方法?
@Tk-archer 可以参考html-webpack-plugin的源码,里面有做处理。留意一下它源码里vm的作用
@lcxfs1991 感谢回复,已经解决了。
我发现其实就算是通过 html-webpack-plugin 类似的方式将模板加入 webpack 处理模块中,还是不够的,还需要一个 loader 去触发解析过程,不然的话只会源文件返回。可以试试直接用 html-webpack-plugin 通过模板文件而不添加相应的 loader 就能看得见我说的这个行为。
所以我最终的解决方案是,既然已经要遍历模板文件了,索性直接自己解析,因为实际上要解析的依赖只有 img 的依赖,还是相对单一好解析,只要吧路径解析出来,剩下的其实就是把 url-loader 的代码搬到这里处理一边,该内联的内联,该给hash的给hash。
恩,html-webpack-plugin有调用loader的功能。
@Tk-archer 我参考了html-webpack-plugin的代码,可以提取image了,但缺点是会经过各种loader的处理,有时候可能不可控。
mark
关于webpack的 Compiler plugin的任务点是 compile -> make -> ... 你的图列有误!
详见 Compiler.js
mark
您好,问一下有没有什么方法或工具可以在插件代码里打断点调试?是只能通过console.log或table来查看吗?
@zhaihaoran vscode给node打断点可以试下
请问编写webpack 插件,如何更好的断点调试,请问有什么好的办法?
在node_modules中找到webpack/bin/webpack.js文件顶部加入一行代码,便于调试,
chrome://inspect在你需要的地方打上debugger;
mark
mark
mark
前言
最近由于用着html-webpack-plugin觉得很不爽,于是乎想自己动手写一个插件。原以为像gulp插件一样半天上手一天写完,但令人郁闷的是完全找不到相关的文章。一进官方文档却是被吓傻了。首先是进入how to write a plugin看了一页简单的介绍。然后教程会告诉你,你需要去了解compiler和compilation这两个对象,才能更好地写webpack的插件,然后作者给了github的链接给你,让你去看源代码,我晕。不过幸好最后给了一个plugins的API文档,才让我开发的过程中稍微有点头绪。
how to write a plugin这个教程还是可以好好看看的,尤其是那个simple example,它会教你在compilation的emit事件或之前,将你需要生成的文件放到webpack的compilation.assets里,这样就可以借助webpack的力量帮你生成文件,而不需要自己手动去写fs.writeFileSync。
主要就是这段代码
基本特性介绍
首先,定义一个函数func,用户设置的options基本就在这里处理。
其次,需要设一个func.prototype.apply函数。这个函数是提供给webpack运行时调用的。webpack会在这里注入compiler对象。
compiler对象
输出complier对象,你会看到这一长串的内容(如下面代码),初步一看,我看出了两大类(有补充的可以告诉我)。一个webpack运行时的参数,例如_plugins,这些数组里的函数应该是webpack内置的函数,用于在compiltion,this-compilation和should-emit事件触发时调用的。另一个是用户写在webpack.config.js里的参数。隐约觉得这里好多未来都可能会是webpack暴露给用户的接口,使webpack的定制化功能更强大。
除此以外,compiler还有一些如run, watch-run的方法以及compilation, normal-module-factory对象。我目前用到的,主要是compilation。其它的等下一篇有机会再说。
compiler还有compiler.plugin函数。这个相当于是插件可以进行处理的webpack的运行中的一些任务点,webpack就是完成一个又一个任务而完成整个打包构建过程的。如下图:![task](https://cloud.githubusercontent.com/assets/3348398/13768093/f46acd18-eaac-11e5-8895-a20a48e0972c.png)
其它的任务点如invalid, after-plugins, after-resolvers具体可参考 compiler对象。
compilation对象
至于compilation,它继承于compiler,所以能拿到一切compiler的内容(所以你也会看到webpack的options),而且也有plugin函数来接入任务点。在compiler.plugin('emit')任务点输出compilation,会得到大致下面的对象数据,因为实在太长,我只保留了最重要的assets部份,如下
assets部份重要是因为如果你想借助webpack帮你生成文件,你需要像官方教程how to write a plugin在assets上写上对应的文件信息。
除此以外,compilation.getStats()这个函数也相当重要,能得到生产文件以及chunkhash的一些信息,如下:
这里的chunks数组里,是对应会生成的文件,以及md5之后的文件名和路径,里面还有文件对应的chunkhash(每个文件不同,但如果你使用ExtractTextPlugin将css文件独立出来的话,它会与require它的js入口文件共享相同的chunkhash),而assets.hash则是统一的hash,对每个文件都一样。值得关注的是chunks里的每个文件,都有source这一项目,提供给开发者直接拿到源文件内容(主要是js,如果是css且使用ExtractTextPlugin,则请自行打印出来参考)。
例子
接下来,会以最近我写的一个插件html-res-webpack-plugin作为引子,来介绍基本的写插件原理。插件的逻辑就写在index.js里。
首先,将用户输入的参数在定好的函数中处理,HtmlResWebpackPlugin。
然后,新增apply函数,在里面写好插件需要切入的webpack任务点。目前HtmlResWebpackPlugin插件只用到emit这个任务点,其它几个仅作为演示。
第三步,调用addFileToWebpackAsset方法,写compilation.assets,借助webpack生成html文件(项目里最新版本新增了添加favicon的功能,因此有2个addFileToWebpackAsset的方法)。这里的核心就是本文一开始那段给compilation.assets添加source和size的代码。
第四步,在开发模式下(isWatch = true),直接生成html,但在生产模式下(isWatch = true),插件会开始对静态资源(js,css)进行md5或者内联。项目用了
_this.options.isWatch
去进行判断。第五步,调用findAssets方法是为了通过compilation.getStats()拿到的数据,去匹配对应的静态资源,还有找到对应的哈希(是chunkhash还是hash)。
最六步,调用addAssets方法,对静态资源分别做内联或者md5文件处理。内联资源的函数是inlineRes,你会看到我使用了compilation.assets[hashFile].source() 及 compilation.assets[hashFile].children[1]._value。前者是针对于js的,后者是针对使用了ExtractTextPlugin的css资源。
最后一步,即是内联和md5完成后,再更新一下compilation.assets中对应生成html的source内容,才能正确地生成内联和md5后的内容。这一步在addAssets方法里有一处代码如下:
后记
有兴趣可以试用一下html-res-webpack-plugin这个插件(为什么要写一个新的html生成插件,我在readme里写了,此处不赘述),看看有哪些用得不爽之处。目前只是第一版,还不适合用于生产环境。希望第二版的时候能适用于更多的场景,以及性能更好。到是,我也会写第二篇插件开发文章,将本文还没提到的地方一一补充完整。也欢迎大家在这里发贴,或者指出本人的谬误之处。