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

Fix no-extraneous-dependencies: Take 2 #1064

Merged
merged 2 commits into from
Oct 15, 2019
Merged

Conversation

cartogram
Copy link
Contributor

@cartogram cartogram commented Sep 27, 2019

Description

Fixes #1001
Follow up from #1026

This PR is split into 2 commits. The first contains only the changes required to make the import/no-extraneous-dependencies rule work for this repo, the second is all the lint fixes required to pass CI.

The fix here was to use the import/resolver setting to override the typescript resolver from plugin:shopify/typescript. The typescript resolver was problematic because it resolves modules to their source location, causing the rule think of them as "internal" (not extraneous) modules. Creating a new configuration and extending it before extending the plugin:shopify/typescript tells the rule to use the node resolver, which looks for these packages in node_modules instead and properly sees them as "external" to the eslint rule.

The downside to having this rule enabled is that it (correctly) enforces all our @shopify/* dependencies to be listed when they are used and thus increases the dependency web and number of "patch" dependency bumps needed (releasing a new version of dependency x causes all related dependencies that use x to need a new version). The largest offender of this was @shopify/react-testing, which is used in all of the @shopify/react-* dependencies.

The fix for this was to add an override for test files that disables this rule. We don't care if @shopify/react-testing is listed or not since its really just needed for development and will never cause a missing dependency error when installed in a consuming package, which is the only thing we really care about here.

@cartogram cartogram changed the title Fix no-extraneous-dependencies: Take 2 [WIP] Fix no-extraneous-dependencies: Take 2 Sep 27, 2019
@cartogram cartogram force-pushed the fix-extraneous-deps branch 7 times, most recently from 70b4b18 to d1405c7 Compare October 4, 2019 03:08
@cartogram cartogram changed the title [WIP] Fix no-extraneous-dependencies: Take 2 Fix no-extraneous-dependencies: Take 2 Oct 4, 2019
@cartogram cartogram force-pushed the fix-extraneous-deps branch 11 times, most recently from 2aee247 to af00114 Compare October 4, 2019 13:19
.eslintrc.js Show resolved Hide resolved
@@ -24,6 +24,7 @@
"dependencies": {
"@types/koa-bodyparser": "*",
"@types/koa-compose": "*",
"@types/koa": "^2.0.50",
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This library uses the Context from koa and would require the consumer to have koa installed in their project. There were a number of packages that met this criteria, and I use the following method to resolve them: 1) Add the packages the host is required to have in the peerDependencies with a pretty loose version range, and 2) add the types packages used to the dependencies.

Why? I added the peerDependency because it is needed (yet unused) in this library. You can't really use a koa middleware as intended without koa, but you also don't need koa to write them. They are, more or less, just functions. I added a loose version range to reduce the chance 2 versions of the package will be installed, in this case koa, as a result of this library.

I added the types in dependencies because there is a middleware, persistedOperationAssociationMiddleware, that uses the Context type in one of its arguments and that function is being exported. Even though the use of the type is tangental, we are not exporting the type itself or expecting consumers will use it, they will use the function that uses the type. For this reason, it needed to be in dependencies.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good rationale. Is this version range too restrictive, though?

@@ -1,3 +1,6 @@
import {memoize as memoizeFn} from '@shopify/function-enhancers';
import {memoize} from '@shopify/decorators';
import {languageFromLocale, regionFromLocale} from '@shopify/i18n';
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With the resolver changes and re-classification of these libraries (from "internal" to "external"), they are being rearranged as a result of import/order.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is still not clear to me why they should have changed position relative to @shopify/dates?

.eslintrc.js Outdated Show resolved Hide resolved
@@ -24,6 +24,7 @@
"dependencies": {
"@types/koa-bodyparser": "*",
"@types/koa-compose": "*",
"@types/koa": "^2.0.50",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good rationale. Is this version range too restrictive, though?

packages/koa-shopify-auth/package.json Outdated Show resolved Hide resolved
packages/react-cookie/src/CookieUniversalProvider.tsx Outdated Show resolved Hide resolved
packages/react-html/package.json Outdated Show resolved Hide resolved
@@ -34,6 +34,8 @@
"intl-pluralrules": "^0.2.1"
},
"dependencies": {
"@babel/template": "^7.6.0",
"@babel/traverse": "^7.6.2",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I'm not sure if these are strictly dependencies. Aren't they just used for types? Babel should generally be a peer/ optional dependency IMO

packages/sewing-kit-koa/src/middleware.ts Outdated Show resolved Hide resolved
Copy link
Contributor

@jgodson jgodson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the FYI and the thorough explanation. It makes sense to me 👍. I just had one minor comment/nitpick.

@BPScott
Copy link
Member

BPScott commented Oct 4, 2019

I wonder if there's some upstream PR we can make to https://github.com/alexgorbatchev/eslint-import-resolver-typescript to allow support for our monorepo use case

@cartogram cartogram force-pushed the fix-extraneous-deps branch 3 times, most recently from 82a2d57 to 11a855a Compare October 4, 2019 19:13
@@ -0,0 +1,13 @@
// We need to specify the import/resolver setting in an extendable
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm surprised this works - rules later in the config overrode earlier ones - it's how you can enable a rule in a config, then disable it in your local eslint config. I would have thought settings would work in the same way.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the import plugin iterates over the setting object, which gets merged together by ESLint's config. However, it merges in the order of plugin addition, and then iterates over the object (iteration happens in insertion order), so resolvers added by earlier plugins are actually handled first.

@cartogram cartogram force-pushed the fix-extraneous-deps branch 2 times, most recently from 4202a6d to 649cf4c Compare October 4, 2019 20:08
@cartogram cartogram force-pushed the fix-extraneous-deps branch 3 times, most recently from 328103c to 36e174c Compare October 7, 2019 08:54
Copy link
Member

@lemonmade lemonmade left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking good, still a few more questions 👍

.eslintrc.js Show resolved Hide resolved
packages/address/src/tests/AddressFormatter.test.ts Outdated Show resolved Hide resolved
packages/graphql-persisted/package.json Outdated Show resolved Hide resolved
packages/graphql-persisted/package.json Outdated Show resolved Hide resolved
packages/jest-dom-mocks/package.json Outdated Show resolved Hide resolved
packages/koa-shopify-auth/package.json Outdated Show resolved Hide resolved
packages/react-app-bridge-universal-provider/package.json Outdated Show resolved Hide resolved
packages/react-effect-apollo/package.json Outdated Show resolved Hide resolved
"koa-mount": "^4.0.0"
"koa-mount": "^4.0.0",
"fs-extra": "^8.1.0",
"isomorphic-fetch": "2.2.1"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this actually used for it directly?

Copy link
Contributor Author

@cartogram cartogram Oct 10, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It isn't no. It is just imported.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might make more sense as a peer dependency.

"chalk": "^2.4.2",
"koa": "^2.5.0",
"koa-compose": "^4.1.0",
"koa-mount": "^4.0.0"
"koa-mount": "^4.0.0",
"fs-extra": "^8.1.0",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is this used for?

Copy link
Contributor Author

@cartogram cartogram Oct 10, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is used for checking if there is a Gemfile, when getting the manifest file. See pathExistsSync below.

function getManifestPath(root: string) {
  const gemFileExists = pathExistsSync(join(root, 'Gemfile'));
  if (!gemFileExists) {
    return;
  }

  // eslint-disable-next-line no-process-env
  return process.env.NODE_ENV === 'development'
    ? `tmp/sewing-kit/sewing-kit-manifest.json`
    : `public/bundles/sewing-kit-manifest.json`;
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like it's an alias for the built in fs.existsSync.

https://github.com/jprichardson/node-fs-extra/blob/master/lib/path-exists/index.js#L11

@cartogram cartogram force-pushed the fix-extraneous-deps branch 5 times, most recently from 433a2db to 271d749 Compare October 11, 2019 19:03
@@ -27,14 +27,15 @@
"@shopify/network": "^1.4.2",
"@shopify/performance": "^1.2.0",
"@shopify/statsd": "^1.1.0",
"@types/koa": "^2.0.0",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Weird spacing

"@types/koa-bodyparser": "*",
"@types/koa-compose": "*",
"change-case": "^3.1.0",
"koa-bodyparser": ">=4.0.0 <5.0.0",
"koa-compose": ">=3.0.0 <4.0.0"
},
"peer-dependencies": {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

whoops

"apollo-cache-inmemory": "^1.6.2",
"apollo-client": "^2.6.0",
"apollo-link": "^1.2.13",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably want a much less restrictive version here

"intl-pluralrules": "^0.2.1"
},
"dependencies": {
"@babel/types": ">=7.0.0",
"@types/babel__template": "^7.0.0",
"@types/babel__traverse": "^7.0.0",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I actually had a bit of a change of heart on this, while technically they do make sense as dependencies, in practice they probably don't because you never consume the Babel dependency directly (only Babel consumes it). So, IMO, dev dependencies

@@ -1,3 +1,6 @@
import {memoize as memoizeFn} from '@shopify/function-enhancers';
import {memoize} from '@shopify/decorators';
import {languageFromLocale, regionFromLocale} from '@shopify/i18n';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is still not clear to me why they should have changed position relative to @shopify/dates?

"webpack-virtual-modules": "^0.1.12"
"webpack-virtual-modules": "^0.1.12",
"koa-mount": "^3.0.0",
"@types/koa-mount": "^3.0.1"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Neither of the above are dependencies, both can be in devDependencies

@cartogram cartogram merged commit 6b3794d into master Oct 15, 2019
@cartogram cartogram deleted the fix-extraneous-deps branch November 8, 2019 15:07
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.

Prevent missing @shopify/* packages from going out to releases
4 participants