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
实例中。或者也可以在此基础之上再进行封装,做成可配置化,提供例如 命名规则、是否查找子目录、自动话开关等等配置项。无论是简单的约定规则,还是复杂强大的配置化规则,都会对前端整个团队的规范有帮助。