在实际的项目开发中,可能会引入不同来源的模块依赖,一般情况下webpack在打包时的模块依赖分为两大类:
- 模块来源自自己编写的代码
- 模块来源于npm安装的第三方库
那么webpack在打包的时候遇到import语句或者require语句的时候,该如何正确的引入合适的模块代码呢? 这就要用到resolve配置,resolve下的配置都是用来告诉webpack从每个require/import语句中,找到需要引入到bundle中的模块代码。所以resolve的作用就是帮助webpack寻找模块绝对路径的。当打包模块时,webpack 使用 enhanced-resolve 来解析文件路径。
webpack可以对三种文件路径进行解析:
如果模块的路径是一个绝对路径,那么无需再做进一步的解析,比如:
import '/home/me/file';
import 'C:\\Users\\me\\file';
如果模块的路径是一个相对路径,那么就会分两步来确定最终导入模块的绝对路径:
- 首先确定当前使用import或者require的文件的目录,这个目录也就是上下文目录;
- 然后读取import语句导入时的相对路径,拼接上前面的上下文路径,得到模块的绝对路径
比如在main.js中导入模块:
import APP from "./pages/app.vue"
首先确定当前使用import或者require的文件的目录也就是上下文目录,可以使用path.resolve(__dirname)来进行获取,获取到的路径如下:
C:\Users\克林辣舞\Desktop\webpack\webpack-demo\src
然后将相对路径"./pages/app.vue"拼接即可,得到最终的模块绝对路径:
C:\Users\克林辣舞\Desktop\webpack\webpack-demo\src\pages\app.vue
如果import/require语句导入了一个第三方模块,那么此时webpack就会基于resolve.modules的配置去指定的目录检索模块,默认情况下resolve.modules的值为"node_modules",这也就意味着webpack默认就会去"node_modules"文件夹中读取模块。当然
在解析完路径之后,如果路径的末尾是一个没有后缀名的文件或者是一个文件夹,那么还需要借助于resolve.extensions和resolve.mainFiles属性来正确的找到最终的模块。
- 文件有拓展名,比如后面是.js、.jsx等,那么就直接加载这个模块即可,比如:
import home from "./pages/home.jsx"
- 文件没有拓展名,此时webpack并不知道你要加载的是何种类型的模块,此时webpack就会去读取resolve.extensions属性的值,并且读取该属性的值来为此模块加上一个后缀名,然后再加载模块
import utils from "./utils/math"
读取resolve.extensions属性的值:
module.exports = {
resolve:{
extensions:['.js', '.json', '.wasm','.jsx','.vue']
},
}
为math模块拼接上.js后缀,最终得到完整路径:
import utils from "./utils/math.js"
- webpack首先会读取resolve.mainFiles属性的值,并按照resolve.extensions配置指定的文件顺序查找。resolve.extensions的默认值是["index"]
- 再根据resolve.extensions属性配置的值为该文件添加上一个拓展名
import app from "./pages"
首先查找resolve.mainFiles配置的值:
module.exports = {
resolve:{
extensions:['.js', '.json', '.wasm','.jsx','.vue'],
mainFiles: ['index','main'],
},
}
等于读取到的文件为:
import app from "./pages/index"
然后再读取resolve.extensions属性的值为.js,所以最终解析出的文件路径为:
import app from "./pages/index.js"
当我们项目的目录结构比较深的时候,此时如果我们引用一个模块的时候可能需要使用"../../../../"这种相对路径来引入,为了避免这种多个../的书写问题,我们可以在resolve中对常见的路径配置一个项目目录别名:
module.exports = {
resolve:{
extensions:['.js', '.json', '.wasm','.jsx','.vue','.mjs','.ts'],
mainFiles: ['index','main'],
alias:{
"@":path.resolve(__dirname,'./src');
"pages":path.resolve(__dirname,'./src/pages');
}
},
}
alias的值是一个对象,可以接受多个项目目录别名配置,在配置之后就可以在项目中基于别名来引入资源:
import Home from "@/Home.vue";
当我们在代码中导入一个来自node_modules包的时候,默认情况下其实是以下字段的顺序去包的package.json文件下导入模块:
module.exports = {
resolve:{
mainFields:['browser','module','main']
}
}
上面代码的意思是默认情况下,webpack在打包时候遇到第三方模块的时候,是按照'browser'-'module'-'main'字段的顺序去导入模块的,一般情况下都是main字段对应的文件路径,也就是导入模块的路径。