Skip to content
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

Breaking changes in dependency-cruiser v13 #794

Closed
sverweij opened this issue Apr 22, 2023 · 0 comments
Closed

Breaking changes in dependency-cruiser v13 #794

sverweij opened this issue Apr 22, 2023 · 0 comments
Labels
enhancement this will make dependency-cruiser sweeter

Comments

@sverweij
Copy link
Owner

sverweij commented Apr 22, 2023

To keep dependency-cruiser future proof (and sweeter to use) it was necessary to make some breaking changes in v13.

Most of the breaking changes impact only the API/ library. We've worked hard to avoid it, but some affect the CLI as well.

Summary

Improvements

Support for ESM in dependency-cruiser, babel and webpack configurations

As dependency-cruiser itself is now written in ESM, it can now also read .dependency-cruiser, babel and webpack configurations in ESM, so you can write them in more modern JavaScript if you want to. Previously supported formats (commonjs, json5 etc) remain supported

No need to pass --config anymore

In previous versions, even when you had a dependency-cruiser configuration with one of the default names, you still need to pass --config on the command line to tell it to use that configuration. As of version 13 this is not necessary anymore. Otherwise, the --config option still work as it did before.

If you want to run the dependency-cruiser CLI without a configuration file you'll have to explicitly pass it --no-config.

Let me know if you do! I'm interested in these use cases.

dot reporters: dynamic dependencies show up as dotted lines

This was already possible - in v13, we've made it the default as it proved useful to distinguish dynamic imports from regular ones. See #801 for details.

Performance improvements

When I converted dependency-cruiser from commonjs to ESM (on node 19) it turned out dependency-cruiser's self scan took longer than it did before the conversion. Dependency-cruiser's performance-log and closer analysis with node --cpu-prof showed that most of the extra time was added at startup time, importing modules. Because I set myself as a goal to have v13 at least as fast as v12 I took a closer look at what was loaded, that might not be necessary at startup.

#795: lazy loading own code: (-100ms)

  • typically you only run dependency-cruiser with one reporter at a time. Because we're using static imports, however, all reporters were loaded, some of which are reasonably large - taking import parse time. By dynamically importing only the one reporter we need, and only when we needed it we shaved of ~40ms from the startup time.
  • After having run --init once, you're not going to need it anymore. The init code was statically imported, though. Dynamically importing it only when --init was engaged shaved off ~40ms of regular startup time.
  • If you don't run with caching (you should, it's awesome) - caching code shouldn't be imported either - lazy loading that saves ~20ms.

defer loading analytical modules (-100ms - -700ms for cache only runs)

I also realized dependency-cruiser's serving 100% from cache scenario hardly needs to run any static analysis code. Lazy loading these modules till after we've established we need them shaves off ~100ms - ~700ms from 100% from cache runs. The 700ms is extreme though - it's because in dependency-cruiser's self scan babel, vue, svelte, typescript, swc and even coffeescript are available at the same time. I pity you if your real live project has this as well...

It is possible to go deeper here and lazy load the individual transpilers as well, making dependency-cruiser's self-scan nice and fast but the gain in practical situations (where you have only one or two of them in place) would be limited, unless there's a transpiler installed you don't use in your setup (but e.g. only have because a devDependency has it - babel is a logical candidate for this). This improvement might come in a future version of dependency-cruiser.

Breaking changes: CLI and API

Dropped support for node 14

Nodejs 14 is end of life by the end of April 2023 (source). This will mean that most projects will by then have moved to higher versions. If you can't move to nodejs 14 you can keep using dependency-cruiser v12 for a while.

Dropped support for yarn 1 plug'n play

Yarn 1 is still nominally maintained - the yarn team encourages everyone to migrate to yarn 3, which is now maintained for a longer time than yarn 1 ever was. While yarn 1 itself still works fantastically, its pnp implementation won't keep up with new developments in the node landscape (e.g. the node: prefix doesn't work, ES modules don't work) - they do work in later versions of yarn, so if you're still on yarn 1 with PnP you probably want to upgrade to yarn 3 anyway.

