Bundle service worker conditionally

This commit is contained in:
tusooa 2025-02-28 13:29:27 -05:00
commit eb6d9cdd4b
No known key found for this signature in database
GPG key ID: 42AEC43D48433C51
4 changed files with 108 additions and 44 deletions

View file

@ -3,14 +3,20 @@ import { readFile } from 'node:fs/promises'
import { dirname, resolve } from 'node:path'
import { fileURLToPath } from 'node:url'
const i18nDir = resolve(
dirname(dirname(fileURLToPath(import.meta.url))),
'src/i18n'
)
export const i18nFiles = languages.reduce((acc, lang) => {
const name = langCodeToJsonName(lang)
const file = resolve(i18nDir, name + '.json')
acc[lang] = file
return acc
}, {})
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 msgArray = await Promise.all(Object.entries(i18nFiles).map(async ([lang, file]) => {
const fileContent = await readFile(file, 'utf-8')
const msg = {
notifications: JSON.parse(fileContent).notifications || {}

View file

@ -1,28 +1,43 @@
import { fileURLToPath } from 'node:url'
import { dirname } from 'node:path'
import { dirname, resolve } from 'node:path'
import { readFile } from 'node:fs/promises'
import { build } from 'vite'
import { generateServiceWorkerMessages } from './service_worker_messages.js'
import * as esbuild from 'esbuild'
import { generateServiceWorkerMessages, i18nFiles } from './service_worker_messages.js'
const getSWMessagesAsText = async () => {
const messages = await generateServiceWorkerMessages()
return `export default ${JSON.stringify(messages, undefined, 2)}`
}
const projectRoot = dirname(dirname(fileURLToPath(import.meta.url)))
export const devSwPlugin = ({
swSrc,
swDest,
transformSW,
alias
}) => {
const swFullSrc = resolve(projectRoot, swSrc)
const esbuildAlias = {}
Object.entries(alias).forEach(([source, dest]) => {
esbuildAlias[source] = dest.startsWith('/') ? projectRoot + dest : dest
})
return {
name: 'dev-sw-plugin',
apply: 'serve',
configResolved (conf) {
},
resolveId (id) {
const name = id.startsWith('/') ? id.slice(1) : id
if (name === swDest) {
return swSrc
return swFullSrc
}
return null
},
async load (id) {
if (id === swSrc) {
return readFile(swSrc, 'utf-8')
if (id === swFullSrc) {
return readFile(swFullSrc, 'utf-8')
}
return null
},
@ -31,27 +46,45 @@ export const devSwPlugin = ({
* 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
// }
// }
async transform (code, id) {
if (id === swFullSrc && transformSW) {
const res = await esbuild.build({
entryPoints: [swSrc],
bundle: true,
write: false,
outfile: 'sw-pleroma.js',
alias: esbuildAlias,
plugins: [{
name: 'vite-like-root-resolve',
setup (b) {
b.onResolve(
{ filter: new RegExp(/^\//) },
args => ({
path: resolve(projectRoot, args.path.slice(1))
})
)
}
}, {
name: 'sw-messages',
setup (b) {
b.onResolve(
{ filter: new RegExp('^' + swMessagesName + '$') },
args => ({
path: args.path,
namespace: 'sw-messages'
}))
b.onLoad(
{ filter: /.*/, namespace: 'sw-messages' },
async () => ({
contents: await getSWMessagesAsText()
}))
}
}]
})
const text = res.outputFiles[0].text
return text
}
}
}
}
@ -112,6 +145,9 @@ export const swMessagesPlugin = () => {
name: 'sw-messages-plugin',
resolveId (id) {
if (id === swMessagesName) {
Object.values(i18nFiles).forEach(f => {
this.addWatchFile(f)
})
return swMessagesNameResolved
} else {
return null
@ -119,8 +155,7 @@ export const swMessagesPlugin = () => {
},
async load (id) {
if (id === swMessagesNameResolved) {
const messages = await generateServiceWorkerMessages()
return `export default ${JSON.stringify(messages, undefined, 2)}`
return await getSWMessagesAsText()
}
return null
}

View file

@ -4,6 +4,9 @@ import { storage } from 'src/lib/storage.js'
import { parseNotification } from './services/entity_normalizer/entity_normalizer.service.js'
import { prepareNotificationObject } from './services/notification_utils/notification_utils.js'
import { createI18n } from 'vue-i18n'
// Collects all messages for service workers
// Needed because service workers cannot use dynamic imports
// See /build/sw_plugin.js for more information
import messages from 'virtual:pleroma-fe/service_worker_messages'
const i18n = createI18n({

View file

@ -8,6 +8,7 @@ import { VitePWA } from 'vite-plugin-pwa'
import { devSwPlugin, buildSwPlugin, swMessagesPlugin } from './build/sw_plugin.js'
import copyPlugin from './build/copy_plugin.js'
const localConfigPath = '<projectRoot>/config/local.json'
const getLocalDevSettings = async () => {
try {
const settings = (await import('./config/local.json')).default
@ -16,20 +17,38 @@ const getLocalDevSettings = async () => {
// 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(`Using local dev server settings (${localConfigPath}):`)
console.info(JSON.stringify(settings, null, 2))
return settings
} catch (e) {
console.info('Local dev server settings not found (/config/local.json)', e)
console.info(`Local dev server settings not found (${localConfigPath}), using default`, e)
return {}
}
}
const projectRoot = dirname(fileURLToPath(import.meta.url))
const getTransformSWSettings = (settings) => {
if ('transformSW' in settings) {
return settings.transformSW
} else {
console.info(
'`transformSW` is not present in your local settings.\n' +
'This option controls whether the service worker should be bundled and transformed into iife (immediately-invoked function expression) during development.\n' +
'If set to false, the service worker will be served as-is, as an ES Module.\n' +
'Some browsers (e.g. Firefox) does not support ESM service workers.\n' +
'To avoid surprises, it is defaulted to true, but this can be slow.\n' +
'If you are using a browser that supports ESM service workers, you can set this option to false.\n' +
`No matter your choice, you can set the transformSW option in ${localConfigPath} in to disable this message.`
)
return true
}
}
export default defineConfig(async ({ mode, command }) => {
const settings = await getLocalDevSettings()
const target = settings.target || 'http://localhost:4000/'
const transformSW = getTransformSWSettings(settings)
const proxy = {
'/api': {
target,
@ -60,6 +79,11 @@ export default defineConfig(async ({ mode, command }) => {
const swSrc = 'src/sw.js'
const swDest = 'sw-pleroma.js'
const alias = {
src: '/src',
components: '/src/components',
...(mode === 'test' ? { vue: 'vue/dist/vue.esm-bundler.js' } : {})
}
return {
plugins: [
@ -76,7 +100,7 @@ export default defineConfig(async ({ mode, command }) => {
}
}),
vueJsx(),
devSwPlugin({ swSrc, swDest }),
devSwPlugin({ swSrc, swDest, transformSW, alias }),
buildSwPlugin({ swSrc, swDest }),
swMessagesPlugin(),
copyPlugin({
@ -85,16 +109,12 @@ export default defineConfig(async ({ mode, command }) => {
})
],
resolve: {
alias: {
src: '/src',
components: '/src/components',
...(mode === 'test' ? { vue: 'vue/dist/vue.esm-bundler.js' } : {})
}
alias
},
define: {
'process.env': JSON.stringify({
NODE_ENV: command === 'serve' ? 'development' : 'production',
HAS_MODULE_SERVICE_WORKER: command === 'serve'
HAS_MODULE_SERVICE_WORKER: command === 'serve' && !transformSW
}),
'COMMIT_HASH': JSON.stringify('DEV'),
'DEV_OVERRIDES': JSON.stringify({})