前端开发那些事儿前端养成

day01: 开发一个loader

2021-05-25  本文已影响0人  云海成长

知识回顾

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

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

一般情况下,我们像这样使用已有的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/

上一篇下一篇

猜你喜欢

热点阅读