Skip to content

Comments

feat: add import and export rules#981

Merged
susnux merged 2 commits intomainfrom
feat/imports-fast
Apr 24, 2025
Merged

feat: add import and export rules#981
susnux merged 2 commits intomainfrom
feat/imports-fast

Conversation

@susnux
Copy link
Contributor

@susnux susnux commented Apr 10, 2025

  • Enforce file extensions
  • Enforce consistent named import / export sorting
  • Enforce consistent module sorting

Do not use eslint-plugin-import(-x) because it is quite slow and has many issues with parsing different formats like vue script-setup in Typescript and similar.

@susnux susnux added enhancement New feature or request 3. to review labels Apr 10, 2025
@susnux susnux force-pushed the feat/imports-fast branch 2 times, most recently from 40be8f7 to 0f2d689 Compare April 10, 2025 10:00
ShGKme

This comment was marked as resolved.

@ShGKme
Copy link
Contributor

ShGKme commented Apr 10, 2025

import type { NcSelectOption } from '../composables/useNcSelectModel.ts'                        // type

import { t } from '@nextcloud/l10n'                                                             // external (@nextcloud)
import NcButton from '@nextcloud/vue/components/NcButton'                                       // external (Vue) (@nextcloud)
import NcCheckboxRadioSwitch from '@nextcloud/vue/components/NcCheckboxRadioSwitch'             // external (Vue) (@nextcloud)
import NcNoteCard from '@nextcloud/vue/components/NcNoteCard'                                   // external (Vue) (@nextcloud)
import NcTextField from '@nextcloud/vue/components/NcTextField'                                 // external (Vue) (@nextcloud)
import { storeToRefs } from 'pinia'                                                             // external
import { computed, ref } from 'vue'                                                             // external
import { ZOOM_MAX, ZOOM_MIN } from '../../../constants.js'                                      // INTERNAL
import { useNcSelectModel } from '../composables/useNcSelectModel.ts'                           // INTERNAL
import { useAppConfigStore } from './appConfig.store.ts'                                        // INTERNAL
import { useAppConfigValue } from './useAppConfigValue.ts'                                      // INTERNAL
import SettingsFormGroup from './components/SettingsFormGroup.vue'                              // INTERNAL (Vue)
import SettingsSelect from './components/SettingsSelect.vue'                                    // INTERNAL (Vue)
import SettingsSubsection from './components/SettingsSubsection.vue'                            // INTERNAL (Vue)
import IconBellRingOutline from 'vue-material-design-icons/BellRingOutline.vue'                 // external (Vue)
import IconCardAccountPhoneOutline from 'vue-material-design-icons/CardAccountPhoneOutline.vue' // external (Vue)
import IconMagnify from 'vue-material-design-icons/Magnify.vue'                                 // external (Vue)
import IconMinus from 'vue-material-design-icons/Minus.vue'                                     // external (Vue)
import IconPhoneRingOutline from 'vue-material-design-icons/PhoneRingOutline.vue'               // external (Vue)
import IconPlus from 'vue-material-design-icons/Plus.vue'                                       // external (Vue)
import IconRestore from 'vue-material-design-icons/Restore.vue'                                 // external (Vue)
import IconThemeLightDark from 'vue-material-design-icons/ThemeLightDark.vue'                   // external (Vue)
import IconVolumeHigh from 'vue-material-design-icons/VolumeHigh.vue'                           // external (Vue)

IMHO:

  • External modules vue-material-design-icons should not go after internal even they are .vue
  • Would be nice to have imports like from 'vue' on top of from '@nextcloud/*'
  • Would be nice to have @nextcloud/vue components close to all the other components
  • I'd also put styles to the end to side effects
import type { NcSelectOption } from '../composables/useNcSelectModel.ts'                        // type

