Hello guys!!
Currently as a tech lead I got task of optimizing Vite App which was also using vue and inertia. I read many blogs but they all were either made for webpack or didn't made reasonable output,
After lot of research I had implemented some solutions which you must use.
Vite is awesome tool for bundling which already implements multiple strategies like chunking, versioning, compression for optimizing you app, so we can save some hard work.
Hence, if you are not using Vite you must look forward for new technology.
In my case the project was already big enough so the code written by different developers wasn't implementing ways to decrease load of app.
So for summary here's what I'm going to implement
- Common bundle for legacy packages.
- API defer.
- Third party script async and defer.
- Vite plugins.
Let's discuss them in detail
1. Common bundle for legacy packages.
- Vite already separates pages and components into different bundles which you can see in network tab but some of those bundles are still size heavy, hence take much time.
- Vite also implements versioning so each time you release new version users have to download those heavy bundles again.
- Also they have to download images again. All this effort can be saved with browser cache.
Only thing is you must know what to put in browser cache and what not.- For suggestion, you may choose all images to not included in versioning.
- And for packages which you may choose legacy packages like moment and package you will not update in coming years.
- Although it's not suggested to use legacy packages but in reality for large or legacy project it's not an easy job.
- You can also identify big chunks or packages from visualizer plugin of Vite, link given below.
- Here's the code you can attach in vite.config.js for having more control over versioning.
build: {
rollupOptions: {
output: {
entryFileNames: `assets/[name]-[hash].js`,
assetFileNames: (assetInfo) => {
// Get the name from the array of names (usually the first/only entry)
const fileName = assetInfo.names?.[0] ?? '';
if (/\.(png|jpg|jpeg|gif|svg|webp)$/.test(fileName)) {
return `images/[name][extname]`;
}
return `css/[name]-[hash][extname]`;
},
chunkFileNames: (chunkInfo) => {
const is_manual_chunk = ['core', 'chart', 'quill', 'datepicker', 'moment', 'jsoneditor'].some(el => chunkInfo.name.startsWith(el));
if (is_manual_chunk) {
return `js/[name].js`;
}
return `js/[name]-[hash].js`;
},
manualChunks: {
core: ['vue', '@inertiajs/vue3', '@sentry/vue'],
chart: ['@j-t-mcc/vue3-chartjs', 'chart.js'],
quill: ['@vueup/vue-quill'],
datepicker: ['@vuepic/vue-datepicker'],
jsoneditor: ['@json-editor/json-editor'],
moment: ['moment', 'moment-timezone', 'moment-duration-format']
},
},
},
},
2. API defer.
- This second step looks so easy but brings a great difference to app load. All you have to do load important API's first and non-important API's at last.
- For the API's which you wanna load first, call them from created hook or setup initial lines in vue3 of layout file.
- A bad approach would be to call it from entry-file because it blocks app mounting, but you may use it if necessary.
- The API's which you wanna load in last, keep them in
defineAsyncComponentin vue. For react you can use async component via composition but it's difficult so react lover please give some suggestion in comment. - The API's you wanna load in between, try to put them in mounted or useEffect hook part not created hook or directly in script part.
- Try to use less API call, as it will take some time to go through DNS, then server, then firewall, then your code Middlewares and with some extra code dependencies. In my case I combined multiple API into initial-data API.
3. Third party script async and defer.
- Your project may be using third party scripts in main HTML element like google analytics, chat plugin etc.
- If you define this scripts in head section then they will block further scripts and load first which is not needed at all. If your user can't interact with app quickly what's the point of all other tools.
- Try to use these scripts in bottom body part instead of head section.
- Now we have to decide between defer and acync script for those who don't know defer will call your script after page loads and async will load script in parallel thread non-blocking you main app JS.
- In my case I used async for loading third party scripts
<script async src="https://www.googletagmanager.com/gtag/js?id=G-DNJN1PF3CS"></script>
- and defer for executing those script
<script defer>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'G-XXXXXXX');
</script>
4. Vite plugins.
Vite provides various other packages to enhance your app. some of the packages I will mention here with link so you can read in detail about them, if you know others please mention them in comment
ViteCompression from "vite-plugin-compression"
VitePWA from "vite-plugin-pwa"
Visualizer from "rollup-plugin-visualizer"
pluginUnused from "@gatsbylabs/vite-plugin-unused"
AutoImport from "unplugin-vue-components/vite"- Also please try to use import.meta.env
5. Optimize Inertia, if you use it
Last but not the least tip, if you use Inertia, please don't make HandleInertiaMiddleware heavy, either store and load the data in session if necessary, else keep it lightweight.
Thanks for read and Have a great day. ❤️
Please give your love and support to this post.
SOCIAL SHARE CARD GENERATOR