引入
在运用前端主流框架(react,vue,angular)开发过程中,引入一个模块或文件路径,是如何解析到目标文件的?是按照什么样的规则和顺序查找到的?这个问题乍一看是简单,尤其在小型项目中,模块和文件并不多的情况下。但遇到一些比较复杂的项目,模块和文件路径的引入需要谨慎小心,这就需要深入地理解一下webpack的代码路径解析规则了。
路径
首先,综合一下在项目中配置路径的三种形式
- 相对路径
相对路径是相对于当前目录的路径
import {button} from '../component/button'
复制代码
- 绝对路径
绝对路径直接指明了文件的具体位置,直接可以查找到(不建议使用)
import {button} from '/home/me/file'
复制代码
- 模块名
直接引入模块名,会查找当前文件目录,父级目录直至根目录下的 node_modules(默认) 文件夹,看是否有对应名称的模块。
import React from 'react'
import "module/lib/file";
复制代码
注意:默认的node_modules可以根据webpack配置的
resolve.modules
进行更改
注意:查找中会根据webpack配置的
resolve.extensions
自动补全扩展名
注意:查找中会根据wepack配置的
resolve.alias
替换掉别名
路径解析
根据上述规则解析路径后,解析器将路径指向文件或者文件夹(目录)
-
如果是文件,直接加载
-
如果是文件夹,查找里面是否有package.json文件
1)如果有,默认按照里面的main字段的文件名查找文件 (可以通过
resolve.mainFields
配置更改)2)如果没有,默认查找index.js文件(可以通过
resolve.mainFiles
配置更改)
resolve配置
了解上述的路径形式和最终的解析规则后,根据我的一些标识,大致上也能够看出webpack路径配置的发挥空间了。
webpack解析代码路径的核心模块是
enhanced-resolve
模块
webpack解析匹配代码路径的配置在
resolve
里面
接下来将着重对resolve中alias,extensions,modules,mainFields,mainFiles属性做单独详细的介绍。
resolve.alias
alias,顾名思义,是指路径的别名。简单点说,就是用一个简单的别名来替换一个常用的或者复杂的文件路径。
原理:先替换,后解析。在引入模块时,先将模块路径中匹配alias中的key替换成对应的value,再做查找。
注意一下几点:
- 替换掉的路径可以是相对路径,也可以是绝对路径。
resolve: {
alias: {
'@': path.resolve(__dirname, 'components'),
// 这里使用 path.resolve 和 __dirname 来获取绝对路径
// import '@/Button.js' 等同于 import '[项目绝对路径]/components/Button.js'
x: './src/components' // 相对路径
}
}
复制代码
2.这里的匹配是模糊匹配,不是精确匹配。即路径中携带别名即可匹配
3.注意精确匹配的用法。在key的末尾带一个$字符
resolve: {
alias: {
'vue$': 'vue/dist/vue.esm.js',
'x$': 'module/dir'
// Import 'x/file.js' // 这里不能匹配
}
}
复制代码
resolve.extensions
extensions中指定了webpack可以识别的文件扩展名。
注意一下几点:
- 扩展名匹配的先后顺序。从左到右依次匹配。比如下例中,引入import {Button} from './component/button',优先匹配的是button.js,如果没有button.js,会匹配button.vue,依次往下。
- extensions中没有的后缀,是不会自动补全的。比如下例中没有css的扩展名,如果想引入import {Button} from './style/button',是匹配不到button.css文件的
resolve: {
extensions: ['js', 'vue', 'json']
}
复制代码
resolve.modules
查找声明依赖名的模块,默认搜索node_modules目录。一般我们不修改这个配置。
resolve: {
modules: ['node_modules']
},
复制代码
resolve.mainFields
在引用模块时,指明使用package.json中哪个字段指定的文件,默认是“main”
resolve: {
// 配置 target === "web" 或者 target === "webworker" 时 mainFields 默认值是:
mainFields: ['browser', 'module', 'main'],
// target 的值为其他时,mainFields 默认值为:
mainFields: ["module", "main"],
}
复制代码
因为通常情况下,模块的 package 都不会声明 browser 或 module 字段,所以便是使用 main 了。
resolve.mainFiles
在目录中没有package.json时,指明使用该目录中哪个文件,默认是index.js
resolve: {
mainFiles: ['index'], // 可以添加其他默认使用的文件名
}
复制代码
最后
resolve除了上面介绍的几个属性外,还有其他一些属性,有兴趣的筒子们可以再深入研究一下。希望我这篇文章对还不太清楚webpack代码路径的童鞋有一定的指引作用~~