Giter VIP home page Giter VIP logo

oxc-resolver's Introduction

OXC Logo

Crates.io Docs.rs

MIT licensed Build Status Code Coverage CodSpeed Badge Sponsors Discord chat

Oxc Resolver

Rust port of enhanced-resolve.

Usage

The following usages apply to both Rust and Node.js; the code snippets are written in JavaScript.

To handle the exports field in package.json, ESM and CJS need to be differentiated.

ESM

Per ESM Resolution algorithm

defaultConditions is the conditional environment name array, ["node", "import"].

This means when the caller is an ESM import (import "module"), resolve options should be

{
  "conditionNames": ["node", "import"]
}

CJS

Per CJS Resolution algorithm

LOAD_PACKAGE_EXPORTS(X, DIR)

  1. let MATCH = PACKAGE_EXPORTS_RESOLVE(pathToFileURL(DIR/NAME), "." + SUBPATH, package.json "exports", ["node", "require"]) defined in the ESM resolver.

This means when the caller is a CJS require (require("module")), resolve options should be

{
  "conditionNames": ["node", "require"]
}

Cache

To support both CJS and ESM with the same cache:

const esmResolver = ResolverFactory({
  conditionNames: ["node", "import"]
});

const cjsResolver = esmResolver.cloneWithOptions({
  conditionNames: ["node", "require"]
});

Browser Field

From this non-standard spec:

The browser field is provided to JavaScript bundlers or component tools when packaging modules for client side use.

The option is

{
  "aliasFields": ["browser"]
}

Main Field

{
  "mainFields": ["module", "main"]
}

Quoting esbuild's documentation:

  • main - This is the standard field for all packages that are meant to be used with node. The name main is hard-coded in to node's module resolution logic itself. Because it's intended for use with node, it's reasonable to expect that the file path in this field is a CommonJS-style module.
  • module - This field came from a proposal for how to integrate ECMAScript modules into node. Because of this, it's reasonable to expect that the file path in this field is an ECMAScript-style module. This proposal wasn't adopted by node (node uses "type": "module" instead) but it was adopted by major bundlers because ECMAScript-style modules lead to better tree shaking, or dead code removal.
  • browser - This field came from a proposal that allows bundlers to replace node-specific files or modules with their browser-friendly versions. It lets you specify an alternate browser-specific entry point. Note that it is possible for a package to use both the browser and module field together (see the note below).

Errors

  • Error: Package subpath '.' is not defined by "exports" in - occurs when resolving without conditionNames.

Options

The options are aligned with enhanced-resolve.

Field Default Description
alias [] A list of module alias configurations or an object which maps key to value
aliasFields [] A list of alias fields in description files
extensionAlias {} An object which maps extension to extension aliases
conditionNames [] A list of exports field condition names
descriptionFiles ["package.json"] A list of description files to read from
enforceExtension false Enforce that a extension from extensions must be used
exportsFields ["exports"] A list of exports fields in description files
extensions [".js", ".json", ".node"] A list of extensions which should be tried for files
fallback [] Same as alias, but only used if default resolving fails
fileSystem The file system which should be used
fullySpecified false Request passed to resolve is already fully specified and extensions or main files are not resolved for it (they are still resolved for internal requests)
mainFields ["main"] A list of main fields in description files
mainFiles ["index"] A list of main files in directories
modules ["node_modules"] A list of directories to resolve modules from, can be absolute path or folder name
resolveToContext false Resolve to a context instead of a file
preferRelative false Prefer to resolve module requests as relative request and fallback to resolving as module
preferAbsolute false Prefer to resolve server-relative urls as absolute paths before falling back to resolve in roots
restrictions [] A list of resolve restrictions
roots [] A list of root paths
symlinks true Whether to resolve symlinks to their symlinked location

Unimplemented Options

Field Default Description
cachePredicate function() { return true }; A function which decides whether a request should be cached or not. An object is passed to the function with path and request properties.
cacheWithContext true If unsafe cache is enabled, includes request.context in the cache key
plugins [] A list of additional resolve plugins which should be applied
resolver undefined A prepared Resolver to which the plugins are attached
unsafeCache false Use this cache object to unsafely cache the successful requests

Debugging

Rspack

The following environment variable will emit tracing information.

RSPACK_PROFILE='TRACE=filter=oxc_resolver=trace&layer=logger' rspack build

Test

Tests are ported from

Test cases are located in ./src/tests, fixtures are located in ./tests

  • alias.test.js
  • browserField.test.js
  • dependencies.test.js
  • exportsField.test.js
  • extension-alias.test.js
  • extensions.test.js
  • fallback.test.js
  • fullSpecified.test.js
  • identifier.test.js (see unit test in crates/oxc_resolver/src/request.rs)
  • importsField.test.js
  • incorrect-description-file.test.js (need to add ctx.fileDependencies)
  • missing.test.js
  • path.test.js (see unit test in crates/oxc_resolver/src/path.rs)
  • plugins.test.js
  • pnp.test.js
  • resolve.test.js
  • restrictions.test.js (partially done, regex is not supported yet)
  • roots.test.js
  • scoped-packages.test.js
  • simple.test.js
  • symlink.test.js

