diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 9826d4f23..4a214defd 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -16,9 +16,9 @@ Please follow these guidelines before sending your pull request and making contr
* Stick to a similar style of code already in the project. Please look at current code to get an idea on how to do this.
* Follow [ES6](https://rse.github.io/es6-features/) standards in your code. Ex: Use `let` and `const` instead of `var`. Do not use `function(response){//code}` for callbacks, use `(response) => {//code}`.
* Comment your code when necessary. Follow the [JavaScript Documentation and Comments Standard](https://www.drupal.org/docs/develop/standards/javascript/javascript-api-documentation-and-comment-standards) for functions.
-* Please follow proper Vue structure when creating new code / components. Use existing code as well as the [Vue.js Guide](https://vuejs.org/v2/guide/) for reference.
+* Please follow proper Vue structure when creating new code / components. Use existing code as well as the [Vue.js Guide](https://vuejs.org/guide/introduction.html) for reference.
* Please test your code. Make sure new features work as well as existing core features such as watching videos or loading subscriptions. New features need to work with both the Local API as well as the Invidious API
-* Please make sure your code does not violate any standards set by our linter. It's up to you to make fixes whenever necessary. You can run `npm run lint` to check locally and `npm run lint-fix` to automatically fix smaller issues.
+* Please make sure your code does not violate any standards set by our linter. It's up to you to make fixes whenever necessary. You can run `yarn run lint` to check locally and `yarn run lint-fix` to automatically fix smaller issues.
* Please limit the amount of Node Modules that you introduce into the project. Only include them when **absolutely necessary** for your code to work (Ex: Using nedb for databases) or if a module provides similar functionality to what you are trying to achieve (Ex: Using autolinker to create links to outside URLs instead of writing the functionality myself).
* Please try to stay involved with the community and maintain your code. We are only a handful of developers working on FreeTube in our spare time. We do not have time to work on everything, and it would be nice if you can maintain your code when necessary.
diff --git a/_scripts/webpack.renderer.config.js b/_scripts/webpack.renderer.config.js
index a0f3cc5b0..c849d5688 100644
--- a/_scripts/webpack.renderer.config.js
+++ b/_scripts/webpack.renderer.config.js
@@ -2,7 +2,7 @@ const path = require('path')
const { readFileSync, readdirSync } = require('fs')
const webpack = require('webpack')
const HtmlWebpackPlugin = require('html-webpack-plugin')
-const VueLoaderPlugin = require('vue-loader/lib/plugin')
+const { VueLoaderPlugin } = require('vue-loader')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin')
const ProcessLocalesPlugin = require('./ProcessLocalesPlugin')
@@ -56,7 +56,7 @@ const config = {
loader: 'vue-loader',
options: {
compilerOptions: {
- whitespace: 'condense',
+ isCustomElement: (tag) => tag === 'swiper-container' || tag === 'swiper-slide'
}
}
},
@@ -133,6 +133,12 @@ const config = {
'process.env.IS_ELECTRON': true,
'process.env.IS_ELECTRON_MAIN': false,
'process.env.SUPPORTS_LOCAL_API': true,
+ __VUE_OPTIONS_API__: 'true',
+ __VUE_PROD_DEVTOOLS__: 'false',
+ __VUE_PROD_HYDRATION_MISMATCH_DETAILS__: 'false',
+ __VUE_I18N_LEGACY_API__: 'true',
+ __VUE_I18N_FULL_INSTALL__: 'false',
+ __INTLIFY_PROD_DEVTOOLS__: 'false',
'process.env.LOCALE_NAMES': JSON.stringify(processLocalesPlugin.localeNames),
'process.env.GEOLOCATION_NAMES': JSON.stringify(readdirSync(path.join(__dirname, '..', 'static', 'geolocations')).map(filename => filename.replace('.json', ''))),
'process.env.SWIPER_VERSION': `'${swiperVersion}'`,
@@ -180,9 +186,6 @@ const config = {
],
resolve: {
alias: {
- vue$: 'vue/dist/vue.runtime.esm.js',
- 'portal-vue$': 'portal-vue/dist/portal-vue.esm.js',
-
DB_HANDLERS_ELECTRON_RENDERER_OR_WEB$: path.resolve(__dirname, '../src/datastores/handlers/electron.js'),
'youtubei.js$': 'youtubei.js/web',
diff --git a/_scripts/webpack.web.config.js b/_scripts/webpack.web.config.js
index 664bc63e4..afe6c942c 100644
--- a/_scripts/webpack.web.config.js
+++ b/_scripts/webpack.web.config.js
@@ -2,7 +2,7 @@ const path = require('path')
const fs = require('fs')
const webpack = require('webpack')
const HtmlWebpackPlugin = require('html-webpack-plugin')
-const VueLoaderPlugin = require('vue-loader/lib/plugin')
+const { VueLoaderPlugin } = require('vue-loader')
const CopyWebpackPlugin = require('copy-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const JsonMinimizerPlugin = require('json-minimizer-webpack-plugin')
@@ -45,7 +45,7 @@ const config = {
loader: 'vue-loader',
options: {
compilerOptions: {
- whitespace: 'condense',
+ isCustomElement: (tag) => tag === 'swiper-container' || tag === 'swiper-slide',
}
}
},
@@ -128,6 +128,12 @@ const config = {
'process.env.IS_ELECTRON': false,
'process.env.IS_ELECTRON_MAIN': false,
'process.env.SUPPORTS_LOCAL_API': false,
+ __VUE_OPTIONS_API__: 'true',
+ __VUE_PROD_DEVTOOLS__: 'false',
+ __VUE_PROD_HYDRATION_MISMATCH_DETAILS__: 'false',
+ __VUE_I18N_LEGACY_API__: 'true',
+ __VUE_I18N_FULL_INSTALL__: 'false',
+ __INTLIFY_PROD_DEVTOOLS__: 'false',
'process.env.SWIPER_VERSION': `'${swiperVersion}'`
}),
new webpack.ProvidePlugin({
@@ -158,9 +164,6 @@ const config = {
],
resolve: {
alias: {
- vue$: 'vue/dist/vue.runtime.esm.js',
- 'portal-vue$': 'portal-vue/dist/portal-vue.esm.js',
-
DB_HANDLERS_ELECTRON_RENDERER_OR_WEB$: path.resolve(__dirname, '../src/datastores/handlers/web.js'),
// change to "shaka-player.ui.debug.js" to get debug logs (update jsconfig to get updated types)
diff --git a/eslint.config.mjs b/eslint.config.mjs
index 5ac25984a..c37b0a9c1 100644
--- a/eslint.config.mjs
+++ b/eslint.config.mjs
@@ -33,9 +33,9 @@ export default [
ts: false,
}),
js.configs.recommended,
- ...eslintPluginVue.configs['flat/vue2-recommended'],
+ ...eslintPluginVue.configs['flat/recommended'],
...vuejsAccessibility.configs["flat/recommended"],
- ...intlifyVueI18N.configs['flat/recommended'],
+ ...intlifyVueI18N.configs['recommended'],
{
files: [
'**/*.{js,vue}',
@@ -63,7 +63,7 @@ export default [
settings: {
'vue-i18n': {
localeDir: `./static/locales/{${activeLocales.join(',')}}.yaml`,
- messageSyntaxVersion: '^8.0.0',
+ messageSyntaxVersion: '^11.0.0',
},
},
@@ -79,7 +79,6 @@ export default [
'no-unused-vars': 'warn',
'no-undef': 'warn',
'object-shorthand': 'off',
- 'vue/no-template-key': 'warn',
'vue/multi-word-component-names': 'off',
'vuejs-accessibility/label-has-for': ['error', {
@@ -119,8 +118,6 @@ export default [
ignoreText: ['-', '•', '/', 'YouTube', 'Invidious', 'FreeTube'],
}],
- '@intlify/vue-i18n/no-deprecated-tc': 'off',
- 'vue/require-explicit-emits': 'error',
'vue/no-unused-emit-declarations': 'error',
'jsdoc/check-alignment': 'error',
@@ -166,7 +163,7 @@ export default [
settings: {
'vue-i18n': {
localeDir: `./static/locales/{${activeLocales.join(',')}}.yaml`,
- messageSyntaxVersion: '^8.0.0',
+ messageSyntaxVersion: '^11.0.0',
},
},
},
@@ -191,7 +188,7 @@ export default [
settings: {
'vue-i18n': {
localeDir: `./static/locales/{${activeLocales.join(',')}}.yaml`,
- messageSyntaxVersion: '^8.0.0',
+ messageSyntaxVersion: '^11.0.0',
},
},
},
@@ -210,7 +207,7 @@ export default [
settings: {
'vue-i18n': {
localeDir: `./static/locales/{${activeLocales.join(',')}}.yaml`,
- messageSyntaxVersion: '^8.0.0',
+ messageSyntaxVersion: '^11.0.0',
},
},
},
diff --git a/jsconfig.json b/jsconfig.json
index dad8a7949..2a959e13b 100644
--- a/jsconfig.json
+++ b/jsconfig.json
@@ -1,6 +1,6 @@
{
"vueCompilerOptions": {
- "target": 2.7
+ "target": 3.5
},
"compilerOptions": {
"strictNullChecks": true,
diff --git a/package.json b/package.json
index b9339c4a6..4aed27245 100644
--- a/package.json
+++ b/package.json
@@ -58,21 +58,21 @@
"@fortawesome/free-brands-svg-icons": "^6.7.2",
"@fortawesome/free-regular-svg-icons": "^6.7.2",
"@fortawesome/free-solid-svg-icons": "^6.7.2",
- "@fortawesome/vue-fontawesome": "^2.0.10",
+ "@fortawesome/vue-fontawesome": "^3.0.8",
"@seald-io/nedb": "^4.1.2",
"autolinker": "^4.1.5",
"bgutils-js": "^3.2.0",
"electron-context-menu": "^4.1.1",
"marked": "^16.4.1",
- "portal-vue": "^2.1.7",
+ "portal-vue": "^3.0.0",
"process": "^0.11.10",
"shaka-player": "^4.16.6",
"swiper": "^12.0.3",
- "vue": "^2.7.16",
- "vue-i18n": "^8.28.2",
- "vue-observe-visibility": "^1.0.0",
- "vue-router": "^3.6.5",
- "vuex": "^3.6.2",
+ "vue": "^3.5.22",
+ "vue-i18n": "^11.1.12",
+ "vue-observe-visibility": "^2.0.0-alpha.1",
+ "vue-router": "^4.6.3",
+ "vuex": "^4.1.0",
"youtubei.js": "^16.0.1"
},
"devDependencies": {
@@ -80,7 +80,7 @@
"@babel/preset-env": "^7.28.5",
"@double-great/stylelint-a11y": "^3.4.0",
"@eslint/js": "^9.38.0",
- "@intlify/eslint-plugin-vue-i18n": "^3.2.0",
+ "@intlify/eslint-plugin-vue-i18n": "^4.1.0",
"babel-loader": "^10.0.0",
"copy-webpack-plugin": "^13.0.1",
"css-loader": "^7.1.2",
@@ -112,9 +112,8 @@
"stylelint-high-performance-animation": "^1.11.0",
"stylelint-use-logical-spec": "^5.0.1",
"tree-kill": "1.2.2",
- "vue-devtools": "^5.1.4",
"vue-eslint-parser": "^10.2.0",
- "vue-loader": "^15.10.0",
+ "vue-loader": "^17.4.2",
"webpack": "^5.102.1",
"webpack-cli": "^6.0.1",
"webpack-dev-server": "^5.2.2",
diff --git a/src/main/index.js b/src/main/index.js
index 806e55761..8ad29ae72 100644
--- a/src/main/index.js
+++ b/src/main/index.js
@@ -710,14 +710,6 @@ function runApp() {
await createWindow()
- if (process.env.NODE_ENV === 'development') {
- try {
- require('vue-devtools').install()
- } catch (err) {
- console.error(err)
- }
- }
-
if (isDebug) {
mainWindow.webContents.openDevTools()
}
diff --git a/src/renderer/App.css b/src/renderer/App.css
index 542cbd58d..c0b4712bf 100644
--- a/src/renderer/App.css
+++ b/src/renderer/App.css
@@ -56,8 +56,8 @@
transition: opacity 0.15s;
}
-.fade-enter,
-.fade-leave-to /* .fade-leave-active below version 2.1.8 */ {
+.fade-enter-from,
+.fade-leave-to {
opacity: 0;
}
diff --git a/src/renderer/App.js b/src/renderer/App.js
index 87c46e0f6..91ff638f0 100644
--- a/src/renderer/App.js
+++ b/src/renderer/App.js
@@ -209,18 +209,16 @@ export default defineComponent({
}, 500)
})
- this.$router.onReady(() => {
- if (this.$router.currentRoute.path === '/') {
- this.$router.replace({ path: this.landingPage })
- }
+ if (this.$route.path === '/') {
+ this.$router.replace({ path: this.landingPage })
+ }
- this.setWindowTitle()
- })
+ this.setWindowTitle()
})
document.addEventListener('dragstart', this.handleDragStart)
},
- beforeDestroy: function () {
+ beforeUnmount: function () {
document.removeEventListener('dragstart', this.handleDragStart)
},
methods: {
@@ -332,8 +330,8 @@ export default defineComponent({
this.showBlogBanner = false
},
- handlePromptPortalUpdate: function(newVal) {
- this.isPromptOpen = newVal
+ handlePromptPortalUpdate: function(data) {
+ this.isPromptOpen = data.hasContent
},
openDownloadsPage: function () {
diff --git a/src/renderer/App.vue b/src/renderer/App.vue
index 99030dd88..3736ea62f 100644
--- a/src/renderer/App.vue
+++ b/src/renderer/App.vue
@@ -1,7 +1,6 @@
-
- {{ $tc('Global.Counts.Channel Count', channelCount, {count: formattedChannelCount}) }} + {{ $t('Global.Counts.Channel Count', {count: formattedChannelCount}, channelCount) }}