-
Notifications
You must be signed in to change notification settings - Fork 13
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
import.meta path helpers proposal #54
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
# Helpers on `import.meta` for working with paths | ||
|
||
## Background | ||
|
||
A common user request from developers writing ESM code is easy access to file path information of the current module. Or put another way, they miss the `__dirname` and `__filename` local variables from CommonJS, that define the directory and full path of the current module. These values are distinct from `import.meta.url`, which is the URL of the current module. To illustrate: | ||
|
||
- `import.meta.url` is a string like `file:///Users/Geoffrey/my-project/src/index.js` | ||
- `__filename` is a string like `/Users/Geoffrey/my-project/src/index.js` | ||
- `__dirname` is a string like `/Users/Geoffrey/my-project/src` | ||
|
||
Since `__filename` and `__dirname` have been around [since Node.js 0.1.27](https://nodejs.org/api/modules.html#__dirname), released in 2010, they are very well known to Node.js developers and very broadly referenced by `npm` packages. It is common to find documentation suggesting passing `__dirname` into a function for serving the static assets of a folder, for example, or passing `__filename` into a function used for logging. | ||
|
||
In Node.js, developers working with such path-based APIs need to jump through a few hoops. Node.js provides a helper `fileURLToPath` that developers can import from `node:url`, to enable code like `serveStaticAssets(dirname(fileURLToPath(import.meta.url)))`. A common complaint of Node.js developers is that this is too verbose, and a way to achieve the same with simpler code and without needing to import utility helpers would be preferable. | ||
|
||
## Proposal | ||
|
||
For runtimes that support filesystem-based modules, we propose adding two new optional properties to `import.meta`: | ||
|
||
### `import.meta.filename` | ||
|
||
A string containing the full absolute filesystem path to the current module, like CommonJS `__filename`. This is the same as `fileURLToPath(import.meta.url)` in Node.js. An example value would be `/Users/Geoffrey/my-project/src/index.js`. | ||
|
||
The property will be absent for modules that are not loaded from the filesystem, such as modules whose `import.meta.url` begins with `http` or `data`. | ||
|
||
### `import.meta.dirname` | ||
|
||
A string containing the full absolute filesystem path of the folder containing the current module, like CommonJS `__dirname`. This is the same as `dirname(fileURLToPath(import.meta.url))` in Node.js. An example value would be `/Users/Geoffrey/my-project/src`. | ||
|
||
The value should not have a trailing slash. This is consistent with CommonJS `__dirname`, so that it can be used as a drop-in replacement. | ||
|
||
The value will be undefined for modules that are not loaded from the filesystem, such as modules whose `import.meta.url` begins with `http` or `data`. | ||
|
||
## Notes | ||
|
||
These properties would be optional, even if a runtime supports filesystem-based modules. This allows for runtimes where modules are _primarily_ run from HTTP / HTTPS URLs to avoid creating a portability hazard where these properties exist while developers are working locally but are undefined when the code is deployed. | ||
|
||
This portability hazard is a primary objection to this proposal. We feel that on balance, the convenience of these properties outweighs the potential hazard; and that a different portability hazard exists without these helpers, in that developers will write code such as `fileURLToPath(import.meta.url)` that works locally but not over CDN similarly to how `import.meta.filename` would work locally but not over CDN. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I really wish we have clarification and standards about Windows path normalization and consider forward slash possibility as standard once we have a chance with new spec or at least mentioned briefly to be under considration. An example URL would be Modern Windows systems well support forward slashes (some history). Forward slashes make life much better in the Javascript ecosystem where as backslash is a escape character. upath and pathe are already being used by >18M users weekly. (sorry for rambling in the comments, just wanted to trigger a discussion from somewhere) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Related: denoland/deno#957, nodejs/node#25324. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I had the same thought too at first, but now I’m not so sure. I think the existing behavior is because Node’s There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks for the references. I think it might be sensible for Node.js util which is inheriting legacy reasons for preserving backslashes (while I hope that would be something they might consider for the new Since this is a proposal, would it makes sense to at least mention the possibility of a "recommendation" to prefer forward slashes and increasing web/url compatibility? Especially with new runtimes adopting AFAIK bun is not windows supported yet, that would be a really good example of adoption and increasing compatibility with toolings. Today Nuxt, Vitest and dozens of packages in the ecosystem are doing this normalization in each place to just make sure windows is compatible... unofficially due to Node.js legacy behavior. |
||
|
||
## Alternatives Considered | ||
|
||
### `import.meta.__filename` or `import.meta.__dirname` | ||
|
||
As the primary goal of this proposal is convenience, we feel that shorter names are preferable; and the `__` prefix is inconsistent with other `import.meta` properties. | ||
|
||
### `import.meta.path` or `import.meta.dir` | ||
|
||
Bun has shipped `import.meta.path`, an equivalent to the `import.meta.filename` proposed here; and `import.meta.dir`, an equivalent to the `import.meta.dirname` proposed here. | ||
|
||
On the one hand, Bun’s names are shorter and `import.meta.path` is arguably more correct of a name for a value that refers to a full absolute path like `/Users/Geoffrey/my-project/src/index.js` rather than just the filename `index.js`. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In my opinion, all of |
||
|
||
On the other hand, `__filename` and `__dirname` are _so_ well known by developers, being used by just about every Node.js developer who has written any CommonJS code over the past decade-plus, that preserving those names might aid in usability due to familiarity and consistency with documentation of existing ecosystem libraries. | ||
|
||
We feel that on balance, the familiarity and legacy of `__filename` and `__dirname` outweighs the benefits of new names that are shorter and more technically correct. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Correct. |
||
|
||
### `import.meta.dirname` by itself, without `import.meta.filename` | ||
|
||
There are many more use cases for `dirname` than for `filename`. It’s very common to want to reference files that are siblings to the current module; it’s less common to need to reference the current module itself. We also have `import.meta.url` as an URL-based reference to the current module, that can be converted to `import.meta.filename` easily enough. | ||
|
||
However it feels incomplete to offer a helper only for the current module’s parent folder, and not also to the current module itself. This feels inconsistent with `import.meta.url`, and to the legacy of `__dirname` and `__filename`. | ||
|
||
### Also `import.meta.file` or `import.meta.basename` | ||
|
||
If we’re going to have `import.meta.dirname`, a helper for the file path of the containing folder, why not also a helper for the current module’s filename such as Bun’s `import.meta.file` (returning a string like `index.js`)? This would be equivalent to `basename(fileURLToPath(import.meta.url))`. | ||
|
||
Along the lines of the previous section, it’s not common enough to refer to the current file _as a file path_ to warrant a helper on `import.meta`. The current module’s filename can easily be derived via helper utilities. | ||
|
||
## Prior Art | ||
|
||
- [Node.js `__dirname` and `__filename` documentation](https://nodejs.org/api/modules.html#__dirname) | ||
- [Bun `import.meta.path` and `import.meta.dir`](https://bun.sh/docs/api/import-meta) | ||
- [Node.js PR to add `import.meta.dirname` and `import.meta.filename`](https://github.com/nodejs/node/pull/48740) | ||
- [Earlier Node.js PR to add `import.meta.__dirname` and `import.meta.__filename`](https://github.com/nodejs/node/pull/39147) | ||
|
||
## References | ||
|
||
- [WinterCG issue](https://github.com/wintercg/proposal-common-minimum-api/issues/50) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It’s also consistent with filesystems, where the trailing slash means inside the directory, and without the slash means the directory.