import { storeToRefs } from 'pinia'                                                             // external
import { computed, ref } from 'vue'                                                             // external
import { t } from '@nextcloud/l10n'                                                             // external (@nextcloud)
import NcButton from '@nextcloud/vue/components/NcButton'                                       // external (Vue) (@nextcloud)
import NcCheckboxRadioSwitch from '@nextcloud/vue/components/NcCheckboxRadioSwitch'             // external (Vue) (@nextcloud)
import NcNoteCard from '@nextcloud/vue/components/NcNoteCard'                                   // external (Vue) (@nextcloud)
import NcTextField from '@nextcloud/vue/components/NcTextField'                                 // external (Vue) (@nextcloud)
import IconBellRingOutline from 'vue-material-design-icons/BellRingOutline.vue'                 // external (Vue)
import IconCardAccountPhoneOutline from 'vue-material-design-icons/CardAccountPhoneOutline.vue' // external (Vue)
import IconMagnify from 'vue-material-design-icons/Magnify.vue'                                 // external (Vue)
import IconMinus from 'vue-material-design-icons/Minus.vue'                                     // external (Vue)
import IconPhoneRingOutline from 'vue-material-design-icons/PhoneRingOutline.vue'               // external (Vue)
import IconPlus from 'vue-material-design-icons/Plus.vue'                                       // external (Vue)
import IconRestore from 'vue-material-design-icons/Restore.vue'                                 // external (Vue)
import IconThemeLightDark from 'vue-material-design-icons/ThemeLightDark.vue'                   // external (Vue)
import IconVolumeHigh from 'vue-material-design-icons/VolumeHigh.vue'                           // external (Vue)
import SettingsFormGroup from './components/SettingsFormGroup.vue'                              // INTERNAL (Vue)
import SettingsSelect from './components/SettingsSelect.vue'                                    // INTERNAL (Vue)
import SettingsSubsection from './components/SettingsSubsection.vue'                            // INTERNAL (Vue)
import { ZOOM_MAX, ZOOM_MIN } from '../../../constants.js'                                      // INTERNAL
import { useNcSelectModel } from '../composables/useNcSelectModel.ts'                           // INTERNAL
import { useAppConfigStore } from './appConfig.store.ts'                                        // INTERNAL
import { useAppConfigValue } from './useAppConfigValue.ts'                                      // INTERNAL

Comment on lines 67 to 72
// everything else which is everything internal
'unknown',
// import style from 'my.module.css'
'style',
// Vue components
'vue',
Copy link
Contributor

@Antreesy Antreesy Apr 10, 2025

Choose a reason for hiding this comment

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

Agree with Grigorii (but also because I used to this order):

Suggested change
// everything else which is everything internal
'unknown',
// import style from 'my.module.css'
'style',
// Vue components
'vue',
// Imports from @nextcloud ecosystem
'nextcloud',
// Imports from @nextcloud/vue library
'nextcloud-vue',
// Vue components
'vue',
// everything else which is everything internal
'unknown',
// import style from 'my.module.css'
'style',

],
customGroups: {
value: {
vue: '\\.vue$',
Copy link
Contributor

@Antreesy Antreesy Apr 10, 2025

Choose a reason for hiding this comment

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

Suggested change
vue: '\\.vue$',
nextcloud: '^@nextcloud.*',
'nextcloud-vue': '^@nextcloud\/vue.*',
vue: '\\.vue$',

This what is used in Talk:

// group @nextcloud imports
pattern: '@nextcloud/{!(vue),!(vue)/**}',
// group @nextcloud/vue imports
pattern: '{@nextcloud/vue,@nextcloud/vue/**}',

@susnux
Copy link
Contributor Author

susnux commented Apr 20, 2025

External modules vue-material-design-icons should not go after internal even they are .vue

Fixed ✅

Would be nice to have @nextcloud/vue components close to all the other components

Fixed ✅

I'd also put styles to the end to side effects

Fixed ✅

Would be nice to have imports like from 'vue' on top of from '@nextcloud/*'

What is the use case? Its just a namespace, like every other, I would consider it really weird to see:

import { foo } from '@foo/bar'
import { computed } from 'vue'
import { t } from '@nextcloud/l10n'

instead of consistent alphabetical ordering of normal modules¹:

import { foo } from '@foo/bar'
import { t } from '@nextcloud/l10n'
import { computed } from 'vue'

¹ I mean like type imports or Vue components are a special kind of modules one is just type information that will be stripped away and the other is UI components for use in the template, compared to everything else which is logic code that will be used.

If I import that code form one namespace or another makes no difference for reading the code, it does not provide any information except that is a Nextcloud maintained library but what does that help you in your flow?


TL;DR: I am fine with it if others agree with that sorting but I would prefer only sort by module type rather than package maintainer.

@ShGKme

This comment was marked as resolved.

@ShGKme

This comment was marked as resolved.

@ShGKme

This comment was marked as resolved.

@ShGKme

This comment was marked as resolved.

@susnux

This comment was marked as resolved.

@ShGKme

This comment was marked as resolved.

@susnux susnux force-pushed the feat/imports-fast branch from c3c8f1c to d0623b1 Compare April 24, 2025 14:09
@susnux
Copy link
Contributor Author

susnux commented Apr 24, 2025

Fixed performance issue by using the new config format.

@susnux

This comment was marked as resolved.

@susnux susnux requested a review from ShGKme April 24, 2025 14:21
@susnux susnux force-pushed the feat/imports-fast branch from 4b33d4d to a523673 Compare April 24, 2025 14:27
Copy link
Contributor

@ShGKme ShGKme left a comment

Choose a reason for hiding this comment

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

Works well now

// type first
'external-type',
'type',
{ newlinesBetween: 'always' },
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe remove these empty lines as well?

Copy link
Contributor

Choose a reason for hiding this comment

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

So imports are a single block, separated by an empty line from the remaining module code.
Type imports are separated visually via import type prefix anyway.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Suggested change
{ newlinesBetween: 'always' },
{ newlinesBetween: 'ignore' },

Maybe?

Copy link
Contributor

@Antreesy Antreesy left a comment

Choose a reason for hiding this comment

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

Gonna be painful to get used to it

Comment on lines +67 to +70
// everything else which is everything internal
'unknown',
// Vue components
'vue', // external modules (e.g. nextcloud-vue)
Copy link
Contributor

Choose a reason for hiding this comment

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

So we decided to go with this? external .vue components are now listed after internal non-vue modules
image

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@Antreesy one problem here is that you use the old imports they are not recognized as vue components. (The /dist/Components).
Instead use /components/Nc...

Copy link
Contributor

Choose a reason for hiding this comment

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

From the config it is:

  • external
  • internal
  • vue external
  • vue internal

Which is indeed different from the proposal above

Copy link
Contributor Author

@susnux susnux Apr 24, 2025

Choose a reason for hiding this comment

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

It was always like that here 👀

  • Typescript (external | internal)
  • Javascript (external | internal)
  • Vue (external | internal)
  • Styles (external | internal)

Otherwise why should you sort vue independently if you mix it with Javascript?

Copy link
Contributor

@ShGKme ShGKme Apr 24, 2025

Choose a reason for hiding this comment

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

Typescript (external | internal)
Javascript (external | internal)

Does it actually separate TS from JS, or types from modules?

Copy link
Contributor

Choose a reason for hiding this comment

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

Otherwise why should you sort vue independently if you mix it with Javascript?

To not break it in the middle, because it can be in a single batch without mixing externals with internals

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Does it actually separate TS from JS, or types from modules?

I do not mean .ts files I meat types.

  • Types are stripped away so that block is only for type checking.
  • Javascript is the code that stays so its the most important block.
  • Vue files are components, you do not care in <script> about them so they do not need to interrupt reading the script sources. They are only relevant for the <template>.

susnux added 2 commits April 24, 2025 23:17
- Enforce file extensions
- Enforce consistent named import / export sorting
- Enforce consistent module sorting

Do not use eslint-plugin-import(-x) because it is quite slow and has
many issues with parsing different formats like vue script-setup in
Typescript and similar.

Signed-off-by: Ferdinand Thiessen <[email protected]>
@susnux susnux force-pushed the feat/imports-fast branch from a523673 to aca2d69 Compare April 24, 2025 21:17
@susnux susnux merged commit cc3d228 into main Apr 24, 2025
10 checks passed
@susnux susnux deleted the feat/imports-fast branch April 24, 2025 21:18
@susnux susnux mentioned this pull request Apr 24, 2025
@ShGKme
Copy link
Contributor

ShGKme commented Apr 24, 2025

External modules vue-material-design-icons should not go after internal even they are .vue

Fixed ✅

This is why I thought, it was fixed, and externals don't go after internals

@susnux
Copy link
Contributor Author

susnux commented Apr 24, 2025

Well then it was a misunderstanding. Currently there is really mixed sorting in e.g. server, but for me it seemed to be agreed that Vue components are sorted extra as they belong to <template> rather than <script>.
Thats where this sorting was coming from.

In most components this leads to

import { computed } from 'vue'
import { getSomething } from '../../utils/myUtil.ts'
import NcButton from '@nextcloud/vue/components/NcButton'
import MyComponent from './MyComponent.vue'

Which I thought is more common than

import { computed } from 'vue'
import NcButton from '@nextcloud/vue/components/NcButton'
import MyComponent from './MyComponent.vue'
import { getSomething } from '../../utils/myUtil.ts'

So it was about seeing directly what are components vs seeing what origins from where.
But I do not mind a different sorting if it is agreed upon at least its consistent.

@ShGKme
Copy link
Contributor

ShGKme commented Apr 25, 2025

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

Labels

3. to review enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants