关于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的更多相关文章

  1. 如何开发webpack plugin

    继上回介绍了如何开发webpack loader 之后.趁热打铁,来继续看下webpack另一个核心组成:plugin. 下面也和loader一样,让我们一起从基本的官方文档着手看起. loader和 ...

  2. 怎样写一个webpack loader

    div{display:table-cell;vertical-align:middle}#crayon-theme-info .content *{float:left}#crayon-theme- ...

  3. 手把手教你撸一个 Webpack Loader

    文:小 boy(沪江网校Web前端工程师) 本文原创,转载请注明作者及出处 经常逛 webpack 官网的同学应该会很眼熟上面的图.正如它宣传的一样,webpack 能把左侧各种类型的文件(webpa ...

  4. vue(9)—— 组件化开发 - webpack(3)

    前面两个终于把webpack相关配置解析完了.现在终于进入vue的开发了 vue组件化开发预热 前期准备 创建如下项目: app.js: footer.js: main.js: webpack.con ...

  5. vue(8)—— 组件化开发 - webpack(2)

    webpack的常用loder和插件 loder和插件是什么,现在暂且不表,看到后面你就懂了 引入css问题 直接用link标签导入css 在前面的 vue(7)—— 组件化开发 — webpack( ...

  6. 揭秘webpack loader

    前言 Loader(加载器) 是 webpack 的核心之一.它用于将不同类型的文件转换为 webpack 可识别的模块.本文将尝试深入探索 webpack 中的 loader,揭秘它的工作原理,以及 ...

  7. 案例实战之如何写一个webpack loader

    通过以下几个实例掌握webpack loader的写法 1.写一个多语言替换的loader 在index.js在页面上插入了一个{{title}}文本,我们需要在打包的时候将其替换成对应的多语言 fu ...

  8. 发布一个npm包(webpack loader)

    发布一个npm包,webpack loader: reverse-color-loader,实现颜色反转. 初始化项目 mkdir reverse-color-loader cd ./reverse- ...

  9. webpack loader & pulgin

    webpack loader & plugin https://webpack.js.org/concepts/loaders/ https://webpack.js.org/concepts ...

随机推荐

  1. 结对编程1 (四则运算基于GUI)

    https://git.coding.net/Luo_yujie/sizeyunsuan.app.git 201421123034 201421123032 1. 需求分析 这次作业新引用了语言选择, ...

  2. 201521123051《Java程序设计》第十三周学习总结

    1. 本周学习总结 以你喜欢的方式(思维导图.OneNote或其他)归纳总结多网络相关内容. 2. 书面作业 1. 网络基础 1.1 比较ping www.baidu.com与ping cec.jmu ...

  3. 201521123070《Java程序设计》 第11周学习总结

    本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结多线程相关内容. 书面作业 本次PTA作业题集多线程 互斥访问与同步访问 完成题集4-4(互斥访问)与4-5(同步访问) 1.1 除了使用 ...

  4. sublime text3 好用的插件!!!

    1.首先,你要保证sublime有Package Control,所以,如果没有,那么将Ctrl+`打开sublime控制台,将下列代码复制进去! import urllib.request,os; ...

  5. dup和dup2详解

    C语言中dup和dup2函数的不同和使用 发表时间: 2012年11月15日 | 作者: 陈杰斌 | 所属分类: C语言 | 评论: 0 | 浏览: 1024 在unix高级编程中有介绍dup和dup ...

  6. bookStore第三篇【用户模块、购买模块、订单模块】

    用户模块 要登陆后才能购买,因此我们先写购买模块 设计实体 private String id; private String username; private String password; p ...

  7. Struts2第十二篇【模型驱动】

    什么是模型驱动 在Struts2中模型驱动就是用来封装数据的..完成数据的自动封装. 为什么要使用模型驱动? 我们之前就使用过Sturts2的数据自动封装功能,是用params拦截器完成的-既然有了p ...

  8. Shiro初识与总结

    1.1简介 Apache Shiro是一个强大且易用的Java安全框架,执行身份验证.授权.密码学和会话管理.使用Shiro的易于理解的API,您可以快速.轻松地获得任何应用程序,从最小的移动应用程序 ...

  9. Servlet 3.0 使用注解配置URl提示404错误

    我的环境是  Eclipse oxygen + Servlet 3.0 因为3.0已经开始使用注解了 之前我都是配置listenner 还有Servlet mapping  在 web.xml 中 就 ...

  10. oracle11g 体系结构详解

    1.oracle内存由SGA+PGA所构成 2.oracle数据库体系结构数据库的体系结构是指数据库的组成.工作过程与原理,以及数据在数据库中的组织与管理机制. oracle工作原理: 1).在数据库 ...