一、初始化一个webpack项目

二、src同级目录下新建loaders文件夹

新建markLoader.js
loader就是一个函数,注意不能写箭头函数,因为要使用this。

  1. module.exports = function(source) {
  2. return source.replace('hello', 'helloword');
  3. }
  1. webpack配置
  2. module: {
  3. rules: [
  4. {
  5. test: /\.js$/,
  6. exclude: /node_modules/,
  7. use: [
  8. // 不传参数
  9. path.resolve(__dirname, './loaders/markLoader.js')
  10. ]
  11. }
  12. ]
  13. }

三、loader如何接收webpack配置的参数

  1. loader
  2. module.exports = function(source) {
  3. console.log(this.query) // 通过this可以拿到配置中的参数
  4. console.log(this.query.name) // 拿到loader下options参数的配置
  5. return source.replace('hello', 'helloword');
  6. }
  1. webpack.config.js
  2. module: {
  3. rules: [
  4. {
  5. test: /\.js$/,
  6. exclude: /node_modules/,
  7. use: [
  8. {
  9. loader: path.resolve(__dirname, './loaders/markLoader.js'),
  10. options: { // 传递参数
  11. name:'helloword'
  12. }
  13. }
  14. ]
  15. }
  16. ]
  17. }

通过loader-utils来处理参数

  1. loader
  2. // 如果参数不好解析,可以使用loader-utils
  3. const loaderUtils = require('loader-utils');
  4. module.exports = function(source) {
  5. // console.log(this.query) // 通过this可以拿到配置中的参数
  6. const option = loaderUtils.getOptions(this)
  7. return source.replace('hello', option.name);
  8. }

通过schema-utils来验证参数

  1. schema.json
  2. {
  3. "type": "object",
  4. "properties": {
  5. "name": {
  6. "type": "string",
  7. "description": "名称"
  8. }
  9. },
  10. "additionalProperties": true // 可以有多个,如果是false,json定义几个参数,外部只能传几个参数
  11. }
  1. const { validate } = require('schema-utils')
  2. const schema = require('/schema');
  3. module.exports = function(source) {
  4. validate(schema, source, {
  5. name: 'lodaler1' // 报错的lodaler
  6. })
  7. }

四、loader中传递源代码的同时想要带参数

  1. // this.callback()
  2. const loaderUtils = require('loader-utils');
  3. module.exports = function(source) {
  4. // console.log(this.query) // 通过this可以拿到配置中的参数
  5. const option = loaderUtils.getOptions(this)
  6. const result = source.replace('hello', option.name);
  7. this.callback(null, result);
  8. }
  9. // 此外 this.callbak还可以传递sourceMap等等

五、如何编写异步loader

  1. const loaderUtils = require('loader-utils');
  2. module.exports = function(source) {
  3. const option = loaderUtils.getOptions(this)
  4. const callback = this.async();
  5. // this.async() 就是一个callback
  6. setTimeout(() => {
  7. const result = source.replace('hello', option.name);
  8. callback(null, result)
  9. }, 1000)
  10. }

六、多个loader配合使用

新建两个loader

  1. webpack.config.js
  2. module: {
  3. rules: [
  4. {
  5. test: /\.js$/,
  6. exclude: /node_modules/,
  7. // 新使用markLoader1进行处理,处理完成之后,交给markLoader2处理
  8. use: [
  9. {
  10. loader: path.resolve(__dirname, './loaders/markLoader2.js'),
  11. options: { // 传递参数
  12. name:'helloword'
  13. }
  14. },
  15. {
  16. loader: path.resolve(__dirname, './loaders/markLoader1.js'),
  17. options: { // 传递参数
  18. name:'helloword'
  19. }
  20. }
  21. ]
  22. }
  23. ]
  24. }

loader执行顺序

  1. 如果有多个loader,是把loader放在数组中,loader是从数组的后面开始执行
  2. loader上有个pitck方法,是从前向后执行

七、写loader的时候,去掉path.resolve

  1. webpack.config.js
  2. resolveLoader: {
  3. // 定义loader先去node_modules中查找,如果没有,就去自定义的loader文件夹下查找
  4. modules: ['node_modules', './loaders']
  5. },
  6. module: {
  7. rules: [
  8. {
  9. test: /\.js$/,
  10. exclude: /node_modules/,
  11. // 新使用markLoader1进行处理,处理完成之后,交给markLoader2处理
  12. use: [
  13. {
  14. loader: 'markLoader2',
  15. options: { // 传递参数
  16. name:'helloword'
  17. }
  18. },
  19. {
  20. loader: 'markLoader1',
  21. options: { // 传递参数
  22. name:'helloword'
  23. }
  24. }
  25. ]
  26. }
  27. ]
  28. }

八、项目中用到的自定义loader

1、jquery代码中添加异常捕获

如果一个一个在jq代码中添加异常捕获,这样太麻烦
可以使用loader

  1. loader
  2. const loaderUtils = require('loader-utils');
  3. module.exports = function(source) {
  4. // source就是源代码,拿到源代码之后,通过ast进行分析
  5. // 找到function,并对function进行处理
  6. // 将function都放在try-catch中执行
  7. try{
  8. function(){}
  9. }catch(e) {
  10. console.log(e)
  11. }
  12. }

2、网站国际化

  1. loader
  2. module.exports = function(source) {
  3. if (Node全局变量 == '中文'){
  4. source.repalce('{{title}}', '中文')
  5. }else {
  6. source.repalce('{{title}}', 'en')
  7. }
  8. }