Skip to content

Conversation

mitsuki31
Copy link

This PR addresses the long-standing TODO item in browser.js by integrating path-browserify to provide robust path normalization and resolution capabilities for browser environments.

Previously, browser.js relied on no-op implementations for normalize and resolve.

yargs-parser/browser.js

Lines 7 to 16 in 553c808

const parser = new YargsParser({
cwd: () => { return '' },
format: (str, arg) => { return str.replace('%s', arg) },
normalize: (str) => { return str },
resolve: (str) => { return str },
require: () => {
throw Error('loading config from files not currently supported in browser')
},
env: () => {}
})

After integrating path-browserify, the normalize and resolve functions have been updated to directly reference path-browserify.normalize and path-browserify.resolve, respectively.

yargs-parser/browser.js

Lines 6 to 18 in 08254e3

// Using `path-browserify` package from local dependency
import path from './vendor/path-browserify/index.js';
const parser = new YargsParser({
cwd: () => { return '' },
format: (str, arg) => { return str.replace('%s', arg) },
normalize: path.normalize, // Use `path-browserify`
resolve: path.resolve, // Use `path-browserify`
require: () => {
throw Error('loading config from files not currently supported in browser')
},
env: () => {}
})

Implementation

Integration of path-browserify as a Vendored Module

  • The path-browserify library, which offers a browser-compatible API mirroring Node.js's path module (specifically Node.js v10.3), has been included directly within the vendor/path-browserify directory.
  • This package was fetched directly from the official npm registry (path-browserify-1.0.1.tgz) using wget.
    wget https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz

    I also removed the path-browserify's "test" directory to ensure the package size as small as possible.

  • To ensure compatibility with browser ES module imports, the path-browserify's primary entry point (index.js) has been slightly modified to use ES module exports (export default posix;).
    // module.exports = posix;
    // Refactored this part to ensure it treated as ESM, which browser needs
    export default posix;

browser.js Path Function Update

  • The normalize and resolve functions within the YargsParser constructor in browser.js now directly reference path-browserify.normalize and path-browserify.resolve, leveraging the new capabilities.

Build and Linting Adjustments

  • .eslintignore file has been reconfigured to ignore the vendor directory during linting.
  • The project's bundling configuration has been updated to explicitly include the contents of the vendor directory, ensuring path-browserify is correctly bundled into the final distribution.

Justification for Dependency Management Strategy (Manual Vendoring)

The decision to manually vendor path-browserify (by fetching the 1.0.1.tgz directly from the npm registry) rather than adding it as a standard npm dependency was made for the following reasons:

  • The path-browserify package, while functionally complete for this purpose, has not received updates on npm for a number of years. Manually vendoring allows for precise control over the exact version included in yargs-parser's browser bundle, isolating it from potential future npm dependency changes or deprecations.
  • This approach allows for the necessary modification of path-browserify's index.js to expose ES module exports, which is crucial for browser.js's current import structure.

Testing

<!DOCTYPE html>
<body>
  <script type="module">
    import yargs from "./browser.js";

    const argv = yargs(
      '--testPath=/foo/bar/../bazz//a/filename.txt --testPath-2=a/b/../f/../../foo/file.txt',
      {
        normalize: ['testPath', 'testPath-2']
      }
    )
    console.log(argv.testPath)
    console.log(argv.testPath2)
    console.log(argv.testPath === '/foo/bazz/a/filename.txt')  // Should return true
    console.log(argv.testPath2 === 'foo/file.txt')             // Should return true
  </script>
</body>

I am keen to discuss these considerations and explore any preferred alternative approaches to integrating Browser version of Node.js path module.

This module is independent from npm dependencies and live in `vendor`
directory. As browser only support importing ES modules, I've changed a bit
the module exports to use ESM instead.

The `path-browserify` package matches with Node.js v10.3 API.
- Updated the `normalize` and `resolve` function to use equivalent
  functions from `path-browserify` package
@shadowspawn
Copy link
Member

To understand a bit more about what this would allow. Is opts.normalize an option you want to use yourself in the browser? What is the use case that it helps with?

@mitsuki31
Copy link
Author

Hi @shadowspawn,

I understand that explicit path normalization/resolution might seem niche for browser environments, where there's no direct file system interaction. However, the intent behind this PR isn't to enable file system operations in the browser, but to address a known TODO in browser.js itself, indicates an acknowledgment that normalize and resolve were missing proper browser equivalents. This PR provides those.

Even in a browser, arguments often look like file paths (e.g., --config ./src/../config.json). The opts.normalize and opts.resolve functions allow yargs-parser to:

  1. Clean up these path-like strings, for example: normalize turns ./foo//bar/../baz into /foo/baz.
  2. Combine path-like strings, for example: resolve can combine /base and sub/path into /base/sub/path.

This ensures that yargs-parser provides predictable path string handling for browser users, just like it does in Node.js.

Hope this clarifies the intended use case!

@mitsuki31
Copy link
Author

To be clear, I'm not personally using yargs in the browser, but I wanted to help clear this TODO task and make the browser version more complete and ready for future needs where correct path string handling is useful.

@shadowspawn
Copy link
Member

Interesting to see you found a module for this very purpose.

My initial thought is that vendoring in path-browserify is more overhead than we want for a feature that no one has asked about in a less common runtime. (i.e. I don't see any issues in yargs or yargs-browser mentioning normalize and browser.)

I was interested to see that according to the path-browserify README, it was included by default in some bundlers. If that is still a common pattern, a light weight approach might be to look for an available implementation supplied by the bundler.

You usually do not have to install path-browserify yourself! If your code runs in Node.js, path is built in. If your code runs in the browser, bundlers like browserify or webpack include the path-browserify module by default.

Another approach would be to make it possible to supply own implementations so end-user can implement it if needed.

It would be much smaller to only vendor the relevant routines.

I am only one maintainer! I suggest you wait for feedback from other maintainers or end users before doing more work on this.

@mitsuki31
Copy link
Author

Thank you for the clear guidance.

I understand your concerns about the overhead of the current vendoring approach for path-browserify and the current demand for this functionality in the browser runtime. To keep the queue clear, I'm glad to close this PR if the present vendoring approach doesn't seem to be the preferred direction for this project.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants