import...from... 和 require 如何找到模块位置?

简介: 昨天写了一篇文章,是关于 Vite 的,基于 Vite 从 0 到 1 启动一个 Vue2 项目,文章后面留下了几个问题是关于模块寻址问题,举个 Vue 项目里比较常用的 Vue 模块导入例子 import Vue from "vue"; 为什么不用写相对地址和绝对地址就能够导出 Vue 呢?似乎也没有配置路径?也没有配置映射,那么究竟 from "vue"; 对应的究竟是那个路径呢?

昨天写了一篇文章,是关于 Vite 的,基于 Vite 从 0 到 1 启动一个 Vue2 项目,文章后面留下了几个问题是关于模块寻址问题,举个 Vue 项目里比较常用的 Vue 模块导入例子

import Vue from "vue";
AI 代码解读

为什么不用写相对地址和绝对地址就能够导出 Vue 呢?似乎也没有配置路径?也没有配置映射,那么究竟 from "vue"; 对应的究竟是那个路径呢?

先提出两个可能的方案

  1. VS Code/WebStorm 这些 IDE 自己编撰的映射,并缓存了
  2. Webpack/Vite 这些开发工具自带的映射

关于上面这两个方案其实很容易验证,基于终端/命令行去运行项目并且不使用 WebpackVite 这两个库

  1. 第一步,执行以下语句
npm init
# shelljs 是一个可以使用 node 执行 shell 脚本的库
# 例子中使用 shelljs 测试输出
npm install shelljs
AI 代码解读
  1. 第二步,在 package.json 同目录下创建 index.js,内容如下
const shelljs = require("shelljs");

shelljs.exec("echo Hello World");
AI 代码解读
  1. 第三步,测试运行 node index.js,输出如下

IMG

即证与 IDEWebpack/Vite 无关

那究竟是怎么找到的呢?

node 模块

仔细观察 node index.js 是通过 node 执行的,所以有没有可能是通过 node 去找到的模块呢?

那么 node 执行 .js 文件时是按照什么规则来寻找的呢?

假设在 Y 路径执行 index.js

// index.js
const module = require(X)
AI 代码解读

X 以 或 './' 或 '../' 开头

判断 Y + X 是文件还是目录

Y + X 是文件

  1. 如果 X 是一个文件,加载 X 作为 JavaScript 文本。结束
  2. 如果 X.js 是一个文件,加载 X.js 作为 JavaScript 文本。结束
  3. 如果 X.json 是一个文件,解析 X.json 成一个 JavaScript 对象。结束
  4. 如果 X.node 是一个文件,加载 X.node 作为二进制插件。结束

例子

// index.js
const shelljs = require("./X");

shelljs.exec("echo Hello World");
AI 代码解读
// X.js
module.exports = {
  exec: () => {
    console.log("Hello World");
  }
}
AI 代码解读
├── index.js
└── X.js
AI 代码解读

IMG

注意,有文档称,require(/X) 这种方式也可以找到对于的模块,但在 node@16.15.1 的版本中已经不行,是无法找到的

Y + X 是目录

判断是否有名称为 index 的文件

Y + X 目录下有名为 index 的文件

  1. 如果 X/index.js 是一个文件,加载 X/index.js 作为 JavaScript 文本。结束
  2. 如果 X/index.json 是一个文件,解析 X/index.json 成一个 JavaScript 对象。结束
  3. 如果 X/index.node 是一个文件,加载 X/index.node 作为二进制插件。结束

Y + X 目录下没有名为 index 的文件

根据 Y + X 目录下的 package.json"main" 字段找到对应的文件

没有 package.json 怎么办?当然是报错咯

X 是模块名称

  1. 先去系统模块寻找
  2. 系统模块没有找到就去执行环境的同目录下找 node_modules,查看有无同名的 .js 文件

    1. 没有同名的 .js 文件就去找同名目录

      1. 如果找到了,就查看文件夹里有没有 index.js
      2. 没有找到就查看 package.json"main" 属性来确定
    2. 没有同名目录,抛出错误
  3. 同目录找不到 node_modules 就去父目录找,父目录找不到就找父目录的父目录,直至找到全局 node_modules

关于 node 更加详细的‘寻模块’规则,可以去查阅这个文档,里面有一个伪代码,非常详细和清晰

ES Module

上面讲了 require 的寻找规则,但是没讲 ES Module 的寻找规则(即 import),其实它们的寻址方式是一致的,不过 ES Module 需要在 package.json 设置 "type" 字段为 module 才可以开启,而且找的是package.json"module" 字段对应的文件

// package.json
{
  "type": "module"
}
AI 代码解读

那么回到文章一开始提到的 import Vue from "vue";,它最终找到的模块是什么呢?因为 Vue 本身提供多种打包文件(Commen.jsES Module

IMG

如上图所示 import Vue from "vue"; 最终找的是 vue.runtime.esm.js,这也就解释了为什么导出来的 Vue 是不带编译时只有运行时的了

目录
打赏
0
1
1
0
3
分享
相关文章
苹果电脑 Mac OS X 系统上防止误按 command+Q 退出软件
在Mac系统操作中,Command + W 关闭一个窗口,Command + Q 退出整个程序,这用起来很方便快捷。然而,由于Q和W、A紧紧挨着已经有N次想关窗口的时候,或者想全选的时候,按成了Command Q,简直疯了有没有?…… 为了避免这种悲剧的发生,查找收集了几个方法: 1、针对Chrome 可以勾选退出前提示: 2、小工具 QBlocker QBlocker 是一款能够帮你暂时禁止使用 command + Q 的小工具。
10604 1
4步教你用rvest抓取网页并保存为CSV文件
本文介绍如何使用R语言的`rvest`包抓取网页数据并保存为CSV文件,以界面新闻网站为例。通过设置代理IP(如亿牛云)、User-Agent和Cookie,增强访问稳定性和安全性。代码涵盖环境配置、数据抓取、解析及保存步骤,确保高效、稳定地获取网页数据。适用于数据分析和统计分析场景。
166 8
4步教你用rvest抓取网页并保存为CSV文件
在K8S中,节点故障驱逐pod过程时间怎么定义?
在K8S中,节点故障驱逐pod过程时间怎么定义?
写歌词的技巧和方法:优化歌词结构的秘诀,妙笔生词AI智能写歌词软件
歌词是音乐的灵魂,优化其结构能让作品更加动人。掌握开头吸引人、主体结构清晰、情感递进自然及结尾余味悠长等技巧至关重要。同时,借助《妙笔生词智能写歌词软件》的多种AI功能,如智能写词、押韵优化等,可有效提升创作效率与质量,为你的歌词增添光彩。
java制作海报三:获取微信二维码详情,并改变大小,合成到海报(另一张图片)上
这篇文章介绍了如何使用Java获取微信小程序的二维码,并将其调整大小后合成到海报(另一张图片)上。
155 0
C++一分钟之-内存模型与数据竞争
【7月更文挑战第10天】了解C++11内存模型对多线程编程至关重要。它定义了线程间同步规则,包括顺序一致性、原子操作和内存屏障。数据竞争可能导致不确定行为,如脏读和丢失更新。可通过互斥量、原子操作和无锁编程避免竞争。示例展示了`std::mutex`和`std::atomic`的使用。掌握内存模型规则,有效防止数据竞争,确保多线程安全和性能。
167 0
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等

登录插画

登录以查看您的控制台资源

管理云资源
状态一览
快捷访问