resolver
是一个帮助寻找模块绝对路径的库。 一个模块可以作为另一个模块的依赖模块,然后被后者引用,如下:
import foo from 'path/to/module';
// 或者
require('path/to/module');
所依赖的模块可以是来自应用程序的代码或第三方库。 resolver
帮助 webpack
从每个 require
/import
语句中,找到需要引入到 bundle
中的模块代码。 当打包模块时,webpack
使用 enhanced-resolve 来解析文件路径。
使用 enhanced-resolve
,webpack 能解析三种文件路径:
import '/home/me/file';
import 'C:\\Users\\me\\file';
由于已经获得文件的绝对路径,因此不需要再做进一步解析。
import '../src/file1';
import './file2';
这种情况下,使用 import
或 require
的资源文件所处的目录,被认为是上下文目录。 在import/require
中给定的相对路
径,enhanced-resolve
会拼接此上下文路径,来生成模块的绝对路径(path.resolve(__dirname, RelativePath)
) 。 这也是我们在写代码时最常用的方式之一,另一种最常用的方式则是模块路径。
import 'module';
import 'module/lib/file';
也就是在 resolve.modules
中指定的所有目录检索模块(node_modules
里的模块已经被默认配置了)。 你可以通过配置别名的方式来替
换初始模块路径, 具体请参照下面 resolve.alias
配置选项。
object
上文中提到我们可以通过 resolve.alias
来自定义配置模块路径。现在我们来实现一下:
首先,我们 src
目录下新建一个 utils
文件夹,并新建一个 add.js
文件,对外暴露出一个add
函数。
// src/utils/add.js
export default function add(a, b){
return a + b;
}
然后我们在src/index.js
中基于相对路径引用并使用它:
import add from './utils/add';
console.log(add);
运行项目并且没有报错。 这时我们期望能用 @/utils/add
的方式去引用它,于是我们这样写了:
import add from '@/utils/add';
console.log(add(a,b));
很明显它会报错,因为webpack
会将其当做一个模块路径来识别———所以无法找到 @
这个模块。 这时,我们配置下resolve
:
// webpack.config.js
const path = require('path');
module.exports = {
//...
resolve: {
alias: {
"@": path.resolve(__dirname, './src')
},
},
};
如代码所示,我们将 src
文件夹的绝对路径配置为一个模块路径,起一个别名为 @
。 重启服务发现,代码跑起来了。模块识别成功了。
[string] = ['.js', '.json', '.wasm']
上述代码中我们发现,只需要 import add from '@utils/add
, webpack
就可以帮我们找到add.js。 事实上,这与import add from ‘@utils/add.js’ 的效果是一致的。 为什么会这样? 原来webpack的内置解析器已经默认定义好了一些 文件/目录 的路径解析规则。 比如当我们
import utils from './utils';
utils
是一个文件目录而不是模块(文件),但webpack
在这种情况下默认帮我们添加了后缀/index.js
,从而将此相对路径指向到utils里的 index.js
。 这是webpack
解析器默认内置好的规则。 那么现在有一个问题: 当utils
文件夹下同时拥有add.js
add.json
时,@utils/add
会指向谁呢?
@utils/add.json
{ "name": "add" }
我们发现仍然指向到add.js
。 当我们删掉add.js
,会发现此时的引入的add
变成了一个json
对象。 上述现象似乎表明了这是一个默认
配置的优先级的问题。 而webpack
对外暴露了配置属性: resolve.extensions
, 它的用法形如:
// webpack.config.js
module.exports = {
//...
resolve: {
extensions: ['.js', '.json', '.wasm'],
},
};
webpack会按照数组顺序去解析这些后缀名,对于同名的文件,webpack总是会先解析列在数组首位的后缀名的文件。
externals
配置选项提供了「从输出的 bundle 中排除依赖」的方法。相反,所创建的 bundle 依赖于那些存在于用户环境(consumer’s environment)中的依赖。此功能通常对 library 开发人员来说是最有用的,然而也会有各种各样的应用程序用到它。
string
[string]
object
function
RegExp
有时候我们为了减小 bundle
的体积或者想要让我们写的npm组件/类库
依赖用户环境,防止将某些 import
的包(package)打包到 bundle
中,而是在运行时(runtime)再去从外部获取这些扩展依赖(external dependencies),这时我们可以用到外部扩展(Externals)
例如,从 CDN 引入 jQuery,而不是把它打包:
index.html
<script
src="https://code.jquery.com/jquery-3.1.0.js"
integrity="sha256-slogkvB1K3VOkzAI8QITxV3VzpOnkeNVsKvtkYLMjfk="
crossorigin="anonymous"
>script>
webpack.config.js
module.exports = {
//...
externals: {
jquery: 'jQuery',
},
};
其中 jquery
是暴露给你内部代码使用的模块名;jQuery
是外部环境存在的模块名
这样就剥离了那些不需要改动的依赖模块,换句话,下面展示的代码还可以正常运行:
import $ from 'jquery';
$('.my-element').animate(/* ... */);
未完待续~