前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
首页程序员面试题库import.meta.url 浏览器与 Node.js 差异
JavaScript模块与语言机制

import.meta.url 在浏览器和 Node.js 里分别拿到的是什么?

import.meta.url 是当前这个模块文件自己的完整 URL。浏览器里是 https://... 地址,Node.js 里是 file:///... 地址。最常见的用法是 new URL("./x.png", import.meta.url),拿到和当前模块同目录的资源地址。

前端进阶之旅 · 一题精讲更新于 2026.09.29
JavaScript#模块与语言机制
先看核心答案读代码示例
理解线索

同一个属性,两种环境

  1. 浏览器模块脚本的请求地址;内联模块脚本拿到的是页面地址
  2. Node.jsfile:// 开头的绝对路径 URL,要转路径得用 fileURLToPath
  3. import.meta宿主提供的模块元信息对象,每个模块一份

它是 URL 不是文件路径,里面的空格、中文都是百分号编码过的。在 Node.js 里直接拿它去 fs.readFile 或者手动截掉 file://,遇到这类路径就会出错。

核心回答

先记住这个答案

import.meta.url 是当前模块文件自己的完整 URL。在浏览器里,它是这个模块脚本被请求时的地址,比如 https://cdn.example.com/lib/a.js;在 Node.js 里,它是 file:///Users/me/app/a.mjs 这样的文件 URL。它和页面地址、入口文件都没关系,每个模块读到的都是自己的地址。所以它主要用来定位「和我放在一起的其它文件」。

  • 它是当前模块的地址,不是页面地址,也不是入口文件地址
  • 浏览器通常是网络 URL,Node 是文件 URL
  • ESM 用 import.meta.url 定位当前文件
  • new URL() 可定位相邻资源

Node.js 里替代 __dirname

CommonJS 里有 __filename 和 __dirname,换成 ESM 后这两个变量不存在了,直接用会报 ReferenceError。替代方案就是从 import.meta.url 推出来。

从 URL 得到文件路径和目录JavaScript
// /Users/me/app/src/config.mjs
import { fileURLToPath } from 'node:url'
import path from 'node:path'

console.log(import.meta.url)
// file:///Users/me/app/src/config.mjs

const __filename = fileURLToPath(import.meta.url) // /Users/me/app/src/config.mjs
const __dirname = path.dirname(__filename) // /Users/me/app/src

// 读同目录的文件,也可以直接传 URL 对象给 fs
const tplUrl = new URL('./template.html', import.meta.url)

一定要用 fileURLToPath 转换,不要用字符串把 file:// 截掉。路径里有空格或中文时,URL 里是 %20、%E4%B8%AD 这样的编码,手动截取得到的路径根本找不到文件,Windows 上还会多出一个开头的斜杠。 较新版本的 Node.js 直接提供了 import.meta.dirname 和 import.meta.filename,效果和上面两行一样。项目要兼容旧版本时还是用 fileURLToPath 最稳。

浏览器里的值和资源定位

浏览器里 import.meta.url 就是模块脚本的最终请求地址,包括查询参数。如果是写在 HTML 里的内联 <script type="module">,它没有自己的文件,拿到的是页面的地址。

用 new URL 定位静态资源
组件库里经常要加载和自己放在一起的图片、字体或 WASM。写 new URL("./icon.svg", import.meta.url).href,拿到的地址会跟着模块走:模块部署到 CDN,图片地址也自动是 CDN 上的地址,不受页面路径影响。 这个写法还有一个好处,Vite 和 Webpack 5 都能识别 new URL("./x", import.meta.url) 这种固定形式,构建时会把对应文件一起打包并改写成带哈希的地址。所以写法要保持字面量形式,路径拼成变量就识别不出来了。
回答前,多想一步

容易答错的地方

以为它是页面的 URL
只有内联模块脚本才是页面地址。外部模块拿到的是模块自己的地址,页面在 /user/list,模块在 /assets/a.js,读到的就是后者。要页面地址用 location.href。
以为 Node.js 里它就是文件路径
它是 URL 对象的字符串形式,带 file:// 前缀,字符经过编码。传给需要路径的 API 前要先 fileURLToPath。好在 fs 的大部分方法本身也接受 URL 对象,传 new URL(...) 也行。
在 CommonJS 或普通脚本里用它
import.meta 只能出现在 ES 模块里。CommonJS 文件或普通 <script> 里写它,解析阶段就是语法错误,不是运行时返回 undefined。
试着用自己的话回答

面试官还会怎么问?

为什么 ESM 不提供 __dirname?

ESM 是为浏览器和服务端共同设计的,浏览器里的模块根本没有「目录」的概念,只有 URL。所以规范统一给的是 URL,文件路径由 Node.js 这类宿主自己换算。__dirname 是 CommonJS 包装函数注入的局部变量,本来就不是语言的一部分。

加了查询参数的导入,import.meta.url 会带上吗?

会。import("./a.mjs?v=2") 加载的模块里,import.meta.url 末尾就是 ?v=2。同时它也会被当成一个新模块再执行一次,因为模块缓存是按完整 URL 区分的。

Worker 里怎么用它?

创建模块 Worker 时写 new Worker(new URL("./worker.js", import.meta.url), { type: "module" }),保证 Worker 文件相对当前模块定位。Vite 和 Webpack 5 也专门识别这个写法,会把 Worker 文件单独打包。

从一道题,走向一组知识

把知识连起来

模块与语言机制

好几个文件都 import 同一个模块,它的代码会执行几次?

模块按 URL 缓存,import.meta.url 带不带查询参数,决定了会不会被当成另一个模块再执行一次。

模块与语言机制

import * as ns 拿到的对象是冻结的吗?能改它的属性吗?

import.meta 和模块命名空间对象都是宿主给模块的特殊对象,一个放元信息,一个放导出。

参考资料

  • JavaScript:模块与语言机制参考资料

示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。

本题目录
  1. 先记住这个答案
  2. Node.js 里替代 __dirname
  3. 浏览器里的值和资源定位
  4. 容易答错的地方
  5. 面试官还会怎么问
  6. 把知识连起来
读懂,再试着讲出来

先看核心答案,再读代码。最后展开追问,检查自己有没有遗漏边界。

试着回答追问
浏览全部面试题理解原理,也关注真实的使用场景。回到顶部 ↑