Comments (12)
Hi @JakeSidSmith thanks again for your help - the addition is part of the freshly released [email protected]
Regarding the webpackConfig/ ResolveOptions - the options specified in .dependency-cruiser.js config files indeed only give the option to specify a webpack configuration file and nothing else. The main
function, however takes an (expanded) webpack configuration object with all bells and whistles. It looks like this is not properly reflected in the typings of the main function - something that needs to be fixed as well. I have other reasons to take a closer look at the typings soon, and I'll try to rectify that at that time as well.
from dependency-cruiser.
Well, I think I've figured it out. After some hunting I discovered that engine.io
provides a browser
field in the package.json
(https://github.com/search?q=repo%3Asocketio%2Fengine.io-client%20xmlhttprequest.browser.js&type=code).
Which works in the same way (as far as I can tell) as an exports
field, so simply updating my config to the following has resolved my issues:
exportsFields: ['browser', 'exports'],
from dependency-cruiser.
Nope, now I have additional issues. 😂
Fails to resolve @emotion/is-prop-valid
from react-jss
.
@emotion/is-prop-valid
also defines a browser
field, and my new config seems to prefer resolving the browser
field over the module
field, even though the import is of @emotion/is-prop-valid
rather than any sub module/directory e.g. @emotion/is-prop-valid/dist/whatever.js
.
Which I think is a bug with dep-cruiser? It should use the module
field for a default import, not one of the browser
/ exports
fields.
The version of @emotion/is-prop-valid
is 0.7.3
(as in below link) in my project, and I assume wouldn't be an issue with newer versions, but as it's dependency of one of my dependencies I'm not sure I can fix it myself.
emotion-js/emotion@515f254#diff-ea92ceb68d9de797ff6ccd926051ee30fd069382b1d5d0989626bc25582182deR2
from dependency-cruiser.
After further investigation this is not limited to @emotion/is-prop-valid
.
Any package that specifies a browser
field (as an object) does not resolve default imports (unless presumably defined as .
in the browser
field).
from dependency-cruiser.
Here's the spec for the browser
field when used as an object in case it helps: https://github.com/defunctzombie/package-browser-field-spec#replace-specific-files---advanced
Not quite the same as an exports
field.
from dependency-cruiser.
@emotion/is-prop-valid
also defines a browser field, and my new config seems to prefer resolving the browser field over the module field, even though the import is of @emotion/is-prop-valid rather than any sub module/directory e.g. @emotion/is-prop-valid/dist/whatever.js.
It's what I'd indeed expect would happen - with the exportsFields
we tell the resolver in which order to evaluate fields in package.json. So if browser
is at the start it'll try to interpret that which is in the browser
field as an exports
field first. And that clearly ends up in tears as you've found.
The browser
predates the exports
field. The exports
field solves the same problem in a more generic fashion. This is likely why @emotion/is-prop-valid@latest
has migrated to exports as well. I would expect that if the browser
field is a simple string, putting browser
in front of the mainFields
array would work. It might work for browser-field-as-an-object as well, but this depends on the implementation of the resolver dependency-cruiser currently uses (enhanced-resolve). According to this webpack issue which points to webpack's resolver's [mainFields](https://webpack.js.org/configuration/resolve/#resolvemainfields documentation it should work as expected.
I'd love to have tried this before posting this, but it's late and I'm too tired
to do anything coherent with code a.t.m.
Another approach that might be better cut for your use case
Your initial query was to resolve e.g. const { thing } = require("./some-module")
to "./some-module.browser.js"
if it exists and to "./some-module.js"
if it didn't (check?).
That is something that can be accomplished with the extensions option. Normally you'd use this for extensions like .ts, .cts, .d.ts, .js, .cjs, .jsx etc - but it works for other things as well. When the resolver gets the the module name, it'd plonk the first extension from that array the name and do an fs.access(Sync)
. If it exists it's done. If it doesn't it'll continue down the array. So
// ...
enhancedResolveOptions: {
extensions: [".browser.js", ".js"] // add your own list of extensions you have in use to this array
}
// ...
might be the only thing you need.
from dependency-cruiser.
I'd rather avoid the need for me to manually manipulate the imports (I'm already doing a lot of that), and have the browser files resolved from the browser
field.
I've tried with browser
in mainFields
and exportsFields
, and .browser.js
in the extensions, but all of them have other adverse effects.
Presumably some config is required for enhanced-resolve
to resolve the browser
field?
Do you believe dep-cruiser should already be resolving the browser
field?
If so, I can put together a small replication to demonstrate the issue.
from dependency-cruiser.
Update: discovered that this needs to be manually configured with the aliasFields
property
import fs from 'node:fs';
import { cruise } from 'dependency-cruiser';
import enhancedResolve from 'enhanced-resolve';
const DEFAULT_CACHE_DURATION = 4000;
const dependencies = await cruise(
pathnames,
{
baseDir: process.cwd(),
builtInModules: {
override: [],
add: [],
},
enhancedResolveOptions: {
mainFields: ['module', 'main'],
exportsFields: ['exports'],
conditionNames: ['import', 'require', 'default'],
},
},
{
fileSystem: new enhancedResolve.CachedInputFileSystem(
fs,
DEFAULT_CACHE_DURATION
),
aliasFields: ['browser'], // this bit
resolveDeprecations: true,
}
);
Have a few questions related to this:
Why are resolveOptions
specified separately from enhancedResolveOptions
?
Is there a way to define this without the need to specify the fileSystem
and resolveDeprecations
?
It would be nice if these had default values so I don't have to manually reference enhanced-resolve
etc.
If not, could dep-cruiser expose the DEFAULT_CACHE_DURATION
so I don't have to redefine this?
from dependency-cruiser.
Hi @JakeSidSmith - oh wow! Thanks for the research. It'd indeed make sense to add this 'aliasFields' property by default to what dependency-cruiser passes to enhanced-resolve or - in the least - provide an easy way to pass it.
On your questions
Why are resolveOptions specified separately from enhancedResolveOptions?
Good question.
- resolveOptionsreflects the (expanded) webpack.config.js you can pass in the .dependency-cruiser.js config (or as a cli parameter)
- enhancedResolveOptions is the object you can pass in .dependency-cruiser.js for when you don't use webpack, don't want to have a webpack config but still need to tweak parameters in enhanced resolve.
In hindsight in the main function these two could've been combined when we'd design it from the ground up again, possibly moving the logic to combine the two to the cli.
Is there a way to define this without the need to specify the fileSystem and resolveDeprecations?
- On the cli passing a webpack config with the adapted resolve parameters would work.
- Likewise, with the API passing it in the parameter that reflects the webpack config should work.
from dependency-cruiser.
Would be great to see this included with the enhancedResolveOptions
. 🥳
Likewise, with the API passing it in the parameter that reflects the webpack config should work.
I don't believe the types currently allow it to be passed anywhere but the resolveOptions
.
![Screenshot 2023-11-15 at 22 58 14](https://private-user-images.githubusercontent.com/5850625/283271583-a39b3bc9-715f-452f-8f55-280eaa96b694.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjE0NzMwMDksIm5iZiI6MTcyMTQ3MjcwOSwicGF0aCI6Ii81ODUwNjI1LzI4MzI3MTU4My1hMzliM2JjOS03MTVmLTQ1MmYtOGY1NS0yODBlYWE5NmI2OTQucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDcyMCUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA3MjBUMTA1MTQ5WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9MWJmZDUxYjRhNGUzYmQ3ZmMxZDgzNWJjMDRkYTdjOWNhNmRjMDA3MGM5YWY0NDBhYjk3NTM0M2FhYjM1MDgyYSZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.17dHm7Q1mBTe2D1p0GvIoHn-ByYO9S14EGWuPYHN9pE)
![Screenshot 2023-11-15 at 22 58 24](https://private-user-images.githubusercontent.com/5850625/283271585-3ac883b1-cf09-4bc8-b43f-ae8a22fedfa3.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjE0NzMwMDksIm5iZiI6MTcyMTQ3MjcwOSwicGF0aCI6Ii81ODUwNjI1LzI4MzI3MTU4NS0zYWM4ODNiMS1jZjA5LTRiYzgtYjQzZi1hZThhMjJmZWRmYTMucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDcyMCUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA3MjBUMTA1MTQ5WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9NTM4OTNjZDhjZmFhNDc3NWQ4MDJmMDM2OGNmMTk0ZjA2ZDViNmUyMmU1NzA1MmJkMzdhNmMzZGI1NmE0Yjg5YiZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.8tdEsqyZPEKXdzlYfXVPa0pIHuT-I19yEbSOddmyCb0)
![Screenshot 2023-11-15 at 22 58 39](https://private-user-images.githubusercontent.com/5850625/283271586-037442af-1ed6-4291-89c3-d13eb6e7454c.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjE0NzMwMDksIm5iZiI6MTcyMTQ3MjcwOSwicGF0aCI6Ii81ODUwNjI1LzI4MzI3MTU4Ni0wMzc0NDJhZi0xZWQ2LTQyOTEtODljMy1kMTNlYjZlNzQ1NGMucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDcyMCUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA3MjBUMTA1MTQ5WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9OWY2MDM3N2ZlNGI2NjM1ZjI5ZTdhZjg2YzA0OWM5MjM3NWQ2ZTg4NDNmNTMyZjdhMzdlOTU2NmMyYTU3MTdkMyZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.bXkMwsYFwgA7V3IifnW_k-RRBE71B5pptnt3N9IYxYY)
![Screenshot 2023-11-15 at 22 58 45](https://private-user-images.githubusercontent.com/5850625/283271590-cb9ae7ea-3289-48f3-8ac7-5f7f360173e6.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjE0NzMwMDksIm5iZiI6MTcyMTQ3MjcwOSwicGF0aCI6Ii81ODUwNjI1LzI4MzI3MTU5MC1jYjlhZTdlYS0zMjg5LTQ4ZjMtOGFjNy01ZjdmMzYwMTczZTYucG5nP1gtQW16LUFsZ29yaXRobT1BV1M0LUhNQUMtU0hBMjU2JlgtQW16LUNyZWRlbnRpYWw9QUtJQVZDT0RZTFNBNTNQUUs0WkElMkYyMDI0MDcyMCUyRnVzLWVhc3QtMSUyRnMzJTJGYXdzNF9yZXF1ZXN0JlgtQW16LURhdGU9MjAyNDA3MjBUMTA1MTQ5WiZYLUFtei1FeHBpcmVzPTMwMCZYLUFtei1TaWduYXR1cmU9MzQyNGE0MWVkOTJiYWNkMWEyMmE5ODM1MGVmYzZhZDU2MTA1MmI3Yjk3ZjNlMjJkZTZiMzI5YWMyMDMzYjVlNSZYLUFtei1TaWduZWRIZWFkZXJzPWhvc3QmYWN0b3JfaWQ9MCZrZXlfaWQ9MCZyZXBvX2lkPTAifQ.vphvvgY09rrhKZKJvLUKYRmJwe5miGZ-4vt1SZANY6Q)
from dependency-cruiser.
I've checked the typings on the main functions, and it seems they're ok, but I can see where the confusion might stem from as there are three spots to enter things to pass to enhanced resolve ...
export function cruise(
pFileAndDirectoryArray: string[],
pCruiseOptions?: ICruiseOptions,
pResolveOptions?: IResolveOptions,
pTranspileOptions?: ITranspileOptions
): Promise<IReporterOutput>;
Two in ICruiseOptions
:
interface ICruiseOptions {
// ...
/**
* Webpack configuration to use to get resolve options from
* This is the option to point to a webpack.conf.js (fileName
* attribute) and pass arguments and an object of webpack
* env variables. All webpack options (including all those of
* enhanced-resolve) can be passed in that file.
*/
webpackConfig?: IWebpackConfig;
// ....
/**
* Options used in module resolution that for dependency-cruiser's
* use cannot go in a webpack config.
* E.g. when there isn't/ you don't want to have a webpack.conf.js
* but still need to pass things onto it.
*/
enhancedResolveOptions?: {
}
}
And one separately (pResolveOptions
). The cli takes the ICruiseOptions.webpackConfig, expands them into an object and passes them into that guy. If one uses the API they can either put the enhanced-resolve config they want directly in there or use the function in ./config-utl/extract-webpack-resolve-config
to do the expansion of a regular webpack.conf.js:
import type { ResolveOptions, CachedInputFileSystem } from "enhanced-resolve";
/**
* an object with options to pass to the resolver
* see https://github.com/webpack/enhanced-resolve#resolver-options
* for a complete list. Extended with some sauce of our own for practical
* purposes
*/
interface IResolveOptions extends ResolveOptions {
/**
*
* Without bustTheCache (or with the value `false`) the resolver
* is initialized only once per session. If the attribute
* equals `true` the resolver is initialized on each call
* (which is slower, but might is useful in some situations,
* like in executing unit tests that verify if different
* passed options yield different results))
*/
bustTheCache?: boolean;
/**
* We're exclusively using CachedInputFileSystem, hence the
* rude override
*/
fileSystem: CachedInputFileSystem;
/**
* If true also tries to find out whether an external dependency has
* been deprecated. Flagged because that's a relatively expensive
* operation. Typically there's no need to set it as dependency-cruiser
* will derive this from the rule set (if there's at least one rule
* looking for deprecations it flips this flag to true)
*/
resolveDeprecations: boolean;
}
from dependency-cruiser.
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs.
from dependency-cruiser.
Related Issues (20)
- Question: A dependency view of each "TYPE" or "INTERFACE" HOT 3
- Question: monorepo, combinedDependencies & not-dev-dep HOT 2
- Error: No "exports" main defined in <project_name>/node_modules/dependency-cruiser/package.json HOT 3
- What am I missing about rcdot? "'rcdot' is not a valid output type" HOT 2
- Issue: not-to-unresolvable return error when using typescript alias in module project HOT 2
- Why doesn't dependency-cruiser "ignore" my private-registry package like it does with node-modules? HOT 6
- Q: Dep Graph for each file HOT 3
- Feature request: consider symlinked workspaces HOT 5
- Issue: not-to-spec and not-to-dev-dep default config should include tsx and jsx HOT 3
- Issue: using `workspace:` to implement nohoist in a package.json while using pnpm throws an error HOT 4
- Missing mermaid example HOT 1
- Feature request: reporters might report `comment` of rules other than `forbidden` HOT 3
- Issue: cruise API - breaking changes HOT 4
- Question: Resolving typescript source files imported from outside specified package HOT 2
- Question: dependency-cruiser API gives a different result when `baseDir` is changed HOT 6
- Question: Can I access the classes/methods/functions in modules? HOT 4
- Listing dependancy tree via dependency-cruiser gives me the reference from barel files HOT 2
- Feature request: Allow type only imports to be omitted entirely from the dependency graph (typescript) HOT 2
- Issue: failure to run with combinedDependencies: true on a monorepo
- Make it work without installation HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
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.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from dependency-cruiser.