-
Notifications
You must be signed in to change notification settings - Fork 55
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
Useful changes from my setup which I think may be beneficial to others #506
Conversation
lib/ImportStatement.js
Outdated
return [this.path]; | ||
} | ||
return [this.defaultImport || '', ...this.localNames()]; | ||
return [this.defaultImport !== 'React', this.path]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do you want React
to be on top?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because this is the standard everywhere React is used. This way it won't interfere with other people on your project importing themselves (React is the first thing they import). You will omit unnecessary changes to a file.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure I understand. I haven't come across any project where React has to be at the top.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess I was wrong - it is only standard in the firm I work in. Therefore I left it to [this.path] only.
@@ -53,7 +53,7 @@ function normalizeNode(node, context) { | |||
} | |||
|
|||
const isAssignment = KEYS_USED_FOR_ASSIGNMENT.has(key) || | |||
(key === 'key' && parent.parent.type === 'ObjectPattern') || | |||
(key === 'key' && !parent.computed && parent.parent.type === 'ObjectPattern') || |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you come up with a test case demonstrating what this is supposed to fix?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
added tests
lib/Watcher.js
Outdated
if (removed.length) { | ||
this.onFilesRemoved(removed); | ||
} | ||
findAllFiles(this.workingDirectory, this.excludes) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While this may fix an issue for you, it's also going to slow down the file watcher significantly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is an issue with everyone using export * from './somePlace'
I don't think there is any other way to do this.
Also please try it out - I don't notice any slowdown whatsoever.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This method is called every time a change is made to a file (either modified, deleted or added). findAllFiles
will traverse the filesystem, which will be slow on any large project. I think the reason you're not noticing this is that it's being done in the background.
The findExports
module already has code to handle export ... from
declarations. Can you see if you can inject your logic there instead of here?
Line 14 in a6a7728
if (node.type === 'ExportAllDeclaration') { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Say you have a files a.js
, b.js
, c.js
.
The contents of a.js
are const abc = someNewVar
The contents of b.js
are export * from './c'
The contents of c.js
are export someOldVar = 123
When you add export someNewVar = 321
in file c.js
and you try to add the import in a.js
the only option will be c.js
since file b.js
didn't change. This is an incorrect behavior.
We need to add b.js
to the processQueue
method in ModuleFinder.js
Since I don't know how to do that - I implemented the only solution I saw
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, thanks for explaining the use-case. Still, we can't afford traversing through all files on every file modification. I think the way we should solve this is to introduce some kind of dependency list, so that we know to update exports for b.js
when c.js
is modified.
lib/Watcher.js
Outdated
files.forEach(({ path, mtime }: Object) => { | ||
// add files which contain the following: | ||
// export * from 'file' | ||
if (fs.readFileSync(path, 'utf8').match(/export\s+\*\s+from/) !== null) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should go in findExports.js
instead of here.
lib/findProjectRoot.js
Outdated
|
||
if (isRoot) { | ||
return directory; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks useful, and I'm assuming it's a continuation of #462? An update to findProjectRoot-test.js
as well as an entry in the README and I think this is good to go. 👍
I added tests for |
const foo = { 'theValueOfMyConst': 123 }; | ||
const { [MY_CONST]: someAlias } = foo; | ||
`))).toEqual(new Set(['MY_CONST'])); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice.
lib/Watcher.js
Outdated
if (removed.length) { | ||
this.onFilesRemoved(removed); | ||
} | ||
findAllFiles(this.workingDirectory, this.excludes) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, thanks for explaining the use-case. Still, we can't afford traversing through all files on every file modification. I think the way we should solve this is to introduce some kind of dependency list, so that we know to update exports for b.js
when c.js
is modified.
@trotzig I updated the PR, I don't think anything more has to be done. Can you please merge it now? |
@trotzig What is the point of watching JSON files for changes btw? You can't import from json files as far as I know. |
lib/Watcher.js
Outdated
// } | ||
// }); | ||
// }); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This commented-out code isn't adding anything at the moment. I suggest opening a separate issue explaining what change in behavior you'd like to see.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
lib/ImportStatement.js
Outdated
return [this.path]; | ||
} | ||
return [this.defaultImport || '', ...this.localNames()]; | ||
return [this.defaultImport !== 'React', this.path]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure I understand. I haven't come across any project where React has to be at the top.
lib/ExportsStorage.js
Outdated
const filtered = files.filter(({ path: pathToFile, mtime }) => ( | ||
mtime !== mtimes[pathToFile] | ||
const filtered = files.filter(({ path: pathToFile, mtime, exportsAll }) => ( | ||
mtime !== mtimes[pathToFile] || exportsAll |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Revert the changes made to these two lines. The exportsAll
option is not in use after you cleaned out that logic.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for working on this PR!
README.md
Outdated
@@ -117,6 +117,18 @@ Save this file in the root folder of your project (e.g. where the package.json | |||
file is found). You can also save it to the user home directory if you want to | |||
share a global config between different projects. | |||
|
|||
If you have a project inside a project with both containing a `package.json` file, | |||
you can specify that the subproject is not root like this: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because most of the configuration for import JS is in the import JS configuration file, I think it would be helpful to make it clearer that this snippet is showing package.json
. Maybe all we need to do is add "...not root like this in package.json
:" or something
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
lib/ImportStatement.js
Outdated
} | ||
return [this.defaultImport || '', ...this.localNames()]; | ||
toNormalized(): Array<any> { | ||
return [this.defaultImport !== 'React', this.path]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you help me understand why this change is made (including the type change)? It seems weird to have React hard-coded in this project.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I reverted the change. Now it is only [this.path]
I believe I made all the changes |
@trotzig @lencioni added logic for initializing the module finding when using an "init" function> |
return [this.path]; | ||
} | ||
return [this.defaultImport || '', ...this.localNames()]; | ||
return [this.path]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This change will modify sorting of imports. From experience, I know there will be heated discussions around this. Would you mind moving this out of the PR and pushing it as a separate PR? Or better yet, a PR adding support for better user-control over sorting (and grouping).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With this sorting, the node_modules imports will be at the top with them being sorted by package name.
After them will be the rest of the imports which will also be sorted by filename.
I really don't see any other possible sorting as viable. Sorting by the imports themselves and not where they come from doesn't make any sense. This will produce many unnecessary/confusing merge conflicts. Example: instead of only removing a named export, the change will also include the movement of the imports for that file due to the sorting. The same scenario will be for appending named imports.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There has been plenty of discussion around sorting and grouping, and it's pretty clear that we need more flexibility:
#508
#454
#448
#284
I think the best thing we could do is to look at what the sort-imports eslint plugin does and make things configurable the same way.
I'm not going to argue much with what you think is the right order. What's important here is that we can either introduce a breaking change (that doesn't fix the problem) or keep the current sorting until we have a non-breaking and flexible solution. Introducing a breaking change on import sort order right now would mean introducing churn for every project that has been using import-js for a while.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Two of those issues are things that I fixed myself - the empty line between imports being removed and the newly added imports being appended instead of prepended.
The other two issues are from people which want exactly the same sort order as I have currently implemented in this PR.
So I don't really see any conflicts of interest... Everyone wants the same thing.
Those issue links just highlight what I have told you in my previous comment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I really don't see any other possible sorting as viable
Let me present you with a few possible sorting options that are all equally viable:
- a-z on the variable name (the assignment)
- a-z on the module name (the path/package name)
For groups, any combination of the following seems equally viable:
- built-in packages
- node_modules
- non-js files
- side-effect imports (those that have no assignment)
- relative paths
- absolute paths
The right thing here would be to make things configurable, so that you can choose any sorting and any grouping. If we make the default config produce the same sorting and grouping result as what we have today by default, I'll be happy to merge.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
First option:
a-z on the variable name (the assignment)
This is not viable, because of I what I wrote in the first comment...
Since you haven't read it I will quote it here...
Sorting by the imports themselves and not where they come from doesn't make any sense. This will produce many unnecessary/confusing merge conflicts. Example: instead of only removing a named export, the change will also include the movement of the imports for that file due to the sorting. The same scenario will be for appending named imports.
Second option:
a-z on the module name (the path/package name)
This is what I have currently implemented...
For the grouping, it is very simple - exports from outside of the project, after which - local exports. I think everyone will find that as a reasonable default.
If you find any value in adding a custom sorting/grouping function that will benefit anyone (since I haven't seen one such person in the above mentioned issues by you),
then do that yourself. I have done enough work, I am happy with what I've got and I consider it to be the best default behavior for the project.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I currently have a few projects using the current default sorting and grouping rules and I agree that this shouldn't be changed until it's configurable. Otherwise I'll need to turn it off and manually sort and group again, or deal with PR churn for the foreseeable future. I'm sure there are others using the default behaviour that we don't hear from.
Because this is an area where it's down to preference, and an existing default has been in use for a fairly long time, it does not make sense to change the default and push a different preference on those already using the default behaviour.
Now @trotzig has not asked you to implement custom sorting configuration, only to keep the existing defaults so it doesn't create churn for other users.
I understand the frustration of having a PR held up when you feel that you have done a good job, but lets keep some perspective.
Also, you have done a great job here. As a user I always appreciate when someone makes an effort to improve OSS tools for the community
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The current setup doesn't make sense for the reason I have pointed out above. That is why I changed it to something that does. You simply don't want the sorting to be changed because that is what you have used in existing projects. I consider this argument invalid. Keeping wrong code because it is what people have used so far is not correct. Please give me an argument that supports the claim that the current sorting is in any way better than the one I have implemented.
If you can't, someone else will have to implement these features listed here, because I got tired of this.
@@ -243,7 +243,8 @@ export default class ImportStatements { | |||
importsArray, | |||
(importStatement: ImportStatement): boolean => | |||
!importStatement.isParsedAndUntouched(), | |||
); | |||
).reverse(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will have to go too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
#448
This is one of the issues you have commented in the file above.
Look at the bottom.
Sorry for the delay here @ivangeorgiew, I just came back from vacation. 🍹 |
No description provided.