webpack之require.context实现万能批量导入(省去手写import)

前言

webpack 给我们提供了一个批量导入函数 require.context() ,该函数签名如下:

require.context(directory, useSubdirectories, regExp)

  • directory: 批量导入目标文件夹路径
  • useSubdirectories: 是否遍历子目录
  • regExp: 匹配需要导入文件名时的正则

例:

    // 导入当前目录 resources 文件夹内的所有 .js 文件(不包括子目录)
	require.context("./resources", false, /\.js$/);

原理

要实现万能导入,需要先了解 require.context() 的返回值,他将返回一个函数:

该函数传入一个文件的 path 后(函数里形参叫 req ),将把 path 传入 webpackContextResolve() 函数,之后执行 __webpack_require__ 导入模块。

webpackContextResolve() 是什么原理?

我们发现 webpackContextResolve() 只是去 map 这个对象中取了属性 path 对应的值,并且保证他一定可以导入(如果不能导入会抛出 Error

map 这个对象是什么?

我们看一下完整代码:

var map = {
	"./a.js": "./src/require/resources/a.js",
	"./b.js": "./src/require/resources/b.js",
	"./c.js": "./src/require/resources/c.js"
};

function webpackContext(req) {
	var id = webpackContextResolve(req);
	return __webpack_require__(id);
}

function webpackContextResolve(req) {
	if(!__webpack_require__.o(map, req)) {
		var e = new Error("Cannot find module '" + req + "'");
		e.code = 'MODULE_NOT_FOUND';
		throw e;
	}
	return map[req];
}

webpackContext.keys = function webpackContextKeys() {
	return Object.keys(map);
};

webpackContext.resolve = webpackContextResolve;

module.exports = webpackContext;

webpackContext.id = "./src/require/resources sync \\.js$";

到此为止,我们终于知道了 map 原来是可以取得相对项目根目录文件路径的一个对象。

回过头来,我们重点只需关注如何传入 path ,因为只要给 require.context 传入了 path ,他就会去执行导入模块。

使用

在上文源代码中,我们发现 require.context 的返回函数 webpackContext 有一个 keys 方法,它可以给我们提供所有的 path !

于是,得到我们的万能批量导入方法:

const req = require.context("./resources", false, /\.js$/)

req.keys().map(path => {
  // 兼容 cjs 和 esm 模块导入
  req(path).default || req(path)
})

到此为止,./resources 文件夹内的所有 .js 文件均已被自动批量导入。

如果要操作此处导入的文件内容,可以在 req(path) 返回值处操作:

const req = require.context("./resources", false, /\.js$/);

req.keys().map(path => {
  const context = req(path).default || req(path);
  // 此处 context 即为每个 .js 文件的导出内容
  console.log(context);
});

结果:

注:如果没有兼容 esm 和 cjs ,你得到的只会是不均匀的结果

总结

require.context 可以被用在各种需要大量 import 或者 require 的地方,比如导入一大批 .svg 文件,亦或是导入大量分模块的路由表,Vuex module 等等(此时将 req() 返回值组装进相应的对象即可)。

做一个不再手写 import 的打工人。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值