diff --git a/front/src/audio/volume.js b/front/src/audio/volume.js
index 1b7e2bc62f57a3932f746616f84a658b40f306db..5a9ad05f6ea449fc9b53b49faa27f56219767697 100644
--- a/front/src/audio/volume.js
+++ b/front/src/audio/volume.js
@@ -1,6 +1,6 @@
 const DYNAMIC_RANGE = 40 // dB
 
-function toLinearVolumeScale (v) {
+export function toLinearVolumeScale (v) {
   if (v <= 0.0) {
     return 0.0
   }
@@ -11,7 +11,7 @@ function toLinearVolumeScale (v) {
   return Math.pow(10, dB / 20)
 }
 
-function toLogarithmicVolumeScale (v) {
+export function toLogarithmicVolumeScale (v) {
   if (v <= 0.0) {
     return 0.0
   }
diff --git a/front/src/components/Footer.vue b/front/src/components/Footer.vue
index 3f9641e18736252b20973d2f496651bf1b6811ae..b78d4844b8f229822bc578defbae76f636522659 100644
--- a/front/src/components/Footer.vue
+++ b/front/src/components/Footer.vue
@@ -212,7 +212,7 @@
 
 <script>
 import { mapState } from 'vuex'
-import ThemesMixin from '@/components/mixins/Themes'
+import ThemesMixin from '@/components/mixins/Themes.vue'
 import _ from '@/lodash'
 
 export default {
diff --git a/front/src/components/Queue.vue b/front/src/components/Queue.vue
index b823deee50f65cc272dfca0a6b05ea8a696b611e..921927f9e68cd00e8a8dc891cbe00ccdf825414f 100644
--- a/front/src/components/Queue.vue
+++ b/front/src/components/Queue.vue
@@ -346,7 +346,7 @@ import { mapState, mapGetters, mapActions } from 'vuex'
 import $ from 'jquery'
 import moment from 'moment'
 import lodash from '@/lodash'
-import time from '@/utils/time'
+import time from '@/utils/time.js'
 import { createFocusTrap } from 'focus-trap'
 
 export default {
diff --git a/front/src/components/admin/SettingsGroup.vue b/front/src/components/admin/SettingsGroup.vue
index 94e7620e87311425a411d7c3099afd55a7f737c5..4ee4603cde0025286920231adca6ee9dafdbd1f9 100644
--- a/front/src/components/admin/SettingsGroup.vue
+++ b/front/src/components/admin/SettingsGroup.vue
@@ -162,7 +162,7 @@ import lodash from '@/lodash'
 
 export default {
   components: {
-    SignupFormBuilder: () => import(/* webpackChunkName: "signup-form-builder" */ '@/components/admin/SignupFormBuilder')
+    SignupFormBuilder: () => import(/* webpackChunkName: "signup-form-builder" */ '@/components/admin/SignupFormBuilder.vue')
   },
   props: {
     group: { type: Object, required: true },
diff --git a/front/src/components/admin/SignupFormBuilder.vue b/front/src/components/admin/SignupFormBuilder.vue
index 1eb29f632fed68c535878d288c17dab16159e3ec..90c0a87bb9e21db0ea89cfc0e49f030c17462ffb 100644
--- a/front/src/components/admin/SignupFormBuilder.vue
+++ b/front/src/components/admin/SignupFormBuilder.vue
@@ -163,7 +163,7 @@
 <script>
 import lodash from '@/lodash'
 
-import SignupForm from '@/components/auth/SignupForm'
+import SignupForm from '@/components/auth/SignupForm.vue'
 
 function arrayMove (arr, oldIndex, newIndex) {
   if (newIndex >= arr.length) {
diff --git a/front/src/components/audio/ChannelCard.vue b/front/src/components/audio/ChannelCard.vue
index 8578e69ffb47a01fa0e95fddb873bd168edf7fe5..382928b1931e132aa5b6f39004d18c37add3f5a7 100644
--- a/front/src/components/audio/ChannelCard.vue
+++ b/front/src/components/audio/ChannelCard.vue
@@ -75,8 +75,8 @@
 </template>
 
 <script>
-import PlayButton from '@/components/audio/PlayButton'
-import TagsList from '@/components/tags/List'
+import PlayButton from '@/components/audio/PlayButton.vue'
+import TagsList from '@/components/tags/List.vue'
 
 import { momentFormat } from '@/filters'
 import moment from 'moment'
diff --git a/front/src/components/audio/ChannelEntries.vue b/front/src/components/audio/ChannelEntries.vue
index 21c4dc1c85f0571233e2abbd7d1236b4180b8836..ff9e1ea7d4b2a12f1fb975d1e4cc281248b7b2e6 100644
--- a/front/src/components/audio/ChannelEntries.vue
+++ b/front/src/components/audio/ChannelEntries.vue
@@ -56,8 +56,8 @@
 <script>
 import _ from '@/lodash'
 import axios from 'axios'
-import PodcastTable from '@/components/audio/podcast/Table'
-import TrackTable from '@/components/audio/track/Table'
+import PodcastTable from '@/components/audio/podcast/Table.vue'
+import TrackTable from '@/components/audio/track/Table.vue'
 
 export default {
   components: {
diff --git a/front/src/components/audio/ChannelEntryCard.vue b/front/src/components/audio/ChannelEntryCard.vue
index 2ca1f93e0aca7bba744d4aade7b546b555d82de3..b190f7519087bd88369ce6b6a7ba64dccc5c0e99 100644
--- a/front/src/components/audio/ChannelEntryCard.vue
+++ b/front/src/components/audio/ChannelEntryCard.vue
@@ -77,8 +77,8 @@
 </template>
 
 <script>
-import PlayButton from '@/components/audio/PlayButton'
-import TrackFavoriteIcon from '@/components/favorites/TrackFavoriteIcon'
+import PlayButton from '@/components/audio/PlayButton.vue'
+import TrackFavoriteIcon from '@/components/favorites/TrackFavoriteIcon.vue'
 import { mapGetters } from 'vuex'
 
 export default {
diff --git a/front/src/components/audio/ChannelForm.vue b/front/src/components/audio/ChannelForm.vue
index 3c96a9319706453342770f0634a0f5f0537399f4..8426a86463a6b4d1b33881f4c0e5e033a4c23e22 100644
--- a/front/src/components/audio/ChannelForm.vue
+++ b/front/src/components/audio/ChannelForm.vue
@@ -249,8 +249,8 @@
 <script>
 import axios from 'axios'
 
-import AttachmentInput from '@/components/common/AttachmentInput'
-import TagsSelector from '@/components/library/TagsSelector'
+import AttachmentInput from '@/components/common/AttachmentInput.vue'
+import TagsSelector from '@/components/library/TagsSelector.vue'
 
 function slugify (text) {
   return text.toString().toLowerCase()
diff --git a/front/src/components/audio/ChannelSerieCard.vue b/front/src/components/audio/ChannelSerieCard.vue
index ab5542f7529aae693c23f0363c3412453d15441b..269cc410797951107866f89681f17785ede72b39 100644
--- a/front/src/components/audio/ChannelSerieCard.vue
+++ b/front/src/components/audio/ChannelSerieCard.vue
@@ -62,7 +62,7 @@
 </template>
 
 <script>
-import PlayButton from '@/components/audio/PlayButton'
+import PlayButton from '@/components/audio/PlayButton.vue'
 
 export default {
   components: {
diff --git a/front/src/components/audio/ChannelSeries.vue b/front/src/components/audio/ChannelSeries.vue
index 26b0aa0beee205025781d7ed37ba241edc040e7d..ed20b5e3abd22e415fd7d3e63c676bef747ba64e 100644
--- a/front/src/components/audio/ChannelSeries.vue
+++ b/front/src/components/audio/ChannelSeries.vue
@@ -55,8 +55,8 @@
 <script>
 import _ from '@/lodash'
 import axios from 'axios'
-import ChannelSerieCard from '@/components/audio/ChannelSerieCard'
-import AlbumCard from '@/components/audio/album/Card'
+import ChannelSerieCard from '@/components/audio/ChannelSerieCard.vue'
+import AlbumCard from '@/components/audio/album/Card.vue'
 
 export default {
   components: {
diff --git a/front/src/components/audio/ChannelsWidget.vue b/front/src/components/audio/ChannelsWidget.vue
index 68b26feaa06d38e0451241c379b407edc9faf2c6..5974c5e75727346b455c186f0602592ea8064758 100644
--- a/front/src/components/audio/ChannelsWidget.vue
+++ b/front/src/components/audio/ChannelsWidget.vue
@@ -39,7 +39,7 @@
 <script>
 import _ from '@/lodash'
 import axios from 'axios'
-import ChannelCard from '@/components/audio/ChannelCard'
+import ChannelCard from '@/components/audio/ChannelCard.vue'
 
 export default {
   components: {
diff --git a/front/src/components/audio/PlayButton.vue b/front/src/components/audio/PlayButton.vue
index 079faafc64da9467d406da800a3535e89f74bde2..f7165d8402a739898fe76bb9c54eb3688e5a38e0 100644
--- a/front/src/components/audio/PlayButton.vue
+++ b/front/src/components/audio/PlayButton.vue
@@ -126,8 +126,8 @@
 <script>
 import jQuery from 'jquery'
 
-import ReportMixin from '@/components/mixins/Report'
-import PlayOptionsMixin from '@/components/mixins/PlayOptions'
+import ReportMixin from '@/components/mixins/Report.vue'
+import PlayOptionsMixin from '@/components/mixins/PlayOptions.vue'
 
 export default {
   mixins: [ReportMixin, PlayOptionsMixin],
diff --git a/front/src/components/audio/Search.vue b/front/src/components/audio/Search.vue
index a27018da5e47f73cc47988fe27d7fdf8b9a8b39f..0fd5fe1e2fb627140d9514200f3ec966da1624af 100644
--- a/front/src/components/audio/Search.vue
+++ b/front/src/components/audio/Search.vue
@@ -72,8 +72,8 @@
 import _ from '@/lodash'
 import axios from 'axios'
 import logger from '@/logging'
-import AlbumCard from '@/components/audio/album/Card'
-import ArtistCard from '@/components/audio/artist/Card'
+import AlbumCard from '@/components/audio/album/Card.vue'
+import ArtistCard from '@/components/audio/artist/Card.vue'
 
 export default {
   components: {
diff --git a/front/src/components/audio/SearchBar.vue b/front/src/components/audio/SearchBar.vue
index 5690aa742c516f613081394165c8e62cf053ae06..f3a153b22b43df421c0cc775be9ed24ed4cafcbe 100644
--- a/front/src/components/audio/SearchBar.vue
+++ b/front/src/components/audio/SearchBar.vue
@@ -24,7 +24,7 @@
 import jQuery from 'jquery'
 import router from '@/router'
 import lodash from '@/lodash'
-import GlobalEvents from '@/components/utils/global-events'
+import GlobalEvents from '@/components/utils/global-events.vue'
 
 export default {
   components: {
diff --git a/front/src/components/audio/album/Card.vue b/front/src/components/audio/album/Card.vue
index 7f5afac6352df7dab3d5f018d6e98e82cda43f25..381d39613ca8797d189ff3cd12254aa106f5dd3f 100644
--- a/front/src/components/audio/album/Card.vue
+++ b/front/src/components/audio/album/Card.vue
@@ -54,7 +54,7 @@
 </template>
 
 <script>
-import PlayButton from '@/components/audio/PlayButton'
+import PlayButton from '@/components/audio/PlayButton.vue'
 
 export default {
   components: {
diff --git a/front/src/components/audio/artist/Card.vue b/front/src/components/audio/artist/Card.vue
index c02d825f76b8ea72a15e149edcdbcd86ef024aea..bfff6a684ab0690fdc1c7e19d2a957b88a1892c4 100644
--- a/front/src/components/audio/artist/Card.vue
+++ b/front/src/components/audio/artist/Card.vue
@@ -61,8 +61,8 @@
 </template>
 
 <script>
-import PlayButton from '@/components/audio/PlayButton'
-import TagsList from '@/components/tags/List'
+import PlayButton from '@/components/audio/PlayButton.vue'
+import TagsList from '@/components/tags/List.vue'
 
 export default {
   components: {
diff --git a/front/src/components/audio/artist/Widget.vue b/front/src/components/audio/artist/Widget.vue
index 9cf3ae0cc582b9843a6b7dccd17ca5099ca1b5e8..f12c960c04b905621d1360657e2e1431120930d4 100644
--- a/front/src/components/audio/artist/Widget.vue
+++ b/front/src/components/audio/artist/Widget.vue
@@ -52,7 +52,7 @@
 
 <script>
 import axios from 'axios'
-import ArtistCard from '@/components/audio/artist/Card'
+import ArtistCard from '@/components/audio/artist/Card.vue'
 
 export default {
   components: {
diff --git a/front/src/components/audio/podcast/MobileRow.vue b/front/src/components/audio/podcast/MobileRow.vue
index e4f0db9805617d22c403c68cba7e9d6d97ac2bdb..40bf88389de7b0edadff13a85ddc5219b10f210e 100644
--- a/front/src/components/audio/podcast/MobileRow.vue
+++ b/front/src/components/audio/podcast/MobileRow.vue
@@ -139,9 +139,9 @@
 
 <script>
 import { mapActions, mapGetters } from 'vuex'
-import TrackFavoriteIcon from '@/components/favorites/TrackFavoriteIcon'
-import TrackModal from '@/components/audio/track/Modal'
-import PlayOptionsMixin from '@/components/mixins/PlayOptions'
+import TrackFavoriteIcon from '@/components/favorites/TrackFavoriteIcon.vue'
+import TrackModal from '@/components/audio/track/Modal.vue'
+import PlayOptionsMixin from '@/components/mixins/PlayOptions.vue'
 
 export default {
 
diff --git a/front/src/components/audio/podcast/Modal.vue b/front/src/components/audio/podcast/Modal.vue
index e1de0cdb10b600b7a08bb10b932b0693721c0bd5..0a5e396fa49663b4efdb28d44f5e15209b5cacf9 100644
--- a/front/src/components/audio/podcast/Modal.vue
+++ b/front/src/components/audio/podcast/Modal.vue
@@ -226,9 +226,9 @@
 </template>
 
 <script>
-import Modal from '@/components/semantic/Modal'
-import ReportMixin from '@/components/mixins/Report'
-import PlayOptionsMixin from '@/components/mixins/PlayOptions'
+import Modal from '@/components/semantic/Modal.vue'
+import ReportMixin from '@/components/mixins/Report.vue'
+import PlayOptionsMixin from '@/components/mixins/PlayOptions.vue'
 
 export default {
   components: {
diff --git a/front/src/components/audio/podcast/Row.vue b/front/src/components/audio/podcast/Row.vue
index 06bec4855fdd5d3df73b3577f1379827eb2d8c08..1f9eb60c12e0eb5a907abf80ddfaf2b2524ec3e2 100644
--- a/front/src/components/audio/podcast/Row.vue
+++ b/front/src/components/audio/podcast/Row.vue
@@ -83,8 +83,8 @@
 <script>
 import axios from 'axios'
 import { mapActions, mapGetters } from 'vuex'
-import PlayButton from '@/components/audio/PlayButton'
-import PlayOptions from '@/components/mixins/PlayOptions'
+import PlayButton from '@/components/audio/PlayButton.vue'
+import PlayOptions from '@/components/mixins/PlayOptions.vue'
 
 export default {
 
diff --git a/front/src/components/audio/podcast/Table.vue b/front/src/components/audio/podcast/Table.vue
index a2407801f49a149f0539f6ae89b338ce4792cbfe..df737da8ae85f41f9e539c35c47a326031ea4474 100644
--- a/front/src/components/audio/podcast/Table.vue
+++ b/front/src/components/audio/podcast/Table.vue
@@ -77,9 +77,9 @@
 </template>
 
 <script>
-import PodcastRow from '@/components/audio/podcast/Row'
-import TrackMobileRow from '@/components/audio/track/MobileRow'
-import Pagination from '@/components/Pagination'
+import PodcastRow from '@/components/audio/podcast/Row.vue'
+import TrackMobileRow from '@/components/audio/track/MobileRow.vue'
+import Pagination from '@/components/Pagination.vue'
 
 export default {
   components: {
diff --git a/front/src/components/audio/track/MobileRow.vue b/front/src/components/audio/track/MobileRow.vue
index 98005ff9d1d980c14ff046a81614dcfdb2df77c7..bf1f552afe590692949b46b6f1bd7ee6c1e211b7 100644
--- a/front/src/components/audio/track/MobileRow.vue
+++ b/front/src/components/audio/track/MobileRow.vue
@@ -122,9 +122,9 @@
 
 <script>
 import { mapActions, mapGetters } from 'vuex'
-import TrackFavoriteIcon from '@/components/favorites/TrackFavoriteIcon'
-import TrackModal from '@/components/audio/track/Modal'
-import PlayOptionsMixin from '@/components/mixins/PlayOptions'
+import TrackFavoriteIcon from '@/components/favorites/TrackFavoriteIcon.vue'
+import TrackModal from '@/components/audio/track/Modal.vue'
+import PlayOptionsMixin from '@/components/mixins/PlayOptions.vue'
 
 export default {
 
diff --git a/front/src/components/audio/track/Modal.vue b/front/src/components/audio/track/Modal.vue
index e1de0cdb10b600b7a08bb10b932b0693721c0bd5..0a5e396fa49663b4efdb28d44f5e15209b5cacf9 100644
--- a/front/src/components/audio/track/Modal.vue
+++ b/front/src/components/audio/track/Modal.vue
@@ -226,9 +226,9 @@
 </template>
 
 <script>
-import Modal from '@/components/semantic/Modal'
-import ReportMixin from '@/components/mixins/Report'
-import PlayOptionsMixin from '@/components/mixins/PlayOptions'
+import Modal from '@/components/semantic/Modal.vue'
+import ReportMixin from '@/components/mixins/Report.vue'
+import PlayOptionsMixin from '@/components/mixins/PlayOptions.vue'
 
 export default {
   components: {
diff --git a/front/src/components/audio/track/Row.vue b/front/src/components/audio/track/Row.vue
index 12c69f955e6a1978649b2847b93d7528eabc6ac7..64f9d7f2f91c5fa02853555a2bea27a3b3f0a8d2 100644
--- a/front/src/components/audio/track/Row.vue
+++ b/front/src/components/audio/track/Row.vue
@@ -180,11 +180,11 @@
 </template>
 
 <script>
-import PlayIndicator from '@/components/audio/track/PlayIndicator'
+import PlayIndicator from '@/components/audio/track/PlayIndicator.vue'
 import { mapActions, mapGetters } from 'vuex'
-import TrackFavoriteIcon from '@/components/favorites/TrackFavoriteIcon'
-import PlayButton from '@/components/audio/PlayButton'
-import PlayOptions from '@/components/mixins/PlayOptions'
+import TrackFavoriteIcon from '@/components/favorites/TrackFavoriteIcon.vue'
+import PlayButton from '@/components/audio/PlayButton.vue'
+import PlayOptions from '@/components/mixins/PlayOptions.vue'
 
 export default {
 
diff --git a/front/src/components/audio/track/Table.vue b/front/src/components/audio/track/Table.vue
index 038371de85066ac979449d4f3c4ab2981eea012e..e0f5c9a21cba84a6b5570d068fa3ed019d403602 100644
--- a/front/src/components/audio/track/Table.vue
+++ b/front/src/components/audio/track/Table.vue
@@ -160,9 +160,9 @@
 <script>
 import _ from '@/lodash'
 import axios from 'axios'
-import TrackRow from '@/components/audio/track/Row'
-import TrackMobileRow from '@/components/audio/track/MobileRow'
-import Pagination from '@/components/Pagination'
+import TrackRow from '@/components/audio/track/Row.vue'
+import TrackMobileRow from '@/components/audio/track/MobileRow.vue'
+import Pagination from '@/components/Pagination.vue'
 
 export default {
   components: {
diff --git a/front/src/components/audio/track/Widget.vue b/front/src/components/audio/track/Widget.vue
index 85b7c6104cf1aea53f3c9b6383be64ab0822ad97..8caf5bd50f4d507395eba36cc6196e31873cbfef 100644
--- a/front/src/components/audio/track/Widget.vue
+++ b/front/src/components/audio/track/Widget.vue
@@ -137,8 +137,8 @@
 <script>
 import _ from '@/lodash'
 import axios from 'axios'
-import PlayButton from '@/components/audio/PlayButton'
-import TagsList from '@/components/tags/List'
+import PlayButton from '@/components/audio/PlayButton.vue'
+import TagsList from '@/components/tags/List.vue'
 
 export default {
   components: {
diff --git a/front/src/components/auth/ApplicationEdit.vue b/front/src/components/auth/ApplicationEdit.vue
index 4d04f9cdbe8c4ee73a9c37ffb21ba191a4900df0..2e86ba2850399a57847693b6936f6067a79eb03d 100644
--- a/front/src/components/auth/ApplicationEdit.vue
+++ b/front/src/components/auth/ApplicationEdit.vue
@@ -78,7 +78,7 @@
 <script>
 import axios from 'axios'
 
-import ApplicationForm from '@/components/auth/ApplicationForm'
+import ApplicationForm from '@/components/auth/ApplicationForm.vue'
 
 export default {
   components: {
diff --git a/front/src/components/auth/ApplicationForm.vue b/front/src/components/auth/ApplicationForm.vue
index bfbcd580843909d268520cfeb2d488e5b1f3274f..3233a3068c7134f01250ad37b4ac1b96904767e2 100644
--- a/front/src/components/auth/ApplicationForm.vue
+++ b/front/src/components/auth/ApplicationForm.vue
@@ -121,7 +121,7 @@
 <script>
 import _ from '@/lodash'
 import axios from 'axios'
-import TranslationsMixin from '@/components/mixins/Translations'
+import TranslationsMixin from '@/components/mixins/Translations.vue'
 
 export default {
   mixins: [TranslationsMixin],
diff --git a/front/src/components/auth/ApplicationNew.vue b/front/src/components/auth/ApplicationNew.vue
index 8ffa13fe3a3d24a62f0a662bd141ee490980623e..ec95ddcd4edfcd3635c076bb27969487c34e5ffb 100644
--- a/front/src/components/auth/ApplicationNew.vue
+++ b/front/src/components/auth/ApplicationNew.vue
@@ -25,7 +25,7 @@
 </template>
 
 <script>
-import ApplicationForm from '@/components/auth/ApplicationForm'
+import ApplicationForm from '@/components/auth/ApplicationForm.vue'
 
 export default {
   components: {
diff --git a/front/src/components/auth/Authorize.vue b/front/src/components/auth/Authorize.vue
index d86252009972f9dfea6d99c44c4d570feb8bc7c1..004dbc680866bc044c7a2f2d2906af6852c66979 100644
--- a/front/src/components/auth/Authorize.vue
+++ b/front/src/components/auth/Authorize.vue
@@ -142,7 +142,7 @@
 </template>
 
 <script>
-import TranslationsMixin from '@/components/mixins/Translations'
+import TranslationsMixin from '@/components/mixins/Translations.vue'
 
 import axios from 'axios'
 
diff --git a/front/src/components/auth/Settings.vue b/front/src/components/auth/Settings.vue
index d614cf4b3f42467c9c14b3be7feb3c78f5c4440b..92b3e724aa4dd1fdbefca85df500d2dad19ace60 100644
--- a/front/src/components/auth/Settings.vue
+++ b/front/src/components/auth/Settings.vue
@@ -699,10 +699,10 @@
 import $ from 'jquery'
 import axios from 'axios'
 import logger from '@/logging'
-import PasswordInput from '@/components/forms/PasswordInput'
-import SubsonicTokenForm from '@/components/auth/SubsonicTokenForm'
-import TranslationsMixin from '@/components/mixins/Translations'
-import AttachmentInput from '@/components/common/AttachmentInput'
+import PasswordInput from '@/components/forms/PasswordInput.vue'
+import SubsonicTokenForm from '@/components/auth/SubsonicTokenForm.vue'
+import TranslationsMixin from '@/components/mixins/Translations.vue'
+import AttachmentInput from '@/components/common/AttachmentInput.vue'
 
 export default {
   components: {
diff --git a/front/src/components/auth/SignupForm.vue b/front/src/components/auth/SignupForm.vue
index 0711178ae761b1b785074bea43d905fd986cf930..a21f1c88a1c1e99df2395144fe65cee59e2ce65f 100644
--- a/front/src/components/auth/SignupForm.vue
+++ b/front/src/components/auth/SignupForm.vue
@@ -156,8 +156,8 @@
 import axios from 'axios'
 import logger from '@/logging'
 
-import LoginForm from '@/components/auth/LoginForm'
-import PasswordInput from '@/components/forms/PasswordInput'
+import LoginForm from '@/components/auth/LoginForm.vue'
+import PasswordInput from '@/components/forms/PasswordInput.vue'
 
 export default {
   components: {
diff --git a/front/src/components/auth/SubsonicTokenForm.vue b/front/src/components/auth/SubsonicTokenForm.vue
index fce863249491609091c5023485b4d8e22b091fbd..a5e56913cf47bd2bc0d6b3bc4385cf23eea19916 100644
--- a/front/src/components/auth/SubsonicTokenForm.vue
+++ b/front/src/components/auth/SubsonicTokenForm.vue
@@ -145,7 +145,7 @@
 
 <script>
 import axios from 'axios'
-import PasswordInput from '@/components/forms/PasswordInput'
+import PasswordInput from '@/components/forms/PasswordInput.vue'
 
 export default {
   components: {
diff --git a/front/src/components/channels/AlbumModal.vue b/front/src/components/channels/AlbumModal.vue
index cf50cc0314508f2c48e04893b31c7193e17977f3..586bcba85e4b753bac4b78af4be9d395549ce613 100644
--- a/front/src/components/channels/AlbumModal.vue
+++ b/front/src/components/channels/AlbumModal.vue
@@ -48,8 +48,8 @@
 </template>
 
 <script>
-import Modal from '@/components/semantic/Modal'
-import ChannelAlbumForm from '@/components/channels/AlbumForm'
+import Modal from '@/components/semantic/Modal.vue'
+import ChannelAlbumForm from '@/components/channels/AlbumForm.vue'
 
 export default {
   components: {
diff --git a/front/src/components/channels/SubscribeButton.vue b/front/src/components/channels/SubscribeButton.vue
index 3d95305d8a74e8c47ac1737ae212d1e90bdd4564..3d371e97a9b219d5d4655b8d3fc9a5212feead10 100644
--- a/front/src/components/channels/SubscribeButton.vue
+++ b/front/src/components/channels/SubscribeButton.vue
@@ -39,7 +39,7 @@
 </template>
 
 <script>
-import LoginModal from '@/components/common/LoginModal'
+import LoginModal from '@/components/common/LoginModal.vue'
 
 export default {
   components: {
diff --git a/front/src/components/channels/UploadForm.vue b/front/src/components/channels/UploadForm.vue
index 712e9627ba7503b4d205400c3540b778b3c60866..79fc49dbf3cea3414abcee61b7eb8e460507ec8a 100644
--- a/front/src/components/channels/UploadForm.vue
+++ b/front/src/components/channels/UploadForm.vue
@@ -239,10 +239,10 @@
 import axios from 'axios'
 import $ from 'jquery'
 
-import LicenseSelect from '@/components/channels/LicenseSelect'
-import AlbumSelect from '@/components/channels/AlbumSelect'
-import FileUploadWidget from '@/components/library/FileUploadWidget'
-import UploadMetadataForm from '@/components/channels/UploadMetadataForm'
+import LicenseSelect from '@/components/channels/LicenseSelect.vue'
+import AlbumSelect from '@/components/channels/AlbumSelect.vue'
+import FileUploadWidget from '@/components/library/FileUploadWidget.vue'
+import UploadMetadataForm from '@/components/channels/UploadMetadataForm.vue'
 
 function setIfEmpty (obj, k, v) {
   if (obj[k] !== undefined) {
diff --git a/front/src/components/channels/UploadMetadataForm.vue b/front/src/components/channels/UploadMetadataForm.vue
index f7535883cebda7d9572c38864ecd3e187162f43d..127a275e631949fad23f51ee8fd4a71a8294f997 100644
--- a/front/src/components/channels/UploadMetadataForm.vue
+++ b/front/src/components/channels/UploadMetadataForm.vue
@@ -58,8 +58,8 @@
 </template>
 
 <script>
-import TagsSelector from '@/components/library/TagsSelector'
-import AttachmentInput from '@/components/common/AttachmentInput'
+import TagsSelector from '@/components/library/TagsSelector.vue'
+import AttachmentInput from '@/components/common/AttachmentInput.vue'
 
 export default {
   components: {
diff --git a/front/src/components/common/DangerousButton.vue b/front/src/components/common/DangerousButton.vue
index 25a25d2fc01b2c1114f20396a4744943c5061123..b15890da2090b0d66f375cca8bd612a226c23cca 100644
--- a/front/src/components/common/DangerousButton.vue
+++ b/front/src/components/common/DangerousButton.vue
@@ -43,7 +43,7 @@
   </button>
 </template>
 <script>
-import Modal from '@/components/semantic/Modal'
+import Modal from '@/components/semantic/Modal.vue'
 
 export default {
   components: {
diff --git a/front/src/components/common/LoginModal.vue b/front/src/components/common/LoginModal.vue
index 5f2d5b7c20497d47b5dc4b44967292d35e1e2214..5f51b3283623fba554b16e979c21a9397981a37c 100644
--- a/front/src/components/common/LoginModal.vue
+++ b/front/src/components/common/LoginModal.vue
@@ -51,7 +51,7 @@
 </template>
 
 <script>
-import Modal from '@/components/semantic/Modal'
+import Modal from '@/components/semantic/Modal.vue'
 
 export default {
   components: {
diff --git a/front/src/components/common/UserMenu.vue b/front/src/components/common/UserMenu.vue
index da174400454598f5972dc0b95c4cabb76e97d632..e5c7a053731122ab81c1bde64c714faeb5d7bea6 100644
--- a/front/src/components/common/UserMenu.vue
+++ b/front/src/components/common/UserMenu.vue
@@ -155,7 +155,7 @@
 
 import { mapGetters } from 'vuex'
 
-import ThemesMixin from '@/components/mixins/Themes'
+import ThemesMixin from '@/components/mixins/Themes.vue'
 
 export default {
   mixins: [ThemesMixin],
diff --git a/front/src/components/common/UserModal.vue b/front/src/components/common/UserModal.vue
index 3d7c249a59405ba1f11da5639ab405558ed55e8f..7b7cf377e43419236fb30637dc15e6bf163efaa1 100644
--- a/front/src/components/common/UserModal.vue
+++ b/front/src/components/common/UserModal.vue
@@ -174,8 +174,8 @@
 </template>
 
 <script>
-import Modal from '@/components/semantic/Modal'
-import ThemesMixin from '@/components/mixins/Themes'
+import Modal from '@/components/semantic/Modal.vue'
+import ThemesMixin from '@/components/mixins/Themes.vue'
 import { mapGetters } from 'vuex'
 
 export default {
diff --git a/front/src/components/favorites/List.vue b/front/src/components/favorites/List.vue
index 5b143c4f0b6aec9babf4684e3d3371ed4e50f20c..7a4ea9acbef8b421d19f3fa4d900dc0c89dc36a2 100644
--- a/front/src/components/favorites/List.vue
+++ b/front/src/components/favorites/List.vue
@@ -136,13 +136,13 @@
 import axios from 'axios'
 import $ from 'jquery'
 import logger from '@/logging'
-import RadioButton from '@/components/radios/Button'
-import Pagination from '@/components/Pagination'
-import OrderingMixin from '@/components/mixins/Ordering'
-import PaginationMixin from '@/components/mixins/Pagination'
-import TranslationsMixin from '@/components/mixins/Translations'
+import RadioButton from '@/components/radios/Button.vue'
+import Pagination from '@/components/Pagination.vue'
+import OrderingMixin from '@/components/mixins/Ordering.vue'
+import PaginationMixin from '@/components/mixins/Pagination.vue'
+import TranslationsMixin from '@/components/mixins/Translations.vue'
 import { checkRedirectToLogin } from '@/utils'
-import TrackTable from '@/components/audio/track/Table'
+import TrackTable from '@/components/audio/track/Table.vue'
 const FAVORITES_URL = 'tracks/'
 
 export default {
diff --git a/front/src/components/federation/FetchButton.vue b/front/src/components/federation/FetchButton.vue
index 699def21ba31da58b731943760d81bb2d41a818b..bb909a70354d8e01addc0acf1e6c785e94f22454 100644
--- a/front/src/components/federation/FetchButton.vue
+++ b/front/src/components/federation/FetchButton.vue
@@ -213,7 +213,7 @@
 
 <script>
 import axios from 'axios'
-import Modal from '@/components/semantic/Modal'
+import Modal from '@/components/semantic/Modal.vue'
 
 export default {
   components: {
diff --git a/front/src/components/federation/LibraryWidget.vue b/front/src/components/federation/LibraryWidget.vue
index 62683996af24844ad88ac65456504d1749fbccec..7f2941ff9392fb13924852339116c7cccc921a99 100644
--- a/front/src/components/federation/LibraryWidget.vue
+++ b/front/src/components/federation/LibraryWidget.vue
@@ -55,7 +55,7 @@
 <script>
 import _ from '@/lodash'
 import axios from 'axios'
-import LibraryCard from '@/views/content/remote/Card'
+import LibraryCard from '@/views/content/remote/Card.vue'
 
 export default {
   components: {
diff --git a/front/src/components/library/AlbumDetail.vue b/front/src/components/library/AlbumDetail.vue
index 24ce4eca675d3f4497aedd91cc51d515a8455f7f..c8bb360ccbfc6e538f9eef7deafa4b9cb8172854 100644
--- a/front/src/components/library/AlbumDetail.vue
+++ b/front/src/components/library/AlbumDetail.vue
@@ -92,7 +92,7 @@
 
 <script>
 
-import time from '@/utils/time.vue'
+import time from '@/utils/time.js'
 import LibraryWidget from '@/components/federation/LibraryWidget.vue'
 import ChannelEntries from '@/components/audio/ChannelEntries.vue'
 import TrackTable from '@/components/audio/track/Table.vue'
diff --git a/front/src/components/library/AlbumDropdown.vue b/front/src/components/library/AlbumDropdown.vue
index a7f12e155220cef900366dd1c792c542d05b2d1c..a5591bc4e336b8baff0930bf8e8384b45a24dfe2 100644
--- a/front/src/components/library/AlbumDropdown.vue
+++ b/front/src/components/library/AlbumDropdown.vue
@@ -127,9 +127,9 @@
   </span>
 </template>
 <script>
-import EmbedWizard from '@/components/audio/EmbedWizard'
-import Modal from '@/components/semantic/Modal'
-import ReportMixin from '@/components/mixins/Report'
+import EmbedWizard from '@/components/audio/EmbedWizard.vue'
+import Modal from '@/components/semantic/Modal.vue'
+import ReportMixin from '@/components/mixins/Report.vue'
 
 import { getDomain } from '@/utils'
 
diff --git a/front/src/components/library/AlbumEdit.vue b/front/src/components/library/AlbumEdit.vue
index d4d9559c384be96f72cc81e6bdbf6862841d277b..b5b8007436698847b64ec788c5b17078e43429bf 100644
--- a/front/src/components/library/AlbumEdit.vue
+++ b/front/src/components/library/AlbumEdit.vue
@@ -36,7 +36,7 @@
 </template>
 
 <script>
-import EditForm from '@/components/library/EditForm'
+import EditForm from '@/components/library/EditForm.vue'
 export default {
   components: {
     EditForm
diff --git a/front/src/components/library/ArtistBase.vue b/front/src/components/library/ArtistBase.vue
index 95462c09dad33fddbb610f0a4eb5ec3c3d2a11b5..5ec8f3efbdef061774c6010d72eeb635ed526869 100644
--- a/front/src/components/library/ArtistBase.vue
+++ b/front/src/components/library/ArtistBase.vue
@@ -215,15 +215,15 @@
 
 <script>
 import axios from 'axios'
-import logger from '@/logging'
-import PlayButton from '@/components/audio/PlayButton'
-import EmbedWizard from '@/components/audio/EmbedWizard'
-import Modal from '@/components/semantic/Modal'
-import RadioButton from '@/components/radios/Button'
-import TagsList from '@/components/tags/List'
-import ReportMixin from '@/components/mixins/Report'
+import logger from '@/logging.js'
+import PlayButton from '@/components/audio/PlayButton.vue'
+import EmbedWizard from '@/components/audio/EmbedWizard.vue'
+import Modal from '@/components/semantic/Modal.vue'
+import RadioButton from '@/components/radios/Button.vue'
+import TagsList from '@/components/tags/List.vue'
+import ReportMixin from '@/components/mixins/Report.vue'
 
-import { getDomain } from '@/utils'
+import { getDomain } from '@/utils.js'
 
 export default {
   components: {
diff --git a/front/src/components/library/ArtistDetail.vue b/front/src/components/library/ArtistDetail.vue
index 7f8248925a3c79afdf7dd6a625e93f35785c36b3..98f0ad8d1baa088b70e53ce5f552a7a6fb00d677 100644
--- a/front/src/components/library/ArtistDetail.vue
+++ b/front/src/components/library/ArtistDetail.vue
@@ -105,9 +105,9 @@
 
 <script>
 import axios from 'axios'
-import AlbumCard from '@/components/audio/album/Card'
-import TrackTable from '@/components/audio/track/Table'
-import LibraryWidget from '@/components/federation/LibraryWidget'
+import AlbumCard from '@/components/audio/album/Card.vue'
+import TrackTable from '@/components/audio/track/Table.vue'
+import LibraryWidget from '@/components/federation/LibraryWidget.vue'
 
 export default {
   components: {
diff --git a/front/src/components/library/ArtistEdit.vue b/front/src/components/library/ArtistEdit.vue
index 976918ab30ca09ffbadac5387528c4dc0ec4fd6e..b1d0e5400814f18f0380dfd888c1502ca65331fd 100644
--- a/front/src/components/library/ArtistEdit.vue
+++ b/front/src/components/library/ArtistEdit.vue
@@ -36,7 +36,7 @@
 </template>
 
 <script>
-import EditForm from '@/components/library/EditForm'
+import EditForm from '@/components/library/EditForm.vue'
 export default {
   components: {
     EditForm
diff --git a/front/src/components/library/Artists.vue b/front/src/components/library/Artists.vue
index 24a7b09a0120b86d4f182663bf863cff49f7e6dc..56afd95a01eae3fe3300dcdc4d7788b38adabd27 100644
--- a/front/src/components/library/Artists.vue
+++ b/front/src/components/library/Artists.vue
@@ -167,7 +167,7 @@ import qs from 'qs'
 import axios from 'axios'
 import $ from 'jquery'
 
-import logger from '@/logging'
+import logger from '@/logging.js'
 
 import OrderingMixin from '@/components/mixins/Ordering.vue'
 import PaginationMixin from '@/components/mixins/Pagination.vue'
diff --git a/front/src/components/library/EditCard.vue b/front/src/components/library/EditCard.vue
index a5e329414d1f3d33f4ab3e7adb9c0de925e70f2e..21cdc71a916d86eb628580c95c0b53a2304a50dc 100644
--- a/front/src/components/library/EditCard.vue
+++ b/front/src/components/library/EditCard.vue
@@ -215,7 +215,7 @@
 import axios from 'axios'
 import { diffWordsWithSpace } from 'diff'
 
-import edits from '@/edits'
+import edits from '@/edits.js'
 
 function castValue (value) {
   if (value === null || value === undefined) {
diff --git a/front/src/components/library/EditDetail.vue b/front/src/components/library/EditDetail.vue
index dd617e21e00a7795d6d8c09700ce02337b94798b..375e6cbe12440e1cddcbad0fbbcd1daffde099a4 100644
--- a/front/src/components/library/EditDetail.vue
+++ b/front/src/components/library/EditDetail.vue
@@ -12,8 +12,8 @@
 
 <script>
 import axios from 'axios'
-import edits from '@/edits'
-import EditCard from '@/components/library/EditCard'
+import edits from '@/edits.js'
+import EditCard from '@/components/library/EditCard.vue'
 export default {
   components: {
     EditCard
diff --git a/front/src/components/library/EditForm.vue b/front/src/components/library/EditForm.vue
index 90c6b22b68f47e316424059a52bdf6baa5fd7d25..d86fb1f23ab5505412a2cb00c2fb86a85359d585 100644
--- a/front/src/components/library/EditForm.vue
+++ b/front/src/components/library/EditForm.vue
@@ -240,13 +240,13 @@
 
 <script>
 import $ from 'jquery'
-import _ from '@/lodash'
+import _ from '@/lodash.js'
 import axios from 'axios'
-import AttachmentInput from '@/components/common/AttachmentInput'
-import EditList from '@/components/library/EditList'
-import EditCard from '@/components/library/EditCard'
-import TagsSelector from '@/components/library/TagsSelector'
-import edits from '@/edits'
+import AttachmentInput from '@/components/common/AttachmentInput.vue'
+import EditList from '@/components/library/EditList.vue'
+import EditCard from '@/components/library/EditCard.vue'
+import TagsSelector from '@/components/library/TagsSelector.vue'
+import edits from '@/edits.js'
 
 export default {
   components: {
diff --git a/front/src/components/library/EditList.vue b/front/src/components/library/EditList.vue
index e3efd0be31b494e12df8847bc2f09caffd7cb0eb..9ca8aeb7e2c8bb480bbbd02e0849c2d0e509d874 100644
--- a/front/src/components/library/EditList.vue
+++ b/front/src/components/library/EditList.vue
@@ -42,10 +42,10 @@
 </template>
 
 <script>
-import _ from '@/lodash'
+import _ from '@/lodash.js'
 import axios from 'axios'
 
-import EditCard from '@/components/library/EditCard'
+import EditCard from '@/components/library/EditCard.vue'
 
 export default {
   components: {
diff --git a/front/src/components/library/FileUpload.vue b/front/src/components/library/FileUpload.vue
index ca171c65d0160be305cfff0967287fca39fcf5c4..aaa602f0f1355a7a7232d658689b9c812547dea4 100644
--- a/front/src/components/library/FileUpload.vue
+++ b/front/src/components/library/FileUpload.vue
@@ -311,12 +311,12 @@
 </template>
 
 <script>
-import _ from '@/lodash'
+import _ from '@/lodash.js'
 import axios from 'axios'
-import FileUploadWidget from './FileUploadWidget'
-import FsBrowser from './FsBrowser'
-import FsLogs from './FsLogs'
-import LibraryFilesTable from '@/views/content/libraries/FilesTable'
+import FileUploadWidget from './FileUploadWidget.vue'
+import FsBrowser from './FsBrowser.vue'
+import FsLogs from './FsLogs.vue'
+import LibraryFilesTable from '@/views/content/libraries/FilesTable.vue'
 import moment from 'moment'
 
 export default {
diff --git a/front/src/components/library/FileUploadWidget.vue b/front/src/components/library/FileUploadWidget.vue
index 3f5077257cc0596b67443a643d1044e2b60d5b43..082e7adf41edd15183143f8530c6b9511f5e54ea 100644
--- a/front/src/components/library/FileUploadWidget.vue
+++ b/front/src/components/library/FileUploadWidget.vue
@@ -1,6 +1,6 @@
 <script>
 import FileUpload from 'vue-upload-component'
-import { setCsrf } from '@/utils'
+import { setCsrf } from '@/utils.js'
 
 export default {
   extends: FileUpload,
diff --git a/front/src/components/library/Home.vue b/front/src/components/library/Home.vue
index e70eaebb8236f870930238e4469db0bfc9b1be09..a9482ed24c6b8e6f06f257e0f630ea11615af158 100644
--- a/front/src/components/library/Home.vue
+++ b/front/src/components/library/Home.vue
@@ -72,11 +72,11 @@
 
 <script>
 import axios from 'axios'
-import logger from '@/logging'
-import ChannelsWidget from '@/components/audio/ChannelsWidget'
-import TrackWidget from '@/components/audio/track/Widget'
-import AlbumWidget from '@/components/audio/album/Widget'
-import PlaylistWidget from '@/components/playlists/Widget'
+import logger from '@/logging.js'
+import ChannelsWidget from '@/components/audio/ChannelsWidget.vue'
+import TrackWidget from '@/components/audio/track/Widget.vue'
+import AlbumWidget from '@/components/audio/album/Widget.vue'
+import PlaylistWidget from '@/components/playlists/Widget.vue'
 
 const ARTISTS_URL = 'artists/'
 
diff --git a/front/src/components/library/ImportStatusModal.vue b/front/src/components/library/ImportStatusModal.vue
index 839c7fa3da0473145f30442dab4bb8deee8c4c70..50e83b5d347fcc6feaf11a9a8c10bcf9c36cb985 100644
--- a/front/src/components/library/ImportStatusModal.vue
+++ b/front/src/components/library/ImportStatusModal.vue
@@ -132,7 +132,7 @@
   </modal>
 </template>
 <script>
-import Modal from '@/components/semantic/Modal'
+import Modal from '@/components/semantic/Modal.vue'
 
 function getErrors (payload) {
   const errors = []
diff --git a/front/src/components/library/Podcasts.vue b/front/src/components/library/Podcasts.vue
index e6c01b6b69f5a7c18c4f2f5ccdd6a18e5efc8aee..c0730477bae87fb24696678aeb4a07537ab2ec1b 100644
--- a/front/src/components/library/Podcasts.vue
+++ b/front/src/components/library/Podcasts.vue
@@ -199,7 +199,7 @@ import qs from 'qs'
 import axios from 'axios'
 import $ from 'jquery'
 
-import logger from '@/logging'
+import logger from '@/logging.js'
 
 import OrderingMixin from '@/components/mixins/Ordering.vue'
 import PaginationMixin from '@/components/mixins/Pagination.vue'
diff --git a/front/src/components/library/Radios.vue b/front/src/components/library/Radios.vue
index e81c25f58ec8a5348edd86c29634e4d5f194c7ff..c618cc0dc70bd923ea048bf5e39dd71fdf3245d6 100644
--- a/front/src/components/library/Radios.vue
+++ b/front/src/components/library/Radios.vue
@@ -177,7 +177,7 @@
 import axios from 'axios'
 import $ from 'jquery'
 
-import logger from '@/logging'
+import logger from '@/logging.js'
 
 import OrderingMixin from '@/components/mixins/Ordering.vue'
 import PaginationMixin from '@/components/mixins/Pagination.vue'
diff --git a/front/src/components/library/TagDetail.vue b/front/src/components/library/TagDetail.vue
index 60c557b939d4f216679efd4b81e56830a8496326..0506b989dbb97bd8bcb71e6cc7be45e8ae0e61c5 100644
--- a/front/src/components/library/TagDetail.vue
+++ b/front/src/components/library/TagDetail.vue
@@ -89,11 +89,11 @@
 </template>
 
 <script>
-import ChannelsWidget from '@/components/audio/ChannelsWidget'
-import TrackWidget from '@/components/audio/track/Widget'
-import AlbumWidget from '@/components/audio/album/Widget'
-import ArtistWidget from '@/components/audio/artist/Widget'
-import RadioButton from '@/components/radios/Button'
+import ChannelsWidget from '@/components/audio/ChannelsWidget.vue'
+import TrackWidget from '@/components/audio/track/Widget.vue'
+import AlbumWidget from '@/components/audio/album/Widget.vue'
+import ArtistWidget from '@/components/audio/artist/Widget.vue'
+import RadioButton from '@/components/radios/Button.vue'
 
 export default {
   components: {
diff --git a/front/src/components/library/TagsSelector.vue b/front/src/components/library/TagsSelector.vue
index bdff58ee82a373e1ab1bd8781faefb8a9551ce7d..98a1e339e86520e39695537c096dd9a0583702fc 100644
--- a/front/src/components/library/TagsSelector.vue
+++ b/front/src/components/library/TagsSelector.vue
@@ -20,7 +20,7 @@
 <script>
 import $ from 'jquery'
 
-import lodash from '@/lodash'
+import lodash from '@/lodash.js'
 export default {
   props: { value: { type: Array, required: true } },
   watch: {
diff --git a/front/src/components/library/TrackBase.vue b/front/src/components/library/TrackBase.vue
index fd809c74ee4c48bc45224b968fe2eabffebb8d04..452632e500272bf2826eab82335c90627cba4494 100644
--- a/front/src/components/library/TrackBase.vue
+++ b/front/src/components/library/TrackBase.vue
@@ -219,17 +219,17 @@
 </template>
 
 <script>
-import time from '@/utils/time'
+import time from '@/utils/time.js'
 import axios from 'axios'
-import url from '@/utils/url'
-import { getDomain } from '@/utils'
-import logger from '@/logging'
-import PlayButton from '@/components/audio/PlayButton'
-import TrackFavoriteIcon from '@/components/favorites/TrackFavoriteIcon'
-import TrackPlaylistIcon from '@/components/playlists/TrackPlaylistIcon'
-import Modal from '@/components/semantic/Modal'
-import EmbedWizard from '@/components/audio/EmbedWizard'
-import ReportMixin from '@/components/mixins/Report'
+import url from '@/utils/url.js'
+import { getDomain } from '@/utils.js'
+import logger from '@/logging.js'
+import PlayButton from '@/components/audio/PlayButton.vue'
+import TrackFavoriteIcon from '@/components/favorites/TrackFavoriteIcon.vue'
+import TrackPlaylistIcon from '@/components/playlists/TrackPlaylistIcon.vue'
+import Modal from '@/components/semantic/Modal.vue'
+import EmbedWizard from '@/components/audio/EmbedWizard.vue'
+import ReportMixin from '@/components/mixins/Report.vue'
 import { momentFormat } from '@/filters'
 
 const FETCH_URL = 'tracks/'
diff --git a/front/src/components/library/TrackDetail.vue b/front/src/components/library/TrackDetail.vue
index 276edcba9f4891cf94cbd09c7941cacdda5c4a2d..aa89b30ec6abfda8840d2462d5c4a19c1d375df3 100644
--- a/front/src/components/library/TrackDetail.vue
+++ b/front/src/components/library/TrackDetail.vue
@@ -289,9 +289,9 @@
 
 <script>
 import axios from 'axios'
-import LibraryWidget from '@/components/federation/LibraryWidget'
-import TagsList from '@/components/tags/List'
-import PlaylistWidget from '@/components/playlists/Widget'
+import LibraryWidget from '@/components/federation/LibraryWidget.vue'
+import TagsList from '@/components/tags/List.vue'
+import PlaylistWidget from '@/components/playlists/Widget.vue'
 
 export default {
   components: {
diff --git a/front/src/components/library/TrackEdit.vue b/front/src/components/library/TrackEdit.vue
index ce5422796bba857e9117533689fdb0c7d3b10ce3..6b28755d18880525a2ec919b7ec9748380ae3afe 100644
--- a/front/src/components/library/TrackEdit.vue
+++ b/front/src/components/library/TrackEdit.vue
@@ -45,7 +45,7 @@
 <script>
 import axios from 'axios'
 
-import EditForm from '@/components/library/EditForm'
+import EditForm from '@/components/library/EditForm.vue'
 export default {
   components: {
     EditForm
diff --git a/front/src/components/manage/ChannelsTable.vue b/front/src/components/manage/ChannelsTable.vue
index 9399240be32e4e783c217268da57c95d1c28db7e..5fb40c9c902d619bd9e09c7ee9f35bc25fa422c9 100644
--- a/front/src/components/manage/ChannelsTable.vue
+++ b/front/src/components/manage/ChannelsTable.vue
@@ -202,13 +202,13 @@
 <script>
 import axios from 'axios'
 import _ from '@/lodash'
-import time from '@/utils/time'
+import time from '@/utils/time.js'
 import { normalizeQuery, parseTokens } from '@/search'
-import Pagination from '@/components/Pagination'
-import ActionTable from '@/components/common/ActionTable'
-import OrderingMixin from '@/components/mixins/Ordering'
-import TranslationsMixin from '@/components/mixins/Translations'
-import SmartSearchMixin from '@/components/mixins/SmartSearch'
+import Pagination from '@/components/Pagination.vue'
+import ActionTable from '@/components/common/ActionTable.vue'
+import OrderingMixin from '@/components/mixins/Ordering.vue'
+import TranslationsMixin from '@/components/mixins/Translations.vue'
+import SmartSearchMixin from '@/components/mixins/SmartSearch.vue'
 
 export default {
   components: {
diff --git a/front/src/components/manage/library/AlbumsTable.vue b/front/src/components/manage/library/AlbumsTable.vue
index 8ccc63d5e75b2eba2b2e20d610c00670941200b3..d88d2d8741663923f805692da6b499985307be6f 100644
--- a/front/src/components/manage/library/AlbumsTable.vue
+++ b/front/src/components/manage/library/AlbumsTable.vue
@@ -187,13 +187,13 @@
 <script>
 import axios from 'axios'
 import _ from '@/lodash'
-import time from '@/utils/time'
+import time from '@/utils/time.js'
 import { normalizeQuery, parseTokens } from '@/search'
-import Pagination from '@/components/Pagination'
-import ActionTable from '@/components/common/ActionTable'
-import OrderingMixin from '@/components/mixins/Ordering'
-import TranslationsMixin from '@/components/mixins/Translations'
-import SmartSearchMixin from '@/components/mixins/SmartSearch'
+import Pagination from '@/components/Pagination.vue'
+import ActionTable from '@/components/common/ActionTable.vue'
+import OrderingMixin from '@/components/mixins/Ordering.vue'
+import TranslationsMixin from '@/components/mixins/Translations.vue'
+import SmartSearchMixin from '@/components/mixins/SmartSearch.vue'
 
 export default {
   components: {
diff --git a/front/src/components/manage/library/ArtistsTable.vue b/front/src/components/manage/library/ArtistsTable.vue
index ba211828792a8cc9ebb1189c733dedce51a62a9d..60069207372dca46306e9b578262575b76547066 100644
--- a/front/src/components/manage/library/ArtistsTable.vue
+++ b/front/src/components/manage/library/ArtistsTable.vue
@@ -186,13 +186,13 @@
 <script>
 import axios from 'axios'
 import _ from '@/lodash'
-import time from '@/utils/time'
+import time from '@/utils/time.js'
 import { normalizeQuery, parseTokens } from '@/search'
-import Pagination from '@/components/Pagination'
-import ActionTable from '@/components/common/ActionTable'
-import OrderingMixin from '@/components/mixins/Ordering'
-import TranslationsMixin from '@/components/mixins/Translations'
-import SmartSearchMixin from '@/components/mixins/SmartSearch'
+import Pagination from '@/components/Pagination.vue'
+import ActionTable from '@/components/common/ActionTable.vue'
+import OrderingMixin from '@/components/mixins/Ordering.vue'
+import TranslationsMixin from '@/components/mixins/Translations.vue'
+import SmartSearchMixin from '@/components/mixins/SmartSearch.vue'
 
 export default {
   components: {
diff --git a/front/src/components/manage/library/EditsCardList.vue b/front/src/components/manage/library/EditsCardList.vue
index 7a19df986ee2c47a03f276dbb171fb2d46a7b9fd..f379d5d417e6b1f2ad5e92377510c3601ee73a62 100644
--- a/front/src/components/manage/library/EditsCardList.vue
+++ b/front/src/components/manage/library/EditsCardList.vue
@@ -132,13 +132,13 @@
 <script>
 import axios from 'axios'
 import _ from '@/lodash'
-import time from '@/utils/time'
-import Pagination from '@/components/Pagination'
-import OrderingMixin from '@/components/mixins/Ordering'
-import TranslationsMixin from '@/components/mixins/Translations'
-import EditCard from '@/components/library/EditCard'
+import time from '@/utils/time.js'
+import Pagination from '@/components/Pagination.vue'
+import OrderingMixin from '@/components/mixins/Ordering.vue'
+import TranslationsMixin from '@/components/mixins/Translations.vue'
+import EditCard from '@/components/library/EditCard.vue'
 import { normalizeQuery, parseTokens } from '@/search'
-import SmartSearchMixin from '@/components/mixins/SmartSearch'
+import SmartSearchMixin from '@/components/mixins/SmartSearch.vue'
 
 import edits from '@/edits'
 
diff --git a/front/src/components/manage/library/LibrariesTable.vue b/front/src/components/manage/library/LibrariesTable.vue
index 0700a5782f0bcbf412dd981444e1f37e1c4be718..75b0cfd394b0b19b7b16968d5d94c191d1d90411 100644
--- a/front/src/components/manage/library/LibrariesTable.vue
+++ b/front/src/components/manage/library/LibrariesTable.vue
@@ -217,13 +217,13 @@
 <script>
 import axios from 'axios'
 import _ from '@/lodash'
-import time from '@/utils/time'
+import time from '@/utils/time.js'
 import { normalizeQuery, parseTokens } from '@/search'
-import Pagination from '@/components/Pagination'
-import ActionTable from '@/components/common/ActionTable'
-import OrderingMixin from '@/components/mixins/Ordering'
-import TranslationsMixin from '@/components/mixins/Translations'
-import SmartSearchMixin from '@/components/mixins/SmartSearch'
+import Pagination from '@/components/Pagination.vue'
+import ActionTable from '@/components/common/ActionTable.vue'
+import OrderingMixin from '@/components/mixins/Ordering.vue'
+import TranslationsMixin from '@/components/mixins/Translations.vue'
+import SmartSearchMixin from '@/components/mixins/SmartSearch.vue'
 
 export default {
   components: {
diff --git a/front/src/components/manage/library/TagsTable.vue b/front/src/components/manage/library/TagsTable.vue
index 8a5bd87eabed497d204138ad3e5ed992ba52f64a..5213a0529f6aa62fd7a8277a1eb6c54a39926c26 100644
--- a/front/src/components/manage/library/TagsTable.vue
+++ b/front/src/components/manage/library/TagsTable.vue
@@ -148,14 +148,14 @@
 <script>
 import axios from 'axios'
 import _ from '@/lodash'
-import time from '@/utils/time'
+import time from '@/utils/time.js'
 import { normalizeQuery, parseTokens } from '@/search'
-import Pagination from '@/components/Pagination'
-import ActionTable from '@/components/common/ActionTable'
-import OrderingMixin from '@/components/mixins/Ordering'
-import TranslationsMixin from '@/components/mixins/Translations'
-import SmartSearchMixin from '@/components/mixins/SmartSearch'
-import ImportStatusModal from '@/components/library/ImportStatusModal'
+import Pagination from '@/components/Pagination.vue'
+import ActionTable from '@/components/common/ActionTable.vue'
+import OrderingMixin from '@/components/mixins/Ordering.vue'
+import TranslationsMixin from '@/components/mixins/Translations.vue'
+import SmartSearchMixin from '@/components/mixins/SmartSearch.vue'
+import ImportStatusModal from '@/components/library/ImportStatusModal.vue'
 
 export default {
   components: {
diff --git a/front/src/components/manage/library/TracksTable.vue b/front/src/components/manage/library/TracksTable.vue
index 3989015b30d0c614c5ee893d5b0e9b17b5ba17cd..09410eb16059dc97856708991ed4a0a934c68a9d 100644
--- a/front/src/components/manage/library/TracksTable.vue
+++ b/front/src/components/manage/library/TracksTable.vue
@@ -200,13 +200,13 @@
 <script>
 import axios from 'axios'
 import _ from '@/lodash'
-import time from '@/utils/time'
+import time from '@/utils/time.js'
 import { normalizeQuery, parseTokens } from '@/search'
-import Pagination from '@/components/Pagination'
-import ActionTable from '@/components/common/ActionTable'
-import OrderingMixin from '@/components/mixins/Ordering'
-import TranslationsMixin from '@/components/mixins/Translations'
-import SmartSearchMixin from '@/components/mixins/SmartSearch'
+import Pagination from '@/components/Pagination.vue'
+import ActionTable from '@/components/common/ActionTable.vue'
+import OrderingMixin from '@/components/mixins/Ordering.vue'
+import TranslationsMixin from '@/components/mixins/Translations.vue'
+import SmartSearchMixin from '@/components/mixins/SmartSearch.vue'
 
 export default {
   components: {
diff --git a/front/src/components/manage/library/UploadsTable.vue b/front/src/components/manage/library/UploadsTable.vue
index f0d08794f59f48a6c48a8e0039e3f88d23935f64..4881d89c566357a9836b2f1caec7608e6c95390d 100644
--- a/front/src/components/manage/library/UploadsTable.vue
+++ b/front/src/components/manage/library/UploadsTable.vue
@@ -309,14 +309,14 @@
 <script>
 import axios from 'axios'
 import _ from '@/lodash'
-import time from '@/utils/time'
+import time from '@/utils/time.js'
 import { normalizeQuery, parseTokens } from '@/search'
-import Pagination from '@/components/Pagination'
-import ActionTable from '@/components/common/ActionTable'
-import OrderingMixin from '@/components/mixins/Ordering'
-import TranslationsMixin from '@/components/mixins/Translations'
-import SmartSearchMixin from '@/components/mixins/SmartSearch'
-import ImportStatusModal from '@/components/library/ImportStatusModal'
+import Pagination from '@/components/Pagination.vue'
+import ActionTable from '@/components/common/ActionTable.vue'
+import OrderingMixin from '@/components/mixins/Ordering.vue'
+import TranslationsMixin from '@/components/mixins/Translations.vue'
+import SmartSearchMixin from '@/components/mixins/SmartSearch.vue'
+import ImportStatusModal from '@/components/library/ImportStatusModal.vue'
 
 export default {
   components: {
diff --git a/front/src/components/manage/moderation/AccountsTable.vue b/front/src/components/manage/moderation/AccountsTable.vue
index 076689bb49991ccdbe461720c5d6966ccaf91b12..edcac3dc12b2ad0242f19f3c8b6937902c0a4961 100644
--- a/front/src/components/manage/moderation/AccountsTable.vue
+++ b/front/src/components/manage/moderation/AccountsTable.vue
@@ -173,13 +173,13 @@
 <script>
 import axios from 'axios'
 import _ from '@/lodash'
-import time from '@/utils/time'
+import time from '@/utils/time.js'
 import { normalizeQuery, parseTokens } from '@/search'
-import Pagination from '@/components/Pagination'
-import ActionTable from '@/components/common/ActionTable'
-import OrderingMixin from '@/components/mixins/Ordering'
-import TranslationsMixin from '@/components/mixins/Translations'
-import SmartSearchMixin from '@/components/mixins/SmartSearch'
+import Pagination from '@/components/Pagination.vue'
+import ActionTable from '@/components/common/ActionTable.vue'
+import OrderingMixin from '@/components/mixins/Ordering.vue'
+import TranslationsMixin from '@/components/mixins/Translations.vue'
+import SmartSearchMixin from '@/components/mixins/SmartSearch.vue'
 
 export default {
   components: {
diff --git a/front/src/components/manage/moderation/DomainsTable.vue b/front/src/components/manage/moderation/DomainsTable.vue
index a4c9c7d255f0ec08f1ba060f18ade37b5fec9749..b6804957511759f77a1792bd81894348100f4490 100644
--- a/front/src/components/manage/moderation/DomainsTable.vue
+++ b/front/src/components/manage/moderation/DomainsTable.vue
@@ -184,11 +184,11 @@
 <script>
 import axios from 'axios'
 import _ from '@/lodash'
-import time from '@/utils/time'
-import Pagination from '@/components/Pagination'
-import ActionTable from '@/components/common/ActionTable'
-import OrderingMixin from '@/components/mixins/Ordering'
-import TranslationsMixin from '@/components/mixins/Translations'
+import time from '@/utils/time.js'
+import Pagination from '@/components/Pagination.vue'
+import ActionTable from '@/components/common/ActionTable.vue'
+import OrderingMixin from '@/components/mixins/Ordering.vue'
+import TranslationsMixin from '@/components/mixins/Translations.vue'
 
 export default {
   components: {
diff --git a/front/src/components/manage/moderation/InstancePolicyModal.vue b/front/src/components/manage/moderation/InstancePolicyModal.vue
index 555c0df645c65c42947c5ed656f406b8de49abd2..fb10b91431cd3f4719c47c543438d6b351547203 100644
--- a/front/src/components/manage/moderation/InstancePolicyModal.vue
+++ b/front/src/components/manage/moderation/InstancePolicyModal.vue
@@ -66,9 +66,9 @@
 
 <script>
 import axios from 'axios'
-import InstancePolicyForm from '@/components/manage/moderation/InstancePolicyForm'
-import InstancePolicyCard from '@/components/manage/moderation/InstancePolicyCard'
-import Modal from '@/components/semantic/Modal'
+import InstancePolicyForm from '@/components/manage/moderation/InstancePolicyForm.vue'
+import InstancePolicyCard from '@/components/manage/moderation/InstancePolicyCard.vue'
+import Modal from '@/components/semantic/Modal.vue'
 
 export default {
   components: {
diff --git a/front/src/components/manage/moderation/ReportCard.vue b/front/src/components/manage/moderation/ReportCard.vue
index d2dd0a54cad2347bbbd639dec4943672b1a2ad72..d90bf4682430bd748cf5a065e3f6a386ff726344 100644
--- a/front/src/components/manage/moderation/ReportCard.vue
+++ b/front/src/components/manage/moderation/ReportCard.vue
@@ -390,10 +390,10 @@
 
 <script>
 import axios from 'axios'
-import NoteForm from '@/components/manage/moderation/NoteForm'
-import NotesThread from '@/components/manage/moderation/NotesThread'
-import ReportCategoryDropdown from '@/components/moderation/ReportCategoryDropdown'
-import InstancePolicyModal from '@/components/manage/moderation/InstancePolicyModal'
+import NoteForm from '@/components/manage/moderation/NoteForm.vue'
+import NotesThread from '@/components/manage/moderation/NotesThread.vue'
+import ReportCategoryDropdown from '@/components/moderation/ReportCategoryDropdown.vue'
+import InstancePolicyModal from '@/components/manage/moderation/InstancePolicyModal.vue'
 import entities from '@/entities'
 import { setUpdate } from '@/utils'
 import showdown from 'showdown'
diff --git a/front/src/components/manage/moderation/UserRequestCard.vue b/front/src/components/manage/moderation/UserRequestCard.vue
index 8cf93a53b6318cd5575939b4c181fdddeb47f5ce..8439d35547113760545d0faab177818e97c1f417 100644
--- a/front/src/components/manage/moderation/UserRequestCard.vue
+++ b/front/src/components/manage/moderation/UserRequestCard.vue
@@ -225,8 +225,8 @@
 
 <script>
 import axios from 'axios'
-import NoteForm from '@/components/manage/moderation/NoteForm'
-import NotesThread from '@/components/manage/moderation/NotesThread'
+import NoteForm from '@/components/manage/moderation/NoteForm.vue'
+import NotesThread from '@/components/manage/moderation/NotesThread.vue'
 import showdown from 'showdown'
 
 export default {
diff --git a/front/src/components/manage/users/InvitationsTable.vue b/front/src/components/manage/users/InvitationsTable.vue
index b3b64cabc732385b3af040452607214563be86b2..53992c898bc9f605903adb0d0279a0d3ad89a876 100644
--- a/front/src/components/manage/users/InvitationsTable.vue
+++ b/front/src/components/manage/users/InvitationsTable.vue
@@ -159,10 +159,10 @@
 import axios from 'axios'
 import moment from 'moment'
 import _ from '@/lodash'
-import Pagination from '@/components/Pagination'
-import ActionTable from '@/components/common/ActionTable'
-import OrderingMixin from '@/components/mixins/Ordering'
-import TranslationsMixin from '@/components/mixins/Translations'
+import Pagination from '@/components/Pagination.vue'
+import ActionTable from '@/components/common/ActionTable.vue'
+import OrderingMixin from '@/components/mixins/Ordering.vue'
+import TranslationsMixin from '@/components/mixins/Translations.vue'
 
 export default {
   components: {
diff --git a/front/src/components/manage/users/UsersTable.vue b/front/src/components/manage/users/UsersTable.vue
index 4d81684287145f3ff4d672a1b07be12cc14607c7..a638c3e336f9dd952560ab0691eddc56513bac5c 100644
--- a/front/src/components/manage/users/UsersTable.vue
+++ b/front/src/components/manage/users/UsersTable.vue
@@ -201,11 +201,11 @@
 <script>
 import axios from 'axios'
 import _ from '@/lodash'
-import time from '@/utils/time'
-import Pagination from '@/components/Pagination'
-import ActionTable from '@/components/common/ActionTable'
-import OrderingMixin from '@/components/mixins/Ordering'
-import TranslationsMixin from '@/components/mixins/Translations'
+import time from '@/utils/time.js'
+import Pagination from '@/components/Pagination.vue'
+import ActionTable from '@/components/common/ActionTable.vue'
+import OrderingMixin from '@/components/mixins/Ordering.vue'
+import TranslationsMixin from '@/components/mixins/Translations.vue'
 
 export default {
   components: {
diff --git a/front/src/components/moderation/ReportCategoryDropdown.vue b/front/src/components/moderation/ReportCategoryDropdown.vue
index c3fcc552c590ef68a50a8942a327193f9b5784ad..f9a5eceb3f36b162f9bd274ee6a7d3a6cbe06b79 100644
--- a/front/src/components/moderation/ReportCategoryDropdown.vue
+++ b/front/src/components/moderation/ReportCategoryDropdown.vue
@@ -25,7 +25,7 @@
 </template>
 
 <script>
-import TranslationsMixin from '@/components/mixins/Translations'
+import TranslationsMixin from '@/components/mixins/Translations.vue'
 import lodash from '@/lodash'
 export default {
   mixins: [TranslationsMixin],
diff --git a/front/src/components/playlists/Card.vue b/front/src/components/playlists/Card.vue
index d02aac56b75cb27fe95a15e2dc0925ce1d9862ec..0097948568a6a236edf757ad4b9380792da67475 100644
--- a/front/src/components/playlists/Card.vue
+++ b/front/src/components/playlists/Card.vue
@@ -55,7 +55,7 @@
 </template>
 
 <script>
-import PlayButton from '@/components/audio/PlayButton'
+import PlayButton from '@/components/audio/PlayButton.vue'
 
 export default {
   components: {
diff --git a/front/src/components/playlists/CardList.vue b/front/src/components/playlists/CardList.vue
index e3c17e6366f1950f5eadc5851c5d43437a25d654..f88cf5f74e96583e2629c014e27966823293ce78 100644
--- a/front/src/components/playlists/CardList.vue
+++ b/front/src/components/playlists/CardList.vue
@@ -12,7 +12,7 @@
 
 <script>
 
-import PlaylistCard from '@/components/playlists/Card'
+import PlaylistCard from '@/components/playlists/Card.vue'
 
 export default {
   components: {
diff --git a/front/src/components/playlists/Editor.vue b/front/src/components/playlists/Editor.vue
index 68ce6a10c996137b7fb867bb62e183f5481829ff..dc74406b7d25e13b267d8f61b19a2a35d3200495 100644
--- a/front/src/components/playlists/Editor.vue
+++ b/front/src/components/playlists/Editor.vue
@@ -176,7 +176,7 @@
 <script>
 import { mapState } from 'vuex'
 import axios from 'axios'
-import PlaylistForm from '@/components/playlists/Form'
+import PlaylistForm from '@/components/playlists/Form.vue'
 
 import draggable from 'vuedraggable'
 
diff --git a/front/src/components/playlists/Form.vue b/front/src/components/playlists/Form.vue
index 9d53013883d6210c70780e678a993d446999545e..1703bce91e9f6bcd1cd897572b463516166c3fda 100644
--- a/front/src/components/playlists/Form.vue
+++ b/front/src/components/playlists/Form.vue
@@ -100,7 +100,7 @@
 <script>
 import $ from 'jquery'
 import axios from 'axios'
-import TranslationsMixin from '@/components/mixins/Translations'
+import TranslationsMixin from '@/components/mixins/Translations.vue'
 
 import logger from '@/logging'
 
diff --git a/front/src/components/radios/Card.vue b/front/src/components/radios/Card.vue
index e280a91a947781a3f88f7436245660cc0450eea9..5ec3515455142eb9e14aaf9eb4c09a12d374d370 100644
--- a/front/src/components/radios/Card.vue
+++ b/front/src/components/radios/Card.vue
@@ -48,7 +48,7 @@
 </template>
 
 <script>
-import RadioButton from './Button'
+import RadioButton from './Button.vue'
 
 export default {
   components: {
diff --git a/front/src/views/Notifications.vue b/front/src/views/Notifications.vue
index 26bc12c3978cb90795b29ee0fd4810d00182e7e4..1555a5d243353b229db3be7c43ec8300b8baf0f1 100644
--- a/front/src/views/Notifications.vue
+++ b/front/src/views/Notifications.vue
@@ -217,7 +217,7 @@ import axios from 'axios'
 import showdown from 'showdown'
 import moment from 'moment'
 
-import NotificationRow from '@/components/notifications/NotificationRow'
+import NotificationRow from '@/components/notifications/NotificationRow.vue'
 
 export default {
   components: {
diff --git a/front/src/views/Search.vue b/front/src/views/Search.vue
index 5fb6820eda4eaf7cd996e892a1f87eb27104c0d0..3ac5152d2e926da168be10d0320e5219a563a76d 100644
--- a/front/src/views/Search.vue
+++ b/front/src/views/Search.vue
@@ -137,14 +137,14 @@
 </template>
 
 <script>
-import RemoteSearchForm from '@/components/RemoteSearchForm'
-import ArtistCard from '@/components/audio/artist/Card'
-import AlbumCard from '@/components/audio/album/Card'
-import TrackTable from '@/components/audio/track/Table'
-import Pagination from '@/components/Pagination'
-import PlaylistCardList from '@/components/playlists/CardList'
-import RadioCard from '@/components/radios/Card'
-import TagsList from '@/components/tags/List'
+import RemoteSearchForm from '@/components/RemoteSearchForm.vue'
+import ArtistCard from '@/components/audio/artist/Card.vue'
+import AlbumCard from '@/components/audio/album/Card.vue'
+import TrackTable from '@/components/audio/track/Table.vue'
+import Pagination from '@/components/Pagination.vue'
+import PlaylistCardList from '@/components/playlists/CardList.vue'
+import RadioCard from '@/components/radios/Card.vue'
+import TagsList from '@/components/tags/List.vue'
 
 import axios from 'axios'
 
diff --git a/front/src/views/admin/ChannelDetail.vue b/front/src/views/admin/ChannelDetail.vue
index 4f83947fe137f2b2c7f407d961d7f799fbad3685..da8f5d6fcbfad2faeb12c9629e5eda626c2261f5 100644
--- a/front/src/views/admin/ChannelDetail.vue
+++ b/front/src/views/admin/ChannelDetail.vue
@@ -416,8 +416,8 @@
 <script>
 import axios from 'axios'
 
-import TagsList from '@/components/tags/List'
-import FetchButton from '@/components/federation/FetchButton'
+import TagsList from '@/components/tags/List.vue'
+import FetchButton from '@/components/federation/FetchButton.vue'
 
 export default {
   components: {
diff --git a/front/src/views/admin/ChannelsList.vue b/front/src/views/admin/ChannelsList.vue
index 2a86598efd8c7092b75984de72e1f8d1d0c6d882..3ab794dd7a0b9992b0290d9823414b7b9b33869f 100644
--- a/front/src/views/admin/ChannelsList.vue
+++ b/front/src/views/admin/ChannelsList.vue
@@ -14,7 +14,7 @@
 </template>
 
 <script>
-import ChannelsTable from '@/components/manage/ChannelsTable'
+import ChannelsTable from '@/components/manage/ChannelsTable.vue'
 
 export default {
   components: {
diff --git a/front/src/views/admin/Settings.vue b/front/src/views/admin/Settings.vue
index ade695e93fb48264e277cca6ba5c56930804d27b..d1848c7a73d0a2daac863c9552aaea5b083c6dbf 100644
--- a/front/src/views/admin/Settings.vue
+++ b/front/src/views/admin/Settings.vue
@@ -45,7 +45,7 @@
 import axios from 'axios'
 import $ from 'jquery'
 
-import SettingsGroup from '@/components/admin/SettingsGroup'
+import SettingsGroup from '@/components/admin/SettingsGroup.vue'
 
 export default {
   components: {
diff --git a/front/src/views/admin/library/AlbumDetail.vue b/front/src/views/admin/library/AlbumDetail.vue
index 50cba8da70470033d7414ccb97cc693788bc33e9..cb4c68261dcd3a1846e62769c97eeaf29aa64b29 100644
--- a/front/src/views/admin/library/AlbumDetail.vue
+++ b/front/src/views/admin/library/AlbumDetail.vue
@@ -399,8 +399,8 @@
 
 <script>
 import axios from 'axios'
-import FetchButton from '@/components/federation/FetchButton'
-import TagsList from '@/components/tags/List'
+import FetchButton from '@/components/federation/FetchButton.vue'
+import TagsList from '@/components/tags/List.vue'
 
 export default {
   components: {
diff --git a/front/src/views/admin/library/AlbumsList.vue b/front/src/views/admin/library/AlbumsList.vue
index 419449959b4565f7304b4643c18a209fbcdb27ab..82ceca196b1be139ca68bfaa622c0d7b908802c1 100644
--- a/front/src/views/admin/library/AlbumsList.vue
+++ b/front/src/views/admin/library/AlbumsList.vue
@@ -14,7 +14,7 @@
 </template>
 
 <script>
-import AlbumsTable from '@/components/manage/library/AlbumsTable'
+import AlbumsTable from '@/components/manage/library/AlbumsTable.vue'
 
 export default {
   components: {
diff --git a/front/src/views/admin/library/ArtistDetail.vue b/front/src/views/admin/library/ArtistDetail.vue
index 8da0906cc007e4ddb35de875f7f74549000fd3a6..875082bbbe12841324b87f00998ebc2083eeecc6 100644
--- a/front/src/views/admin/library/ArtistDetail.vue
+++ b/front/src/views/admin/library/ArtistDetail.vue
@@ -411,8 +411,8 @@
 <script>
 import axios from 'axios'
 
-import TagsList from '@/components/tags/List'
-import FetchButton from '@/components/federation/FetchButton'
+import TagsList from '@/components/tags/List.vue'
+import FetchButton from '@/components/federation/FetchButton.vue'
 
 export default {
   components: {
diff --git a/front/src/views/admin/library/ArtistsList.vue b/front/src/views/admin/library/ArtistsList.vue
index 7e07353e018b66eada2caed031d6f736d20af003..fcbca0f977e128dd2036ac28ee40dc8d9f794321 100644
--- a/front/src/views/admin/library/ArtistsList.vue
+++ b/front/src/views/admin/library/ArtistsList.vue
@@ -14,7 +14,7 @@
 </template>
 
 <script>
-import ArtistsTable from '@/components/manage/library/ArtistsTable'
+import ArtistsTable from '@/components/manage/library/ArtistsTable.vue'
 
 export default {
   components: {
diff --git a/front/src/views/admin/library/EditsList.vue b/front/src/views/admin/library/EditsList.vue
index 2b67c69b6121f85c6b4fa716eceda6ae178beb34..9ce83dcd692801205893dba48bd42d6289710324 100644
--- a/front/src/views/admin/library/EditsList.vue
+++ b/front/src/views/admin/library/EditsList.vue
@@ -16,7 +16,7 @@
 </template>
 
 <script>
-import EditsCardList from '@/components/manage/library/EditsCardList'
+import EditsCardList from '@/components/manage/library/EditsCardList.vue'
 
 export default {
   components: {
diff --git a/front/src/views/admin/library/LibrariesList.vue b/front/src/views/admin/library/LibrariesList.vue
index 7e06cf21cdcef8df86720402d4d5be7c9fa3d296..7a9b03446822fd1f097da064ba18aed4b4dd23cc 100644
--- a/front/src/views/admin/library/LibrariesList.vue
+++ b/front/src/views/admin/library/LibrariesList.vue
@@ -14,7 +14,7 @@
 </template>
 
 <script>
-import LibrariesTable from '@/components/manage/library/LibrariesTable'
+import LibrariesTable from '@/components/manage/library/LibrariesTable.vue'
 
 export default {
   components: {
diff --git a/front/src/views/admin/library/LibraryDetail.vue b/front/src/views/admin/library/LibraryDetail.vue
index ee58f13fad7f4c90aac1176161d175ec8196e9ac..d7c56ab4a167bb4e628a866a7a2febe95db07eed 100644
--- a/front/src/views/admin/library/LibraryDetail.vue
+++ b/front/src/views/admin/library/LibraryDetail.vue
@@ -360,7 +360,7 @@
 <script>
 import axios from 'axios'
 import logger from '@/logging'
-import TranslationsMixin from '@/components/mixins/Translations'
+import TranslationsMixin from '@/components/mixins/Translations.vue'
 
 export default {
   mixins: [
diff --git a/front/src/views/admin/library/TagsList.vue b/front/src/views/admin/library/TagsList.vue
index 8f388cdf05c7e82b37386abdca0c3b0d3becf44f..5ca37165ae4aaf9fa0103974ef20b764c33b24c9 100644
--- a/front/src/views/admin/library/TagsList.vue
+++ b/front/src/views/admin/library/TagsList.vue
@@ -14,7 +14,7 @@
 </template>
 
 <script>
-import TagsTable from '@/components/manage/library/TagsTable'
+import TagsTable from '@/components/manage/library/TagsTable.vue'
 
 export default {
   components: {
diff --git a/front/src/views/admin/library/TrackDetail.vue b/front/src/views/admin/library/TrackDetail.vue
index 4a7789387bacae439059e1a2c826229734341db8..de8074cdf5c0eaba537055a121457f3c4e0efd85 100644
--- a/front/src/views/admin/library/TrackDetail.vue
+++ b/front/src/views/admin/library/TrackDetail.vue
@@ -452,8 +452,8 @@
 
 <script>
 import axios from 'axios'
-import FetchButton from '@/components/federation/FetchButton'
-import TagsList from '@/components/tags/List'
+import FetchButton from '@/components/federation/FetchButton.vue'
+import TagsList from '@/components/tags/List.vue'
 
 export default {
   components: {
diff --git a/front/src/views/admin/library/TracksList.vue b/front/src/views/admin/library/TracksList.vue
index 4588a4e5b976aa2e9c2c811f9d6d212046dec15e..e171e8b01fd7b318d3a7c254779891826d89ac42 100644
--- a/front/src/views/admin/library/TracksList.vue
+++ b/front/src/views/admin/library/TracksList.vue
@@ -14,7 +14,7 @@
 </template>
 
 <script>
-import TracksTable from '@/components/manage/library/TracksTable'
+import TracksTable from '@/components/manage/library/TracksTable.vue'
 
 export default {
   components: {
diff --git a/front/src/views/admin/library/UploadDetail.vue b/front/src/views/admin/library/UploadDetail.vue
index 3c701c32ab2ab19d8a455cc1559c470cc08b5a32..6c5e41ca49fa2c859e1caea5cf4ba5565f60188d 100644
--- a/front/src/views/admin/library/UploadDetail.vue
+++ b/front/src/views/admin/library/UploadDetail.vue
@@ -377,9 +377,9 @@
 
 <script>
 import axios from 'axios'
-import TranslationsMixin from '@/components/mixins/Translations'
-import ImportStatusModal from '@/components/library/ImportStatusModal'
-import time from '@/utils/time'
+import TranslationsMixin from '@/components/mixins/Translations.vue'
+import ImportStatusModal from '@/components/library/ImportStatusModal.vue'
+import time from '@/utils/time.js'
 
 export default {
   components: {
diff --git a/front/src/views/admin/library/UploadsList.vue b/front/src/views/admin/library/UploadsList.vue
index 2e2a5d77812b86852b2b35843800ce084bb993a7..247e9fd4e78d31aaea02bfd03a86d403b2a90428 100644
--- a/front/src/views/admin/library/UploadsList.vue
+++ b/front/src/views/admin/library/UploadsList.vue
@@ -14,7 +14,7 @@
 </template>
 
 <script>
-import UploadsTable from '@/components/manage/library/UploadsTable'
+import UploadsTable from '@/components/manage/library/UploadsTable.vue'
 
 export default {
   components: {
diff --git a/front/src/views/admin/moderation/AccountsDetail.vue b/front/src/views/admin/moderation/AccountsDetail.vue
index 03d6d8ec0465923538aae0ff95a1a3f0cf617694..7e2b7f28a8b328f9939e676f2c34fab9d6c0deb3 100644
--- a/front/src/views/admin/moderation/AccountsDetail.vue
+++ b/front/src/views/admin/moderation/AccountsDetail.vue
@@ -571,8 +571,8 @@ import logger from '@/logging'
 import lodash from '@/lodash'
 import $ from 'jquery'
 
-import InstancePolicyForm from '@/components/manage/moderation/InstancePolicyForm'
-import InstancePolicyCard from '@/components/manage/moderation/InstancePolicyCard'
+import InstancePolicyForm from '@/components/manage/moderation/InstancePolicyForm.vue'
+import InstancePolicyCard from '@/components/manage/moderation/InstancePolicyCard.vue'
 
 export default {
   components: {
diff --git a/front/src/views/admin/moderation/AccountsList.vue b/front/src/views/admin/moderation/AccountsList.vue
index 559694464534154abe4092ec99286a54e583770a..fa53798915b3616e87d4bf6e96ebecf23059d930 100644
--- a/front/src/views/admin/moderation/AccountsList.vue
+++ b/front/src/views/admin/moderation/AccountsList.vue
@@ -16,7 +16,7 @@
 </template>
 
 <script>
-import AccountsTable from '@/components/manage/moderation/AccountsTable'
+import AccountsTable from '@/components/manage/moderation/AccountsTable.vue'
 
 export default {
   components: {
diff --git a/front/src/views/admin/moderation/DomainsDetail.vue b/front/src/views/admin/moderation/DomainsDetail.vue
index 17293512d3c9536b75f6aff8add005815547e4d4..1802149e0fa6a7cfc7219b8c903b1a08ab9ef407 100644
--- a/front/src/views/admin/moderation/DomainsDetail.vue
+++ b/front/src/views/admin/moderation/DomainsDetail.vue
@@ -460,8 +460,8 @@
 import axios from 'axios'
 import lodash from '@/lodash'
 
-import InstancePolicyForm from '@/components/manage/moderation/InstancePolicyForm'
-import InstancePolicyCard from '@/components/manage/moderation/InstancePolicyCard'
+import InstancePolicyForm from '@/components/manage/moderation/InstancePolicyForm.vue'
+import InstancePolicyCard from '@/components/manage/moderation/InstancePolicyCard.vue'
 
 export default {
   components: {
diff --git a/front/src/views/admin/moderation/DomainsList.vue b/front/src/views/admin/moderation/DomainsList.vue
index 0182961e9a70793be36677bd7461757c631f4511..3095817a25623ad2b19abf17322cea75215297bd 100644
--- a/front/src/views/admin/moderation/DomainsList.vue
+++ b/front/src/views/admin/moderation/DomainsList.vue
@@ -73,7 +73,7 @@
 <script>
 import axios from 'axios'
 
-import DomainsTable from '@/components/manage/moderation/DomainsTable'
+import DomainsTable from '@/components/manage/moderation/DomainsTable.vue'
 export default {
   components: {
     DomainsTable
diff --git a/front/src/views/admin/moderation/ReportDetail.vue b/front/src/views/admin/moderation/ReportDetail.vue
index 37bdbbac7a7c5008a1c1f031f80e52913bed8b85..b59192d75bd00e7037e8f4c3ffa2644bf2bccb64 100644
--- a/front/src/views/admin/moderation/ReportDetail.vue
+++ b/front/src/views/admin/moderation/ReportDetail.vue
@@ -17,7 +17,7 @@
 <script>
 import axios from 'axios'
 
-import ReportCard from '@/components/manage/moderation/ReportCard'
+import ReportCard from '@/components/manage/moderation/ReportCard.vue'
 
 export default {
   components: {
diff --git a/front/src/views/admin/moderation/ReportsList.vue b/front/src/views/admin/moderation/ReportsList.vue
index bf9bdca45e2d82527cfc83e3bbee8fb094f963f3..05721de74d76bfee92ef4f0de8e1a4f6f586cc33 100644
--- a/front/src/views/admin/moderation/ReportsList.vue
+++ b/front/src/views/admin/moderation/ReportsList.vue
@@ -128,14 +128,14 @@
 
 import axios from 'axios'
 import _ from '@/lodash'
-import time from '@/utils/time'
-import Pagination from '@/components/Pagination'
-import OrderingMixin from '@/components/mixins/Ordering'
-import TranslationsMixin from '@/components/mixins/Translations'
-import ReportCard from '@/components/manage/moderation/ReportCard'
-import ReportCategoryDropdown from '@/components/moderation/ReportCategoryDropdown'
+import time from '@/utils/time.js'
+import Pagination from '@/components/Pagination.vue'
+import OrderingMixin from '@/components/mixins/Ordering.vue'
+import TranslationsMixin from '@/components/mixins/Translations.vue'
+import ReportCard from '@/components/manage/moderation/ReportCard.vue'
+import ReportCategoryDropdown from '@/components/moderation/ReportCategoryDropdown.vue'
 import { normalizeQuery, parseTokens } from '@/search'
-import SmartSearchMixin from '@/components/mixins/SmartSearch'
+import SmartSearchMixin from '@/components/mixins/SmartSearch.vue'
 
 export default {
   components: {
diff --git a/front/src/views/admin/moderation/RequestDetail.vue b/front/src/views/admin/moderation/RequestDetail.vue
index ca089ad8f0d0f240fd80a88d036e6dd92589e878..e25fb8360b106c24e39b3bf7c27823b1ff96e1e5 100644
--- a/front/src/views/admin/moderation/RequestDetail.vue
+++ b/front/src/views/admin/moderation/RequestDetail.vue
@@ -17,7 +17,7 @@
 <script>
 import axios from 'axios'
 
-import UserRequestCard from '@/components/manage/moderation/UserRequestCard'
+import UserRequestCard from '@/components/manage/moderation/UserRequestCard.vue'
 
 export default {
   components: {
diff --git a/front/src/views/admin/moderation/RequestsList.vue b/front/src/views/admin/moderation/RequestsList.vue
index 0e88c2c1affcd63438b4e2c5572ed714d43471fc..8fa8057b1264b393068992b9bd5cb9be9cc6491e 100644
--- a/front/src/views/admin/moderation/RequestsList.vue
+++ b/front/src/views/admin/moderation/RequestsList.vue
@@ -126,13 +126,13 @@
 
 import axios from 'axios'
 import _ from '@/lodash'
-import time from '@/utils/time'
-import Pagination from '@/components/Pagination'
-import OrderingMixin from '@/components/mixins/Ordering'
-import TranslationsMixin from '@/components/mixins/Translations'
-import UserRequestCard from '@/components/manage/moderation/UserRequestCard'
+import time from '@/utils/time.js'
+import Pagination from '@/components/Pagination.vue'
+import OrderingMixin from '@/components/mixins/Ordering.vue'
+import TranslationsMixin from '@/components/mixins/Translations.vue'
+import UserRequestCard from '@/components/manage/moderation/UserRequestCard.vue'
 import { normalizeQuery, parseTokens } from '@/search'
-import SmartSearchMixin from '@/components/mixins/SmartSearch'
+import SmartSearchMixin from '@/components/mixins/SmartSearch.vue'
 
 export default {
   components: {
diff --git a/front/src/views/admin/users/InvitationsList.vue b/front/src/views/admin/users/InvitationsList.vue
index d95b387da405c3255ada08a1a58ae5ec766c0ebc..dd4cb4d63cf12dd051636394212b9774f4a27e92 100644
--- a/front/src/views/admin/users/InvitationsList.vue
+++ b/front/src/views/admin/users/InvitationsList.vue
@@ -12,8 +12,8 @@
 </template>
 
 <script>
-import InvitationForm from '@/components/manage/users/InvitationForm'
-import InvitationsTable from '@/components/manage/users/InvitationsTable'
+import InvitationForm from '@/components/manage/users/InvitationForm.vue'
+import InvitationsTable from '@/components/manage/users/InvitationsTable.vue'
 
 export default {
   components: {
diff --git a/front/src/views/admin/users/UsersList.vue b/front/src/views/admin/users/UsersList.vue
index 29141850f1a782589919f93af3e92ce1ca276f95..42efc38fb419085100d71e14e5f7b4f8b9417a72 100644
--- a/front/src/views/admin/users/UsersList.vue
+++ b/front/src/views/admin/users/UsersList.vue
@@ -11,7 +11,7 @@
 </template>
 
 <script>
-import UsersTable from '@/components/manage/users/UsersTable'
+import UsersTable from '@/components/manage/users/UsersTable.vue'
 
 export default {
   components: {
diff --git a/front/src/views/auth/PasswordResetConfirm.vue b/front/src/views/auth/PasswordResetConfirm.vue
index 3653135a0b3edd2d6878c331850600af43124d43..bbc01870f52daad943b8d20bd93c278a3e318474 100644
--- a/front/src/views/auth/PasswordResetConfirm.vue
+++ b/front/src/views/auth/PasswordResetConfirm.vue
@@ -87,7 +87,7 @@
 
 <script>
 import axios from 'axios'
-import PasswordInput from '@/components/forms/PasswordInput'
+import PasswordInput from '@/components/forms/PasswordInput.vue'
 
 export default {
   components: {
diff --git a/front/src/views/auth/Plugins.vue b/front/src/views/auth/Plugins.vue
index 6e6400ffd0a8142b6efc0932847c1ff9b1e8d0a0..501a0377da427098d7d2f4a25869aaa4d4218638 100644
--- a/front/src/views/auth/Plugins.vue
+++ b/front/src/views/auth/Plugins.vue
@@ -29,7 +29,7 @@
 
 <script>
 import axios from 'axios'
-import PluginForm from '@/components/auth/Plugin'
+import PluginForm from '@/components/auth/Plugin.vue'
 
 export default {
   components: {
diff --git a/front/src/views/auth/ProfileActivity.vue b/front/src/views/auth/ProfileActivity.vue
index 433bd657058ad46c6c840ac9892ef3ecd56bb26e..ca7f8dc64cb9578c3e29d195455abaac326557cc 100644
--- a/front/src/views/auth/ProfileActivity.vue
+++ b/front/src/views/auth/ProfileActivity.vue
@@ -50,9 +50,9 @@
 </template>
 
 <script>
-import TrackWidget from '@/components/audio/track/Widget'
-import PlaylistWidget from '@/components/playlists/Widget'
-import RadioButton from '@/components/radios/Button'
+import TrackWidget from '@/components/audio/track/Widget.vue'
+import PlaylistWidget from '@/components/playlists/Widget.vue'
+import RadioButton from '@/components/radios/Button.vue'
 
 export default {
   components: { TrackWidget, PlaylistWidget, RadioButton },
diff --git a/front/src/views/auth/ProfileBase.vue b/front/src/views/auth/ProfileBase.vue
index bf525640c2faaadfdf910d181954c3570c9c64f7..7650f8ab5a1805722ce6e4f54727524c44d9567e 100644
--- a/front/src/views/auth/ProfileBase.vue
+++ b/front/src/views/auth/ProfileBase.vue
@@ -139,7 +139,7 @@
 <script>
 import axios from 'axios'
 
-import ReportMixin from '@/components/mixins/Report'
+import ReportMixin from '@/components/mixins/Report.vue'
 
 export default {
   mixins: [ReportMixin],
diff --git a/front/src/views/auth/ProfileOverview.vue b/front/src/views/auth/ProfileOverview.vue
index 43c1428f2e9cd1974409bb0c992e784b15e1a444..d71f45cecb5c392434ad2d0fdf96aca304516b9a 100644
--- a/front/src/views/auth/ProfileOverview.vue
+++ b/front/src/views/auth/ProfileOverview.vue
@@ -139,10 +139,10 @@
 </template>
 
 <script>
-import Modal from '@/components/semantic/Modal'
-import LibraryWidget from '@/components/federation/LibraryWidget'
-import ChannelsWidget from '@/components/audio/ChannelsWidget'
-import ChannelForm from '@/components/audio/ChannelForm'
+import Modal from '@/components/semantic/Modal.vue'
+import LibraryWidget from '@/components/federation/LibraryWidget.vue'
+import ChannelsWidget from '@/components/audio/ChannelsWidget.vue'
+import ChannelForm from '@/components/audio/ChannelForm.vue'
 
 export default {
   components: { ChannelsWidget, LibraryWidget, ChannelForm, Modal },
diff --git a/front/src/views/auth/Signup.vue b/front/src/views/auth/Signup.vue
index 605658727fd7415d3ef687020263103227fd8279..7a4353b7373d325e6f5ef94483cccc5b3db56931 100644
--- a/front/src/views/auth/Signup.vue
+++ b/front/src/views/auth/Signup.vue
@@ -21,7 +21,7 @@
 
 <script>
 
-import SignupForm from '@/components/auth/SignupForm'
+import SignupForm from '@/components/auth/SignupForm.vue'
 
 export default {
   components: {
diff --git a/front/src/views/channels/DetailBase.vue b/front/src/views/channels/DetailBase.vue
index 5e53474ed15621c6197871d9fb926bd8f53bf5fd..d2e70d5689af734233c9cd92982a6e642537875e 100644
--- a/front/src/views/channels/DetailBase.vue
+++ b/front/src/views/channels/DetailBase.vue
@@ -436,14 +436,14 @@
 
 <script>
 import axios from 'axios'
-import PlayButton from '@/components/audio/PlayButton'
-import EmbedWizard from '@/components/audio/EmbedWizard'
-import Modal from '@/components/semantic/Modal'
-import TagsList from '@/components/tags/List'
-import ReportMixin from '@/components/mixins/Report'
+import PlayButton from '@/components/audio/PlayButton.vue'
+import EmbedWizard from '@/components/audio/EmbedWizard.vue'
+import Modal from '@/components/semantic/Modal.vue'
+import TagsList from '@/components/tags/List.vue'
+import ReportMixin from '@/components/mixins/Report.vue'
 
-import SubscribeButton from '@/components/channels/SubscribeButton'
-import ChannelForm from '@/components/audio/ChannelForm'
+import SubscribeButton from '@/components/channels/SubscribeButton.vue'
+import ChannelForm from '@/components/audio/ChannelForm.vue'
 
 export default {
   components: {
diff --git a/front/src/views/channels/DetailEpisodes.vue b/front/src/views/channels/DetailEpisodes.vue
index 6d01f8736e055de2d8a87eace074f74d52a00004..6aafda2fcebd921ee2b2c2a3b3a63b874dad07f5 100644
--- a/front/src/views/channels/DetailEpisodes.vue
+++ b/front/src/views/channels/DetailEpisodes.vue
@@ -10,7 +10,7 @@
 </template>
 
 <script>
-import ChannelEntries from '@/components/audio/ChannelEntries'
+import ChannelEntries from '@/components/audio/ChannelEntries.vue'
 
 export default {
   components: {
diff --git a/front/src/views/channels/DetailOverview.vue b/front/src/views/channels/DetailOverview.vue
index cca63ded17f3e38d40ef0b939a9dc3e8cfb216f6..6e12a74cb9f26e6f06f1f1c1f8f32ee6824d7137 100644
--- a/front/src/views/channels/DetailOverview.vue
+++ b/front/src/views/channels/DetailOverview.vue
@@ -143,9 +143,9 @@
 import axios from 'axios'
 import qs from 'qs'
 
-import ChannelEntries from '@/components/audio/ChannelEntries'
-import ChannelSeries from '@/components/audio/ChannelSeries'
-import AlbumModal from '@/components/channels/AlbumModal'
+import ChannelEntries from '@/components/audio/ChannelEntries.vue'
+import ChannelSeries from '@/components/audio/ChannelSeries.vue'
+import AlbumModal from '@/components/channels/AlbumModal.vue'
 
 export default {
   components: {
diff --git a/front/src/views/channels/SubscriptionsList.vue b/front/src/views/channels/SubscriptionsList.vue
index 30fff8f273a45db93cb19a91fcf475a895bc4ac0..c2f86df32fdad639a89eba5eedc619a9e132bd3c 100644
--- a/front/src/views/channels/SubscriptionsList.vue
+++ b/front/src/views/channels/SubscriptionsList.vue
@@ -71,10 +71,10 @@
 
 <script>
 import axios from 'axios'
-import Modal from '@/components/semantic/Modal'
+import Modal from '@/components/semantic/Modal.vue'
 
-import ChannelsWidget from '@/components/audio/ChannelsWidget'
-import RemoteSearchForm from '@/components/RemoteSearchForm'
+import ChannelsWidget from '@/components/audio/ChannelsWidget.vue'
+import RemoteSearchForm from '@/components/RemoteSearchForm.vue'
 
 export default {
   components: {
diff --git a/front/src/views/content/libraries/Card.vue b/front/src/views/content/libraries/Card.vue
index d7cb065d69672dfc2c12b5a3ccccd3b65169f0d0..837d0889c2e5547d1a2b1a6f49d6c0b6010e6b0c 100644
--- a/front/src/views/content/libraries/Card.vue
+++ b/front/src/views/content/libraries/Card.vue
@@ -78,7 +78,7 @@
 </template>
 
 <script>
-import TranslationsMixin from '@/components/mixins/Translations'
+import TranslationsMixin from '@/components/mixins/Translations.vue'
 
 export default {
   mixins: [TranslationsMixin],
diff --git a/front/src/views/content/libraries/FilesTable.vue b/front/src/views/content/libraries/FilesTable.vue
index e38e61344b02a5c0dab0827b4cdd17ea822c8072..4d1091cc6b6b7daee15caa603b8a719f8c66b0ac 100644
--- a/front/src/views/content/libraries/FilesTable.vue
+++ b/front/src/views/content/libraries/FilesTable.vue
@@ -268,15 +268,15 @@
 <script>
 import axios from 'axios'
 import _ from '@/lodash'
-import time from '@/utils/time'
+import time from '@/utils/time.js'
 import { normalizeQuery, parseTokens } from '@/search'
 
-import Pagination from '@/components/Pagination'
-import ActionTable from '@/components/common/ActionTable'
-import OrderingMixin from '@/components/mixins/Ordering'
-import TranslationsMixin from '@/components/mixins/Translations'
-import SmartSearchMixin from '@/components/mixins/SmartSearch'
-import ImportStatusModal from '@/components/library/ImportStatusModal'
+import Pagination from '@/components/Pagination.vue'
+import ActionTable from '@/components/common/ActionTable.vue'
+import OrderingMixin from '@/components/mixins/Ordering.vue'
+import TranslationsMixin from '@/components/mixins/Translations.vue'
+import SmartSearchMixin from '@/components/mixins/SmartSearch.vue'
+import ImportStatusModal from '@/components/library/ImportStatusModal.vue'
 
 export default {
   components: {
diff --git a/front/src/views/content/remote/Card.vue b/front/src/views/content/remote/Card.vue
index 813ed48c0d3fecc97e806c02abbfb8c9837e104b..ca890ba5f29d855d4ae8cf74b3074323411f36ab 100644
--- a/front/src/views/content/remote/Card.vue
+++ b/front/src/views/content/remote/Card.vue
@@ -224,8 +224,8 @@
 </template>
 <script>
 import axios from 'axios'
-import ReportMixin from '@/components/mixins/Report'
-import RadioButton from '@/components/radios/Button'
+import ReportMixin from '@/components/mixins/Report.vue'
+import RadioButton from '@/components/radios/Button.vue'
 
 export default {
   components: {
diff --git a/front/src/views/library/DetailAlbums.vue b/front/src/views/library/DetailAlbums.vue
index dcac36832e16fc093ef3804582328e0735be0f75..ac0e2f06b3930fad9217a4b51cc06b6fc4e5878e 100644
--- a/front/src/views/library/DetailAlbums.vue
+++ b/front/src/views/library/DetailAlbums.vue
@@ -30,7 +30,7 @@
 </template>
 
 <script>
-import AlbumWidget from '@/components/audio/album/Widget'
+import AlbumWidget from '@/components/audio/album/Widget.vue'
 
 export default {
   components: {
diff --git a/front/src/views/library/DetailBase.vue b/front/src/views/library/DetailBase.vue
index 88b5cbc3bed8abfcb03c3681ef7d507323f43285..e0068f8e273e06ce09e21b9c12b6ee61b426578c 100644
--- a/front/src/views/library/DetailBase.vue
+++ b/front/src/views/library/DetailBase.vue
@@ -227,9 +227,9 @@
 
 <script>
 import axios from 'axios'
-import LibraryFollowButton from '@/components/audio/LibraryFollowButton'
-import ReportMixin from '@/components/mixins/Report'
-import RadioButton from '@/components/radios/Button'
+import LibraryFollowButton from '@/components/audio/LibraryFollowButton.vue'
+import ReportMixin from '@/components/mixins/Report.vue'
+import RadioButton from '@/components/radios/Button.vue'
 
 export default {
   components: {
diff --git a/front/src/views/library/DetailOverview.vue b/front/src/views/library/DetailOverview.vue
index d66984814406f5a057b09b1a12daf94aac772d22..5743515891ceab1341a5fec22dfecba7fb266687 100644
--- a/front/src/views/library/DetailOverview.vue
+++ b/front/src/views/library/DetailOverview.vue
@@ -39,7 +39,7 @@
 </template>
 
 <script>
-import ArtistWidget from '@/components/audio/artist/Widget'
+import ArtistWidget from '@/components/audio/artist/Widget.vue'
 
 export default {
   components: {
diff --git a/front/src/views/library/DetailTracks.vue b/front/src/views/library/DetailTracks.vue
index 45f55addd5a37ce000073380242ba6fbac25514d..4271019a510ae3dbc55313cb1f4ca1addca208cc 100644
--- a/front/src/views/library/DetailTracks.vue
+++ b/front/src/views/library/DetailTracks.vue
@@ -29,7 +29,7 @@
 </template>
 
 <script>
-import TrackTable from '@/components/audio/track/Table'
+import TrackTable from '@/components/audio/track/Table.vue'
 
 export default {
   components: {
diff --git a/front/src/views/library/Edit.vue b/front/src/views/library/Edit.vue
index 00ba50c71e7cefddc1bf1bd6991a8ba27c6cc1b0..55d1bf2c349a8f2a74708f7924c6ce206c7bb0ab 100644
--- a/front/src/views/library/Edit.vue
+++ b/front/src/views/library/Edit.vue
@@ -114,8 +114,8 @@
 </template>
 
 <script>
-import LibraryFilesTable from '@/views/content/libraries/FilesTable'
-import LibraryForm from '@/views/content/libraries/Form'
+import LibraryFilesTable from '@/views/content/libraries/FilesTable.vue'
+import LibraryForm from '@/views/content/libraries/Form.vue'
 import axios from 'axios'
 
 export default {
diff --git a/front/src/views/library/Upload.vue b/front/src/views/library/Upload.vue
index 48dda7e29132abc3c9fb5772e47be6c34d8559a0..08813503a133364268b312b9729bb1f4c1cc647a 100644
--- a/front/src/views/library/Upload.vue
+++ b/front/src/views/library/Upload.vue
@@ -11,7 +11,7 @@
 
 <script>
 
-import FileUpload from '@/components/library/FileUpload'
+import FileUpload from '@/components/library/FileUpload.vue'
 
 export default {
   components: {
diff --git a/front/src/views/playlists/Detail.vue b/front/src/views/playlists/Detail.vue
index 8cc6fa6d20fcad8741d73a2fa4c0d823b3538e8d..b1ac1223843891d5ea971dd8532c37472956937b 100644
--- a/front/src/views/playlists/Detail.vue
+++ b/front/src/views/playlists/Detail.vue
@@ -174,11 +174,11 @@
 </template>
 <script>
 import axios from 'axios'
-import TrackTable from '@/components/audio/track/Table'
-import PlayButton from '@/components/audio/PlayButton'
-import PlaylistEditor from '@/components/playlists/Editor'
-import EmbedWizard from '@/components/audio/EmbedWizard'
-import Modal from '@/components/semantic/Modal'
+import TrackTable from '@/components/audio/track/Table.vue'
+import PlayButton from '@/components/audio/PlayButton.vue'
+import PlaylistEditor from '@/components/playlists/Editor.vue'
+import EmbedWizard from '@/components/audio/EmbedWizard.vue'
+import Modal from '@/components/semantic/Modal.vue'
 
 export default {
   components: {
diff --git a/front/src/views/playlists/List.vue b/front/src/views/playlists/List.vue
index 4ad0cdb1260c885887c498adad67e864b7b33f42..177775e3213d077123630aedb0efff768d02fd02 100644
--- a/front/src/views/playlists/List.vue
+++ b/front/src/views/playlists/List.vue
@@ -140,11 +140,11 @@
 import axios from 'axios'
 import $ from 'jquery'
 
-import OrderingMixin from '@/components/mixins/Ordering'
-import PaginationMixin from '@/components/mixins/Pagination'
-import TranslationsMixin from '@/components/mixins/Translations'
-import PlaylistCardList from '@/components/playlists/CardList'
-import Pagination from '@/components/Pagination'
+import OrderingMixin from '@/components/mixins/Ordering.vue'
+import PaginationMixin from '@/components/mixins/Pagination.vue'
+import TranslationsMixin from '@/components/mixins/Translations.vue'
+import PlaylistCardList from '@/components/playlists/CardList.vue'
+import Pagination from '@/components/Pagination.vue'
 
 const FETCH_URL = 'playlists/'
 
diff --git a/front/src/views/radios/Detail.vue b/front/src/views/radios/Detail.vue
index 7c72ff87b233765a4c859e7f58245be88adb7c91..0fb038512f389e70c2664cce1650cf3a8bd94041 100644
--- a/front/src/views/radios/Detail.vue
+++ b/front/src/views/radios/Detail.vue
@@ -111,9 +111,9 @@
 
 <script>
 import axios from 'axios'
-import TrackTable from '@/components/audio/track/Table'
-import RadioButton from '@/components/radios/Button'
-import Pagination from '@/components/Pagination'
+import TrackTable from '@/components/audio/track/Table.vue'
+import RadioButton from '@/components/radios/Button.vue'
+import Pagination from '@/components/Pagination.vue'
 
 export default {
   components: {