So, I've been struggling really hard on this, been working for a long time on a big update for my app, everything runs smooth and great on development, but once I build for production some of the CSS rules are missing, some elements are not ok, colors aren't showing as they should, and flexbox seems off...
So let me start from the beginning:
Evironment:
- Vite 2.6.11
- Vue 3.2.20
- ref sugar
- Firebase Hosting
Here are my dependencies
"dependencies": {
"@ckeditor/ckeditor5-build-classic": "30.0.0",
"@ckeditor/ckeditor5-vue": "2.0.1",
"@hennge/vue3-pagination": "^1.0.17",
"@iconify/iconify": "2.0.4",
"@mapbox/mapbox-gl-geocoder": "4.7.4",
"@popperjs/core": "2.10.2",
"@vueform/multiselect": "2.2.0",
"@vueform/slider": "2.0.5",
"@vuelidate/core": "^2.0.0-alpha.21",
"@vuelidate/validators": "^2.0.0-alpha.18",
"@vueuse/core": "6.7.3",
"@vueuse/head": "0.6.0",
"animate.css": "^4.1.1",
"ant-design-vue": "^2.2.8",
"apexcharts": "3.28.3",
"axios": "0.22.0",
"billboard.js": "3.1.5",
"bulma": "0.9.3",
"bulma-css-vars": "0.7.0",
"dayjs": "1.10.7",
"dragula": "3.7.3",
"dropzone": "5.9.3",
"filepond": "4.30.3",
"filepond-plugin-file-validate-size": "2.2.5",
"filepond-plugin-file-validate-type": "1.2.6",
"filepond-plugin-image-crop": "2.0.6",
"filepond-plugin-image-edit": "1.6.3",
"filepond-plugin-image-exif-orientation": "1.0.11",
"filepond-plugin-image-preview": "4.6.10",
"filepond-plugin-image-resize": "2.0.10",
"filepond-plugin-image-transform": "3.8.7",
"firebase": "9.1.3",
"flag-icon-css": "^3.5.0",
"imask": "6.2.2",
"mapbox-gl": "2.5.0",
"markdown-it-emoji": "2.0.0",
"notyf": "3.10.0",
"nprogress": "0.2.0",
"photoswipe": "4.1.3",
"pinia": "^2.0.0-rc.15",
"pinia-plugin-persist": "^0.0.92",
"qrcode-vue3": "^1.4.17",
"simple-datatables": "3.1.2",
"simplebar": "6.0.0-beta.10",
"simplebar-vue": "2.0.0-beta.10",
"stylelint-csstree-validator": "^1.9.0",
"sweetalert2": "^10.16.7",
"tiny-slider": "2.9.3",
"tippy.js": "6.3.2",
"tslib": "2.3.1",
"v-calendar": "3.0.0-alpha.5",
"v-offline": "^3.0.0",
"vant": "^3.2.6",
"vee-validate": "4.5.4",
"vivus": "0.4.6",
"vue": "3.2.20",
"vue-accessible-color-picker": "3.0.0",
"vue-currency-input": "^2.0.1",
"vue-i18n": "9.2.0-beta.15",
"vue-router": "4.0.12",
"vue-scrollto": "2.20.0",
"vue-stripe-menu": "^2.1.1",
"vue-tippy": "6.0.0-alpha.33",
"vue-toastification": "^2.0.0-rc.1",
"vue3-apexcharts": "1.4.1",
"vue3-burger-menu": "^1.1.1",
"vue3-carousel": "^0.1.28",
"vue3-clipboard": "^1.0.0",
"vueperslides": "^3.3.2",
"xlsx": "^0.17.3",
"yup": "0.32.9"
},
"devDependencies": {
"@commitlint/cli": "13.2.0",
"@commitlint/config-conventional": "13.2.0",
"@commitlint/prompt-cli": "13.2.0",
"@iconify/json": "1.1.410",
"@intlify/vite-plugin-vue-i18n": "2.4.0",
"@types/dragula": "3.7.1",
"@types/luxon": "^1.27.1",
"@types/mapbox-gl": "2.4.2",
"@types/mapbox__mapbox-gl-geocoder": "4.7.1",
"@types/markdown-it": "12.2.1",
"@types/node": "16.10.2",
"@types/nprogress": "0.2.0",
"@types/photoswipe": "4.1.2",
"@types/prismjs": "1.16.6",
"@types/simplebar": "5.3.3",
"@types/vivus": "0.4.4",
"@typescript-eslint/eslint-plugin": "4.33.0",
"@typescript-eslint/parser": "4.33.0",
"@vitejs/plugin-vue": "1.9.3",
"@vue/compiler-sfc": "3.2.20",
"autoprefixer": "9.8.6",
"commitlint": "13.2.0",
"cross-env": "7.0.3",
"cypress": "8.5.0",
"eslint": "7.32.0",
"eslint-config-prettier": "8.3.0",
"eslint-plugin-md": "1.0.19",
"eslint-plugin-vue": "7.19.0",
"eslint-plugin-vuejs-accessibility": "^0.7.1",
"gray-matter": "4.0.3",
"lint-staged": "11.2.0",
"markdown-it": "12.2.0",
"markdown-it-anchor": "8.3.1",
"npm-run-all": "4.1.5",
"path": "^0.12.7",
"plyr": "3.6.8",
"postcss-nested": "4.2.3",
"prettier": "2.4.1",
"prismjs": "1.25.0",
"rimraf": "3.0.2",
"rollup": "2.58.3",
"rollup-plugin-purgecss": "^4.0.3",
"sass": "1.32.13",
"standard-version": "9.3.2",
"stylelint": "13.13.1",
"stylelint-config-prettier": "8.0.2",
"stylelint-config-standard": "22.0.0",
"stylelint-scss": "3.21.0",
"typescript": "4.4.3",
"unplugin-vue-components": "0.16.0",
"vfonts": "^0.1.0",
"vite": "2.6.11",
"vite-imagetools": "3.6.8",
"vite-plugin-fonts": "0.2.2",
"vite-plugin-imagemin": "0.4.6",
"vite-plugin-pages": "0.18.1",
"vite-plugin-purge-icons": "0.7.0",
"vite-plugin-pwa": "0.11.3",
"vite-plugin-radar": "0.2.0",
"vite-svg-loader": "^2.2.0",
"vue-tsc": "0.3.0",
"yorkie": "2.0.0"
}
Here is my vite.config.ts
import { defineConfig } from 'vite'
// @ts-ignore
import path from 'path'
import Vue from '@vitejs/plugin-vue'
import Pages from 'vite-plugin-pages'
import Components from 'unplugin-vue-components/vite'
import ViteFonts from 'vite-plugin-fonts'
import ViteRadar from 'vite-plugin-radar'
import PurgeIcons from 'vite-plugin-purge-icons'
import { imagetools } from 'vite-imagetools'
import ImageMin from 'vite-plugin-imagemin'
import { vueI18n } from '@intlify/vite-plugin-vue-i18n'
import { VitePWA } from 'vite-plugin-pwa'
import purgecss from 'rollup-plugin-purgecss'
import ViteComponents, {
AntDesignVueResolver,
VantResolver
} from 'unplugin-vue-components/resolvers'
const SILENT = Boolean(process.env.SILENT) ?? false
const SOURCE_MAP = Boolean(process.env.SOURCE_MAP) ?? false
/**
* This is the main configuration file for vitejs
*
* @see https://vitejs.dev/config
*/
export default defineConfig({
// Project root directory (where index.html is located).
root: process.cwd(),
// Base public path when served in development or production.
// You also need to add this base like `history: createWebHistory('my-subdirectory')`
// in ./src/router.ts
// base: '/my-subdirectory/',
base: '/',
// Directory to serve as plain static assets.
publicDir: 'public',
// Adjust console output verbosity.
logLevel: SILENT ? 'error' : 'info',
/**
* By default, Vite will crawl your index.html to detect dependencies that
* need to be pre-bundled. If build.rollupOptions.input is specified,
* Vite will crawl those entry points instead.
*
* @see https://vitejs.dev/config/#optimizedeps-entries
*/
optimizeDeps: {
include: [
'@ckeditor/ckeditor5-vue',
'@ckeditor/ckeditor5-build-classic',
'@iconify/iconify',
'@mapbox/mapbox-gl-geocoder/dist/mapbox-gl-geocoder.min.js',
'@vueuse/core',
'@vueuse/head',
'@vueform/multiselect',
'@vueform/slider',
'axios',
'billboard.js',
'dayjs',
'dropzone',
'dragula',
'filepond',
'filepond-plugin-file-validate-size',
'filepond-plugin-file-validate-type',
'filepond-plugin-image-exif-orientation',
'filepond-plugin-image-crop',
'filepond-plugin-image-edit',
'filepond-plugin-image-preview',
'filepond-plugin-image-resize',
'filepond-plugin-image-transform',
'imask',
'nprogress',
'notyf',
'mapbox-gl',
'photoswipe/dist/photoswipe',
'photoswipe/dist/photoswipe-ui-default',
'plyr',
'v-calendar',
'vee-validate',
'vue',
'vue-scrollto',
'vue3-apexcharts',
'vue-tippy',
'simplebar',
'simple-datatables',
'tiny-slider/src/tiny-slider',
'vue-accessible-color-picker',
'yup',
'ant-design-vue',
'vant'
],
},
// Will be passed to @rollup/plugin-alias as its entries option.
resolve: {
alias: [
{
find: '/~/',
replacement: `/src/assets/`,
},
{
find: '/@src/',
replacement: `/src/`,
},
],
},
build: {
sourcemap: SOURCE_MAP,
// Turning off brotliSize display can slightly reduce packaging time
brotliSize: !SILENT,
chunkSizeWarningLimit: 2000,
minify: 'esbuild',
cssCodeSplit: true,
},
plugins: [
/**
* plugin-vue plugin inject vue library and allow sfc files to work (*.vue)
*
* @see https://github.com/vitejs/vite/tree/main/packages/plugin-vue
*/
Vue({
include: [/\.vue$/],
}),
/**
* vite-plugin-vue-i18n plugin does i18n resources pre-compilation / optimizations
*
* @see https://github.com/intlify/bundle-tools/tree/main/packages/vite-plugin-vue-i18n
*/
vueI18n({
include: path.resolve(__dirname, './src/locales/**'),
}),
/**
* unplugin-vue-components plugin is responsible of autoloading components
* documentation and md file are loaded for elements and components sections
*
* @see https://github.com/antfu/unplugin-vue-components
*/
Components({
dirs: ['src/components', 'src/layouts', 'src/views'],
extensions: ['vue', 'md'],
dts: true,
include: [/\.vue$/, /\.vue\?vue/, /\.md$/],
resolvers: [
AntDesignVueResolver(),
VantResolver()
]
}),
/**
* vite-plugin-purge-icons plugin is responsible of autoloading icones from multiples providers
*
* @see https://icones.netlify.app/
* @see https://github.com/antfu/purge-icons/tree/main/packages/vite-plugin-purge-icons
*/
PurgeIcons(),
/**
* vite-plugin-fonts plugin inject webfonts from differents providers
*
* @see https://github.com/stafyniaksacha/vite-plugin-fonts
*/
ViteFonts({
google: {
families: [
{
name: 'Fira Code',
styles: 'wght@400;600',
},
{
name: 'Montserrat',
styles: 'wght@500;600;700;800;900',
},
{
name: 'Roboto',
styles: 'wght@300;400;500;600;700',
},
],
},
}),
/**
* vite-plugin-radar plugin inject snippets from analytics providers
*
* @see https://github.com/stafyniaksacha/vite-plugin-radar
*/
ViteRadar({
analytics: {
id: '',
},
}),
/**
* vite-plugin-pwa generate manifest.json and register services worker to enable PWA
*
* @see https://github.com/antfu/vite-plugin-pwa
*/
VitePWA({
registerType: 'autoUpdate',
base: '/',
includeAssets: [
'favicon.svg',
'favicon.ico',
'robots.txt',
'apple-touch-icon.png',
],
manifest: {
name: 'Treebū Admin',
short_name: 'Treebū Admin',
start_url: '/?utm_source=pwa',
display: 'standalone',
theme_color: '#ffffff',
background_color: '#ffffff',
icons: [
{
src: 'pwa-192x192.png',
sizes: '192x192',
type: 'image/png',
},
{
src: 'pwa-512x512.png',
sizes: '512x512',
type: 'image/png',
},
{
src: 'pwa-512x512.png',
sizes: '512x512',
type: 'image/png',
purpose: 'any maskable',
},
],
},
}),
/**
* rollup-plugin-purgecss plugin is responsible of purging css rules
* that are not used in the bundle
*
* @see https://github.com/FullHuman/purgecss/tree/main/packages/rollup-plugin-purgecss
*/
purgecss({
content: [`./src/**/*.vue`],
variables: false,
safelist: {
standard: [
/(autv|lnil|lnir|fas?)/,
/-(leave|enter|appear)(|-(to|from|active))$/,
/^(?!(|.*?:)cursor-move).+-move$/,
/^router-link(|-exact)-active$/,
/data-v-.*/,
],
},
defaultExtractor(content) {
const contentWithoutStyleBlocks = content.replace(
/<style[^]+?<\/style>/gi,
''
)
return (
contentWithoutStyleBlocks.match(/[A-Za-z0-9-_/:]*[A-Za-z0-9-_/]+/g) ||
[]
)
},
}),
/**
* vite-imagetools plugin allow to perform transformation (blur, resize, crop, etc)
* on images at build time
*
* @see https://github.com/JonasKruckenberg/vite-imagetools
*/
imagetools({
silent: SILENT,
}),
/**
* vite-plugin-imagemin optimize all images sizes from public or asset folder
*
* @see https://github.com/anncwb/vite-plugin-imagemin
*/
ImageMin({
verbose: !SILENT,
gifsicle: {
optimizationLevel: 7,
interlaced: false,
},
optipng: {
optimizationLevel: 7,
},
mozjpeg: {
quality: 60,
},
pngquant: {
quality: [0.8, 0.9],
speed: 4,
},
svgo: {
plugins: [
{
name: 'removeViewBox',
active: false,
},
{
name: 'removeEmptyAttrs',
active: false,
},
],
},
}),
],
})
This is my index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<!--iOS configuration-->
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="google" content="notranslate">
<!--ICONS-->
<link rel="apple-touch-icon" href="/images/mobile-icons/ios/apple-icon.png">
<link rel="apple-touch-icon" sizes="57x57" href="/images/mobile-icons/ios/apple-icon-57x57.png">
<link rel="apple-touch-icon" sizes="60x60" href="/images/mobile-icons/ios/apple-icon-60x60.png">
<link rel="apple-touch-icon" sizes="72x72" href="/images/mobile-icons/ios/apple-icon-72x72.png">
<link rel="apple-touch-icon" sizes="76x76" href="/images/mobile-icons/ios/apple-icon-76x76.png">
<link rel="apple-touch-icon" sizes="114x114" href="/images/mobile-icons/ios/apple-icon-114x114.png">
<link rel="apple-touch-icon" sizes="120x120" href="/images/mobile-icons/ios/apple-icon-120x120.png">
<link rel="apple-touch-icon" sizes="144x144" href="/images/mobile-icons/ios/apple-icon-144x144.png">
<link rel="apple-touch-icon" sizes="152x152" href="/images/mobile-icons/ios/apple-icon-152x152.png">
<link rel="apple-touch-icon" sizes="180x180" href="/images/mobile-icons/ios/apple-icon-180x180.png">
<!-- Splashscreen-->
<link href="/images/splashscreens/iphone5_splash.png" media="(device-width: 320px) and (device-height: 568px) and (-webkit-device-pixel-ratio: 2)" rel="apple-touch-startup-image" />
<link href="/images/splashscreens/iphone6_splash.png" media="(device-width: 375px) and (device-height: 667px) and (-webkit-device-pixel-ratio: 2)" rel="apple-touch-startup-image" />
<link href="/images/splashscreens/iphoneplus_splash.png" media="(device-width: 621px) and (device-height: 1104px) and (-webkit-device-pixel-ratio: 3)" rel="apple-touch-startup-image" />
<link href="/images/splashscreens/iphonex_splash.png" media="(device-width: 375px) and (device-height: 812px) and (-webkit-device-pixel-ratio: 3)" rel="apple-touch-startup-image" />
<link href="/images/splashscreens/iphonexr_splash.png" media="(device-width: 414px) and (device-height: 896px) and (-webkit-device-pixel-ratio: 2)" rel="apple-touch-startup-image" />
<link href="/images/splashscreens/iphonexsmax_splash.png" media="(device-width: 414px) and (device-height: 896px) and (-webkit-device-pixel-ratio: 3)" rel="apple-touch-startup-image" />
<link href="/images/splashscreens/ipad_splash.png" media="(device-width: 768px) and (device-height: 1024px) and (-webkit-device-pixel-ratio: 2)" rel="apple-touch-startup-image" />
<link href="/images/splashscreens/ipadpro1_splash.png" media="(device-width: 834px) and (device-height: 1112px) and (-webkit-device-pixel-ratio: 2)" rel="apple-touch-startup-image" />
<link href="/images/splashscreens/ipadpro3_splash.png" media="(device-width: 834px) and (device-height: 1194px) and (-webkit-device-pixel-ratio: 2)" rel="apple-touch-startup-image" />
<link href="/images/splashscreens/ipadpro2_splash.png" media="(device-width: 1024px) and (device-height: 1366px) and (-webkit-device-pixel-ratio: 2)" rel="apple-touch-startup-image" />
<!--Status Bar-->
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<meta name="theme-color" content="#2f3048">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<meta content="initial-scale=1.0, maximum-scale=1.0, width=device-width, user-scalable=no, shrink-to-fit=no" name="viewport">
<link
rel="apple-toucv-icon"
sizes="180x180"
href="/icons/apple-touch-icon.png"
/>
<link
rel="icon"
type="image/png"
sizes="32x32"
href="/icons/favicon-32x32.png"
/>
<link
rel="icon"
type="image/png"
sizes="16x16"
href="/icons/favicon-16x16.png"
/>
<link rel="mask-icon" href="/icons/safari-pinned-tab.svg" color="#5bbad5" />
<meta name="msapplication-TileColor" content="#232326" />
<!-- <meta name="theme-color" content="#ffffff" />-->
<title>Treebū Hotels</title>
<script>
/**
* this is a hack for dragula used on KanbanApp
*
* @see src/components/pages/apps/KanbanApp.vue
*/
var global = global || window
</script>
<link
rel="preload"
as="style"
onload="this.rel='stylesheet'"
href="/vendors/font-awesome-v5.css"
/>
<link
rel="preload"
as="style"
onload="this.rel='stylesheet'"
href="/vendors/line-icons-pro.css"
/>
<link
rel="preload"
as="style"
onload="this.rel='stylesheet'"
href="/vendors/prism-coldark-cold.css"
/>
</head>
<body>
<div data-teleport-bg></div>
<div id="app" class="app-wrapper"></div>
<script type="module" src="/src/styles.ts"></script>
<script type="module" src="/src/main.ts"></script>
</body>
</html>
Please note the differences in the following images between the dev version and the production version:
Dev Version:
As you can see there is a mismatch in styles... lets continue:
Dev version, flexbox working correctly:

There are no warnings or errors on console on the build version,
I have tried removing antd, vant, and other custom css styles, just in case there is some conflict, but I get the same result, also tried with
minify: 'esbuild', // or false
cssCodeSplit: true, //or false
In the vite.config
Everything works perfectly on development but it's just messed up on build.
Any hints? ideas? possibilities? chances?
Thanks in advance!.



