前端批量导入的三种方式以及深入理解require.content中的mode参数

384 阅读1分钟

以下说明都以批量导入路由为例

1.基于Webpack的require.context批量导入

//files返回一个函数
const files = require.context('./modules', false, /\.tsx$/, 'sync')//默认是sync模式
//如果是路由这种开始就要导入的就用同步sync模式,如果是异步组件这种就用异步导入
export const rootRouter: RouteObject[] = [
  {
    path: '/',
    //非懒加载组件
    element: <Login />,
    //路由元信息
  },
]

//通过files.keys()遍历获取每个id,然后调用files(id),把遍历获取的id传入这个函数,最后返回一个模块,通过.default获取
files.keys().forEach(key => {
  //1.通过sync方式(会阻塞同步代码)
  rootRouter.push(...files(key).default)
  //2.通过lazy,lazy-once,eager方式,返回一个promise,(调用时不会阻塞同步代码)
  files(key).then((module: any) => {
    rootRouter.push(...module.default)
  })
})


require.context的第四个参数模式:

前言:我现在有四个路由模块,批量导入,可以理解为bundle是打包后当前整个文件的代码,chunk相当于是当前导入部分用到的的代码块

  • sync 直接打包到当前文件的bundle中(导入的这部分代码会被立即打包到bundle中并且直接执行,可以理解为开始就加载并执行),不生成单独chunk,同步加载并执行 image.png 四个模块全部被打包到当前文件的bundle了

  • lazy 延迟加载(异步导入)会为每个模块分离出单独的 chunk 文件(发起导入的这部分代码不会被预打包到bundle中,在执行时生成chunk加载该部分的代码并且执行,可以理解为开始不加载,调用执行时再加载代码并执行),返回promise需要时调用(调用时异步执行代码不阻塞同步代码,每次执行都会重新发起请求异步导入一次) image.png 可以看到被分离为了四个不同的chunk,并且每次重载都会重新导入一次这四个模块

  • lazy-once 延迟加载会分离出单独的 chunk 文件但是多个模块会合成一个chunk(发起导入的这部分代码不会被预打包到bundle中,在执行时生成chunk加载该部分的代码并且执行,可以理解为开始不加载,调用执行时再加载代码并执行),返回promise需要时调用,加载过下次再加载直接读取内存里的代码(并建立缓存,后续再次导入使用第一次导入的数据)

image.png

  • eager 和sync相同,代码会预先被打包到一个bundle中(发起导入的这部分代码会预打包到bundle中,可以理解为开始就加载,但是不立即执行),区别是eager返回的promise可以延迟执行(但是代码其实是预加载到了bundle中,只是何时执行由我们决定)

2.基于Vite的glob和globEager(代码以globEager为例)

const metaRouters = import.meta.globEager("./modules/*.ts");


export const routerArray: RouteRecordRaw[] = [];
//globEager不像require.context返回一个函数,然后接收keys再回头调用这个函数,它可以直接用Object.values遍历返回的值
Object.values(metaRouters).forEach(item => {
	console.log(item["default"]);

	routerArray.push(...item["default"]);
});

glob和globEager的区别:与require.context的第四个参数一样,globEager相当于sync,glob相当与lazy

3.node基于fs模块导入后端路由(代码以sync为例)

import Koa from 'koa'
import Router from 'koa-router'
import fs from 'fs'
const useRoutes = function (app: Koa) {
  fs.readdirSync(__dirname).forEach((file: any) => {
    try {
      if (file === 'index.js' || file === 'index.ts') return
      else if (/.[jt]s$/.test(file)) {
        const router: Router = require(`./${file}`).default
        app.use(router.routes()).use(router.allowedMethods())
      }
    } catch (error) {
      console.errtime('路由注册失败:' + error + '文件名:' + file)
    }
  })
}

fs如果想要变成异步可以用fs/promise

import fs from 'fs/promise'
 fs.readdir()//node中从xx/promise导入node自带的异步方法的模块,方法不需要以Sync结尾