To be clear:

  • dependency-cruiser >= v13 still works with yarn 3 (and 2) plug'n play . We actively maintain an integration test to ensure it keeps doing so.
  • depencency-cruiser >= v13 will keep running in yarn 1 installations that don't have plug'n play engaged. Even if PnP is engaged, it probably would still work when you 'eject' dependency-cruiser from PnP.
  • dependency-cruiser <= v12 will still run with yarn 1 + PnP

Not passing --config now means 'use default configuration file'

In previous versions, even when you had a dependency-cruiser configuration with one of the default names, you still need to pass --config on the command line to tell it to use that configuration. This was confusing to many because it's different from most other tools out there in the same space do it.

As of version 13 this is not necessary anymore to pass a --config option to read the default configuration. Otherwise, the --config option still work as it did before.

If you want to run the dependency-cruiser CLI without a configuration file you'll have to explicitly pass it --no-config.

Let me know if you do! I'm interested in these use cases.

For glob patterns on windows use forward slashes

We've bumped to the most recent version of node-glob which has a breaking change where it doesn't accept \ as path separators anymore - and instead advises to use forward slashes (/) in stead.

API only

API is ESM only

Dependency-cruiser is now implemented in ESM - which means that it can only be called from ESM code anymore. I've been looking for ways to compile it down to commonjs, but the transpiler chains I've tried so far can't (e.g. by refusing to convert top level awaits).

API is async (cruise, format, config-utl)

Because in ESM (dynamically) importing modules is an asynchronous affair, all dependency-cruiser interfaces that weren't already had to become asynchronous as well, with the exception of the configuration utility to extract TypeScript configurations.

For an example - see Example to call cruise.

cruise signature change

Apart from becoming asynchronous, we've rationalised the parameters to cruise. In the old interface the fourth parameter was reserved to passing a (normalized) TypeScript configuration only, while having no room to pass a babel configuration or any other (future) transpilation configuration.

The new interface makes the fourth parameter an object that can take a tsConfig, a babelConfig, or both of them.

See example to call cruise below to see how a call could look right now.

Example call to cruise

Before:

import { cruise } from 'dependency-cruiser';
import extractDepcruiseConfig from "dependency-cruiser/config-utl/extract-depcruise-config";
import extractTSConfig from "dependency-cruiser/config-utl/extract-ts-config";
import extractWebpackResolveConfig from "dependency-cruiser/config-utl/extract-webpack-resolve-config"
import extractBabelConfig from "dependency-cruiser/config-utl/extract-babel-config";

const lCruiseOptions = {
  // ...
};

const lResult = cruise(
  ["src", "test"],
  await extractDepcruiseConfig("./.dependency-cruiser.js"),
  extractWebpackResolveConfig("webpack.config.js"),
  extractTSConfig("./tsconfig.json"),
  // not possible to pass a babel configuration
  }
);

After:

import { cruise } from "dependency-cruiser";
import extractDepcruiseConfig from "dependency-cruiser/config-utl/extract-depcruise-config";
import extractTSConfig from "dependency-cruiser/config-utl/extract-ts-config";
import extractWebpackResolveConfig from "dependency-cruiser/config-utl/extract-webpack-resolve-config";
import extractBabelConfig from "dependency-cruiser/config-utl/extract-babel-config";

const lResult = await cruise(
  ["src", "test"],
  await extractDepcruiseConfig("./.dependency-cruiser.js"),
  await extractWebpackResolveConfig("webpack.config.js"),
  {
    tsConfig: extractTSConfig("./tsconfig.json"),
    babelConfig: await extractBabelConfig("./babel.conf.json"),
  }
);

List of changes

@sverweij sverweij pinned this issue Apr 22, 2023
@sverweij sverweij changed the title Breaking changes in the next major version (dependency-cruiser v13) Breaking changes in dependency-cruiser v13 Apr 22, 2023
@sverweij sverweij added the enhancement this will make dependency-cruiser sweeter label Apr 22, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement this will make dependency-cruiser sweeter
Projects
None yet
Development

No branches or pull requests

1 participant