Skip to content

Commit

Permalink
perf: code-split the application (#2456)
Browse files Browse the repository at this point in the history
Code-split the application (but without lazy loading, aka dynamic imports aka async modules, so all the assets are loaded on app load, not when requested: this is needed for ensuring an smooth experience over slow networks)

Lighthouse performance score went from 66 to 77

There's still a lot of work to do, but this is a good start.

Signed-off-by: Fernando Fernández <[email protected]>
  • Loading branch information
ferferga authored Sep 9, 2024
1 parent ef55e26 commit cf82a14
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 27 deletions.
4 changes: 2 additions & 2 deletions frontend/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-capable" content="yes">
<title>Jellyfin Vue</title>
<script type="module" src="src/splashscreen.ts"></script>
<script type="module" src="src/splashscreen.ts" fetchpriority="high"></script>
<script type="module" src="src/main.ts"></script>
</head>
<body class="j-splash">
<img src="./icon.svg" alt="Jellyfin Logo" loading="eager" decoding="async">
<img src="./icon.svg" alt="Jellyfin Logo" loading="eager" decoding="sync">
</body>
</html>
44 changes: 44 additions & 0 deletions frontend/scripts/plugins/chunking.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import type { Plugin } from 'vite';

/**
* Creates the Rollup's chunking strategy of the application (for code-splitting)
*/
export function JellyfinVueChunking(): Plugin {
return {
name: 'Jellyfin_Vue:chunking',
config: () => ({
build: {
rollupOptions: {
output: {
/**
* This is the first thing that should be debugged when there are issues
* withe the bundle. Check these issues:
* - https://github.com/vitejs/vite/issues/5142
* - https://github.com/evanw/esbuild/issues/399
* - https://github.com/rollup/rollup/issues/3888
*/
manualChunks(id) {
const match = /node_modules\/([^/]+)/.exec(id)?.[1];

if (id.includes('virtual:locales') || ((id.includes('vuetify') || id.includes('date-fns')) && id.includes('locale'))) {
return 'localization/meta';
}

if (id.includes('@intlify/unplugin-vue-i18n/messages')
) {
return 'localization/messages';
}

/**
* Split each vendor in its own chunk
*/
if (match) {
return `vendor/${match.replace('@', '')}`;
}
}
}
}
}
})
};
}
2 changes: 1 addition & 1 deletion frontend/src/components/lib/JSplashscreen.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
src="./icon.svg"
alt="Jellyfin Logo"
loading="eager"
decoding="async">
decoding="sync">
<JTransition
name="slide-y-reverse"
appear>
Expand Down
29 changes: 5 additions & 24 deletions frontend/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,15 @@ import { defineConfig } from 'vite';
import { entrypoints, localeFilesFolder, srcRoot } from './scripts/paths';
import virtualModules from './scripts/virtual-modules';
import { JellyfinVueAnalysis } from './scripts/plugins/analysis';
import { JellyfinVueChunking } from './scripts/plugins/chunking';

export default defineConfig({
appType: 'spa',
base: './',
cacheDir: '../node_modules/.cache/vite',
plugins: [
JellyfinVueAnalysis(),
JellyfinVueChunking(),
Virtual(virtualModules),
VueRouter({
dts: './types/global/routes.d.ts',
Expand Down Expand Up @@ -64,7 +66,8 @@ export default defineConfig({
compositionOnly: true,
fullInstall: false,
forceStringify: true,
include: localeFilesFolder
include: localeFilesFolder,
dropMessageCompiler: true
}),
UnoCSS(),
VueDevTools()
Expand All @@ -77,7 +80,6 @@ export default defineConfig({
/**
* Disable chunk size warnings
*/
chunkSizeWarningLimit: Number.NaN,
cssCodeSplit: true,
cssMinify: 'lightningcss',
modulePreload: false,
Expand All @@ -89,28 +91,7 @@ export default defineConfig({
index: entrypoints.index
},
output: {
chunkFileNames: (chunkInfo) => {
/**
* This is the default value: https://rollupjs.org/configuration-options/#output-chunkfilenames
*/
return chunkInfo.name === 'validation' ? 'assets/common-[hash].js' : '[name]-[hash].js';
},
validate: true,
/**
* This is the first thing that should be debugged when there are issues
* withe the bundle. Check these issues:
* - https://github.com/vitejs/vite/issues/5142
* - https://github.com/evanw/esbuild/issues/399
* - https://github.com/rollup/rollup/issues/3888
*/
manualChunks(id) {
if (
id.includes('virtual:locales')
|| id.includes('@intlify/unplugin-vue-i18n/messages')
) {
return 'assets/locales';
}
}
validate: true
}
}
},
Expand Down

0 comments on commit cf82a14

Please sign in to comment.