Verified Commit e9c4bfe9 authored by Georg Krause's avatar Georg Krause
Browse files

Start migration to vite

parent 593cff43
......@@ -14,7 +14,6 @@ module.exports = {
parserOptions: {
ecmaVersion: 2018,
sourceType: 'module',
parser: '@babel/eslint-parser'
},
plugins: [
'vue'
......
......@@ -6,8 +6,9 @@
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<meta name="generator" content="Funkwhale">
<link rel="icon" href="<%= BASE_URL %>favicon.png">
<link rel="icon" href="/favicon.png">
<title>Funkwhale</title>
<script type="module" src="/src/main.js"></script>
<style>
#fake-app {
width: 100vw;
......
......@@ -5,8 +5,9 @@
"description": "Funkwhale front-end",
"author": "Funkwhale Collective <contact@funkwhale.audio>",
"scripts": {
"serve": "[ ! -d src/translations ] && npm run i18n-compile; vue-cli-service serve --port ${VUE_PORT:-8080} --host ${VUE_HOST:-0.0.0.0}",
"build": "scripts/i18n-compile.sh && vue-cli-service build",
"dev": "vite",
"build": "vite build",
"serve": "vite preview",
"test:unit": "vue-cli-service test:unit --reporter mocha-junit-reporter",
"lint": "eslint --ext .js,.vue src",
"fix-fomantic-css": "scripts/fix-fomantic-css.sh",
......@@ -17,7 +18,6 @@
"dependencies": {
"axios": "0.26.0",
"axios-auth-refresh": "2.2.8",
"core-js": "3.21.1",
"diff": "5.0.0",
"django-channels": "2.1.3",
"focus-trap": "6.7.3",
......@@ -44,12 +44,9 @@
"vuex-router-sync": "5.0.0"
},
"devDependencies": {
"@babel/eslint-parser": "7.17.0",
"@vue/cli-plugin-babel": "~5.0.1",
"@vue/cli-plugin-pwa": "~5.0.1",
"@vue/cli-plugin-unit-mocha": "~5.0.1",
"@vue/cli-service": "~5.0.1",
"@vitejs/plugin-vue": "^2.2.2",
"@vue/test-utils": "1.3.0",
"autoprefixer": "^10.4.2",
"chai": "4.3.6",
"easygettext": "2.17.0",
"eslint": "8.9.0",
......@@ -63,12 +60,10 @@
"mocha": "9.2.1",
"mocha-junit-reporter": "2.0.2",
"moxios": "0.4.0",
"preload-webpack-plugin": "3.0.0-beta.4",
"purgecss-webpack-plugin": "4.1.3",
"sass-loader": "10.2.1",
"sinon": "13.0.1",
"vue-template-compiler": "2.6.14",
"webpack-bundle-size-analyzer": "3.1.0"
"vite": "^2.8.4",
"vite-plugin-vue2": "^1.9.3",
"vue-template-compiler": "^2.6.14"
},
"eslintConfig": {
"root": true,
......
......@@ -2,7 +2,8 @@
<div
id="app"
:key="String($store.state.instance.instanceUrl)"
:class="[$store.state.ui.queueFocused ? 'queue-focused' : '', {'has-bottom-player': $store.state.queue.tracks.length > 0}, `is-${ $store.getters['ui/windowSize']}`]"
:class="[$store.state.ui.queueFocused ? 'queue-focused' : '',
{'has-bottom-player': $store.state.queue.tracks.length > 0}]"
>
<!-- here, we display custom stylesheets, if any -->
<link
......@@ -51,23 +52,23 @@ import axios from 'axios'
import _ from '@/lodash'
import { mapState, mapGetters } from 'vuex'
import { WebSocketBridge } from 'django-channels'
import GlobalEvents from '@/components/utils/global-events'
import GlobalEvents from '@/components/utils/global-events.vue'
import locales from './locales'
import { getClientOnlyRadio } from '@/radios'
export default {
name: 'App',
components: {
Player: () => import(/* webpackChunkName: "audio" */ '@/components/audio/Player'),
Queue: () => import(/* webpackChunkName: "audio" */ '@/components/Queue'),
PlaylistModal: () => import(/* webpackChunkName: "auth-audio" */ '@/components/playlists/PlaylistModal'),
ChannelUploadModal: () => import(/* webpackChunkName: "auth-audio" */ '@/components/channels/UploadModal'),
Sidebar: () => import(/* webpackChunkName: "core" */ '@/components/Sidebar'),
ServiceMessages: () => import(/* webpackChunkName: "core" */ '@/components/ServiceMessages'),
SetInstanceModal: () => import(/* webpackChunkName: "core" */ '@/components/SetInstanceModal'),
ShortcutsModal: () => import(/* webpackChunkName: "core" */ '@/components/ShortcutsModal'),
FilterModal: () => import(/* webpackChunkName: "moderation" */ '@/components/moderation/FilterModal'),
ReportModal: () => import(/* webpackChunkName: "moderation" */ '@/components/moderation/ReportModal'),
Player: () => import('@/components/audio/Player.vue'),
Queue: () => import('@/components/Queue.vue'),
PlaylistModal: () => import('@/components/playlists/PlaylistModal.vue'),
ChannelUploadModal: () => import('@/components/channels/UploadModal.vue'),
Sidebar: () => import('@/components/Sidebar.vue'),
ServiceMessages: () => import('@/components/ServiceMessages.vue'),
SetInstanceModal: () => import('@/components/SetInstanceModal.vue'),
ShortcutsModal: () => import('@/components/ShortcutsModal.vue'),
FilterModal: () => import('@/components/moderation/FilterModal.vue'),
ReportModal: () => import('@/components/moderation/ReportModal.vue'),
GlobalEvents
},
data () {
......@@ -179,7 +180,7 @@ export default {
self.$language.current = newValue
return self.$store.commit('ui/momentLocale', 'en')
}
import(/* webpackChunkName: "locale-[request]" */ `./translations/${newValue}.json`).then((response) => {
import('./translations/en_GB.json').then((response) => {
Vue.$translations[newValue] = response.default[newValue]
}).finally(() => {
// set current language twice, otherwise we seem to have a cache somewhere
......@@ -188,12 +189,12 @@ export default {
self.$language.current = newValue
})
const momentLocale = newValue.replace('_', '-').toLowerCase()
import(/* webpackChunkName: "moment-locale-[request]" */ `moment/locale/${momentLocale}.js`).then(() => {
import('moment/locale/en-gb.js').then(() => {
self.$store.commit('ui/momentLocale', momentLocale)
}).catch(() => {
console.log('No momentjs locale available for', momentLocale)
const shortLocale = momentLocale.split('-')[0]
import(/* webpackChunkName: "moment-locale-[request]" */ `moment/locale/${shortLocale}.js`).then(() => {
import('moment/locale/en-gb.js').then(() => {
self.$store.commit('ui/momentLocale', shortLocale)
}).catch(() => {
console.log('No momentjs locale available for', shortLocale)
......@@ -279,7 +280,9 @@ export default {
// 1. use the url provided in settings.json, if any
// 2. use the url specified when building via VUE_APP_INSTANCE_URL
// 3. use the current url
const defaultInstanceUrl = this.$store.state.instance.frontSettings.defaultServerUrl || process.env.VUE_APP_INSTANCE_URL || this.$store.getters['instance/defaultUrl']()
const defaultInstanceUrl =
this.$store.state.instance.frontSettings.defaultServerUrl ||
import.meta.env.VUE_APP_INSTANCE_URL || this.$store.getters['instance/defaultUrl']()
this.$store.commit('instance/instanceUrl', defaultInstanceUrl)
} else {
// needed to trigger initialization of axios / service worker
......@@ -423,7 +426,8 @@ export default {
// let token = 'test'
const bridge = new WebSocketBridge()
this.bridge = bridge
let url = this.$store.getters['instance/absoluteUrl'](`api/v1/activity?token=${token}`)
let url =
this.$store.getters['instance/absoluteUrl']('api/v1/activity?token=${token}')
url = url.replace('http://', 'ws://')
url = url.replace('https://', 'wss://')
bridge.connect(
......@@ -442,7 +446,7 @@ export default {
const albumArtist = (track.album) ? track.album.artist.name : null
const artistName = (
(track.artist) ? track.artist.name : albumArtist)
const text = `${trackTitle}${artistName}`
const text = '♫ ${trackTitle} – ${artistName} ♫'
return text
},
updateDocumentTitle () {
......@@ -474,8 +478,8 @@ export default {
},
setTheme (theme) {
const oldTheme = (theme === 'light') ? 'dark' : 'light'
document.body.classList.remove(`theme-${oldTheme}`)
document.body.classList.add(`theme-${theme}`)
document.body.classList.remove('theme-${oldTheme}')
document.body.classList.add('theme-${theme}')
}
}
}
......
......@@ -254,8 +254,8 @@ import _ from '@/lodash'
import showdown from 'showdown'
import { humanSize } from '@/filters'
import SignupForm from '@/components/auth/SignupForm'
import LogoText from '@/components/LogoText'
import SignupForm from '@/components/auth/SignupForm.vue'
import LogoText from '@/components/LogoText.vue'
export default {
components: {
......
......@@ -328,10 +328,10 @@
import _ from '@/lodash'
import { mapState } from 'vuex'
import showdown from 'showdown'
import AlbumWidget from '@/components/audio/album/Widget'
import ChannelsWidget from '@/components/audio/ChannelsWidget'
import LoginForm from '@/components/auth/LoginForm'
import SignupForm from '@/components/auth/SignupForm'
import AlbumWidget from '@/components/audio/album/Widget.vue'
import ChannelsWidget from '@/components/audio/ChannelsWidget.vue'
import LoginForm from '@/components/auth/LoginForm.vue'
import SignupForm from '@/components/auth/SignupForm.vue'
import { humanSize } from '@/filters'
export default {
......
......@@ -351,9 +351,11 @@ import { createFocusTrap } from 'focus-trap'
export default {
components: {
TrackFavoriteIcon: () => import(/* webpackChunkName: "auth-audio" */ '@/components/favorites/TrackFavoriteIcon'),
TrackPlaylistIcon: () => import(/* webpackChunkName: "auth-audio" */ '@/components/playlists/TrackPlaylistIcon'),
draggable: () => import(/* webpackChunkName: "draggable" */ 'vuedraggable')
TrackFavoriteIcon: () =>
import('@/components/favorites/TrackFavoriteIcon.vue'),
TrackPlaylistIcon: () =>
import('@/components/playlists/TrackPlaylistIcon.vue'),
draggable: () => import('vuedraggable')
},
data () {
return {
......
......@@ -105,7 +105,7 @@
</template>
<script>
import Modal from '@/components/semantic/Modal'
import Modal from '@/components/semantic/Modal.vue'
import axios from 'axios'
import _ from '@/lodash'
......
......@@ -62,7 +62,7 @@
export default {
components: {
Modal: () => import(/* webpackChunkName: "modal" */ '@/components/semantic/Modal')
Modal: () => import('@/components/semantic/Modal.vue')
},
props: { show: { type: Boolean, required: true } },
computed: {
......
......@@ -472,12 +472,12 @@
<script>
import { mapState, mapActions, mapGetters } from 'vuex'
import UserModal from '@/components/common/UserModal'
import Logo from '@/components/Logo'
import SearchBar from '@/components/audio/SearchBar'
import ThemesMixin from '@/components/mixins/Themes'
import UserMenu from '@/components/common/UserMenu'
import Modal from '@/components/semantic/Modal'
import UserModal from '@/components/common/UserModal.vue'
import Logo from '@/components/Logo.vue'
import SearchBar from '@/components/audio/SearchBar.vue'
import ThemesMixin from '@/components/mixins/Themes.vue'
import UserMenu from '@/components/common/UserMenu.vue'
import Modal from '@/components/semantic/Modal.vue'
import $ from 'jquery'
......
......@@ -342,8 +342,8 @@
<script>
import { mapState, mapGetters, mapActions } from 'vuex'
import GlobalEvents from '@/components/utils/global-events'
import { toLinearVolumeScale } from '@/audio/volume'
import GlobalEvents from '@/components/utils/global-events.vue'
import { toLinearVolumeScale } from '@/audio/volume.js'
import { Howl, Howler } from 'howler'
import _ from '@/lodash'
import url from '@/utils/url'
......@@ -351,9 +351,11 @@ import axios from 'axios'
export default {
components: {
VolumeControl: () => import(/* webpackChunkName: "audio" */ './VolumeControl'),
TrackFavoriteIcon: () => import(/* webpackChunkName: "auth-audio" */ '@/components/favorites/TrackFavoriteIcon'),
TrackPlaylistIcon: () => import(/* webpackChunkName: "auth-audio" */ '@/components/playlists/TrackPlaylistIcon'),
VolumeControl: () => import('./VolumeControl.vue'),
TrackFavoriteIcon: () =>
import('@/components/favorites/TrackFavoriteIcon.vue'),
TrackPlaylistIcon: () =>
import('@/components/playlists/TrackPlaylistIcon.vue'),
GlobalEvents
},
data () {
......
......@@ -56,7 +56,7 @@
<script>
import axios from 'axios'
import AlbumCard from '@/components/audio/album/Card'
import AlbumCard from '@/components/audio/album/Card.vue'
export default {
components: {
......
......@@ -87,7 +87,7 @@
</template>
<script>
import PasswordInput from '@/components/forms/PasswordInput'
import PasswordInput from '@/components/forms/PasswordInput.vue'
export default {
components: {
......
......@@ -142,8 +142,8 @@
</template>
<script>
import Modal from '@/components/semantic/Modal'
import ChannelUploadForm from '@/components/channels/UploadForm'
import Modal from '@/components/semantic/Modal.vue'
import ChannelUploadForm from '@/components/channels/UploadForm.vue'
import { humanSize } from '@/filters'
export default {
......
import Vue from 'vue'
Vue.component('HumanDate', () => import(/* webpackChunkName: "common" */ '@/components/common/HumanDate'))
Vue.component('HumanDuration', () => import(/* webpackChunkName: "common" */ '@/components/common/HumanDuration'))
Vue.component('Username', () => import(/* webpackChunkName: "common" */ '@/components/common/Username'))
Vue.component('UserLink', () => import(/* webpackChunkName: "common" */ '@/components/common/UserLink'))
Vue.component('ActorLink', () => import(/* webpackChunkName: "common" */ '@/components/common/ActorLink'))
Vue.component('ActorAvatar', () => import(/* webpackChunkName: "common" */ '@/components/common/ActorAvatar'))
Vue.component('Duration', () => import(/* webpackChunkName: "common" */ '@/components/common/Duration'))
Vue.component('DangerousButton', () => import(/* webpackChunkName: "common" */ '@/components/common/DangerousButton'))
Vue.component('Message', () => import(/* webpackChunkName: "common" */ '@/components/common/Message'))
Vue.component('CopyInput', () => import(/* webpackChunkName: "common" */ '@/components/common/CopyInput'))
Vue.component('AjaxButton', () => import(/* webpackChunkName: "common" */ '@/components/common/AjaxButton'))
Vue.component('Tooltip', () => import(/* webpackChunkName: "common" */ '@/components/common/Tooltip'))
Vue.component('EmptyState', () => import(/* webpackChunkName: "common" */ '@/components/common/EmptyState'))
Vue.component('ExpandableDiv', () => import(/* webpackChunkName: "common" */ '@/components/common/ExpandableDiv'))
Vue.component('CollapseLink', () => import(/* webpackChunkName: "common" */ '@/components/common/CollapseLink'))
Vue.component('ActionFeedback', () => import(/* webpackChunkName: "common" */ '@/components/common/ActionFeedback'))
Vue.component('RenderedDescription', () => import(/* webpackChunkName: "common" */ '@/components/common/RenderedDescription'))
Vue.component('ContentForm', () => import(/* webpackChunkName: "common" */ '@/components/common/ContentForm'))
Vue.component('InlineSearchBar', () => import(/* webpackChunkName: "common" */ '@/components/common/InlineSearchBar'))
Vue.component('HumanDate', () => import('@/components/common/HumanDate.vue'))
Vue.component('HumanDuration', () => import('@/components/common/HumanDuration.vue'))
Vue.component('Username', () => import('@/components/common/Username.vue'))
Vue.component('UserLink', () => import('@/components/common/UserLink.vue'))
Vue.component('ActorLink', () => import('@/components/common/ActorLink.vue'))
Vue.component('ActorAvatar', () => import('@/components/common/ActorAvatar.vue'))
Vue.component('Duration', () => import('@/components/common/Duration.vue'))
Vue.component('DangerousButton', () => import('@/components/common/DangerousButton.vue'))
Vue.component('Message', () => import('@/components/common/Message.vue'))
Vue.component('CopyInput', () => import('@/components/common/CopyInput.vue'))
Vue.component('AjaxButton', () => import('@/components/common/AjaxButton.vue'))
Vue.component('Tooltip', () => import('@/components/common/Tooltip.vue'))
Vue.component('EmptyState', () => import('@/components/common/EmptyState.vue'))
Vue.component('ExpandableDiv', () => import('@/components/common/ExpandableDiv.vue'))
Vue.component('CollapseLink', () => import('@/components/common/CollapseLink.vue'))
Vue.component('ActionFeedback', () => import('@/components/common/ActionFeedback.vue'))
Vue.component('RenderedDescription', () => import('@/components/common/RenderedDescription.vue'))
Vue.component('ContentForm', () => import('@/components/common/ContentForm.vue'))
Vue.component('InlineSearchBar', () => import('@/components/common/InlineSearchBar.vue'))
export default {}
......@@ -250,10 +250,10 @@
<script>
import axios from 'axios'
import lodash from '@/lodash'
import PlayButton from '@/components/audio/PlayButton'
import TagsList from '@/components/tags/List'
import ArtistLabel from '@/components/audio/ArtistLabel'
import AlbumDropdown from './AlbumDropdown'
import PlayButton from '@/components/audio/PlayButton.vue'
import TagsList from '@/components/tags/List.vue'
import ArtistLabel from '@/components/audio/ArtistLabel.vue'
import AlbumDropdown from './AlbumDropdown.vue'
function groupByDisc (initial) {
function inner (acc, track) {
......
......@@ -92,11 +92,11 @@
<script>
import time from '@/utils/time'
import LibraryWidget from '@/components/federation/LibraryWidget'
import ChannelEntries from '@/components/audio/ChannelEntries'
import TrackTable from '@/components/audio/track/Table'
import PlayButton from '@/components/audio/PlayButton'
import time from '@/utils/time.vue'
import LibraryWidget from '@/components/federation/LibraryWidget.vue'
import ChannelEntries from '@/components/audio/ChannelEntries.vue'
import TrackTable from '@/components/audio/track/Table.vue'
import PlayButton from '@/components/audio/PlayButton.vue'
export default {
components: {
......
......@@ -153,12 +153,12 @@ import $ from 'jquery'
import logger from '@/logging'
import OrderingMixin from '@/components/mixins/Ordering'
import PaginationMixin from '@/components/mixins/Pagination'
import TranslationsMixin from '@/components/mixins/Translations'
import AlbumCard from '@/components/audio/album/Card'
import Pagination from '@/components/Pagination'
import TagsSelector from '@/components/library/TagsSelector'
import OrderingMixin from '@/components/mixins/Ordering.vue'
import PaginationMixin from '@/components/mixins/Pagination.vue'
import TranslationsMixin from '@/components/mixins/Translations.vue'
import AlbumCard from '@/components/audio/album/Card.vue'
import Pagination from '@/components/Pagination.vue'
import TagsSelector from '@/components/library/TagsSelector.vue'
const FETCH_URL = 'albums/'
......
......@@ -169,12 +169,12 @@ import $ from 'jquery'
import logger from '@/logging'
import OrderingMixin from '@/components/mixins/Ordering'
import PaginationMixin from '@/components/mixins/Pagination'
import TranslationsMixin from '@/components/mixins/Translations'
import ArtistCard from '@/components/audio/artist/Card'
import Pagination from '@/components/Pagination'
import TagsSelector from '@/components/library/TagsSelector'
import OrderingMixin from '@/components/mixins/Ordering.vue'
import PaginationMixin from '@/components/mixins/Pagination.vue'
import TranslationsMixin from '@/components/mixins/Translations.vue'
import ArtistCard from '@/components/audio/artist/Card.vue'
import Pagination from '@/components/Pagination.vue'
import TagsSelector from '@/components/library/TagsSelector.vue'
const FETCH_URL = 'artists/'
......
......@@ -201,14 +201,14 @@ import $ from 'jquery'
import logger from '@/logging'
import OrderingMixin from '@/components/mixins/Ordering'
import PaginationMixin from '@/components/mixins/Pagination'
import TranslationsMixin from '@/components/mixins/Translations'
import ArtistCard from '@/components/audio/artist/Card'
import Pagination from '@/components/Pagination'
import TagsSelector from '@/components/library/TagsSelector'
import Modal from '@/components/semantic/Modal'
import RemoteSearchForm from '@/components/RemoteSearchForm'
import OrderingMixin from '@/components/mixins/Ordering.vue'
import PaginationMixin from '@/components/mixins/Pagination.vue'
import TranslationsMixin from '@/components/mixins/Translations.vue'
import ArtistCard from '@/components/audio/artist/Card.vue'
import Pagination from '@/components/Pagination.vue'
import TagsSelector from '@/components/library/TagsSelector.vue'
import Modal from '@/components/semantic/Modal.vue'
import RemoteSearchForm from '@/components/RemoteSearchForm.vue'
const FETCH_URL = 'artists/'
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment