webpack中require.context的作用
在我们项目开发中,经常需要import或者export各种模块,那么有没有什么办法可以简化这种引入或者导出操作呢?答案是肯定的,下面就为大家介绍一下require.context
我们会这样引入组件:
import A from 'components/A'import B from 'components/B'import C from 'components/C'import D from 'components/D'// ...
这样很蛋疼,因为每加一个组件,可能都要写这么一句,这样有规律的事,是否可以通过自动化完成?
看下Webpack [Dependency Management | webpack]
require.context
require.context(directory, useSubdirectories, regExp)
- directory: 要查找的文件路径
- useSubdirectories: 是否查找子目录
- regExp: 要匹配文件的正则
用法
require.context('./components/', true, /\.js$/)

目录结构
上面调用方法,到底返回的是什么?
var map = {"./A.js": "./src/components/test/components/A.js","./B.js": "./src/components/test/components/B.js","./C.js": "./src/components/test/components/C.js","./D.js": "./src/components/test/components/D.js"};function webpackContext(req) {var id = webpackContextResolve(req);return __webpack_require__(id);}function webpackContextResolve(req) {var id = map[req];if(!(id + 1)) { // check for number or stringvar e = new Error("Cannot find module '" + req + "'");e.code = 'MODULE_NOT_FOUND';throw e;}return id;}webpackContext.keys = function webpackContextKeys() {return Object.keys(map);};webpackContext.resolve = webpackContextResolve;module.exports = webpackContext;webpackContext.id = "./src/components/test/components sync recursive \\.js$";
代码很简单,require.context执行后,返回一个方法webpackContext,这个方法又返回一个webpack_require,这个webpack_require就相当于require或者import。同时webpackContext还有二个静态方法keys与resolve,一个id属性。
- keys: 返回匹配成功模块的名字组成的数组
- resolve: 接受一个参数request,request为test文件夹下面匹配文件的相对路径,返回这个匹配文件相对于整个工程的相对路径
- id: 执行环境的id,返回的是一个字符串,主要用在module.hot.accept,应该是热加载
看下keys是作用
const ctx = require.context('./components/', true, /\.js$/)console.log(ctx.keys())// ["./A.js", "./B.js", "./C.js", "./D.js"]
其实就是
var map = {"./A.js": "./src/components/test/components/A.js","./B.js": "./src/components/test/components/B.js","./C.js": "./src/components/test/components/C.js","./D.js": "./src/components/test/components/D.js"};Object.keys(map)
只不过map是模块内部变量,无法直接访问,所以通过其实提供的keys方法访问
那么如何引入ABCD组件呢?
const ctx = require.context('./components/', true, /\.js$/)const map = {}for (const key of ctx.keys()) {map[key] = ctx(key)}console.log(map)
看到了吧!成功import进来了,但’./A.js’这样的key有点不太好,自己可以处理字符串生成自己想要的key
可以优化一下,生成一个公共的方法
const importAll = context => {const map = {}for (const key of context.keys()) {const keyArr = key.split('/')keyArr.shift() // 移除.map[keyArr.join('.').replace(/\.js$/g, '')] = context(key)}return map}export default importAll
使用
import importAll from '$common/importAll'export default importAll(require.context('./', true, /\.js$/))
什么时候需要用到require.context
如果有以下情况就可以用到
index批量导入modules文件

在Vue写的项目中,我把路由通过不同的功能划分成不同的模块,在index.js中一个个导入(原谅ide的警告-.-),但是如果项目变大了之后,每次手动import会显得有些力不从心,这里可以使用require.context函数遍历modules文件夹的所有文件一次性导入到index.js中
写法如下:
import Vue from 'vue'import Vuex from 'vuex'import getters from './getters'Vue.use(Vuex)// https://webpack.js.org/guides/dependency-management/#requirecontextconst modulesFiles = require.context('./modules', true, /\.js$/)// you do not need `import app from './modules/app'`// it will auto require all vuex module from modules fileconst modules = modulesFiles.keys().reduce((modules, modulePath) => {// set './app.js' => 'app'const moduleName = modulePath.replace(/^\.\/(.*)\.\w+$/, '$1')const value = modulesFiles(modulePath)modules[moduleName] = value.defaultreturn modules}, {})const store = new Vuex.Store({modules,getters})export default store
小记:
array.reduce(function(total, currentValue, currentIndex, arr), initialValue)
工程思路:
- 首先调用require.context导入某个文件夹的所有匹配文件,返回执行上下文的环境赋值给files变量
- 声明一个configRouters用来暴露给外层index.js作为vue-router的数组
- 调用files函数的keys方法返回modules文件夹下所有以.js结尾的文件的文件名,返回文件名组成的数组
- 遍历数组每一项,如果是index.js就跳过(index.js并不是路由模块),调用files函数传入遍历的元素返回一个Modules模块
- 因为我的路径是用export default导出的,所以在Module模块的default属性中获取到我导出的内容(即路由的结构),类似这种样子
svg优雅引入require.context的应用
require.context另外一个常用的地方是svg图标,可以不用每次导入图标文件,相对于以前的iconfont,svg有很多好处强烈推荐,详情可以看这个
手摸手,带你优雅的使用 icon
