Webpack之Loader原理及自定义Loader
文章目录
- 1. Loader 分类与执行顺序
- 1.1 Loader 分类
- 1.2 Loader 执行顺序
- 1.3 使用Loader方式
- 1.3.1 内联 Loader
- 2. 开发 Loader 步骤
- 2.1 开发环境
- 2.2 最简单的 Loader
- 2.3 Loader 分类
- 2.3.1 同步 Loader
- 2.3.2 异步 loader
- 2.3.3 Raw Loader
- 2.3.4 Pitching Loader
- 2.4 loader API
- 3. 自定义Loader
- 3.1 clean-log-loader
- 3.2 banner-loader
- 3.3 babel-loader
- 3.4 file-loader
- 4. 小结
webpack
作为前端项目的打包工具,具有很好的学习价值。下面来学习下其中的 Loader
Loader
可以帮助webpack
将不同类型的文件转换为webpack
可识别的模块
webpack
中Loader
使用:https://www.webpackjs.com/loaders/
webpack
中Loader API
的介绍:https://www.webpackjs.com/api/loaders/
在Webpack
中,默认的配置文件为:webpack.config.js
。在学习Loader
之前,要先了解下webpack.config.js
和vue.config.js
的区别:
webpack.config.js
是webpack
的配置文件,所有使用webpack
作为打包工具的项目都可以使用,vue
项目可以使用,react
项目也可以使用vue.config.js
是vue
项目的配置文件,专用于vue
项目。通过vue.config.js
中常用功能的配置,简化配置工作,当然如果需要更专业的配置工作,两者在vue
项目中是可以并存的vue-cli3
创建项目时并不会自动创建vue.config.js
,因为这个是可选项,所以一般都是修改webpack
时才会自己创建一个vue.config.js
因为
vue-cli3
内部高度集成了webpack
,一般来说使用者不需要再为webpack
做什么配置,所以没有暴露webpack
的配置文件,但开发中依然可以创建vue.config.js
去修改默认的webpack
Vue
项目中vue.config.js
文件就等同于webpack
的webpack.config.js
vue 中配置文件说明:https://cli.vuejs.org/zh/config/
1. Loader 分类与执行顺序
1.1 Loader 分类
pre
: 前置loader
normal
: 普通loader
inline
: 内联loader
post
: 后置loader
1.2 Loader 执行顺序
- 4 类
loader
的执行优级为:pre > normal > inline > post
- 相同优先级的
loader
执行顺序为:从右到左,从下到上
// 此时loader执行顺序:loader3 - loader2 - loader1
module: {rules: [{test: /\.js$/,loader: "loader1",},{test: /\.js$/,loader: "loader2",},{test: /\.js$/,loader: "loader3",},],
},
// 此时loader执行顺序:loader1 - loader2 - loader3
module: {rules: [{enforce: "pre",test: /\.js$/,loader: "loader1",},{// 没有enforce就是normaltest: /\.js$/,loader: "loader2",},{enforce: "post",test: /\.js$/,loader: "loader3",},],
},
1.3 使用Loader方式
- 配置方式:在
webpack.config.js
文件中指定loader
。(pre
、normal
、post
) - 内联方式:在每个
import
语句中显式指定loader
。(inline loader
)
1.3.1 内联 Loader
用法:import Styles from 'style-loader!css-loader?modules!./styles.css';
含义:
- 使用
css-loader
和style-loader
处理styles.css
文件 - 通过
!
将资源中的loader
分开
inline loader
可以通过添加不同前缀,跳过其他类型 loader
!
跳过normal loader
import Styles from '!style-loader!css-loader?modules!./styles.css';
-!
跳过pre
和normal loader
import Styles from '-!style-loader!css-loader?modules!./styles.css';
!!
跳过pre
、normal
和post loader
import Styles from '!!style-loader!css-loader?modules!./styles.css';
2. 开发 Loader 步骤
2.1 开发环境
新建一个文件在,并在里面新建一个webpack.config.js
文件,同时新建src
、public
文件夹,具体目录结构如下:
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')module.exports = {entry: './src/main.js',output: {path: path.resolve(__dirname, './dist'),filename: 'js/[name].js',clean: true,},module: {rules: [{test: /\.js$/,loader: './loaders/test-loader/test-loader.js',},],},plugins: [new HtmlWebpackPlugin({template: path.resolve(__dirname, 'public/index.html'),}),],mode: 'development',
}
然后打开终端,来到项目根目录,分别运行以下指令:
- 初始化
package.json
,此时会生成一个基础的package.json
文件
npm init -y
- 下载依赖
npm i webpack webpack-cli -D
安装
html-webpack-plugin
插件该插件生成一个
HTML
文件,使用自己提供的模板编写
main.js
文件
// 很简单的一句打印
console.log('hello main')
- 启用
Webpack
开发模式:npx webpack ./src/main.js --mode=development
生产模式:npx webpack ./src/main.js --mode=production
npx webpack
: 是用来运行本地安装 Webpack
包的。./src/main.js
: 指定 Webpack
从 main.js
文件开始打包,不但会打包 main.js
,还会将其依赖也一起打包进来。--mode=xxx
:指定模式(环境)
npx是执行Node软件包的工具,它从npm5.2版本开始,就与npm捆绑在一起
npx作用:
- 默认情况下,首先检查路径中是否存在要执行的包(即在项目中)
- 如果存在,它将执行
- 若不存在,意味着尚未安装该软件包,npx将安装其最新版本,然后执行它
执行完上面操作后,会在项目根目录下生成一个dist
文件夹,把其中的index.html
文件在浏览器打开
2.2 最简单的 Loader
在loaders
文件夹下新建test-loader/test-loader.js
文件
// loaders/test-loader/test-loader.js
module.exports = function (content, map, meta) {console.log('hello test loader ... ')// 将源文件中的main替换成webpackreturn content.replace('main', 'webpack')
}
它接受要处理的源码作为参数,输出转换后的 js
代码。Loader
接受的参数
content
:源文件的内容map
:SourceMap
数据meta
数据:可以是任何内容
在webpack.config.js
文件中,使用该Loader
module: {rules: [{test: /\.js$/,loader: './loaders/test-loader/test-loader.js',},],
},
执行打包命令,并查询运行结果:
2.3 Loader 分类
2.3.1 同步 Loader
module.exports = function (content, map, meta) {return content;
};
this.callback
方法则更灵活,因为它允许传递多个参数,而不仅仅是 content
。
module.exports = function (content, map, meta) {/*第一个参数:err 代表是否有错误第二个参数:content 处理后的内容第三个参数:source-map 继续传递source-map第四个参数:meta 给下一个loader传递参数*/this.callback(null, content, map, meta);// 同步loader中不能进行异步操作return; // 当调用 callback() 函数时,总是返回 undefined
};
2.3.2 异步 loader
module.exports = function (content, map, meta) {// 异步操作const callback = this.async();// 进行异步操作setTimeout(() => {callback(null, result, map, meta);}, 1000);
};
由于同步计算过于耗时,在 Node.js 这样的单线程环境下进行此操作并不是好的方案,建议尽可能地使loader 异步化。但如果计算量很小,同步 loader 也是可以的。
2.3.3 Raw Loader
默认情况下,资源文件会被转化为 UTF-8
字符串,然后传给 loader
。通过设置 raw
为 true
,loader
可以接收原始的 Buffer
。
module.exports = function (content) {// content是一个Buffer数据return content;
};
module.exports.raw = true; // 开启 Raw Loader
2.3.4 Pitching Loader
module.exports = function (content) {return content;
};
module.exports.pitch = function (remainingRequest, precedingRequest, data) {console.log("do somethings");
};
webpack
会先从左到右执行 loader
链中的每个 loader
上的 pitch
方法(如果有),然后再从右到左执行 loader
链中的每个 loader
上的普通 loader
方法
在这个过程中如果任何 pitch
有返回值,则 loader
链被阻断。webpack
会跳过后面所有的的 pitch
和 loa
der,直接进入上一个 loader
。
2.4 loader API
方法名 | 含义 | 用法 |
---|---|---|
this.async | 异步回调 loader。返回 this.callback | const callback = this.async() |
this.callback | 可以同步或者异步调用的并返回多个结果的函数 | this.callback(err, content, sourceMap?, meta?) |
this.getOptions(schema) | 获取 loader 的 options | this.getOptions(schema) |
this.emitFile | 产生一个文件 | this.emitFile(name, content, sourceMap) |
this.utils.contextify | 返回一个相对路径 | this.utils.contextify(context, request) |
this.utils.absolutify | 返回一个绝对路径 | this.utils.absolutify(context, request) |
3. 自定义Loader
3.1 clean-log-loader
需求:清理 js
代码中的console.log
- 在
loaders
文件夹下新建clean-log-loader/clean-log-loader.js
文件
// loaders/clean-log-loader/clean-log-loader.js
module.exports = function cleanLogLoader(content) {// 将console.log替换为空return content.replace(/console\.log\(.*\);?/g, "");
};
- 在
webpack.config.js
文件中,使用该Loader
module: {rules: [{test: /\.js$/,loader: './loaders/clean-log-loader/clean-log-loader.js',},],
},
3.2 banner-loader
需求:给 js
代码添加文本注释
- 在
loaders
文件夹下新建banner-loader/banner-loader.js
和schema.json
文件
const schema = require("./schema.json");module.exports = function (content) {// schema对options的验证规则// schema符合JSON Schema的规则const options = this.getOptions(schema);const prefix = `/** Author: ${options.author}*/`;return prefix + content;
};
loaders/banner-loader/schema.json
文件可以对在配置loader
时的参数进行校验
{"type": "object","properties": {"author": {"type": "string"}},"additionalProperties": false
}
webpack.config.js
配置文件
{test: /\.js$/,loader: "./loaders/banner-loader/banner-loader.js",// 传入的参数options: {author: "scorpios",},
},
3.3 babel-loader
需求:编译 js
代码,将 ES6+
语法编译成 ES5
语法。(虽然这个功能已经有现场的loader
,但可以自己模拟,加深理解)
- 下载依赖
npm i @babel/core @babel/preset-env -D
- 在
loaders
文件夹下新建babel-loader/babel-loader.js
和schema.json
文件
const babel = require("@babel/core");
const schema = require("./schema.json");// https://www.babeljs.cn/docs/babel-coremodule.exports = function (content) {// 异步loaderconst callback = this.async();const options = this.getOptions(schema);// 使用babel对代码进行编译babel.transform(content, options, function (err, result) {if (err) callback(err);else callback(null, result.code);});
};
loaders/banner-loader/schema.json
{"type": "object","properties": {"presets": {"type": "array"}},"additionalProperties": true
}
webpack.config.js
配置文件
{test: /\.js$/,loader: "./loaders/babel-loader/babel-loader.js",options: {presets: ["@babel/preset-env"],},
}
3.4 file-loader
需求:将文件原封不动输出出去
- 下载包
npm i loader-utils -D
- 在
loaders
文件夹下新建file-loader/file-loader.js
文件
const loaderUtils = require("loader-utils");module.exports = function (content) {// 1. 根据文件内容生成带hash值文件名let interpolatedName = loaderUtils.interpolateName(this, "[hash].[ext][query]", {content,});interpolatedName = `images/${interpolatedName}`// console.log(interpolatedName);// 2. 将文件输出出去this.emitFile(interpolatedName, content);// 3. 返回:module.exports = "文件路径(文件名)"return `module.exports = "${interpolatedName}"`;
};// 需要处理图片、字体等文件。它们都是buffer数据
// 需要使用raw loader才能处理
module.exports.raw = true;
webpack.config.js
配置文件
{test: /\.(png|jpe?g|gif)$/,loader: "./loaders/file-loader/file-loader.js",type: "javascript/auto", // 解决图片重复打包问题
},
4. 小结
Loader
就是一个函数, 当webpack
解析资源时,会调用相应的Loader
去处理, Loader
接受到文件内容作为参数,返回内容出去。
content
: 文件内容map
:SourceMap
meta
: 别的Loader
传递的数据
Webpack之Loader原理及自定义Loader相关推荐
- vue-cli Webpack之Loader原理及自定义Loader
文章目录 1. Loader 分类与执行顺序 1.1 Loader 分类 1.2 Loader 执行顺序 1.3 使用Loader方式 1.3.1 内联 Loader 2. 开发 Loader 步骤 ...
- webpack loader解析及自定义loader
自定义实现webpack loader加载模块,解析指定的类型文件 loader loader是一个导出为函数的node模块,可通过this访问上下文. 特点: loader单一职责,只负责解决单一的 ...
- webpack自定义loader
创建自己的Loader 创建自己的Loader Loader是用于对模块的源代码进行转换(处理),css-loader.style-loader.babel-loader等. 如何自定义自己的Load ...
- Webpack自定义Loader和Plugin方法
手写Loader Loader 本质上是导出函数的 JavaScript 模块,而该模块导出的函数被称为 Normal Loader,在开发 Loader时,我们可以在导出的函数上添加一个 pitch ...
- webpack:自定义loader
以下是一个自定义loader replace-loader,实现一个类似模板引擎变量替换的简单功能 文件目录 . ├── dist │ └── index.js # 打包结果 ├── loaders ...
- 24.重学webpack——loader的原理及常用loader的实现(高频面试题)
[重学webpack系列--webpack5.0] 1-15节主要讲webpack的使用,当然,建议结合<webpack学完这些就够了>一起学习. 从本节开始,专攻webpack原理,只有 ...
- 深度解读Webpack中的loader原理
一.前言 webpack 是一个现代 JavaScript 应用的静态模块打包器.那么 webpack 是怎样实现不同种类资源模块加载的呢? 没错就是通过 loader.loader 用于对模块的源代 ...
- webpack源码分析之三:loader
前言 在webpack特性里面,它可以支持将非javaScript文件打包,但前面写到webpack的模块化打包只能应用于含有特定规范的JavaScript文件.本次介绍的loader则是用来解决这类 ...
- Unity puerts 自定义Loader和调试和ab包的注意点
输出ab包 他会把你创建的ab包都打包 也就是在这里的创建的都打包 string assetBundleDirectory = Path.Combine(Application.streamingAs ...
最新文章
- 与孩子一起学编程 python_【和孩子一起学编程】 python笔记--第五天
- python语言入门电子版-python从入门到精通pdf
- 中国九章量子计算机诞生!比最快的超算快一百万亿倍
- 微信小程序图片轮转播放
- python和sql_Python和SQL 2017的强大功能
- 穷人变富的过程中,最大的阻碍是什么?
- 存储过程和存储函数和触发器示例
- MongoDB 的设计模式策略
- java并发编程实战读书笔记4--生产者消费者模式和队列
- L2TP-***通用原理取证及在华为防火墙上的实施
- NTC热敏电阻温度计算方法,Steinhart-Hart方程和B值法
- 基于产生式系统的野人渡河问题求解
- 目标客户画像_4 种类型 + 10 大步骤,详解用户画像
- 女研究生做“思维导图”与男友吵架!网友:吵架届的“内卷之王”....
- C#开发工控上位机编程 csdn_中吉午餐自动售货机加热自动午餐盒智能便利店【盒饭售货机】_智能云仓储库存wms管理分配货_电子标签价签拣货系统_工控erp上位机软件开发设计...
- 格林尼治时间转换为本地时间
- 前端Jquery使用pagination.js插件进行分页
- 为什么网上都说 AirPods 3 音质不如AirPods Pro?
- 随便拍几张照片赚了3K,近期的风口视频项目
- 支持向量机检测DGA
热门文章
- java孙膑和庞涓问题_庞涓VS孙膑——一个很难的数学问题(智力140以下勿进)
- 在Mac上使用招商银行网银
- 2022-04-16老张修路360笔试-prim构建最小生成树
- Excel VBA 利用FileSystemObject处理文件
- 计算机科学与技术中模电,模拟电子技术基础
- 使用Python获取春节档电影影评,制作可视化词云图
- 【2016 泉市教科】保险箱
- 云和恩墨大讲堂 x 长江鲲鹏 x openGauss Meetup(武汉站)圆满落幕
- 【练习篇】SQLZOO(中文版)习题答案_SELECT from world
- Linear Algebra