工程自动化导入:require.context

require

webpack帮我们把项目打包到dist目录下,不会是无脑把所有文件都打包,会先静态解析,把我们需要用的文件打包,比如没有任何地方引用的图片,打包后,这个图片就不会出现在dist/static/img目录内。

传参无法使用变量

require('./image/title.png')
复制代码

很多时候我们都希望能够将上面这种引入方式,写成动态的

let imagePath = './image/title.png'
require(imagePath)
复制代码

imagePath只有在运行时才会明确知道需要引入的路径,但是这种写法是不允许的,或许从语法上来说不会报错,但是webpack在构建打包时并不能解析出需要的路径
require需要知道至少能确定是哪个目录

let imageFullName = 'title.png'
1. require(`./image/${imageFullName}`)

let imageFullName = 'title'
2. require(`./image/${imageFullName}.png`)
复制代码

以上两种方式都是可以的,就算只有一个明确的目录,webpack也还是可以解析的,但是这样会导致生成的上下文模块context会包含该目录下所有可能会用到的模块。

require.context

require直观上不同的是,require.context是引入多个模块
require.context可以理解为创建自己的上下文模块context
有三个参数:
1.directory 文件目录
2.useSubdirectories 是否查找子目录
3.regExp 要匹配文件的正则表达式

// 引入model目录下的所有以js后缀的文件
require.context('./model',true,/.js$/)
复制代码

require.context可以理解为内部将所有模块整合为一个map,模块以路径为key

{
'./a.js':model,
'./b/f.js':model,
...
}
复制代码

require.context返回一个函数,接受一个key参数,然后返回对应key的模块
require.context返回的函数有三个属性:
1.resolve 是一个函数,它返回 request 被解析后得到的模块 id。
2.keys 是一个函数,返回一个有所有模块的key组成的数组
3.id 是 context module 里面所包含的模块 id

import

import命令是静态引入,先于模块内其他模块执行,与require函数的动态引入不同,如果项目中大量的import命令静态引入模块,会导致初始包变大,直接影响的便是加载时长,所以又提出了一个import()函数,其两者的区别主要是在与一个是静态引入,一个是在运行时引入。
因为import()是运行时执行,所以可以放在任何地方,import命令的话,则必须放在模块顶层
import()返回的是一个Promise

let imageUrl = ''
import('./image/title.png').then(res => {
  imageUrl = res
})
复制代码

import()可以用来解决很多按需加载的性能优化问题,例如vue路由组件的按需加载、局部组件注册时的异步加载

利用require.context完成工程自动化导入

import a from "./a.js"
import b from "./b.js"
import c from "./c.js"
...
复制代码

工作当中经常会遇到以上场景,像这种脱离业务且重复有规律的操作完全可以想办法弄成自动化
vuex分模块设计来举例

//index.js
import Vue from 'vue'
import Vuex from 'vuex'

import app from "./model/app.js"
import user from "./model/user.js"
...

export default new Vuex.Store({
   modules:{
     app,
     user,
     ...
   }
})
复制代码

当项目应用很大时,甚至会分十几上百个模块,届时光引模块的代码都会显得十分冗余。可以利用require.context一次性将模块全部引入

//index.js
import Vue from 'vue'
import Vuex from 'vuex'
import { resetModelName } from './util'

// 自动导入model
const requireModels = require.context('./model', true, /.js$/)
const storeModules = {}
requireModels.keys().forEach((item) => {
    storeModules[resetModelName(item)] = requireModels(item).default
})

export default new Vuex.Store({
   modules:{
     ...requireModels
   }
})


// util.js
/**
 * 文件路径名转格式:例:'./a/b.js' -> 'a_b'
 * @param {*} str String
 * @returns String
 */
export function resetModelName(str) {
    str = str.replace(/.js$/g, '')
    str = str.replace(/\.+\//g, '')
    str = str.replace(/\//g, '_')
    str = str.replace(/\//g, '')
    return str
}
复制代码

按约定好的规则,后面在model目录内添加的模块,会被自动引入到vuex实例中。或者也可以在此基础之上再进行封装,做成可配置化,提供例如 命名规则、是否查找子目录、自动话开关等等配置项。无论是简单的约定规则,还是复杂强大的配置化规则,都会对前端整个团队的规范有帮助。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享