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

no-extraneous-dependencies: Separate packageDir for devDependencies #1214

Closed
hedgepigdaniel opened this issue Oct 13, 2018 · 2 comments
Closed

Comments

@hedgepigdaniel
Copy link

Problem

I have a lerna monorepo and I like to install development only dependencies at the workspace root rather than in individual packages. This is because it is easier to maintain one set of versions for development tools rather than many, and it is not important that the development environment of each package is self contained - the monorepo IS the development environment.

After #1085, this is possible.

However, I still would like the published versions of my packages to have proper entries in dependencies for any other packages that it requires in order to work. Users of the package don't check out the monorepo, they install the package.

Example

To illustrate, imagine the following project structure:

package.json
yarn.lock
packages/
  apple/
    package.json
    devScripts.js
    productionCode.js
// package.json
{
  "devDependencies": {
    "development-tool-orange": "1.0.0"
  }
}
// packages/apple/package.json
{
  "dependencies": {
    "production-dependency-pineapple": "1.0.0"
  }
}
// packages/apple/devScripts.js
import 'development-tool-orange'; // This is fine, this file is only used in development inside the monorepo
// packages/apple/productionCode.js
import 'production-dependency-pineapple'; // This is fine, there is a dependency in this package
import 'development-tool-orange'; // This is bad! the published version will not work!

Suggestion

Allow both devDependencies and packageDir to be used only for specific files which are not used in production:

{
  rules: {
    'import/no-extraneous-dependencies': [
      2,
      {
        groups: [
          {
            dirs: ['/devScripts.js'],
            devDependencies: true,
            packageDir: [
              path.join(__dirname, 'package.json'),
              path.join(__dirname, '../../package.json'),
            ],
          },
        ],
      },
    ],
  },
}
@Izhaki
Copy link

Izhaki commented Jan 9, 2020

Initially this made sense to me, but after thinking about it - it doesn't.

This is how we approach it:

Monorepo Root

package.json

  • Has no dependencies - this is imperative
  • Has devDependencies common to all packages.

.eslintrc.js

// These are allowed to require packages from devDependecies
const devScripts = [
  'scripts/*.js',
  '**/webpack.*.js',
  '**/cosmos.proxies.js',
  '**/*.fixture.jsx',
  '**/next.config.js'
];

module.exports = {
  rules: {
    'import/no-extraneous-dependencies': [
      'error',
      {
        // scripts that are allowed to import from devDependencies
        devDependencies: devScripts
      }
    ],
  },
};

Packages

In each package folder (packages/packageName/):

package.json

  • Has package related dependencies
  • May have unique devDependencies for that specific package

.eslintrc.js

const { join } = require('path');

module.exports = {
  rules: {
    'import/no-extraneous-dependencies': [
      'error',
      // Use package.json from both this package folder and root.
      { packageDir: [__dirname, join(__dirname, '../../')] }
    ]
  }
};

See more on this in #1302 (comment)

@hedgepigdaniel
Copy link
Author

I have ended up using an alternative using eslint overrides with the following features:

  • Dev scripts required to have dependencies listed in the monorepo root in devDependencies
  • Runtime code required to have dependencies listed in the dependencies of the package.json in that package
  • Only one configuration file, at the monorepo root
const path = require('path');

const devConfig = {
  rules: {
    'import/no-extraneous-dependencies': [
      2,
      {
        // Dependencies must be specified in `devDependencies` in the monorepo root
        devDependencies: true,
        packageDir: __dirname,
      },
    ],
  },
};

const runtimeConfig = {
  rules: {
    // Dependencies must be specified in the projects package.json
    'import/no-extraneous-dependencies': [
      2,
      {
        devDependencies: false,
        // default `packageDir` is the closest `package.json` to the file being linted
      },
    ],
  },
};

module.exports = {
  ...,
  overrides: [
    {
      files: ['./packages/*/**/*'],
      ...runtimeConfig,
    },
    {
      files: ['./packages/*/scripts/**/*', './packages/*/*.config.js'],
      ...devConfig,
    },
  ]
};

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

No branches or pull requests

2 participants