如何开发webpack loader
关于webpack
作为近段时间风头正盛的打包工具,webpack基本占领了前端圈。相信你都不好意思说不知道webpack。
有兴趣的同学可以参考下我很早之前的webpack简介 .
确实webpack万事万物皆模块的思路真是极大的方便了我们的开发,将css,图片等文件都能打包的功能离不开形形色色的loader。
对于一个事情要知其然更要知其所以然,抱着这个心态我们一起来看下loader的相关知识及如何开发。
学习方法
对于一个新事物最好的学习方法,我认为是其官方文档。对于loader,将其官方文档看一遍,就知道如何开发最简单的loader了。
只是其官方文档是英文的,我就顺手翻译了一下,一方面加深自己理解。另一方面为其他同学提供个参考。
我相信看完文档你就知道如何开发一个loader了。
什么是loader
loader是一个对面暴露一个方法的node包.当遇到某些资源需要被转换时调用该方法。
简单情况
只有一个loader来处理某个文件时,该loader被调用时只有一个参数,这个参数是该文件的内容转化之后的字符串。
loader在function执行时可以通过this context来访问laoder API 以便更高效的开发。
一个仅仅需要一个值的同步loader可以简单的return 自己。其他情况下,loader可以通过this.callback(err, values...)返回一系列的值。error同样传递给this.callback或者在loader中抛出。
loader期望返回1-2个值,第一个是处理之后作为string或者buffer返回的js代码。第二个是SourceMap或者js 对象
复杂情况:
当多个loader被链式调用时,只有最后一个loader获得资源文件。
同时只有第一个loader被期望返回1-2个值(即上面提到的JavaScript和SourceMap)。
其他loader接收值由上一个loader传递。
换句话说,链式loader执行顺序从右至左或者自下而上。
举个栗子:下面这段代码的执行顺序就是自下而上 foo-loader==>bar-loader
module: {
loaders: [
{
test: /\.js/,
loaders: [
'bar-loader',
'foo-loader'
]
}
]
}
注意:当前weboack只会在nodemodules文件夹下面搜索你指定的loader
如果你的文件夹不在该目录下需要在config下面增加一项配置:
即默认访问node_modules,你的文件夹不在的话就需要手动在配置文件里加上了。
resolveLoader: {
modules: ['node_modules', path.resolve(__dirname, 'loaders')]
}
温馨提示
ps:经过自身实践发现这样写是错的,不需要通过path去解析,直接将文件目录写入即可。
一般来说loader都会发布到npm上进行管理,这种状况不用担心,但是开发阶段如果要自行测试,就面对这种情况了。
例如,我手写的myloader在loaders下面,例子如下。
resolveLoader:{
modules: ['node_modules','loader']
}
Examples
就这么简单就是个普通的loader
module.exports = function(source,map){
this.cacheable && this.cacheable()
this.value = source
return '/*copy@ xiaoxiangdaiyu*/'+JSON.stringify(source)
}
开发指南
loader需要遵循以下事项。
以下事项按优先级排列,第一条具有最高优先级。
一、单一任务
loaders可以被链式调用,为每一步创建一个loader而非一个loader做所有事情
也就是说,在非必要的状况下没有必要将他们转换为js。
例如:通过查询字符串将一个字符串模板转化为html。
如果你写了个loader做了所有事情那么你违背了loader的第一条要求。
你应该为每一个task创建一个loader并且通过管道来使用它们
- jade-loader: 转换模板为一个module
- apply-loader: 创建一个module并通过查询参数来返回结果
- html-loade: 创建一个处理html并返回一个string的模块
二、创建moulde话的模块,即正常的模块
loader产出的module应该和遵循和普通的module一样的设计原则。
举个例子,下面这样设计是不好的,没有模块化,依赖全局状态
require("any-template-language-loader!./xyz.atl");
var html = anyTemplateLanguage.render("xyz");
三、尽量表明该loader是否可以缓存
大部分loaders是cacheable,所以应该标明是否cacheable。
只需要在loader里面调用即可
// Cacheable identity loader
module.exports = function(source) {
this.cacheable();
return source;
};
四、不要在运行和模块之间保存状态
- 一个loader相对于其他编译后的模块应该是独立的。 除非其可以自己处理这些状态
- 一个loader相对于同一模块之前的编译过程应该是独立的。
五、标明依赖
如果该loader引用了其他资源(例如文件系统), 必须声明它们。这些信息用来是缓存的loader失效并且重新编译它们
var path = require("path");
module.exports = function(source) {
this.cacheable();
var callback = this.async();
var headerPath = path.resolve("header.js");
this.addDependency(headerPath);
fs.readFile(headerPath, "utf-8", function(err, header) {
if(err) return callback(err);
callback(null, header + "\n" + source);
});
};
六、解析依赖
很多语言都提供了一些规范来声明依赖,例如css中的 @import 和 url(...)。这些依赖应该被模块系统所解析。
下面是两种解决方式:
- 1、将它们转化成require
- 2、 用this.resolve方法来解析路径
下面是两个示例
- 1、css-loader: 将依赖转化成require,即用require来替换@import和 url(...),解析对其他样式文件的依赖
- 2、less-loader: 不能像css-loader那样做,因为所有的less文件需要一起编译来解析变量和mixins。因此其通过一个公共的路径逻辑来扩展less编译过程。这个公共的逻辑使用this.resolve来解析带有module系统配置项的文件。例如aliasing, custom module directories等。
如果语言仅仅接受相对urls(如css中url(file) 总是代表./file),使用~来说明成模块依赖.
url(file) -> require("./file")
url(~module) -> require("module")
七、抽离公共代码
extract common code 我感觉还是翻译成上面的标题比较好。其实所有语言都遵循该思想,即封装
不要写出来很多每个模块都在使用的代码,在loader中创建一个runtime文件,将公共代码放在其中
八、避免写入绝对路径
不要把绝对路径写入到模块代码中。它们将会破坏hash的过程当项目的根目录发生改变的时候。应该使用loader-utils的 stringifyRequest方法来绝对路径转化为相对路径。
例子:
var loaderUtils = require("loader-utils");
return "var runtime = require(" +
loaderUtils.stringifyRequest(this, "!" + require.resolve("module/runtime")) +
");";
九、使用peerDependencies来指明依赖的库
使用peerDependency允许应用开发者去在package.json里说明依赖的具体版本。这些依赖应该是相对开放的允许工具库升级而不需要重新发布loader版本。简而言之,对于peerDependency依赖的库应该是松耦合的,当工具库版本变化的时候不需要重新变更loader版本。
十、可编程对象作为查询项
有些情况下,loader需要某些可编程的对象但是不能作为序列化的query参数被方法解析。例如less-loader通过具体的less-plugin提供了这种可能。这种情况下,loader应该允许扩展webpack的options对象去获得具体的option。为了避免名字冲突,基于loader的命名空间来命名是很必要的。
// webpack.config.js
module.exports = {
...
lessLoader: {
lessPlugins: [
new LessPluginCleanCSS({advanced: true})
]
}
};
结束语
至此,如何开发一个webpack loader 我相信大家已经知道了,如果还不太清楚的话,可以移步w-loader查看。
另外,对于我这种英语渣渣来说,翻译起来确实难度蛮大的。此处抛砖引玉,希望大家共同探讨学习。
此文为原创文章,转载请注明出处!
如何开发webpack loader的更多相关文章
- 如何开发webpack plugin
继上回介绍了如何开发webpack loader 之后.趁热打铁,来继续看下webpack另一个核心组成:plugin. 下面也和loader一样,让我们一起从基本的官方文档着手看起. loader和 ...
- 怎样写一个webpack loader
div{display:table-cell;vertical-align:middle}#crayon-theme-info .content *{float:left}#crayon-theme- ...
- 手把手教你撸一个 Webpack Loader
文:小 boy(沪江网校Web前端工程师) 本文原创,转载请注明作者及出处 经常逛 webpack 官网的同学应该会很眼熟上面的图.正如它宣传的一样,webpack 能把左侧各种类型的文件(webpa ...
- vue(9)—— 组件化开发 - webpack(3)
前面两个终于把webpack相关配置解析完了.现在终于进入vue的开发了 vue组件化开发预热 前期准备 创建如下项目: app.js: footer.js: main.js: webpack.con ...
- vue(8)—— 组件化开发 - webpack(2)
webpack的常用loder和插件 loder和插件是什么,现在暂且不表,看到后面你就懂了 引入css问题 直接用link标签导入css 在前面的 vue(7)—— 组件化开发 — webpack( ...
- 揭秘webpack loader
前言 Loader(加载器) 是 webpack 的核心之一.它用于将不同类型的文件转换为 webpack 可识别的模块.本文将尝试深入探索 webpack 中的 loader,揭秘它的工作原理,以及 ...
- 案例实战之如何写一个webpack loader
通过以下几个实例掌握webpack loader的写法 1.写一个多语言替换的loader 在index.js在页面上插入了一个{{title}}文本,我们需要在打包的时候将其替换成对应的多语言 fu ...
- 发布一个npm包(webpack loader)
发布一个npm包,webpack loader: reverse-color-loader,实现颜色反转. 初始化项目 mkdir reverse-color-loader cd ./reverse- ...
- webpack loader & pulgin
webpack loader & plugin https://webpack.js.org/concepts/loaders/ https://webpack.js.org/concepts ...
随机推荐
- 【集美大学1411_助教博客】团队作业10——项目复审与事后分析(Beta版本)
写在前面的话 软件工程课结束了,大家开心吗?是不是再也不用熬夜写代码了?如果这门课你真的熬夜写代码了,相信你一定有收获,如果这门课结束了你觉得是自己一个全新的开始,那么这门课的意义就实现了.团队作业全 ...
- 201521123107 《Java程序设计》第5周学习总结
第5周作业-继承.多态.抽象类与接口 1.本周学习总结 2.书面作业 1.代码阅读:Child压缩包内源代码 1.1 com.parent包中Child.java文件能否编译通过?哪句会出现错误?试改 ...
- class中的东西和继承、多态的概念
class中的private.public.protected 最近看了一些视频顺便总结一下class中的这几个类型以及继承 public: 在C++和C#中类的用法,语法是差不多的.当变量,函数之类 ...
- 控制结构(10) 指令序列(opcode)
// 上一篇:管道(pipeline) 发现问题 在一个正式项目的开发周期中,除了源代码版本控制外,还存在着项目的配置/编译/打包/发布等各种高频但非"核心"的脚本代码.职业程序员 ...
- 201521123053《Java程序设计》第四周总结
1. 本周学习总结 1.1 尝试使用思维导图总结有关继承的知识点. 1.2 使用常规方法总结其他上课内容. 现在上课跟着老师的思路走,一般都能理解了.就是课上知识点有些难以记住. 特别讲讲这个思维导图 ...
- Eclipse rap 富客户端开发总结(14) :rap 图片、数据缓存处理
一.概述 在进行了 rap 的基本学习之后,您对 rap 的理解是否进入了更高的一个层次呢,个人觉得,对学习 rap 的人来说,进行 rap 的学习是一个探索的过程,在编程中不断的对其进行理解和分析, ...
- OSGi-入门篇之服务层(03)
前言 作为OSGi框架中最上面的一层,服务层带给了我们更多的动态性,并且使用了大家或多或少都曾了解过的面向服务编程模型,其好处是显而易见的. 1 什么是服务 简单的说,服务就是“为别人所做的工作”,比 ...
- 自学Unity3D 之 贪吃蛇 添加摄像机跟随
在Unity的世界中, 物体的位置都是由向量构成的. 今天所需要做的就是让摄像机保持跟蛇头的相对距离. 首先 设蛇头的位置在A 点 , 摄像机的位置在B 点 则 我们可以知道 他们的offse ...
- 基于React Native的移动平台研发实践分享
转载:http://blog.csdn.net/haozhenming/article/details/72772787 本文目录: 一.React Native 已经成为了移动前端技术的趋势 二.基 ...
- Pro Flight YOKE 设备键位映射踩过的坑
背景 VR游戏项目.街机游戏项目7月阶段版本快要结束了,考虑到带有键鼠外设显得逼格比较Low,所以决定采用"高大上"的专业设备来进行游戏操作. 需求 需要将键盘鼠标操作的18个键位 ...