选用合适的loader来处理不同的资源和不同的功能,以下是一些主流的loader,但这并不是全部,因为每时每刻都可能有新的loader 发布到 npm上
babe-loader 用来处理ES6+并将其编译为ESS,它使我们能够在最新的工程中使用最新语言特性,同时不必特别关注这些特性在不同平台的兼容问题
在安装时推荐使用以下命令:
npm install babel-loader /core /preset-env
在配置 babel-loader 时有一些需要注意的地方。请看下面的例子:
rules:[
{
test: /\.js$/,
exclude: /node_modules/,
use:(
loader: 'babel-loader',
options:{
cacheDirectory: true
presets: [[
'env',{
modules; false,
}
]],
},
),
}
],
由于babel-loader通常属于对所有JS后缀文件设置的规则,所以需要在exclude中添加node_modules,否则会令 babel-loader 编译其中所有的模块,这将严重拖慢打包的速度,并且有可能改变第三方模块的原有行为。
对于babel-loader本身我们添加了cacheDirectory 配置项,它会启用缓存机制在重复打包未改变过的模块时防止二次编译,同样也会加快打包的速度。cacheDirector可以接收一个字符串类型的路径来作为缓存路径,这个值也可以为 true,此时其缓存目录会指向 node_modules/.cache/babel-loader
由于@babel/preset-env会将ES6 Module转化为CommonJS 的形式,这会导致 Webpack中的 tree-shaking 特性失效**@babel/preset-env的modules 配置项设置为false会禁用模块语的转化,而将ESModule的语法交给 Webpack 本身处理。**
ts-loader 与 babel-loader 的性质类似,它是用于连接Webpack 与 Typescript的模块。可使用以下命令进行安装:
npm install ts-loader typescript
Webpack 配置如下:
rules;[
{
test: /\.ts$/,
use:'ts-loader',
}
],
需要注意的是,Typescript本身的配置并不在ts-loader 中,而是必须要放在工程录下的tsconfig.json中。
通过 Typescript 和 ts-loader,我们可以实现代码类型检查。
html-loader用于将HTML文件转化为字符串并进行格式化,这使得我们可以把一个HTML片段通过JS加载进来
安装命令如下:
npm install html-loader
Webpack配置如下
rules;[
{
test: /\.html$/,
use:'html-loader',
}
],
header.html将会转化为字符串,并通过 documentwrite 插人页面中
file-loader 用于打包文件类型的资源,并返回其 publicPath。
安装命令如下:
npm install file-loader
Webpack配置如下
const path = require(path');
module.exports =(
entry:'./app.js',
output: {
path: path.join(__dirname,'dist'),
filename: 'bundle.js',
},
module:(
rules:[
{
test: /\.(png|jpg|gif)$/,
use:'file-loader',
}
],
},
};
4
上面我们对png、jpg、gif这类图片资源使用 file-loader,然后就可以在JS中加载图片了。
import avatarImage from './avatar.jpg';console.log(avatarImage);// c6f482ac9a1905e1d7d22caa909371fc.jpg
url-loader 与 fle-loader 作用类似,唯一的不同在于用户可以设置一个文件大小阈值,当大于该阙傻时与 fle-loader一样返回 publicPath,而小于该值时则返回文件base64 形式编码。
安装命令如下:
npm install url-loader
Webpack 配置如下:
rules:[
{
test:/\.(png|jpg|gif)$/,
use:{
loader: 'url-loader',
options:{
limit: 10240,
name: '[name].[ext]',
publicPath: './assets-path/',
}
}
}
]
url-loader 可接收与 file-loader 相同的参数,如name和 publicPath 等,同时也可以接收一个 limit 参数。
vue-loader 用于处理 vue 组件:
安装命令如下;
npm install vue-loader vue vue-template-compiler css-loader
Webpack配置如下
rules;[
{
test: /\.vue$/,
use:'vue-loader',
}
],
有时会遇到现有 loader 无法很好满足需求的情况,这时就需要我们对其进行修改或者编写新的 loader。如前面代码所演示的一样,loader 本身其实非常简单,下面就从头实现一个loader
我们将实现一个loader,它会为所有JS文件启用产格模式,也就是说它会在文件头部加上如下代码:
'use strict'
在开发一个loader时,我们可以借助 npm/yarn 的软链能进行本地调试(当然之后可以考发布到 npm等)。下面让我们初始化这个loader并配置到工程中。
创建一个 force-strict-loader 目录,然后在该目录下执行 npm初始化命令
npm init -y
接着创建 index.js,也就是 loader 的主体
module.exports = function(content){
var useStrictPrefix = '\'use strict\';\n\n';
return useStrictPrefix + content;
}
现在我们可以在 Webpack 工程中安装并使用这个 loader了。
npm install <path-to-loader>/force-strict-loader
在 Webpack工程目录下使用相对路径安装,会在项目的node modules 中创建一个指向实际 force-strict-loader 目录的软链,也就是说之后我们可以随时修改 loader源码并软链且不需要重复安装了。
下面修改 Webpack 配置
module:{
rules:[
{
test:/\.js$/,
use: 'force-strict-loader'
}
]
}
我们将这个loder设置为对所有JS 文件生效。此时对该工程进行打包应该可以看到JS文件的头部都已经加上了启用严格模式的语句。
启用缓存
当文件输入和其依赖没有发生变化时,应该让 loader 直接使用存,而不
行转换的工作。在 Webpack 中可以使用 his.cacheable 进行控制,修改我们的
module.exports = function(content){
if(this.cacheable){
this.cacheable();
}
var useStrictPrefix = '\'use strict\';\n\n';
return useStrictPrefix + content;
}
通过启用缓存可以加快 Webpack 打包速度,并且可保证相同的输人产生输出。
获取options
前文讲过,loader的配置项通过 use.options 传进来,如:
rules:[
{
test:/\.js$/,
use: {
loader:'force-strict-loader',
options:{
sourceMap: true
}
}
}
]
上面配置了一个配置项sourceMap,接下来要再loader中获取,要先安装一个依库loader-utils,安装命令如下:
npm install loader-utils
loader更新如下
var loaderUtils = require("loader-utils");
module.exports = function(content){
if(this.cacheable){
this.cacheable();
}
var options = loaderUtils.getOptions(this) || {};
var useStrictPrefix = '\'use strict\';\n\n';
return useStrictPrefix + content;
}
通过loaderUtils.getOptions可以获取到配置对象
source-map
source-map可以便于实际开发者在浏览器控制台查看源码。如果没有对source-map进行处理,最终也就无法生成正确的 map 文件,在浏览器的 dev tool中可能就会看到错乱的源码。
下面是支持了source-map特性后的版本
var loaderUtils = require("loader-utils");
var SourceNode = require("source-map").SourceNode;
var SourceMapConsumer = reuqire("source-map").SourceMapConsumer;
module.exports = function(content){
if(this.cacheable){
this.cacheable();
}
var useStrictPrefix = '\'use strict\';\n\n';
return useStrictPrefix + content;
var options = loaderUtils.getOptions(this) || {};
if (options.sourceMap && sourceMap) (
var currentRequest = loaderutils.getCurrentRequest(this);
var node = SourceNode.fromStringWithsourceMap(
content,
new SourceMapConsumer(sourceMap)
);
node.prepend(usestrictPrefix);
var result = node.toStringWithSourceMap(( file: currentRequest ));
var callback =this.async();
callback(null,result.code,result.map.toJSON());
}
//不支持source-map情况
return useStrictPrefix + content;
}
我们通过source-map这个库来对map进行操作,包括接收和消费之前的文件内容和source-map,对内容节点进行修改,最后产生新的source-map
在函数返回的时候要使用this.async获取 callback 函数(主要是为了一次性返回多个值)。callback函数的3个参数分别是抛出的错误、处理后的源码,以及source-map