【node】深入探讨 class URL【node】深入探讨 class URL 📌 浅说 fileURLToPath
【node】深入探讨 class URL
📌 浅说 fileURLToPath()
在vite.config.ts中有这么一段代码:
import { fileURLToPath, URL } from 'node:url'
import { defineConfig } from 'vite'
export default defineConfig({
  resolve: {
    alias: {
      '@': fileURLToPath(new URL('./src', import.meta.url))
    }
  }
})
咱们先来讲讲 fileURLToPath:
// * @param url The file URL string or URL object to convert to a path.
url:url要转换为路径的文件url字符串或url对象。
// * @default undefined
options: 如果' path '应该作为Windows文件路径返回,则为' true ',如果为posix则为' false ',如果为系统默认值则为' undefined '。
// * @return The fully-resolved platform-specific Node.js file path.
返回:特定平台完全解析的Node.js文件路径。
以下示例,来加深理解:
import { fileURLToPath } from 'node:url'
import.meta.url
// file:///D:/test-project/vite.config.ts
fileURLToPath(import.meta.url)
// D:\test-project\vite.config.ts
❌new URL('file:///C:/path/').pathname
// Incorrect: /C:/path/
✔️ fileURLToPath('file:///C:/path/')
// Correct:   C:\path\ (Windows)
❌ new URL('file://nas/foo.txt').pathname
// Incorrect: /foo.txt
✔️ fileURLToPath('file://nas/foo.txt')
// Correct:   \\nas\foo.txt (Windows)
❌ new URL('file:///你好.txt').pathname
// Incorrect: /%E4%BD%A0%E5%A5%BD.txt
✔️ fileURLToPath('file:///你好.txt')
// Correct:   /你好.txt (POSIX)
❌ new URL('file:///hello world').pathname
// Incorrect: /hello%20world
✔️ fileURLToPath('file:///hello world')
// Correct:   /hello world (POSIX)
回到 vite.config.ts 代码段, 来看看这句代码的输出内容是什么:
fileURLToPath(new URL('./src', import.meta.url))
// console
D:\test-project\src
没错,这个输出结果和模块作用域(__filename/_dirname)相似,如:
- __filename
 
__filename
// console
D:\test-project\vite.config.ts
- __dirname
 
__dirname
// console
D:\test-project
- path.dirname(__filename)
 
path.dirname(\_\_filename)
// console
D:\test-project
那么这段代码的含义,就是使用文件系统路径进行别名化处理
alias: {
      '@': fileURLToPath(new URL('./src', import.meta.url))
}
比如,有这么一个文件目录树
test-project/
├── src/
│   ├── assets/
│   │   └── logo.svg
│   └── App.vue
├── index.html
├── vite.config.ts
└── package.json
在 App.vue 中有这么一段代码,来阐述文件路径别名的实际应用:
<img alt="Vue logo" class="logo" src="@/assets/logo.svg" width="125" height="125" />
当然,alias 并不局限对象来实现文件路径别名。它可以是一个 对象,或一个 数组,类型如下:
Record<string, string> |
  Array<{
    find: string | RegExp
    replacement: string
    customResolver?: ResolverFunction | ResolverObject
  }>
🔍 探讨 new URL() 与 new URL() 区别
回到正题,探讨 new URL()
既然有 Web API 的
new URL(),那么nodejs为什么又重写呢?
- 
import { URL } from 'node:url'中的URL是 Node.js 提供的内置模块url中的类,用于处理 URL。 - 
而 MDN 的 URL API 是指 Web 标准中定义的用于处理 URL 的 JavaScript API。
 
这两者虽然都是用于处理 URL,但有一些区别:
- 
Node.js URL 模块:Node.js 的
url模块提供了一组用于解析和格式化 URL 的实用工具。它主要用于服务器端的 JavaScript 程序,如在 HTTP 请求中解析 URL,或在文件系统中处理文件路径。它与浏览器的 URL API 在一些细节上有所不同,因为 Node.js 和浏览器在处理 URL 和文件路径时有不同的需求。 - 
MDN URL API:MDN 上的 URL API 是 Web 标准中定义的 JavaScript API,用于在浏览器环境中处理 URL。它提供了一组用于创建、解析和操作 URL 的方法和属性。与 Node.js 的 URL 模块相比,它更适用于在客户端 JavaScript 中操作 URL,如在 Web 应用程序中处理页面的 URL。
 
