We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
webpack的loader本质上是一个导出的函数,loader runner会调用该函数,在loader函数内部,this的上下文指向是webpack,通常loader内部返回的是一个string或者Buffer。当前loader返回的结果,会传递给下一个执行的loader
webpack
loader
this
string
Buffer
今天一起学习一下webpack5中的loader,让我们进一步加深对webpack的理解
webpack5
正文开始...
首先我们看下,通常情况下loader是怎么使用的
module.exports = { ... module: { rules: [ { test: /\.js$/, use: [ { loader: 'babel-loader', options: { presets: ['@babel/env'] } }, ] } ] }, }
在module.rules下,use是一个数组,数组中是可以有多个loader 默认情况loader:'babel-loader'会从node_modules中的lib/index.js中执行内部的_loader函数,然后通过内部@babel/core这个核心库对源代码进行ast转换,最终编译成es5的代码
module.rules
use
loader:'babel-loader'
node_modules
lib/index.js
_loader
@babel/core
ast
es5
现在需要自己写个loader,参考官方文档writing loader
我们在新建一个loader目录,然后新建test-loader
test-loader
module.exports = function (source) { console.log('hello world'); return source; };
在rules中我们修改下
rules
const path = require('path'); module.exports = { module: { rules: [ { test: /\.js$/, use: [ { loader: path.resolve(__dirname, 'loader/test-loader.js') } ] } ] } };
当我运行npm run start时,我们会发现loader中加载的自定义test-loader已经触发了。
npm run start
但是官方提供另外一种方式
在resolveLoader中可以给加载loader快捷的注册路径,这样就可以像官方一样直接写test-loader了,这个是文件名,文件后缀名默认可以省略。
resolveLoader
module.exports = { module: { rules: [ { test: /\.js$/, use: [ { loader: 'test-loader' } ] } ] }, resolveLoader: { modules: ['node_modules', './loader'] } };
我们知道loader中可以设置options,而在自定义loader是如何获取options的参数呢?
options
官方提供了loader的一些接口api-loader
获取 loader 传过来的options
// loader/test-loader.js module.exports = function (source) { const options = this.getOptions(); console.log(options); console.log('hello world'); return source; };
我们可以看到以下options传入的参数
... use: [ { loader: 'test-loader', options: { name: 'Maic', age: 18 } } ]
在官方提供了一个简单的例子,主要是用schema-utils验证options传入的数据格式是否正确
schema-utils
安装schema-utils
npm i schema-utils --save-dev
在test-loader中引入schema-utils
// 定义schema字段数据类型 const schema = { type: 'object', properties: { name: { type: 'string', description: 'name is require string' }, age: { type: 'number', description: 'age is require number' } } }; // 引入validate const { validate } = require('schema-utils'); module.exports = function (source) { // 获取loader传入的options const options = this.getOptions(); validate(schema, options); console.log(options); console.log('hello world'); return source; };
当我把rules中options修改类型时
{ use: [ { loader: 'test-loader', options: { name: 'Maic', age: '18' } } ]; }
运行npm run start 直接提示报错了,相当于validate这个方法帮我们验证了loader传过来的options,如果传入的options类型不对,那么直接报错了,我们可以用此来检验参数的类型。
validate
babel-loader
在之前的所有项目中,我们都会使用这个babel-loader,那我们能不能自己实现一个自定义的babel-loader呢?
首先我们要确定,babel转换es6,我们需要安装依赖两个插件,一个是@babel/core核心插件,另一个是@babel/preset-env预设插件
babel
es6
@babel/preset-env
修改rules,我们现在使用一个test-babel-loader插件
test-babel-loader
... { module: { rules: [ { test: /\.js$/, use: [ { loader: 'test-babel-loader', options: { presets: ['@babel/preset-env'] // 预设 } }, { loader: 'test-loader', options: { name: 'Maic', age: 18 } } ] } ] }, resolveLoader: { modules: ['node_modules', './loader'] }, }
修改test-babel-loader
// 引入@babel/core核心库 const babelCore = require('@babel/core'); module.exports = function (content) { // 获取options const options = this.getOptions(); // 必须异步方式 const callback = this.async(); // 转换es6 babelCore.transform(content, options, (err, res) => { if (err) { callback(err); } else { callback(null, res.code); } })
在index.js中写入一些 es6 代码
index.js
const sayhello = () => { const str = 'hello world'; console.log(str); }; sayhello();
然后在package.json写入打包命令
package.json
"scripts": { "test": "echo \"Error: no test specified\" && exit 1", "start": "webpack server --port=8081", "build": "webpack" },
我们执行npm run build
npm run build
test-loader与test-babel-loader都会执行,而且生成的main.js源代码的es6已经被转换成es5了。
main.js
markdown-loader
首先我们在loader目录下新建一个markdown-loader.js
markdown-loader.js
// markdown-loader.js module.exports = function (content) { console.log(content); return content; };
然后在rules中加入自定义loader
{ test: /\.md$/, loader: 'markdown-loader' } ...
我们需要在src/index.js中引入md文件
src/index.js
md
import md from '../doc/index.md'; const sayhello = () => { const str = 'hello world'; console.log(str); }; sayhello();
我们运行npm run build
已经获取到了doc/index.md的内容了
doc/index.md
在 loader 中我需要解析md的内容,此时我们需要借助一个第三方的md解析器marked
npm i marked --save-dev
详细使用文档参考markedjs
const { marked } = require('marked'); module.exports = function (content) { // 解析md const ret = marked.parse(content); console.log(ret); return ret; };
此时依然报错,错误提示You may need an additional loader to handle the result of these loaders.
You may need an additional loader to handle the result of these loaders.
所以需要解析html,那么此时需要另外一个loader来解决,html-loader
html
html-loader
npm i html-loader --save-dev
然后添加html-loader
{ test: /\.md$/, use: ['html-loader', 'markdown-loader'] }
我们在看下index.js
import md from '../doc/index.md'; console.log(md); const sayhello = () => { const str = 'hello world'; console.log(str); }; sayhello();
我们在index.js打印引入的md就一段html-loader转换过的最终代码
import md from '../doc/index.md'; const sayhello = () => { const str = 'hello world'; console.log(str); }; sayhello(); const renderMd = () => { const app = document.getElementById('app'); const div = document.createElement('div'); div.innerHTML = md; app.appendChild(div); }; renderMd();
我么最终就看到md文件就成功通过我们自己写的 loader 给转换了
本质上就是将md转换成html标签,然后再渲染到页面上了
了解loader的本质,实际上就是一个导出的函数,该函数只能返回字符串或者Buffer,内部提供了很多钩子,比如getOptions可以获取loader中的options
字符串
getOptions
loader的执行顺序是从下往上或者从右往左,在后一个 loader 中的content是前一个loader返回的结果
content
loader 有两种类型,一种是同步this.callback,另一种是异步this.async
this.callback
this.async
了解自定义babel转换,通过@bable/core,@babel/preset-env实现 es6 转换
@bable/core
实现了一个自定义markdown转换器,主要是利用marked.js这个对md文件转换成 html,但是html标签进一步需要html-loader
markdown
marked.js
本文示例code-example
The text was updated successfully, but these errors were encountered:
No branches or pull requests
今天一起学习一下
webpack5
中的loader
,让我们进一步加深对webpack
的理解正文开始...
开始一个
loader
首先我们看下,通常情况下
loader
是怎么使用的在
module.rules
下,use
是一个数组,数组中是可以有多个loader
默认情况
loader:'babel-loader'
会从node_modules
中的lib/index.js
中执行内部的_loader
函数,然后通过内部@babel/core
这个核心库对源代码进行ast
转换,最终编译成es5
的代码现在需要自己写个
loader
,参考官方文档writing loader我们在新建一个
loader
目录,然后新建test-loader
在
rules
中我们修改下当我运行
npm run start
时,我们会发现loader
中加载的自定义test-loader
已经触发了。但是官方提供另外一种方式
在
resolveLoader
中可以给加载loader
快捷的注册路径,这样就可以像官方一样直接写test-loader
了,这个是文件名,文件后缀名默认可以省略。我们知道
loader
中可以设置options
,而在自定义loader
是如何获取options
的参数呢?官方提供了
loader
的一些接口api-loadergetOptions
获取 loader 传过来的
options
我们可以看到以下
options
传入的参数在官方提供了一个简单的例子,主要是用
schema-utils
验证options
传入的数据格式是否正确安装
schema-utils
在
test-loader
中引入schema-utils
当我把
rules
中options
修改类型时运行
npm run start
直接提示报错了,相当于
validate
这个方法帮我们验证了loader
传过来的options
,如果传入的options
类型不对,那么直接报错了,我们可以用此来检验参数的类型。自定义
babel-loader
在之前的所有项目中,我们都会使用这个
babel-loader
,那我们能不能自己实现一个自定义的babel-loader
呢?首先我们要确定,
babel
转换es6
,我们需要安装依赖两个插件,一个是@babel/core
核心插件,另一个是@babel/preset-env
预设插件修改
rules
,我们现在使用一个test-babel-loader
插件修改
test-babel-loader
在
index.js
中写入一些 es6 代码然后在
package.json
写入打包命令我们执行
npm run build
test-loader
与test-babel-loader
都会执行,而且生成的main.js
源代码的es6
已经被转换成es5
了。写一个自定义
markdown-loader
首先我们在
loader
目录下新建一个markdown-loader.js
然后在
rules
中加入自定义loader
我们需要在
src/index.js
中引入md
文件我们运行
npm run build
已经获取到了
doc/index.md
的内容了在 loader 中我需要解析
md
的内容,此时我们需要借助一个第三方的md
解析器marked详细使用文档参考markedjs
我们运行
npm run build
此时依然报错,错误提示
You may need an additional loader to handle the result of these loaders.
所以需要解析
html
,那么此时需要另外一个loader
来解决,html-loader
然后添加
html-loader
我们在看下
index.js
我们在
index.js
打印引入的md
就一段html-loader
转换过的最终代码我么最终就看到
md
文件就成功通过我们自己写的 loader 给转换了本质上就是将
md
转换成html
标签,然后再渲染到页面上了总结
了解
loader
的本质,实际上就是一个导出的函数,该函数只能返回字符串
或者Buffer
,内部提供了很多钩子,比如getOptions
可以获取loader
中的options
loader
的执行顺序是从下往上或者从右往左,在后一个 loader 中的content
是前一个loader
返回的结果loader 有两种类型,一种是同步
this.callback
,另一种是异步this.async
了解自定义
babel
转换,通过@bable/core
,@babel/preset-env
实现 es6 转换实现了一个自定义
markdown
转换器,主要是利用marked.js
这个对md
文件转换成 html,但是html
标签进一步需要html-loader
本文示例code-example
The text was updated successfully, but these errors were encountered: