require.context - 避免重复import

1. require.context是什么

require.context是webpack针对依赖管理提供的一个API,通过它我们可以创建自己的上下文,它允许你传入一个目录进行搜索,一个标志指示是否应该搜索子目录,还有一个正则表达式来匹配文件。

其实是Webpack通过解析 require()的调用,提取出来如下这些信息:

Directory: ./template
Regular expression: /^.*\.ejs$/

然后来创建我们自己的上下文,什么意思呢,就是我们可以通过这个方法筛选出来我们需要的文件并且读取

2. 使用方法

/**
* @param directory 要搜索的文件夹目录不能是变量,否则在编译阶段无法定位目录
* @param useSubdirectories  是否搜索子目录
* @param regExp 匹配文件的正则表达式
* @return function 返回一个具有 resolve, keys, id 三个属性的方法
          resolve() 它返回请求被解析后得到的模块 id
          keys() 它返回一个数组,由所有符合上下文模块处理的请求组成。 
          id 是上下文模块里面所包含的模块 id. 它可能在你使用 module.hot.accept 的时候被用到
*/
require.context('demo', useSubdirectories = false, regExp = /\.js$/)
// (创建了)一个包含了 demo 文件夹(不包含子目录)下面的、所有文件名以 `js` 结尾的、能被 require 请求到的文件的上下文。

有一个点需要注意的,就是传递给require.context的都必须是常量,使用变量都会报错

接下来我们看下有哪些场景可以使用这个功能

3. 使用场景

3.1 组织路由

对于Vue中的路由,大家都很熟悉,类似于声明式的配置文件,其实已经很简洁了。现在我们来让他更简洁

(1) 分割路由
首先为了方便我们管理,我们把router目录下的文件分割为以下结构

router                           // 路由文件夹
  |__index.js                    // 路由组织器:用来初始化路由等等
  |__common.js                   // 通用路由:声明通用路由
  |__modules                     // 业务逻辑模块:所以的业务逻辑模块
        |__index.js              // 自动化处理文件:自动引入路由的核心文件
        |__home.js               // 业务模块home:业务模块
        |__a.js                  // 业务模块a

(2) modules文件夹中处理业务模块
modules文件夹中存放着我们所有的业务逻辑模块,至于业务逻辑模块怎么分,我相信大家自然有自己的一套标准。我们通过上面提到的require.context()接下来编写自动化的核心部分index.js

const files = require.context('.', true, /\.js$/)

console.log(files.keys()) // ["./home.js"] 返回一个数组
let configRouters = []
/**
* inject routers
*/
files.keys().forEach(key => {
  if (key === './index.js') return
  configRouters = configRouters.concat(files(key).default) // 读取出文件中的default模块
})
export default configRouters // 抛出一个Vue-router期待的结构的数组

自动化部分写完了,那业务组件部分怎么写? 这就很简单了

import Frame from '@/views/frame/Frame'
import Home from '@/views/index/index'
export default [
    // 首页
    {
      path: '/index',
      name: '首页',
      redirect: '/index',
      component: Frame, 
      children: [ // 嵌套路由
        {
          path: '',
          component: Home
        }
      ]
    }
]

(3)common路由处理 我们的项目中有一大堆的公共路由需要处理比如404阿,503阿等等路由我们都在common.js中进行处理。

export default [
  // 默认页面
  {
    path: '/',
    redirect: '/index',
    hidden:true
  },
  // 无权限页面
  {
    path: '/nopermission',
    name: 'nopermission',
    component: () => import('@/views/NoPermission')
  },
  // 404
  {
    path: '*',
    name: 'lost',
    component: () => import('@/views/404')
  }
]

(4) 路由初始化
这是我们的最后一步了,用来初始化我们的项目路由

import Vue from 'vue'
import VueRouter from 'vue-router'
import RouterConfig from './modules' // 引入业务逻辑模块
import CommonRouters from './common' // 引入通用模块
Vue.use(VueRouter)
export default new VueRouter({
  mode: 'history',// 需要服务端支持
  scrollBehavior: () => ({ y: 0 }),
  routes: RouterConfig.concat(CommonRouters)
})

这样处理的好处是什么呢?我们来描述一个场景,比如按照这种结构来划分模块。正常的情况是我们创建完home.js要手动的把这个模块import到路由文件声明的地方去使用。但是有了上面的index.js,在使用的时候你只需要去创建一个home.js并抛出一个符合VueRouter规范的数组,剩下的就不用管了。import RouterConfig from './modules' // 引入业务逻辑模块已经帮你处理完了。

3.2 使用svg画图标

假设我们要做一个带有很多图标的页面,使用普通的图片可能会出现一些问题:高分辨率下模糊、每次更新都需要P图、配合页面换肤功能时只能重新作图,然后就可能使用svg去替换图片的方案。当涉及到有很多个svg文件时,我们可以借助与webpack配合使用的插件svg-sprite-loader来将svg拼接成雪碧图,放到页面中,然后业务组件中使用use来实现复用的效果

(1)npm install svg-sprite-loader并添加到webpack打包配置中

module: {
  rules: [
    {
      test: /\.svg$/,
      loader: 'svg-sprite-loader',
      include: [resolve('src/icons')],
      options: {
        symbolId: 'icon-[name]'
      }
    },
    {
      test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
      loader: 'url-loader',
      options: {
        limit: 10000,
        name: '[name].[hash:7].[ext]'
      },
      exclude: [resolve('src/icons')]
    }
  ]
}

注意这里是 url-loader 中将 icons 文件夹排除, 不让 url-loader 处理该文件夹,而是让svg-sprite-loader去处理

(2) 业务组件中去引用
想要让svg-sprite-loader生效,我们需要在业务组件中通过import语法来将需要用到的svg文件引入进来

<!-- app.vue -->
<template>
  <div class="svg-item">
    <svg class="svg-icon-eyes" aria-hidden="true">
      <use :xlink:href="#icon-eyes"></use>
    </svg>
  </div>
</template>

<script>
import 'assets/icons/icon-eyes.svg';

export default {
  data() {
    return {}
  }
}
</script>

像上面这样,只有一个svg的话还好,那么如果这里需要用到几十个svg文件,难道要import几十遍吗?使用require.context可以解决我们的问题

(3) 在存放svg的文件夹assets/icons下新增一个index.js文件

const requireAll = requireContext => requireContext.keys().forEach(key => requireContext(key));
const req = require.context('.', false, /\.svg$/);
requireAll(req);

如上所示,查找assets/icons文件夹下所有.svg后缀名的文件,然后调用keys方法再做一个遍历,把该文件夹下的.svg文件都require进来

(4) 修改业务组件,去掉原先的import代码

<!-- app.vue -->
<template>
  <div class="svg-item">
    <svg class="svg-icon-eyes" aria-hidden="true">
      <use :xlink:href="#icon-eyes"></use>
    </svg>
  </div>
</template>

<script>
import 'assets/icons/index';

export default {
  data() {
    return {}
  }
}
</script>

这样的话,在业务组件中如果需要使用n个svg资源的话,就不需要写n个import语句,只需要引入assets/icons/index.js,让它去将存放资源的文件夹里面的所有svg资源都引入进来,然后直接在use里面通过href指定即可

假如文件夹中存放的资源太多,不想要引入一些本组件用不到的资源,可以在assets/icons文件夹下以组件为单位创建二级文件夹,只存放该组件用到的资源

本文部分内容转载自掘金文章
作者:MarkMan
原文连接:加快Vue项目的开发速度

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要使用 `require.context` 实现 React Router 6 的约定式路由,需要做以下几个步骤: 1. 在项目中安装 React Router 6:`npm install react-router-dom@next` 2. 创建一个文件夹来存放所有的路由组件,比如 `pages` 文件夹。 3. 在 `pages` 文件夹下创建每个路由对应的组件文件,比如 `Home.js`、`About.js` 等。 4. 在 `pages` 文件夹下创建一个 `index.js` 文件,用于导出所有路由组件。 5. 在根目录下创建一个名为 `routes.js` 的文件,用于定义约定式路由规则。 下面是一个示例的 `routes.js` 文件: ```jsx import { lazy } from 'react'; // 使用 require.context 导入所有的路由组件 const pages = require.context('./pages', true, /\.js$/); const routes = [ { path: '/', element: lazy(() => import('./pages/Home')), }, { path: '/about', element: lazy(() => import('./pages/About')), }, ]; export default routes; ``` 在上面的示例中,我们使用 `require.context` 导入了 `pages` 文件夹下的所有 `.js` 文件,并且定义了每个路由的路径和对应的组件。 最后,在根组件中使用 React Router 6 的 `Routes` 组件来渲染路由: ```jsx import React, { lazy, Suspense } from 'react'; import { BrowserRouter as Router, Routes, Route } from 'react-router-dom'; import routes from './routes'; const App = () => { return ( <Router> <Suspense fallback={<div>Loading...</div>}> <Routes> {routes.map((route, index) => ( <Route key={index} path={route.path} element={<route.element />} /> ))} </Routes> </Suspense> </Router> ); }; export default App; ``` 在上面的示例中,我们遍历 `routes` 数组,并使用 `Route` 组件来渲染每个路由。 这样就可以使用 `require.context` 实现 React Router 6 的约定式路由了。注意,这只是一个简单的示例,你可以根据自己的需求进行修改和扩展。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值