虽然这两者有不同的实现和使用场景,但它们都是用于处理 URL 的工具。如果你在 Node.js 环境下开发,可以使用 node:url 模块中的 URL 类。如果你在浏览器环境下开发,可以使用浏览器原生的 URL API。
方法使用、输出区别
- node
 
// vite.config
import { URL } from 'node:url'
new URL(import.meta.url)
// terminal
URL {
  href: 'file:///D:/test-project/vite.config.ts',
  origin: 'null',
  protocol: 'file:',
  username: '',
  password: '',
  host: '',
  hostname: '',
  port: '',
  pathname: '/D:/test-project/vite.config.ts',
  search: '',
  searchParams: URLSearchParams {},
  hash: ''
}
- WEB API
 
// App.vue
new URL(import.meta.url)
// Browser console
URL {
  hash: "",
  host: "localhost:5173",
  hostname: "localhost",
  href: "http://localhost:5173/src/App.vue",
  origin: "http://localhost:5173",
  password: "",
  pathname: "/src/App.vue",
  port: "5173",
  protocol: "http:",
  search: "",
  searchParams: URLSearchParams {size: 0},
  username: "",
}
本质区别就是 web api: URL 无需引用便可用,它是浏览器中的一个标准,当然由浏览器去解析。
如果浏览器尚不支持
URL()构造函数,则可以使用Window中的Window.URL属性。
但是如果你这么做:
// browser
console.log(new URL(import.meta.url))
// console
Uncaught SyntaxError: Cannot use 'import.meta' outside a module
原因是,浏览器终端无法处理 import.meta, 它由 JavaScript 运行时(即浏览器或 Node.js)负责处理,然后交给浏览器呈现。
当然,你可以这么做:
// Browser console
console.log(new URL('file:///D:/test-project/vite.config.ts'))
// console
URL {
  hash:"",
  host:"",
  hostname:"",
  href:"file:///D:/test-project/vite.config.ts",
  origin:"file://",
  password:"",
  pathname:"/D:/test-project/vite.config.ts",
  port:"",
  protocol:"file:",
  search:"",
  searchParams: URLSearchParams { size:0 },
  username:""
}
来一个横向比较图示:
(pc端看效果更佳)
🔐 剖析 Node class URL
参照标准:URL Standard
让我们来看看nodejs的URL类的基本结构是怎么写样的:
class URL {
  static createObjectURL(blob: NodeBlob): string
  static revokeObjectURL(id: string): void
  static canParse(input: string, base?: string): boolean
  constructor(input: string | { toString: () => string }, base?: string | URL)
  hash: string
  host: string
  hostname: string
  href: string
  readonly origin: string
  password: string
  pathname: string
  port: string
  protocol: string
  search: string
  readonly searchParams: URLSearchParams
  username: string
  toString(): string
  toJSON(): string
}
方法:
- 
createObjectURL(blob)
- 用途:创建一个指向传入的 
Blob对象的 URL。 - 注意事项:需要注意在使用后需要通过 
revokeObjectURL(id)来释放 URL,防止内存泄漏。 - 示例:
const { URL } = require('url') const url = new URL('https://example.com') const blob = new Blob(['Hello, world!'], { type: 'text/plain' }) const objUrl = url.createObjectURL(blob) console.log(objUrl) // 输出类似 'blob:https://example.com/5a3c5ebc-79f9-4a70-a3ec-6d9f8a2f2c5f' url.revokeObjectURL(objUrl) // 使用后需要撤销 URL 
 - 用途:创建一个指向传入的 
 - 
