day01: 开发一个loader

作者: 云海成长 | 来源:发表于2021-05-25 11:42 被阅读0次

    知识回顾

    这里的loader是webpack的核心概念之一,它的作用是将webpack无法识别的其他类型的文件(如css文件,图片)转换为有效 模块,webpack只能理解JavaScript和JSON文件。

    在配置loader时有2个重要属性:

    • test 正则表达式,用于匹配哪些文件
    • use 指定哪些loader对匹配到的文件进行处理

    一般情况下,我们像这样使用已有的loader

    module: {
      rules: [
        {
          test: /\.css$/
          use: ['style-loader', 'css-loader']
        }
      ]
    }
    

    那么,如何使用我们自定义的loader呢?以下面的例子为例:

    一个简单的loader

    1. 创建空目录awesome-webpack

    2. 在awesome-webpack运行npm init -y

    3. 运行npm i webpack webpack-cli -D

    4. 创建项目目录如下

      image.png
      main.css,内容如下:
    body {
        margin: 0 auto;
        padding: 0 20px;
        max-width: 800px;
        background: #f4f8fb;
    }
    

    index.js, 内容如下:

    import './main.css'
    

    此时如果没有在webpack.config.js配置处理css文件的loader直接打包就会报错,

    报错 因为webpack只识别符合JavaScript或JSON语法的内容。

    self-loader.js是自定义的loader,我们使用这个自定义的loader来处理css文件,在webpack.config.js里配置如下:

    const path = require('path')
    const config = {
      entry: path.join(__dirname, 'src/index.js'),
      mode: 'none',
      module: {
        rules: [
          {
            test: /\.css$/,
            use: [
              {
                loader: './src/self-loader',
                options: {
                  name: '参数'
                }
              }
            ]
          }
        ]
      }
    }
    module.exports = config
    

    重点来了,这个loader究竟长什么样呢?

    自定义loader向外暴露一个方法,而这个方法接收一个参数,这个参数的值即为匹配到的文件的内容字符串,结果返回一个字符串。

    self-loader.js

    module.exports = function (source)  {
      console.log(source)
      console.log(this.query)
      return `let style = document.createElement('style');style.innerHTML = ${JSON.stringify(source)}; document.head.append(style)`
    }
    

    上面打印内容如下:


    image.png

    可见,接收参数source是文件内容,而this.query是配置文件里的options的值,这里使用到this就不要用箭头函数。
    自定义loader最后还要返回结果,由于一个文件可以被多个loader处理,那么最后一个处理的loader一定要返回一段能被webpack识别的字符串,如JS代码。

    注意loader是运行在Node.js环境里的,所以应该符合CommonJS规范,所以自定义loader是使用module.exports 而不是export default对外暴露方法。

    打包出来的结果:

    /******/ (() => { // webpackBootstrap
    /******/    var __webpack_modules__ = ([
    /* 0 */,
    /* 1 */
    /***/ (() => {
    
    let style = document.createElement('style');style.innerHTML = "body {\r\n    margin: 0 auto;\r\n    padding: 0 20px;\r\n    max-width: 800px;\r\n    background: #f4f8fb;\r\n}\r\n\r\n\r\n/* console.log('css') */"; document.head.append(style)
    
    /***/ })
    /******/    ]);
    /************************************************************************/
    /******/    // The module cache
    /******/    var __webpack_module_cache__ = {};
    /******/    
    /******/    // The require function
    /******/    function __webpack_require__(moduleId) {
    /******/        // Check if module is in cache
    /******/        var cachedModule = __webpack_module_cache__[moduleId];
    /******/        if (cachedModule !== undefined) {
    /******/            return cachedModule.exports;
    /******/        }
    /******/        // Create a new module (and put it into the cache)
    /******/        var module = __webpack_module_cache__[moduleId] = {
    /******/            // no module.id needed
    /******/            // no module.loaded needed
    /******/            exports: {}
    /******/        };
    /******/    
    /******/        // Execute the module function
    /******/        __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
    /******/    
    /******/        // Return the exports of the module
    /******/        return module.exports;
    /******/    }
    /******/    
    /************************************************************************/
    /******/    /* webpack/runtime/compat get default export */
    /******/    (() => {
    /******/        // getDefaultExport function for compatibility with non-harmony modules
    /******/        __webpack_require__.n = (module) => {
    /******/            var getter = module && module.__esModule ?
    /******/                () => (module['default']) :
    /******/                () => (module);
    /******/            __webpack_require__.d(getter, { a: getter });
    /******/            return getter;
    /******/        };
    /******/    })();
    /******/    
    /******/    /* webpack/runtime/define property getters */
    /******/    (() => {
    /******/        // define getter functions for harmony exports
    /******/        __webpack_require__.d = (exports, definition) => {
    /******/            for(var key in definition) {
    /******/                if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
    /******/                    Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
    /******/                }
    /******/            }
    /******/        };
    /******/    })();
    /******/    
    /******/    /* webpack/runtime/hasOwnProperty shorthand */
    /******/    (() => {
    /******/        __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
    /******/    })();
    /******/    
    /******/    /* webpack/runtime/make namespace object */
    /******/    (() => {
    /******/        // define __esModule on exports
    /******/        __webpack_require__.r = (exports) => {
    /******/            if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
    /******/                Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
    /******/            }
    /******/            Object.defineProperty(exports, '__esModule', { value: true });
    /******/        };
    /******/    })();
    /******/    
    /************************************************************************/
    var __webpack_exports__ = {};
    // This entry need to be wrapped in an IIFE because it need to be in strict mode.
    (() => {
    "use strict";
    __webpack_require__.r(__webpack_exports__);
    /* harmony import */ var _main_css__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1);
    /* harmony import */ var _main_css__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_main_css__WEBPACK_IMPORTED_MODULE_0__);
    // import createTag from "./createTag"
    // import icon from './icon.jpg'
    
    // let ele = createTag('h1', '一级标题')
    // let img = createTag('img')
    // // img.src = icon
    // document.body.append(ele, img)
    })();
    
    /******/ })()
    ;
    

    到这里,一个最简单的自定义loader就完成了。

    扩展

    loader-utils

    这个工具用来分析参数,需要使用npm安装

    callback的使用

    参考https://www.webpackjs.com/api/loaders/

    相关文章

      网友评论

        本文标题:day01: 开发一个loader

        本文链接:https://www.haomeiwen.com/subject/ckyqsltx.html