Webpack高级应用篇(四):模块解析(Module Resolution)

目录

    • webpack 中的解析规则
      • 绝对路径
      • 相对路径
      • 模块路径
    • 解析(Resolve)
      • resolve.alias
      • resolve.extensions
    • 外部扩展(Externals)
      • externals

resolver 是一个帮助寻找模块绝对路径的库。 一个模块可以作为另一个模块的依赖模块,然后被后者引用,如下:

import foo from 'path/to/module';
// 或者
require('path/to/module');

所依赖的模块可以是来自应用程序的代码或第三方库。 resolver 帮助 webpack 从每个 require/import 语句中,找到需要引入到 bundle 中的模块代码。 当打包模块时,webpack 使用 enhanced-resolve 来解析文件路径。

webpack 中的解析规则

使用 enhanced-resolve,webpack 能解析三种文件路径:

绝对路径

import '/home/me/file';

import 'C:\\Users\\me\\file';

由于已经获得文件的绝对路径,因此不需要再做进一步解析。

相对路径

import '../src/file1';
import './file2';

这种情况下,使用 importrequire 的资源文件所处的目录,被认为是上下文目录。 在import/require 中给定的相对路

径,enhanced-resolve 会拼接此上下文路径,来生成模块的绝对路径(path.resolve(__dirname, RelativePath)) 。 这也是我们在写代码时最常用的方式之一,另一种最常用的方式则是模块路径。

模块路径

import 'module';
import 'module/lib/file';

也就是在 resolve.modules 中指定的所有目录检索模块(node_modules里的模块已经被默认配置了)。 你可以通过配置别名的方式来替

换初始模块路径, 具体请参照下面 resolve.alias 配置选项。


解析(Resolve)

object

resolve.alias

上文中提到我们可以通过 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 文件夹的绝对路径配置为一个模块路径,起一个别名为 @。 重启服务发现,代码跑起来了。模块识别成功了。


resolve.extensions

[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)

externals 配置选项提供了「从输出的 bundle 中排除依赖」的方法。相反,所创建的 bundle 依赖于那些存在于用户环境(consumer’s environment)中的依赖。此功能通常对 library 开发人员来说是最有用的,然而也会有各种各样的应用程序用到它。

externals

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(/* ... */);

未完待续~

你可能感兴趣的:(Webpack,前端工程化,webpack,resolve,resolve.alias,extentions,外部扩展externals)