revokeObjectURL(id)
- 用途:释放之前通过 
createObjectURL创建的 URL。 - 注意事项:调用后,之前通过 
createObjectURL创建的 URL 将不再有效,应及时释放以避免内存泄漏。 - 示例:见上面的示例。
 
 - 用途:释放之前通过 
 - 
canParse(input, base)
- 用途:检查给定的字符串是否能被解析为有效的 URL。
 - 注意事项:返回一个布尔值,用于判断是否能够成功解析。
 - 示例:
const { URL } = require('url') console.log(URL.canParse('https://example.com')) // true console.log(URL.canParse('not_a_url')) // false 
 
属性:
- 
hash
- 用途:获取或设置 URL 的片段标识符(即 
#后面的内容)。 - 注意事项:可以直接读取和修改,修改后 URL 对象的其他部分会相应更新。
 - 示例:
const { URL } = require('url') const url = new URL('https://example.com#section') console.log(url.hash) // 输出 '#section' url.hash = '#newsection' console.log(url.href) // 输出 'https://example.com#newsection' 
 - 用途:获取或设置 URL 的片段标识符(即 
 - 
host / hostname / href / origin / password / pathname / port / protocol / search / username
- 用途:分别获取或设置 URL 的主机、主机名、完整 URL、源、用户名、路径名、端口、协议、查询部分。
 - 注意事项:这些属性用于精确控制和操作 URL 的不同部分,修改后 URL 对象的其他部分会相应更新。
 - 示例:
const { URL } = require('url') const url = new URL('https://username:password@example.com:8080/path?query=string#fragment') console.log(url.host) // 输出 'example.com:8080' console.log(url.pathname) // 输出 '/path' url.protocol = 'https:' url.searchParams.set('newparam', 'value') console.log(url.href) // 输出 'https://username:password@example.com:8080/path?query=string&newparam=value#fragment' 
 - 
searchParams
- 用途:获取 URL 查询参数部分的 
URLSearchParams对象,用于操作和管理 URL 的查询参数。 - 注意事项:可以使用 
set()、get()、append()、delete()等方法来修改查询参数,修改后 URL 对象的href属性会相应更新。 - 示例:
const { URL } = require('url') const url = new URL('https://example.com/path?query=string') url.searchParams.set('newparam', 'value') console.log(url.href) // 输出 'https://example.com/path?query=string&newparam=value' 
 - 用途:获取 URL 查询参数部分的 
 
其他方法:
- toString():返回序列化后的完整 URL 字符串。
 - toJSON():返回 URL 对象的 JSON 表示,通常与 
JSON.stringify()结合使用。 
实际应用场景:
这些方法和属性使得 URL 类在 Node.js 中成为处理和操作 URL 非常便捷的工具,特别适用于需要频繁处理 URL 的场景,如 Web 服务器开发、爬虫程序等。
⛳ 总结
当谈论现代 Web 开发时,涉及到多种 URL 相关的概念和工具。
Node.js 中的 URL 类提供了强大的 URL 解析和操作功能,适用于服务器端和脚本任务。例如,它允许开发者轻松解析和修改 URL 的各个部分,如协议、主机名、路径和查询参数。
与此同时,Vite 提供了 fileURLToPath 函数,用于将文件 URL 转换为本地文件路径,便于在开发过程中处理模块和资源。
此外,Vite 还支持使用 alias 别名,使开发者能够通过自定义简短的名称引用复杂或深层次的文件路径,提高了项目结构的清晰度和开发效率。
尽管 Node.js 的 URL 类提供了广泛的 URL 处理功能,但它与 Web API 中的 URL 对象存在一些本质区别。
Node.js 的 URL 类主要用于服务器端编程和脚本任务,它的实现更加偏向于文件系统和模块加载的处理。
而 Web API 中的 URL 对象则更加面向浏览器环境,提供了对当前页面 URL 的访问和修改,以及处理跨域资源共享(CORS)等网络相关的特性。
因此,开发者在使用这两种 URL 类时,需要根据具体的应用场景和需求选择合适的工具来操作和管理 URL。
欢迎评论留言~
转载自:https://juejin.cn/post/7384339127493967872