webpack中require.context的使用
概述
You can create your own context with the require.context() function.
It allows you to pass in a directory to search, a flag indicating whether subdirectories should be searched too, and a regular expression to match files against.
webpack parses for require.context() in the code while building.
require.context是webpack中,用来创建自己的(模块)上下文;webpack会在代码构建的时候去解析该函数
解析
require.context(directory, useSubdirectories = false, regExp = /^\.\//);
该方法有3个参数:
- 需要搜索的文件夹目录(必传)
- 是否需要搜索它的子孙目录,默认为false
- 匹配文件名的正则表达式
例子
// 示例 const test = require.context('./string', false, /\.js$/);
我的目录结构如下:
String
- trim.js
- trimLeft.js
- trimRight.js
test
- test1.js
- *
这时候如果console.log(test)
,就会发现调用require.context之后返回的是一个函数
webpackContext(req) { var id = webpackContextResolve(req); return __webpack_require__(id); }
这次如果还需要深入就需要去webpack打包之后的文件中寻找了:
var map = { "./test/test1.js": "./src/string/test/test1.js", "./trim.js": "./src/string/trim.js", "./trimLeft.js": "./src/string/trimLeft.js", "./trimRight.js": "./src/string/trimRight.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 string var 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/string sync recursive \\.js$";
由上面的代码可以看出,在webpackContext
定义了多个方法和属性
console.log(webpackContext.id) // "./src/string sync recursive \.js$" console.log(webpackContext('./trim.js')) // "./src/string/trim.js" console.log(webpackContext.keys()) // ["./test/test1.js", "./trim.js", "./trimLeft.js", "./trimRight.js"]
使用场景
vue中的基础组件的自动化全局注册
具体就不多说了,直接看文档
vue官方文档 - 基础组件的自动化全局注册
大型单页应用中,路由过多
当你的单页应用变成了大型应用后,路由也在慢慢的增多
// rootRoute.js const rootRoute = { childRoutes: [ { path: "/", component: AppLayout, childRoutes: [ { path: "shop", // 购买详情页 component: ShopLayout, childRoutes: [ { path: "foodDetail", component: FoodDetail }, { path: "shoesDetail", component: ShoesDetail } // 其他 ] }, { path: "order", // 订单页 component: Order, childRoutes: [ { path: "remark", //订单备注 component: Remark }, { path: "invoice", //发票抬头 component: Invoice }, { path: "payment", //付款页面 component: Payment }, { path: "userValidation", //用户验证 component: UserValidation }, { path: "chooseAddress", //选择地址 component: ChooseAddress, childRoutes: [ { path: "addAddress", //添加地址 component: AddAddress, childRoutes: [ { path: "searchAddress", //搜索地址 component: SearchAddress } ] } ] } ] } // ... // 大量新增路由 // ... ] } ] };
当路由变的越来越大,大到已经难以维护时。我们按照react-router
提供的思路,对路由按业务模块进行拆分。
// rootRoute.js const rootRoute = { childRoutes: [ { path: '/', component: AppLayout, childRoutes: [ require('./modules/shop/route'), //购买详情页 require('./modules/order/route'), // 订单页 require('./modules/login/route'), // 登录注册页 require('./modules/service/route'), // 服务中心 // ... // 其他大量新增路由 // ... ] } ] };
再进一步优化的话,就可以使用require.context
const rootRoute = { childRoutes: [ { path: '/', component: AppLayout, childRoutes: (r => { return r.keys().map(key => r(key)); })(require.context('./', true, /^\.\/modules\/((?!\/)[\s\S])+\/route\.js$/)) } ] };
自动引用目录下的文件
比如我现在想要造一个自己的工具库utils,那么随着工具函数数量的增加,势必需要将代码分割得更小,甚至细化到一个工具函数对应一个js文件。
这时如果还需要在入口js文件中一个个手动引用,那么每增加一个js文件,就需要重新去修改入口js一次,工程量是非常大的。
这时就可以使用到require.context
了~
/** * @desc webpack打包入口文件 * @example 自动引入子目录下所有js文件 */ let moduleExports = {}; const r = require.context('./', true, /^\.\/.+\/.+\.js$/); r.keys().forEach(key => { let attr = key.substring(key.lastIndexOf('/') + 1, key.lastIndexOf('.')); moduleExports[attr] = r(key); }); module.exports = moduleExports;