需求

在用vue开发的过程中,我们可能会使用import引入文件,但需要引入多个的时候就会变得繁琐起来,这时我们可以使用require.context去动态引入多个文件。

stackoverflow上的解释非常明确:

require.context is a special feature supported by webpack's compiler that allows you to get all matching modules starting from some base directory. The intention is to tell webpack at compile time to transform that expression into a dynamic list of all the possible matching module requests that it can resolve, in turn adding them as build dependencies and allowing you to require them at runtime.

In short, you would use require.context in the exact same situation when in Node.js at runtime you would use globs to dynamically build a list of module paths to require. The return value is a callable object that behaves like require, whose keys contain the necessary module request data that can be passed to it as an argument to require the module.

There are several ways you can use it, but I think the two most common use cases are to either automagically require some well-known kind of modules (e.g. you just add some.test.js test module and in some module you use require.context to dynamically discover all the tests, thus not having to document and remember to do it manually every time you add a new test module) or to load static assets in the repository to emit files to the build output (new webpack users coming from other build tools are usually surprised that their images, fonts, audio files and other assets do not appear in the output unless they are required from some module).

注意上面提到的“多个文件”并不要求特定类型的文件,因此,这个工具是非常有用的。在开发SPA前端过程中,经常需要如下图所示的任务,即把使用大量的import把子组件注入到一个视图中:

此时,逐个导入费力而且容易出问题,特别是在需求不断变化时。

require.context方案

require.context语法

require.context(directory, useSubdirectories, regExp) 【参数含义】

  • directory: 要查找的文件路径
  • useSubdirectories: 是否查找子目录
  • regExp: 要匹配文件的正则

于是,针对上图中需要使用Import加载大量文件的需求(项目中可能还会存在很多类似需求),可以使用如下方案来简化:

import Vue from 'vue'
import upperFirst from 'lodash/upperFirst'
import camelCase from 'lodash/camelCase'

const requireComponent = require.context(
  '@/components/base', true, /\.vue$/,
)

requireComponent.keys().forEach(fileName => {
  const componentConfig = requireComponent(fileName)

  const componentName = upperFirst(
    camelCase(fileName.replace(/^\.\//, '').replace(/\.\w+$/, '')),
  )
  // 注册组件,传入一个扩展过的构造器or 对象
  Vue.component(`Base${componentName}`, componentConfig.default || componentConfig)
})

上面代码的总体功能描述是:

  • 使用 require.context查询并把符合条件的结果文件名加入到一个键-值对形式的对象 requireComponent中
  • 调整对象中各文件名格式
  • 注册成Vue子组件(使用Vue.component)

引用

  • https://developpaper.com/in-depth-understanding-of-the-requirement-context-of-webpack/#:~:text=Require.context%20is%20actually%20a%20very%20practical%20API.%20But,which%20is%20very%20flexible%20and%20powerful%20%28recursive%20directory%29.
  • https://stackoverflow.com/questions/54059179/what-is-require-context
  • https://segmentfault.com/a/1190000019723837
  • https://www.jianshu.com/p/1a8b2e040f08
  • https://blog.csdn.net/qq_28458369/article/details/100921034