Use vite to replace webpack
2
.gitignore
vendored
|
|
@ -7,5 +7,5 @@ test/e2e/reports
|
||||||
selenium-debug.log
|
selenium-debug.log
|
||||||
.idea/
|
.idea/
|
||||||
config/local.json
|
config/local.json
|
||||||
static/emoji.json
|
src/assets/emoji.json
|
||||||
logs/
|
logs/
|
||||||
|
|
|
||||||
24
build/service_worker_messages.js
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
import { languages, langCodeToJsonName } from '../src/i18n/languages.js'
|
||||||
|
import { readFile } from 'node:fs/promises'
|
||||||
|
import { dirname, resolve } from 'node:path'
|
||||||
|
import { fileURLToPath } from 'node:url'
|
||||||
|
|
||||||
|
export const generateServiceWorkerMessages = async () => {
|
||||||
|
const i18nDir = resolve(
|
||||||
|
dirname(dirname(fileURLToPath(import.meta.url))),
|
||||||
|
'src/i18n'
|
||||||
|
)
|
||||||
|
const msgArray = await Promise.all(languages.map(async lang => {
|
||||||
|
const name = langCodeToJsonName(lang)
|
||||||
|
const file = resolve(i18nDir, name + '.json')
|
||||||
|
const fileContent = await readFile(file, 'utf-8')
|
||||||
|
const msg = {
|
||||||
|
notifications: JSON.parse(fileContent).notifications || {}
|
||||||
|
}
|
||||||
|
return [lang, msg]
|
||||||
|
}))
|
||||||
|
return msgArray.reduce((acc, [lang, msg]) => {
|
||||||
|
acc[lang] = msg
|
||||||
|
return acc
|
||||||
|
}, {})
|
||||||
|
}
|
||||||
128
build/sw_plugin.js
Normal file
|
|
@ -0,0 +1,128 @@
|
||||||
|
import { fileURLToPath } from 'node:url'
|
||||||
|
import { dirname } from 'node:path'
|
||||||
|
import { readFile } from 'node:fs/promises'
|
||||||
|
import { build } from 'vite'
|
||||||
|
import { generateServiceWorkerMessages } from './service_worker_messages.js'
|
||||||
|
|
||||||
|
const projectRoot = dirname(dirname(fileURLToPath(import.meta.url)))
|
||||||
|
|
||||||
|
export const devSwPlugin = ({
|
||||||
|
swSrc,
|
||||||
|
swDest,
|
||||||
|
}) => {
|
||||||
|
return {
|
||||||
|
name: 'dev-sw-plugin',
|
||||||
|
apply: 'serve',
|
||||||
|
resolveId (id) {
|
||||||
|
const name = id.startsWith('/') ? id.slice(1) : id
|
||||||
|
if (name === swDest) {
|
||||||
|
return swSrc
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
},
|
||||||
|
async load (id) {
|
||||||
|
if (id === swSrc) {
|
||||||
|
return readFile(swSrc, 'utf-8')
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* vite does not bundle the service worker
|
||||||
|
* during dev, and firefox does not support ESM as service worker
|
||||||
|
* https://bugzilla.mozilla.org/show_bug.cgi?id=1360870
|
||||||
|
*/
|
||||||
|
// async transform (code, id) {
|
||||||
|
// if (id === swSrc) {
|
||||||
|
// console.log('load virtual')
|
||||||
|
// const res = await build({
|
||||||
|
// entryPoints: [swSrc],
|
||||||
|
// bundle: true,
|
||||||
|
// write: false,
|
||||||
|
// outfile: 'sw-pleroma.js',
|
||||||
|
// alias: {
|
||||||
|
// 'src': projectRoot + '/src',
|
||||||
|
// },
|
||||||
|
// define: {
|
||||||
|
// 'import.meta.glob': 'require'
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
// console.log('res', res)
|
||||||
|
// const text = res.outputFiles[0].text
|
||||||
|
// console.log('text', text)
|
||||||
|
// return text
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Idea taken from
|
||||||
|
// https://github.com/vite-pwa/vite-plugin-pwa/blob/main/src/plugins/build.ts
|
||||||
|
// rollup does not support compiling to iife if we want to code-split;
|
||||||
|
// however, we must compile the service worker to iife because of browser support.
|
||||||
|
// Run another vite build just for the service worker targeting iife at
|
||||||
|
// the end of the build.
|
||||||
|
export const buildSwPlugin = ({
|
||||||
|
swSrc,
|
||||||
|
swDest,
|
||||||
|
}) => {
|
||||||
|
let config
|
||||||
|
return {
|
||||||
|
name: 'build-sw-plugin',
|
||||||
|
enforce: 'post',
|
||||||
|
apply: 'build',
|
||||||
|
configResolved (resolvedConfig) {
|
||||||
|
config = {
|
||||||
|
define: resolvedConfig.define,
|
||||||
|
resolve: resolvedConfig.resolve,
|
||||||
|
plugins: [swMessagesPlugin()],
|
||||||
|
publicDir: false,
|
||||||
|
build: {
|
||||||
|
...resolvedConfig.build,
|
||||||
|
lib: {
|
||||||
|
entry: swSrc,
|
||||||
|
formats: ['iife'],
|
||||||
|
name: 'sw_pleroma'
|
||||||
|
},
|
||||||
|
emptyOutDir: false,
|
||||||
|
rollupOptions: {
|
||||||
|
output: {
|
||||||
|
entryFileNames: swDest
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
configFile: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
closeBundle: {
|
||||||
|
order: 'post',
|
||||||
|
sequential: true,
|
||||||
|
async handler () {
|
||||||
|
console.log('Building service worker for production')
|
||||||
|
await build(config)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const swMessagesName = 'virtual:pleroma-fe/service_worker_messages'
|
||||||
|
const swMessagesNameResolved = '\0' + swMessagesName
|
||||||
|
|
||||||
|
export const swMessagesPlugin = () => {
|
||||||
|
return {
|
||||||
|
name: 'sw-messages-plugin',
|
||||||
|
resolveId (id) {
|
||||||
|
if (id === swMessagesName) {
|
||||||
|
return swMessagesNameResolved
|
||||||
|
} else {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
},
|
||||||
|
async load (id) {
|
||||||
|
if (id === swMessagesNameResolved) {
|
||||||
|
const messages = await generateServiceWorkerMessages()
|
||||||
|
return `export default ${JSON.stringify(messages, undefined, 2)}`
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,27 +1,23 @@
|
||||||
|
|
||||||
module.exports = {
|
import emojis from '@kazvmoe-infra/unicode-emoji-json/data-by-group.json' with { type: 'json' }
|
||||||
updateEmoji () {
|
import fs from 'fs'
|
||||||
const emojis = require('@kazvmoe-infra/unicode-emoji-json/data-by-group')
|
|
||||||
const fs = require('fs')
|
|
||||||
|
|
||||||
Object.keys(emojis)
|
Object.keys(emojis)
|
||||||
.map(k => {
|
.map(k => {
|
||||||
emojis[k].map(e => {
|
emojis[k].map(e => {
|
||||||
delete e.unicode_version
|
delete e.unicode_version
|
||||||
delete e.emoji_version
|
delete e.emoji_version
|
||||||
delete e.skin_tone_support_unicode_version
|
delete e.skin_tone_support_unicode_version
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
const res = {}
|
const res = {}
|
||||||
Object.keys(emojis)
|
Object.keys(emojis)
|
||||||
.map(k => {
|
.map(k => {
|
||||||
const groupId = k.replace('&', 'and').replace(/ /g, '-').toLowerCase()
|
const groupId = k.replace('&', 'and').replace(/ /g, '-').toLowerCase()
|
||||||
res[groupId] = emojis[k]
|
res[groupId] = emojis[k]
|
||||||
})
|
})
|
||||||
|
|
||||||
console.info('Updating emojis...')
|
console.info('Updating emojis...')
|
||||||
fs.writeFileSync('static/emoji.json', JSON.stringify(res))
|
fs.writeFileSync('src/assets/emoji.json', JSON.stringify(res))
|
||||||
console.info('Done.')
|
console.info('Done.')
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -167,6 +167,7 @@
|
||||||
<div id="app" class="hidden"></div>
|
<div id="app" class="hidden"></div>
|
||||||
<div id="modal"></div>
|
<div id="modal"></div>
|
||||||
<!-- built files will be auto injected -->
|
<!-- built files will be auto injected -->
|
||||||
<div id="popovers" />
|
<div id="popovers"></div>
|
||||||
|
<script type="module" src="/src/main.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
||||||
10
package.json
|
|
@ -5,8 +5,8 @@
|
||||||
"author": "Pleroma contributors <https://git.pleroma.social/pleroma/pleroma-fe/-/blob/develop/CONTRIBUTORS.md>",
|
"author": "Pleroma contributors <https://git.pleroma.social/pleroma/pleroma-fe/-/blob/develop/CONTRIBUTORS.md>",
|
||||||
"private": false,
|
"private": false,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "node build/dev-server.js",
|
"dev": "node build/update-emoji.js && vite dev",
|
||||||
"build": "node build/build.js",
|
"build": "node build/update-emoji.js && vite build",
|
||||||
"unit": "karma start test/unit/karma.conf.js --single-run",
|
"unit": "karma start test/unit/karma.conf.js --single-run",
|
||||||
"unit:watch": "karma start test/unit/karma.conf.js --single-run=false",
|
"unit:watch": "karma start test/unit/karma.conf.js --single-run=false",
|
||||||
"e2e": "node test/e2e/runner.js",
|
"e2e": "node test/e2e/runner.js",
|
||||||
|
|
@ -27,6 +27,7 @@
|
||||||
"@ruffle-rs/ruffle": "0.1.0-nightly.2025.1.13",
|
"@ruffle-rs/ruffle": "0.1.0-nightly.2025.1.13",
|
||||||
"@vuelidate/core": "2.0.3",
|
"@vuelidate/core": "2.0.3",
|
||||||
"@vuelidate/validators": "2.0.4",
|
"@vuelidate/validators": "2.0.4",
|
||||||
|
"@web3-storage/parse-link-header": "^3.1.0",
|
||||||
"body-scroll-lock": "3.1.5",
|
"body-scroll-lock": "3.1.5",
|
||||||
"chromatism": "3.0.0",
|
"chromatism": "3.0.0",
|
||||||
"click-outside-vue3": "4.0.1",
|
"click-outside-vue3": "4.0.1",
|
||||||
|
|
@ -58,6 +59,8 @@
|
||||||
"@babel/register": "7.25.9",
|
"@babel/register": "7.25.9",
|
||||||
"@intlify/vue-i18n-loader": "5.0.1",
|
"@intlify/vue-i18n-loader": "5.0.1",
|
||||||
"@ungap/event-target": "0.2.4",
|
"@ungap/event-target": "0.2.4",
|
||||||
|
"@vitejs/plugin-vue": "^5.2.1",
|
||||||
|
"@vitejs/plugin-vue-jsx": "^4.1.1",
|
||||||
"@vue/babel-helper-vue-jsx-merge-props": "1.4.0",
|
"@vue/babel-helper-vue-jsx-merge-props": "1.4.0",
|
||||||
"@vue/babel-plugin-jsx": "1.2.5",
|
"@vue/babel-plugin-jsx": "1.2.5",
|
||||||
"@vue/compiler-sfc": "3.5.13",
|
"@vue/compiler-sfc": "3.5.13",
|
||||||
|
|
@ -123,6 +126,8 @@
|
||||||
"stylelint-config-standard": "29.0.0",
|
"stylelint-config-standard": "29.0.0",
|
||||||
"stylelint-rscss": "0.4.0",
|
"stylelint-rscss": "0.4.0",
|
||||||
"stylelint-webpack-plugin": "^3.3.0",
|
"stylelint-webpack-plugin": "^3.3.0",
|
||||||
|
"vite": "^6.1.0",
|
||||||
|
"vite-plugin-pwa": "^0.21.1",
|
||||||
"vue-loader": "17.4.2",
|
"vue-loader": "17.4.2",
|
||||||
"vue-style-loader": "4.1.3",
|
"vue-style-loader": "4.1.3",
|
||||||
"webpack": "5.97.1",
|
"webpack": "5.97.1",
|
||||||
|
|
@ -130,6 +135,7 @@
|
||||||
"webpack-hot-middleware": "2.26.1",
|
"webpack-hot-middleware": "2.26.1",
|
||||||
"webpack-merge": "0.20.0"
|
"webpack-merge": "0.20.0"
|
||||||
},
|
},
|
||||||
|
"type": "module",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 16.0.0"
|
"node": ">= 16.0.0"
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
module.exports = {
|
import autoprefixer from 'autoprefixer'
|
||||||
|
|
||||||
|
export default {
|
||||||
plugins: [
|
plugins: [
|
||||||
require('autoprefixer')
|
autoprefixer
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
0
static/.gitignore → public/static/.gitignore
vendored
0
public/static/.gitkeep
Normal file
|
Before Width: | Height: | Size: 628 KiB After Width: | Height: | Size: 628 KiB |
|
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 396 KiB After Width: | Height: | Size: 396 KiB |
|
Before Width: | Height: | Size: 521 KiB After Width: | Height: | Size: 521 KiB |
|
Before Width: | Height: | Size: 55 KiB After Width: | Height: | Size: 55 KiB |
|
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 42 KiB |
|
Before Width: | Height: | Size: 1.1 MiB After Width: | Height: | Size: 1.1 MiB |
|
Before Width: | Height: | Size: 1.2 MiB After Width: | Height: | Size: 1.2 MiB |
|
|
@ -1 +0,0 @@
|
||||||
../../static/pleromatan_apology.png
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
../../static/pleromatan_apology_fox.png
|
|
||||||
|
|
@ -3,7 +3,8 @@ import { getTagName, processTextForEmoji, getAttrs } from 'src/services/html_con
|
||||||
import { convertHtmlToTree } from 'src/services/html_converter/html_tree_converter.service.js'
|
import { convertHtmlToTree } from 'src/services/html_converter/html_tree_converter.service.js'
|
||||||
import { convertHtmlToLines } from 'src/services/html_converter/html_line_converter.service.js'
|
import { convertHtmlToLines } from 'src/services/html_converter/html_line_converter.service.js'
|
||||||
import StillImage from 'src/components/still-image/still-image.vue'
|
import StillImage from 'src/components/still-image/still-image.vue'
|
||||||
import MentionsLine, { MENTIONS_LIMIT } from 'src/components/mentions_line/mentions_line.vue'
|
import MentionsLine from 'src/components/mentions_line/mentions_line.vue'
|
||||||
|
import { MENTIONS_LIMIT } from 'src/components/mentions_line/mentions_line.js'
|
||||||
import HashtagLink from 'src/components/hashtag_link/hashtag_link.vue'
|
import HashtagLink from 'src/components/hashtag_link/hashtag_link.vue'
|
||||||
|
|
||||||
import './rich_content.scss'
|
import './rich_content.scss'
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,8 @@ import BooleanSetting from '../helpers/boolean_setting.vue'
|
||||||
import ChoiceSetting from '../helpers/choice_setting.vue'
|
import ChoiceSetting from '../helpers/choice_setting.vue'
|
||||||
import IntegerSetting from '../helpers/integer_setting.vue'
|
import IntegerSetting from '../helpers/integer_setting.vue'
|
||||||
import FloatSetting from '../helpers/float_setting.vue'
|
import FloatSetting from '../helpers/float_setting.vue'
|
||||||
import UnitSetting, { defaultHorizontalUnits } from '../helpers/unit_setting.vue'
|
import UnitSetting from '../helpers/unit_setting.vue'
|
||||||
|
import { defaultHorizontalUnits } from '../helpers/unit_setting.js'
|
||||||
import PaletteEditor from 'src/components/palette_editor/palette_editor.vue'
|
import PaletteEditor from 'src/components/palette_editor/palette_editor.vue'
|
||||||
import Preview from './theme_tab/theme_preview.vue'
|
import Preview from './theme_tab/theme_preview.vue'
|
||||||
import FontControl from 'src/components/font_control/font_control.vue'
|
import FontControl from 'src/components/font_control/font_control.vue'
|
||||||
|
|
|
||||||
|
|
@ -221,12 +221,15 @@ export default {
|
||||||
|
|
||||||
// ## Components stuff
|
// ## Components stuff
|
||||||
// Getting existing components
|
// Getting existing components
|
||||||
const componentsContext = require.context('src', true, /\.style.js(on)?$/)
|
const componentsContext = import.meta.glob(
|
||||||
const componentKeysAll = componentsContext.keys()
|
['/src/**/*.style.js', '/src/**/*.style.json'],
|
||||||
|
{ eager: true }
|
||||||
|
)
|
||||||
|
const componentKeysAll = Object.keys(componentsContext)
|
||||||
const componentsMap = new Map(
|
const componentsMap = new Map(
|
||||||
componentKeysAll
|
componentKeysAll
|
||||||
.map(
|
.map(
|
||||||
key => [key, componentsContext(key).default]
|
key => [key, componentsContext[key].default]
|
||||||
).filter(([, component]) => !component.virtual && !component.notEditable)
|
).filter(([, component]) => !component.virtual && !component.notEditable)
|
||||||
)
|
)
|
||||||
exports.componentsMap = componentsMap
|
exports.componentsMap = componentsMap
|
||||||
|
|
|
||||||
|
|
@ -22,4 +22,4 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script src="./status_bookmark_folder_menu.js"></script>
|
<script src="./status_bookmark_folder_menu.js"></script>
|
||||||
<stlye src="./status_bookmark_folder_menu.scss" />
|
<style src="./status_bookmark_folder_menu.scss" />
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
import Popover from '../popover/popover.vue'
|
import Popover from '../popover/popover.vue'
|
||||||
import NavigationEntry from 'src/components/navigation/navigation_entry.vue'
|
import NavigationEntry from 'src/components/navigation/navigation_entry.vue'
|
||||||
import { mapState } from 'vuex'
|
import { mapState } from 'vuex'
|
||||||
import { ListsMenuContent } from '../lists_menu/lists_menu_content.vue'
|
import ListsMenuContent from '../lists_menu/lists_menu_content.vue'
|
||||||
import { BookmarkFoldersMenuContent } from '../bookmark_folders_menu/bookmark_folders_menu_content.vue'
|
import BookmarkFoldersMenuContent from '../bookmark_folders_menu/bookmark_folders_menu_content.vue'
|
||||||
import { library } from '@fortawesome/fontawesome-svg-core'
|
import { library } from '@fortawesome/fontawesome-svg-core'
|
||||||
import { TIMELINES } from 'src/components/navigation/navigation.js'
|
import { TIMELINES } from 'src/components/navigation/navigation.js'
|
||||||
import { filterNavigation } from 'src/components/navigation/filter.js'
|
import { filterNavigation } from 'src/components/navigation/filter.js'
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,5 @@
|
||||||
import Modal from 'src/components/modal/modal.vue'
|
import Modal from 'src/components/modal/modal.vue'
|
||||||
import { library } from '@fortawesome/fontawesome-svg-core'
|
import { library } from '@fortawesome/fontawesome-svg-core'
|
||||||
import pleromaTan from 'src/assets/pleromatan_apology.png'
|
|
||||||
import pleromaTanFox from 'src/assets/pleromatan_apology_fox.png'
|
|
||||||
import pleromaTanMask from 'src/assets/pleromatan_apology_mask.png'
|
import pleromaTanMask from 'src/assets/pleromatan_apology_mask.png'
|
||||||
import pleromaTanFoxMask from 'src/assets/pleromatan_apology_fox_mask.png'
|
import pleromaTanFoxMask from 'src/assets/pleromatan_apology_fox_mask.png'
|
||||||
|
|
||||||
|
|
@ -14,6 +12,9 @@ library.add(
|
||||||
|
|
||||||
export const CURRENT_UPDATE_COUNTER = 1
|
export const CURRENT_UPDATE_COUNTER = 1
|
||||||
|
|
||||||
|
const pleromaTan = '/static/pleromatan_apology.png'
|
||||||
|
const pleromaTanFox = '/static/pleromatan_apology_fox.png'
|
||||||
|
|
||||||
const UpdateNotification = {
|
const UpdateNotification = {
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,7 @@ const ensureFinalFallback = codes => {
|
||||||
return codeList.includes('en') ? codeList : codeList.concat(['en'])
|
return codeList.includes('en') ? codeList : codeList.concat(['en'])
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
export {
|
||||||
languages,
|
languages,
|
||||||
langCodeToJsonName,
|
langCodeToJsonName,
|
||||||
langCodeToCldrName,
|
langCodeToCldrName,
|
||||||
|
|
|
||||||
|
|
@ -9,23 +9,23 @@
|
||||||
|
|
||||||
import { isEqual } from 'lodash'
|
import { isEqual } from 'lodash'
|
||||||
import { languages, langCodeToJsonName } from './languages.js'
|
import { languages, langCodeToJsonName } from './languages.js'
|
||||||
|
import enMessages from './en.json'
|
||||||
|
|
||||||
const ULTIMATE_FALLBACK_LOCALE = 'en'
|
const ULTIMATE_FALLBACK_LOCALE = 'en'
|
||||||
|
|
||||||
const hasLanguageFile = (code) => languages.includes(code)
|
const hasLanguageFile = (code) => languages.includes(code)
|
||||||
|
|
||||||
|
const languageFileMap = import.meta.glob('./*.json')
|
||||||
|
|
||||||
const loadLanguageFile = (code) => {
|
const loadLanguageFile = (code) => {
|
||||||
return import(
|
const jsonName = langCodeToJsonName(code)
|
||||||
/* webpackInclude: /\.json$/ */
|
return languageFileMap[`./${jsonName}.json`]()
|
||||||
/* webpackChunkName: "i18n/[request]" */
|
|
||||||
`./${langCodeToJsonName(code)}.json`
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const messages = {
|
const messages = {
|
||||||
languages,
|
languages,
|
||||||
default: {
|
default: {
|
||||||
en: require('./en.json').default
|
en: enMessages
|
||||||
},
|
},
|
||||||
setLanguage: async (i18n, language) => {
|
setLanguage: async (i18n, language) => {
|
||||||
const languages = (Array.isArray(language) ? language : [language]).filter(k => k)
|
const languages = (Array.isArray(language) ? language : [language]).filter(k => k)
|
||||||
|
|
|
||||||
|
|
@ -179,9 +179,9 @@ const defaultState = {
|
||||||
}
|
}
|
||||||
|
|
||||||
const loadAnnotations = (lang) => {
|
const loadAnnotations = (lang) => {
|
||||||
|
const code = langCodeToCldrName(lang)
|
||||||
return import(
|
return import(
|
||||||
/* webpackChunkName: "emoji-annotations/[request]" */
|
`../../node_modules/@kazvmoe-infra/unicode-emoji-json/annotations/${code}.json`
|
||||||
`@kazvmoe-infra/unicode-emoji-json/annotations/${langCodeToCldrName(lang)}.json`
|
|
||||||
)
|
)
|
||||||
.then(k => k.default)
|
.then(k => k.default)
|
||||||
}
|
}
|
||||||
|
|
@ -304,7 +304,7 @@ const instance = {
|
||||||
},
|
},
|
||||||
async getStaticEmoji ({ commit }) {
|
async getStaticEmoji ({ commit }) {
|
||||||
try {
|
try {
|
||||||
const values = (await import(/* webpackChunkName: 'emoji' */ '../../static/emoji.json')).default
|
const values = (await import('/src/assets/emoji.json')).default
|
||||||
|
|
||||||
const emoji = Object.keys(values).reduce((res, groupId) => {
|
const emoji = Object.keys(values).reduce((res, groupId) => {
|
||||||
res[groupId] = values[groupId].map(e => ({
|
res[groupId] = values[groupId].map(e => ({
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import escape from 'escape-html'
|
import escape from 'escape-html'
|
||||||
import parseLinkHeader from 'parse-link-header'
|
import { parseLinkHeader } from '@web3-storage/parse-link-header'
|
||||||
import { isStatusNotification } from '../notification_utils/notification_utils.js'
|
import { isStatusNotification } from '../notification_utils/notification_utils.js'
|
||||||
import punycode from 'punycode.js'
|
import punycode from 'punycode.js'
|
||||||
|
|
||||||
|
|
@ -484,8 +484,8 @@ export const parseLinkHeaderPagination = (linkHeader, opts = {}) => {
|
||||||
const flakeId = opts.flakeId
|
const flakeId = opts.flakeId
|
||||||
const parsedLinkHeader = parseLinkHeader(linkHeader)
|
const parsedLinkHeader = parseLinkHeader(linkHeader)
|
||||||
if (!parsedLinkHeader) return
|
if (!parsedLinkHeader) return
|
||||||
const maxId = parsedLinkHeader.next.max_id
|
const maxId = parsedLinkHeader.next?.max_id
|
||||||
const minId = parsedLinkHeader.prev.min_id
|
const minId = parsedLinkHeader.prev?.min_id
|
||||||
|
|
||||||
return {
|
return {
|
||||||
maxId: flakeId ? maxId : parseInt(maxId, 10),
|
maxId: flakeId ? maxId : parseInt(maxId, 10),
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,3 @@
|
||||||
import runtime from 'serviceworker-webpack5-plugin/lib/runtime'
|
|
||||||
|
|
||||||
function urlBase64ToUint8Array (base64String) {
|
function urlBase64ToUint8Array (base64String) {
|
||||||
const padding = '='.repeat((4 - base64String.length % 4) % 4)
|
const padding = '='.repeat((4 - base64String.length % 4) % 4)
|
||||||
const base64 = (base64String + padding)
|
const base64 = (base64String + padding)
|
||||||
|
|
@ -19,7 +17,8 @@ function isPushSupported () {
|
||||||
}
|
}
|
||||||
|
|
||||||
function getOrCreateServiceWorker () {
|
function getOrCreateServiceWorker () {
|
||||||
return runtime.register()
|
const swType = process.env.HAS_MODULE_SERVICE_WORKER ? 'module' : 'classic'
|
||||||
|
return navigator.serviceWorker.register('/sw-pleroma.js', { type: swType })
|
||||||
.catch((err) => console.error('Unable to get or create a service worker.', err))
|
.catch((err) => console.error('Unable to get or create a service worker.', err))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -98,14 +97,14 @@ export async function initServiceWorker (store) {
|
||||||
|
|
||||||
export async function showDesktopNotification (content) {
|
export async function showDesktopNotification (content) {
|
||||||
if (!isSWSupported) return
|
if (!isSWSupported) return
|
||||||
const { active: sw } = await window.navigator.serviceWorker.getRegistration()
|
const { active: sw } = (await window.navigator.serviceWorker.getRegistration()) || {}
|
||||||
if (!sw) return console.error('No serviceworker found!')
|
if (!sw) return console.error('No serviceworker found!')
|
||||||
sw.postMessage({ type: 'desktopNotification', content })
|
sw.postMessage({ type: 'desktopNotification', content })
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function closeDesktopNotification ({ id }) {
|
export async function closeDesktopNotification ({ id }) {
|
||||||
if (!isSWSupported) return
|
if (!isSWSupported) return
|
||||||
const { active: sw } = await window.navigator.serviceWorker.getRegistration()
|
const { active: sw } = (await window.navigator.serviceWorker.getRegistration()) || {}
|
||||||
if (!sw) return console.error('No serviceworker found!')
|
if (!sw) return console.error('No serviceworker found!')
|
||||||
if (id >= 0) {
|
if (id >= 0) {
|
||||||
sw.postMessage({ type: 'desktopNotificationClose', content: { id } })
|
sw.postMessage({ type: 'desktopNotificationClose', content: { id } })
|
||||||
|
|
@ -116,7 +115,7 @@ export async function closeDesktopNotification ({ id }) {
|
||||||
|
|
||||||
export async function updateFocus () {
|
export async function updateFocus () {
|
||||||
if (!isSWSupported) return
|
if (!isSWSupported) return
|
||||||
const { active: sw } = await window.navigator.serviceWorker.getRegistration()
|
const { active: sw } = (await window.navigator.serviceWorker.getRegistration()) || {}
|
||||||
if (!sw) return console.error('No serviceworker found!')
|
if (!sw) return console.error('No serviceworker found!')
|
||||||
sw.postMessage({ type: 'updateFocus' })
|
sw.postMessage({ type: 'updateFocus' })
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -146,9 +146,12 @@ const getTextColorAlpha = (directives, intendedTextColor, dynamicVars, staticVar
|
||||||
}
|
}
|
||||||
|
|
||||||
// Loading all style.js[on] files dynamically
|
// Loading all style.js[on] files dynamically
|
||||||
const componentsContext = require.context('src', true, /\.style.js(on)?$/)
|
const componentsContext = import.meta.glob(
|
||||||
componentsContext.keys().forEach(key => {
|
['/src/**/*.style.js', '/src/**/*.style.json'],
|
||||||
const component = componentsContext(key).default
|
{ eager: true }
|
||||||
|
)
|
||||||
|
Object.keys(componentsContext).forEach(key => {
|
||||||
|
const component = componentsContext[key].default
|
||||||
if (components[component.name] != null) {
|
if (components[component.name] != null) {
|
||||||
console.warn(`Component in file ${key} is trying to override existing component ${component.name}! You have collisions/duplicates!`)
|
console.warn(`Component in file ${key} is trying to override existing component ${component.name}! You have collisions/duplicates!`)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ import { storage } from 'src/lib/storage.js'
|
||||||
import { parseNotification } from './services/entity_normalizer/entity_normalizer.service.js'
|
import { parseNotification } from './services/entity_normalizer/entity_normalizer.service.js'
|
||||||
import { prepareNotificationObject } from './services/notification_utils/notification_utils.js'
|
import { prepareNotificationObject } from './services/notification_utils/notification_utils.js'
|
||||||
import { createI18n } from 'vue-i18n'
|
import { createI18n } from 'vue-i18n'
|
||||||
import messages from './i18n/service_worker_messages.js'
|
import messages from 'virtual:pleroma-fe/service_worker_messages'
|
||||||
|
|
||||||
const i18n = createI18n({
|
const i18n = createI18n({
|
||||||
// By default, use the browser locale, we will update it if neccessary
|
// By default, use the browser locale, we will update it if neccessary
|
||||||
|
|
@ -139,3 +139,5 @@ self.addEventListener('notificationclick', (event) => {
|
||||||
if (clients.openWindow) return clients.openWindow('/')
|
if (clients.openWindow) return clients.openWindow('/')
|
||||||
}))
|
}))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
console.log('sw here')
|
||||||
|
|
|
||||||
135
vite.config.js
Normal file
|
|
@ -0,0 +1,135 @@
|
||||||
|
import { fileURLToPath } from 'node:url'
|
||||||
|
import { dirname, resolve } from 'node:path'
|
||||||
|
import { defineConfig } from 'vite'
|
||||||
|
import vue from '@vitejs/plugin-vue'
|
||||||
|
import vueJsx from '@vitejs/plugin-vue-jsx'
|
||||||
|
import { VitePWA } from 'vite-plugin-pwa'
|
||||||
|
import { devSwPlugin, buildSwPlugin, swMessagesPlugin } from './build/sw_plugin.js'
|
||||||
|
|
||||||
|
const getLocalDevSettings = async () => {
|
||||||
|
try {
|
||||||
|
const settings = (await import('./config/local.json')).default
|
||||||
|
if (settings.target && settings.target.endsWith('/')) {
|
||||||
|
// replacing trailing slash since it can conflict with some apis
|
||||||
|
// and that's how actual BE reports its url
|
||||||
|
settings.target = settings.target.replace(/\/$/, '')
|
||||||
|
}
|
||||||
|
console.info('Using local dev server settings (/config/local.json):')
|
||||||
|
console.info(JSON.stringify(settings, null, 2))
|
||||||
|
return settings
|
||||||
|
} catch (e) {
|
||||||
|
console.info('Local dev server settings not found (/config/local.json)', e)
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const projectRoot = dirname(fileURLToPath(import.meta.url))
|
||||||
|
|
||||||
|
export default defineConfig(async ({ command }) => {
|
||||||
|
const settings = await getLocalDevSettings()
|
||||||
|
const target = settings.target || 'http://localhost:4000/'
|
||||||
|
const proxy = {
|
||||||
|
'/api': {
|
||||||
|
target,
|
||||||
|
changeOrigin: true,
|
||||||
|
cookieDomainRewrite: 'localhost',
|
||||||
|
ws: true
|
||||||
|
},
|
||||||
|
'/nodeinfo': {
|
||||||
|
target,
|
||||||
|
changeOrigin: true,
|
||||||
|
cookieDomainRewrite: 'localhost'
|
||||||
|
},
|
||||||
|
'/socket': {
|
||||||
|
target,
|
||||||
|
changeOrigin: true,
|
||||||
|
cookieDomainRewrite: 'localhost',
|
||||||
|
ws: true,
|
||||||
|
headers: {
|
||||||
|
'Origin': target
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'/oauth': {
|
||||||
|
target,
|
||||||
|
changeOrigin: true,
|
||||||
|
cookieDomainRewrite: 'localhost'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const swSrc = 'src/sw.js'
|
||||||
|
const swDest = 'sw-pleroma.js'
|
||||||
|
|
||||||
|
return {
|
||||||
|
plugins: [
|
||||||
|
vue({
|
||||||
|
template: {
|
||||||
|
compilerOptions: {
|
||||||
|
isCustomElement(tag) {
|
||||||
|
if (tag === 'pinch-zoom') {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
vueJsx(),
|
||||||
|
devSwPlugin({ swSrc, swDest }),
|
||||||
|
buildSwPlugin({ swSrc, swDest }),
|
||||||
|
swMessagesPlugin()
|
||||||
|
],
|
||||||
|
resolve: {
|
||||||
|
alias: {
|
||||||
|
src: '/src',
|
||||||
|
components: '/src/components'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
define: {
|
||||||
|
'process.env': JSON.stringify({
|
||||||
|
NODE_ENV: command === 'serve' ? 'development' : 'production',
|
||||||
|
HAS_MODULE_SERVICE_WORKER: command === 'serve'
|
||||||
|
}),
|
||||||
|
'COMMIT_HASH': JSON.stringify('DEV'),
|
||||||
|
'DEV_OVERRIDES': JSON.stringify({})
|
||||||
|
},
|
||||||
|
build: {
|
||||||
|
sourcemap: true,
|
||||||
|
rollupOptions: {
|
||||||
|
input: {
|
||||||
|
main: 'index.html'
|
||||||
|
},
|
||||||
|
output: {
|
||||||
|
inlineDynamicImports: false,
|
||||||
|
entryFileNames (chunkInfo) {
|
||||||
|
const id = chunkInfo.facadeModuleId
|
||||||
|
if (id.endsWith(swSrc)) {
|
||||||
|
return swDest
|
||||||
|
} else {
|
||||||
|
return 'static/js/[name].[hash].js'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
chunkFileNames (chunkInfo) {
|
||||||
|
return 'static/js/[name].[hash].js'
|
||||||
|
},
|
||||||
|
assetFileNames (assetInfo) {
|
||||||
|
const name = assetInfo.names?.[0] || ''
|
||||||
|
if (/\.(png|jpe?g|gif|svg)(\?.*)?$/.test(name)) {
|
||||||
|
return 'static/img/[name].[hash][extname]'
|
||||||
|
} else if (/\.css$/.test(name)) {
|
||||||
|
return 'static/css/[name].[hash][extname]'
|
||||||
|
} else {
|
||||||
|
return 'static/misc/[name].[hash][extname]'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
server: {
|
||||||
|
proxy,
|
||||||
|
port: Number(process.env.PORT) || 8080
|
||||||
|
},
|
||||||
|
preview: {
|
||||||
|
proxy
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||