diff --git a/.babelrc b/.babelrc index 945211470b..373d2c5993 100644 --- a/.babelrc +++ b/.babelrc @@ -1,5 +1,5 @@ { - "presets": ["@babel/preset-env", "@vue/babel-preset-jsx"], - "plugins": ["@babel/plugin-transform-runtime", "lodash"], + "presets": ["@babel/preset-env"], + "plugins": ["@babel/plugin-transform-runtime", "lodash", "@vue/babel-plugin-jsx"], "comments": false } diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 85d3ee4466..ab60117331 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,7 +1,7 @@ # This file is a template, and might need editing before it works on your project. # Official framework image. Look for the different tagged releases at: # https://hub.docker.com/r/library/node/tags/ -image: node:10 +image: node:12 stages: - lint diff --git a/build/webpack.base.conf.js b/build/webpack.base.conf.js index 900d824b98..f442b2a087 100644 --- a/build/webpack.base.conf.js +++ b/build/webpack.base.conf.js @@ -4,6 +4,7 @@ var utils = require('./utils') var projectRoot = path.resolve(__dirname, '../') var ServiceWorkerWebpackPlugin = require('serviceworker-webpack-plugin') var CopyPlugin = require('copy-webpack-plugin'); +var { VueLoaderPlugin } = require('vue-loader') var env = process.env.NODE_ENV // check env & config/index.js to decide weither to enable CSS Sourcemaps for the @@ -29,12 +30,11 @@ module.exports = { } }, resolve: { - extensions: ['.js', '.vue'], + extensions: ['.js', '.jsx', '.vue'], modules: [ path.join(__dirname, '../node_modules') ], alias: { - 'vue$': 'vue/dist/vue.runtime.common', 'static': path.resolve(__dirname, '../static'), 'src': path.resolve(__dirname, '../src'), 'assets': path.resolve(__dirname, '../src/assets'), @@ -60,7 +60,17 @@ module.exports = { }, { test: /\.vue$/, - use: 'vue-loader' + loader: 'vue-loader', + options: { + compilerOptions: { + isCustomElement(tag) { + if (tag === 'pinch-zoom') { + return true + } + return false + } + } + } }, { test: /\.jsx?$/, @@ -95,6 +105,7 @@ module.exports = { entry: path.join(__dirname, '..', 'src/sw.js'), filename: 'sw-pleroma.js' }), + new VueLoaderPlugin(), // This copies Ruffle's WASM to a directory so that JS side can access it new CopyPlugin({ patterns: [ diff --git a/build/webpack.dev.conf.js b/build/webpack.dev.conf.js index 159572ba1f..4605b93dfb 100644 --- a/build/webpack.dev.conf.js +++ b/build/webpack.dev.conf.js @@ -21,7 +21,9 @@ module.exports = merge(baseWebpackConfig, { new webpack.DefinePlugin({ 'process.env': config.dev.env, 'COMMIT_HASH': JSON.stringify('DEV'), - 'DEV_OVERRIDES': JSON.stringify(config.dev.settings) + 'DEV_OVERRIDES': JSON.stringify(config.dev.settings), + '__VUE_OPTIONS_API__': true, + '__VUE_PROD_DEVTOOLS__': false }), // https://github.com/glenjamin/webpack-hot-middleware#installation--usage new webpack.HotModuleReplacementPlugin(), diff --git a/build/webpack.prod.conf.js b/build/webpack.prod.conf.js index ed11ebad35..a67ed2f627 100644 --- a/build/webpack.prod.conf.js +++ b/build/webpack.prod.conf.js @@ -36,7 +36,9 @@ var webpackConfig = merge(baseWebpackConfig, { new webpack.DefinePlugin({ 'process.env': env, 'COMMIT_HASH': JSON.stringify(commitHash), - 'DEV_OVERRIDES': JSON.stringify(undefined) + 'DEV_OVERRIDES': JSON.stringify(undefined), + '__VUE_OPTIONS_API__': true, + '__VUE_PROD_DEVTOOLS__': false }), // extract css into its own file new MiniCssExtractPlugin({ diff --git a/package.json b/package.json index 7cd940667a..0537780e72 100644 --- a/package.json +++ b/package.json @@ -17,30 +17,31 @@ }, "dependencies": { "@babel/runtime": "7.17.8", - "@chenfengyuan/vue-qrcode": "1.0.2", + "@chenfengyuan/vue-qrcode": "2.0.0", "@fortawesome/fontawesome-svg-core": "1.3.0", "@fortawesome/free-regular-svg-icons": "5.15.4", "@fortawesome/free-solid-svg-icons": "5.15.4", - "@fortawesome/vue-fontawesome": "2.0.6", + "@fortawesome/vue-fontawesome": "3.0.0-5", "@kazvmoe-infra/pinch-zoom-element": "1.2.0", + "@vuelidate/core": "2.0.0-alpha.35", + "@vuelidate/validators": "2.0.0-alpha.27", "body-scroll-lock": "2.7.1", "chromatism": "3.0.0", + "click-outside-vue3": "4.0.1", "cropperjs": "1.5.12", "diff": "3.5.0", "escape-html": "1.0.3", "localforage": "1.10.0", "parse-link-header": "1.0.1", "phoenix": "1.4.0", - "portal-vue": "2.1.7", "punycode.js": "2.1.0", + "qrcode": "1", "ruffle-mirror": "2021.12.31", - "v-click-outside": "2.1.5", - "vue": "2.6.11", - "vue-i18n": "7.8.1", - "vue-router": "3.0.2", + "vue": "^3.2.31", + "vue-i18n": "9.1.9", + "vue-router": "4.0.14", "vue-template-compiler": "2.6.11", - "vuelidate": "0.7.7", - "vuex": "3.0.1" + "vuex": "4.0.2" }, "devDependencies": { "@babel/core": "7.17.8", @@ -49,8 +50,9 @@ "@babel/register": "7.17.7", "@ungap/event-target": "0.2.3", "@vue/babel-helper-vue-jsx-merge-props": "1.2.1", - "@vue/babel-preset-jsx": "1.2.4", - "@vue/test-utils": "1.0.0-beta.28", + "@vue/babel-plugin-jsx": "1.1.1", + "@vue/compiler-sfc": "^3.1.0", + "@vue/test-utils": "2.0.0-rc.17", "autoprefixer": "6.7.7", "babel-eslint": "7.2.3", "babel-loader": "8.2.4", @@ -82,10 +84,10 @@ "iso-639-1": "2.1.13", "isparta-loader": "2.0.0", "json-loader": "0.5.7", - "karma": "3.1.4", + "karma": "6.3.17", "karma-coverage": "1.1.2", "karma-firefox-launcher": "1.3.0", - "karma-mocha": "1.3.0", + "karma-mocha": "2.0.1", "karma-mocha-reporter": "2.2.5", "karma-sinon-chai": "2.0.2", "karma-sourcemap-loader": "0.3.8", @@ -112,7 +114,7 @@ "stylelint-config-standard": "20.0.0", "stylelint-rscss": "0.4.0", "url-loader": "1.1.2", - "vue-loader": "14.2.4", + "vue-loader": "^16.0.0", "vue-style-loader": "4.1.2", "webpack": "4.46.0", "webpack-dev-middleware": "3.7.3", diff --git a/src/App.js b/src/App.js index 05b400d2e1..0a6fa48ce3 100644 --- a/src/App.js +++ b/src/App.js @@ -48,7 +48,7 @@ export default { this.$store.dispatch('setOption', { name: 'interfaceLanguage', value: val }) window.addEventListener('resize', this.updateMobileState) }, - destroyed () { + unmounted () { window.removeEventListener('resize', this.updateMobileState) }, computed: { diff --git a/src/App.scss b/src/App.scss index 3600c68d3f..df8dd69f91 100644 --- a/src/App.scss +++ b/src/App.scss @@ -582,7 +582,7 @@ nav { .fade-enter-active, .fade-leave-active { transition: opacity .2s } -.fade-enter, .fade-leave-active { +.fade-enter-from, .fade-leave-active { opacity: 0 } diff --git a/src/App.vue b/src/App.vue index 7df9019e77..f28e7794e6 100644 --- a/src/App.vue +++ b/src/App.vue @@ -1,6 +1,6 @@ diff --git a/src/boot/after_store.js b/src/boot/after_store.js index c4a0a80099..768327084f 100644 --- a/src/boot/after_store.js +++ b/src/boot/after_store.js @@ -1,7 +1,13 @@ -import Vue from 'vue' -import VueRouter from 'vue-router' -import routes from './routes' +import { createApp } from 'vue' +import { createRouter, createWebHistory } from 'vue-router' +import vClickOutside from 'click-outside-vue3' + +import { FontAwesomeIcon, FontAwesomeLayers } from '@fortawesome/vue-fontawesome' + import App from '../App.vue' +import routes from './routes' +import VBodyScrollLock from 'src/directives/body_scroll_lock' + import { windowWidth } from '../services/window_utils/window_utils' import { getOrCreateApp, getClientToken } from '../services/new_api/oauth.js' import backendInteractorService from '../services/backend_interactor_service/backend_interactor_service.js' @@ -367,25 +373,32 @@ const afterStoreSetup = async ({ store, i18n }) => { getTOS({ store }) getStickers({ store }) - const router = new VueRouter({ - mode: 'history', + const router = createRouter({ + history: createWebHistory(), routes: routes(store), scrollBehavior: (to, _from, savedPosition) => { if (to.matched.some(m => m.meta.dontScroll)) { return false } - return savedPosition || { x: 0, y: 0 } + return savedPosition || { left: 0, top: 0 } } }) - /* eslint-disable no-new */ - return new Vue({ - router, - store, - i18n, - el: '#app', - render: h => h(App) - }) + const app = createApp(App) + + app.use(router) + app.use(store) + app.use(i18n) + + app.use(vClickOutside) + app.use(VBodyScrollLock) + + app.component('FAIcon', FontAwesomeIcon) + app.component('FALayers', FontAwesomeLayers) + + app.mount('#app') + + return app } export default afterStoreSetup diff --git a/src/boot/routes.js b/src/boot/routes.js index 1bc1f9f7da..905ffe41e1 100644 --- a/src/boot/routes.js +++ b/src/boot/routes.js @@ -46,7 +46,7 @@ export default (store) => { { name: 'bookmarks', path: '/bookmarks', component: BookmarkTimeline }, { name: 'conversation', path: '/notice/:id', component: ConversationPage, meta: { dontScroll: true } }, { name: 'remote-user-profile-acct', - path: '/remote-users/(@?):username([^/@]+)@:hostname([^/@]+)', + path: '/remote-users/:_(@)?:username([^/@]+)@:hostname([^/@]+)', component: RemoteUserResolver, beforeEnter: validateAuthenticatedRoute }, @@ -69,7 +69,7 @@ export default (store) => { { name: 'search', path: '/search', component: Search, props: (route) => ({ query: route.query.query }) }, { name: 'who-to-follow', path: '/who-to-follow', component: WhoToFollow, beforeEnter: validateAuthenticatedRoute }, { name: 'about', path: '/about', component: About }, - { name: 'user-profile', path: '/(users/)?:name', component: UserProfile } + { name: 'user-profile', path: '/:_(users)?/:name', component: UserProfile } ] if (store.state.instance.pleromaChatMessagesAvailable) { diff --git a/src/components/async_component_error/async_component_error.vue b/src/components/async_component_error/async_component_error.vue index b1b59638d5..26ab5d21c3 100644 --- a/src/components/async_component_error/async_component_error.vue +++ b/src/components/async_component_error/async_component_error.vue @@ -19,6 +19,7 @@ @@ -15,25 +14,27 @@