Irrelevant tests

  • CachedInputFileSystem.test.js
  • SyncAsyncFileSystemDecorator.test.js
  • forEachBail.test.js
  • getPaths.test.js
  • pr-53.test.js
  • unsafe-cache.test.js
  • yield.test.js

πŸ“– License

oxc_resolver is free and open-source software licensed under the MIT License.

Oxc partially copies code from the following projects.

Project License
webpack/enhanced-resolve MIT
dividab/tsconfig-paths MIT
parcel-bundler/parcel MIT
tmccombs/json-comments-rs Apache 2.0

oxc-resolver's People

Contributors

boshen avatar renovate[bot] avatar iwanabethatguy avatar brooooooklyn avatar ematipico avatar ahabhgk avatar hyf0 avatar dependabot[bot] avatar kraenhansen avatar milesj avatar xc2 avatar msdlisper avatar

Stargazers

Rintaro Itokawa avatar zhushijie avatar George Kontridze avatar ι™ˆη£Š avatar JoaquΓ­n SΓ‘nchez avatar Sarath S Menon avatar Ihoey avatar  avatar xiaotian avatar Zhazha_JiaYiZhen avatar Volen avatar Wesley Luyten avatar Zero avatar Dilshad avatar Ramesh avatar Ze-Zheng Wu avatar Lewin Kelly avatar Tryggvi Gylfason avatar uncenter avatar kazuya kawaguchi avatar mizdra avatar Valentin Gurkov avatar  avatar Nikola Hristov avatar ppdbb avatar Nirvana avatar Shein Lin Phyo avatar zoomdong avatar Cong-Cong Pan avatar Karl Aleksandrov avatar GZ avatar Denis Denisov avatar Jacob Groß avatar  avatar Adi avatar Marshall avatar Scarlet avatar  avatar Hyeseong Kim avatar Cosmo Shin (μ‹ μ˜ν•˜) avatar Tiberiu Ichim avatar Esteban Fuentealba avatar Sibelius Seraphini avatar Soon avatar Brenton Wheeler avatar FlashSoft avatar  avatar Sander Verweij avatar Geoff Goodman avatar ruiming avatar Denis Bezrukov avatar Akko avatar  avatar ζœ¨ζ‰ avatar ubugeeei avatar

Watchers

 avatar  avatar  avatar

oxc-resolver's Issues

More code coverage

Code coverage is at 95%, but some branches are still missing a test case. There are also TODOs in many places 😞

API / Docs feedback

(as mentioned on discord) I've been working on migrating a project from some custom resolution logic to oxc-resolver. Here's some feedback about my experience so far:

path argument

There are no docs describing the public API of the crate - the page for the resolver just has a link to an example as the only documentation. The example includes a comment which says Path to directory, must be in absolute path.

The crate docs just say: Resolve specifier at an absolute path with no mention of the requirement that it be a folder.

I misread this in example and made the assumption that I was passing the "target" file path (the file that "owns" the dependencies) to the resolve function. This caused many resolutions to fail because the code assumes the path is a folder and does path.join(relative).

Suggestions:

  • Improve docs for the API
  • Add an error if the path passed to .resolve is a file instead of a folder
    • Alternately - take the .parent().unwrap() of a file automatically

extensions option

I had all my extensions configured without a leading .. This caused all my extensionless resolutions to fail because the code assumes the extension starts with a . and does concatenate(path, extension).

The docs allude to this expectation by showing the defaults as having a leading . but it does not state the requirement.

Suggestions:

  • Describe the assumptions in the docs
  • Add an error if any of the extensions passed to the config does not start with a .
    • Alternately - normalise the extensions to start with a .

Issue resolving exports (Node)

Hi there, I know the oxc-resolver npm package is still in development, but I was trying it out on a POC I was working on and wanted to report this issue.

"Error: Package subpath '.' is not defined by "exports" in [path]/node_modules/css-tree/package.json"

I actually see the error for a few packages, and all of those packages seem to have their exports correctly defined.

Looking at css-tree for example:
https://github.com/csstree/csstree/blob/ba6dfd8bb0e33055c05f13803d04825d98dd2d8d/package.json#L23-L27

The resolver is set up like this:

  const resolver = new ResolverFactory({
    extensions: ['.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs'],
    mainFields: ['module', 'main'],
  });

Perhaps unrelated, I'm also getting Error: Cannot find module 'fs' for built in modules. We use the node: protocol for built-ins in case that helps there.

Allow to disable validation of "Default condition should be last one"

Related code:

oxc-resolver/src/lib.rs

Lines 1464 to 1468 in e04ca0f

let is_default = matches!(key, ImportExportKey::CustomCondition(condition) if condition == "default");
if i < target.len() - 1 && is_default {
return Err(ResolveError::InvalidPackageConfigDefault(
package_url.join("package.json"),
));

The current behavior of oxc-resolver is correct based on the spec, but not flexable.

"default" - the generic fallback that always matches. Can be a CommonJS or ES module file. This condition should always come last. link

Though spec said the "default" should always come last, but nodejs actually doesn't do strong validation on it. If "default` shows , it will be matched once detecting it.

Context:

Related:

oxc-resolver-has-issue-in-esbuild-test-case-packagejson-2002b

master

i'm dev rolldown for esbuild package_json test cases

when i migrate TestPackageJsonBrowserIssue2002B

https://github.com/evanw/esbuild/blob/main/internal/bundler_tests/bundler_packagejson_test.go#L830

i found some resovle error in oxc-resolver

please help me check

In order to quickly reproduce the bug I've created a git repo of code that can be reproduced.

https://github.com/zhusjfaker/oxc-resolver-has-issue-in-esbuild-test-case-packagejson-2002b/blob/master/tests/mod.rs#L44

https://github.com/zhusjfaker/oxc-resolver-has-issue-in-esbuild-test-case-packagejson-2002b

Action Required: Fix Renovate Configuration

There is an error with this repository's Renovate configuration that needs to be fixed. As a precaution, Renovate will stop PRs until it is resolved.

Location: .github/renovate.json
Error type: The renovate configuration file contains some invalid settings
Message: Invalid schedule: Invalid schedule: Failed to parse "before 8am on on monday"

Publish 1.0

It seems like we can publish 1.0 after all the issues are resolved.

The logic of the oxc_resover implementation may not be quite the same as in esbuild.

https://github.com/evanw/esbuild/blob/main/internal/bundler_tests/bundler_packagejson_test.go#L766

β”œβ”€β”€ _config.json
β”œβ”€β”€ dist
β”‚Β Β  └── entry.js
└── src
    β”œβ”€β”€ demo-pkg
    β”‚Β Β  β”œβ”€β”€ ext
    β”‚Β Β  β”œβ”€β”€ ext-browser
    β”‚Β Β  β”œβ”€β”€ no-ext
    β”‚Β Β  β”œβ”€β”€ no-ext-browser
    β”‚Β Β  └── package.json
    └── entry.js

in the file system

./src/demo-pka/package.json

{
  "browser": {
    "./no-ext": "./no-ext-browser/index.js",
    "./ext/index.js": "./ext-browser/index.js"
  }
}

./src/demo-pka/entry.js

import { browser as a } from './demo-pkg/no-ext'
import { node as b } from './demo-pkg/no-ext/index.js'
import { browser as c } from './demo-pkg/ext'
import { browser as d } from './demo-pkg/ext/index.js'
console.log(a)
console.log(b)
console.log(c)
console.log(d)

i want resolver 'import { browser as a } from './demo-pkg/no-ext'' --> is './src/demo-pkg/no-ext-browser/index.js' but now
is ->

'./src/demo-pkg/no-ext/index.js'

Am I overlooking a configuration item or is there something wrong with the implementation itself?

Handle imports from `@types/foo` type-only packages

In typescript it's possible to import from a module that only has a @types/ definition.
Example -- if you "right click -> peek definition" on the import source you'll see it mentions node_modules/@types/google__maps.

From what I can tell there isn't a way to resolve this import without manually specifying a mapping.
Am I correct in this? Or is there a way to support it?

aliased requests in resolver_context.file_dependencies are not normalized/canonicalized

oxc_resolver: 1.2.0-1.3.0
os: Windows

Summary

let root = dir().join("fixtures\\enhanced_resolve\\test\\fixtures");
let mut ctx = ResolveContext::default();

let resolver = Resolver::new(ResolveOptions {
    alias: vec![(
        "@".into(),
        vec![AliasValue::Path(root.join("alias").to_string_lossy().into())],
    )],
    ..ResolveOptions::default()
});
let _ = resolver.resolve_with_context(root, "@/files/a", &mut ctx);

for d in ctx.file_dependencies.iter() {
    println!("{}", d.to_string_lossy());
}

Expected

C:\Users\imkf\Developer\oxc-resolver\fixtures\enhanced_resolve\test\fixtures\alias\files\a.js seen in output,

Actual

C:\Users\imkf\Developer\oxc-resolver\fixtures\enhanced_resolve\test\fixtures\alias/files/a.js got

Related

web-infra-dev/rspack#5445

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.