2

We purchased a web app written in Vue from someone and we developing to change/improve it. One thing we added was Vuetify so we can use the Vuetify elements and everything has been working great while in development mode, but when we build for production the CSS for Vuetify elements is missing.

I have searched for this online already and have already tried what everybody is suggesting without any luck.

Anybody has an idea of what could be wrong and why npm run build would be missing some of the CSS?

What's weird is that all the UI functionality for Vue elements is working perfectly, just the CSS is missing.

Please see code samples below.

main.js:

import '@fortawesome/fontawesome-free/css/all.css'
import Vue from "vue";
import App from "./App.vue";
import VueMoment from "vue-moment";
import VueAnalytics from "vue-analytics";
import VueMeta from "vue-meta";
import { library } from "@fortawesome/fontawesome-svg-core";
import {
  faCoffee,
  faPlusCircle,
  faChartLine,
  faChevronDown,
  faMobile,
  faEnvelope,
  faClock,
  faUsers,
  faPaperPlane,
  faCheckCircle,
  faCheck,
  faLeaf,
} from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
import axios from "axios";
import router from "./router";
import store from "./store";
import vuetify from './plugins/vuetify';
import Vuetify from 'vuetify/lib'

library.add([
  faCoffee,
  faPlusCircle,
  faChartLine,
  faChevronDown,
  faMobile,
  faEnvelope,
  faClock,
  faUsers,
  faPaperPlane,
  faCheckCircle,
  faCheck,
  faLeaf,
]);

Vue.use(VueAnalytics, {
  id: "xxx",
  router,
});
Vue.use(VueMoment);
Vue.use(VueMeta);
Vue.component("font-awesome-icon", FontAwesomeIcon);

Vue.use(Vuetify)

axios.interceptors.response.use(undefined, async function (error) {
  if (error.response.status === 401) {
    await store.dispatch("auth/logout");
    router.push("/login");
  }
  return Promise.reject(error);
});

// Plugins
// ...

// Sass file
require("./assets/styles/main.css");

Vue.config.productionTip = false;

new Vue({
  router,
  store,
  vuetify,
  render: (h) => h(App)
}).$mount("#app");

App.vue:

<template>
  <v-app>

    <v-main>
      <router-view/>
    </v-main>
  </v-app>
</template>

<style>
  .text-white {
      color: #fff !important;
  }

  .text-gray-600 {
    color: #757575 !important;
  }

  .font-semibold, .text-gray-700 {
    color: #616161 !important;
  }
</style>

package.json:

{
  "name": "reviewgrower-spa",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "serve": "vue-cli-service serve",
    "build": "vue-cli-service build",
    "lint": "vue-cli-service lint",
    "deploy": "git push dokku master"
  },
  "dependencies": {
    "@fortawesome/fontawesome-svg-core": "^1.2.25",
    "@fortawesome/free-solid-svg-icons": "^5.11.2",
    "@fortawesome/vue-fontawesome": "^0.1.8",
    "@fullhuman/postcss-purgecss": "^1.3.0",
    "axios": "^0.19.0",
    "chart.js": "^2.9.4",
    "core-js": "^2.6.10",
    "i": "^0.3.6",
    "jquery": "^3.5.1",
    "npm": "^6.13.0",
    "tailwindcss-spinner": "^0.2.0",
    "tailwindcss-toggle": "github:TowelSoftware/tailwindcss-toggle",
    "url-parse": "^1.4.7",
    "vue": "^2.6.10",
    "vue-analytics": "^5.17.2",
    "vue-chartjs": "^3.5.1",
    "vue-click-outside": "^1.0.7",
    "vue-clickaway": "^2.2.2",
    "vue-feather-icons": "^4.22.0",
    "vue-js-toggle-button": "^1.3.3",
    "vue-meta": "^1.6.0",
    "vue-moment": "^4.0.0",
    "vue-router": "^3.1.3",
    "vue-stripe-elements-plus": "^0.2.10",
    "vuetify": "^2.4.0",
    "vuex": "^3.0.1",
    "vuex-persist": "^2.1.1"
  },
  "devDependencies": {
    "@fortawesome/fontawesome-free": "^5.15.2",
    "@vue/cli-plugin-babel": "^3.12.1",
    "@vue/cli-plugin-eslint": "^3.12.1",
    "@vue/cli-service": "^3.12.1",
    "babel-eslint": "^10.0.3",
    "eslint": "^5.16.0",
    "eslint-plugin-vue": "^5.2.3",
    "sass": "^1.32.0",
    "sass-loader": "^7.1.0",
    "tailwindcss": "^1.1.3",
    "vue-cli-plugin-vuetify": "~2.1.0",
    "vue-template-compiler": "^2.5.21",
    "vuetify-loader": "^1.7.0"
  }
}
2
  • This is going to be impossible to troubleshoot without either code from your nuxt config and package.json, or a sample of your codebase so people can figure out what could be wrong. Commented Feb 19, 2021 at 14:28
  • Thank you for the suggestion. I'm not using nuxt. Added code from main.js, App.vue and package.json. Commented Feb 19, 2021 at 14:39

3 Answers 3

3

It's a little tough to understand what is missing where. If you think that is just missing then please try adding css onto the HTML file from the cdn and check the working.

<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/vuetify.min.css" rel="stylesheet">

I see that you are using webpack to compile the code. So, this could be also something related to webpack configuration. In your webpack rules do you have rules for css and scss. Because vuetify files are in scss.

My webpack configuration is as below when I do these type of circus.

--webpack.config.js--
const path = require("path");

const VuetifyLoaderPlugin = require("vuetify-loader/lib/plugin");
const { VueLoaderPlugin } = require("vue-loader");

module.exports = {
watch: true,
entry: {
 main: 'main.js'
},
module: {
    rules: [
      {
        test: /\.css$/i,
        use: ["style-loader", "css-loader"],
      },
      {
        test: /\.vue$/,
        use: "vue-loader",
      },
      {
        test: /\.s(c|a)ss$/,
        use: [
          "vue-style-loader",
          "css-loader",
          {
            loader: "sass-loader",
            // Requires sass-loader@^8.0.0
            // options: {
            //   implementation: require('sass'),
            //   sassOptions: {
            //     fiber: require('fibers'),
            //     indentedSyntax: true // optional
            //   },
            // },
          },
        ],
      },
    ],
  },
  plugins: [
    new VueLoaderPlugin(),
    new VuetifyLoaderPlugin({
      /**
       * This function will be called for every tag used in each vue component
       * It should return an array, the first element will be inserted into the
       * components array, the second should be a corresponding import
       *
       * originalTag - the tag as it was originally used in the template
       * kebabTag    - the tag normalised to kebab-case
       * camelTag    - the tag normalised to PascalCase
       * path        - a relative path to the current .vue file
       * component   - a parsed representation of the current component
       */
      match(originalTag, { kebabTag, camelTag, path, component }) {
        if (kebabTag.startsWith("core-")) {
          return [
            camelTag,
            `import ${camelTag} from '@/components/core/${camelTag.substring(
              4
            )}.vue'`,
          ];
        }
      },
    }),
  ],
}
Sign up to request clarification or add additional context in comments.

1 Comment

Anees, dude.. you are a life saver! The CDN solution worked perfectly for me. Thank you very much! Everything looks great now, no CSS is missing. I appreciate your help.
1

Check your postcss.config.js, see if it has something to do with the purgecss. You have to config the whitelist to ignore the vuetify styles. Here is a sample for your reference:

const autoprefixer = require("autoprefixer");
const postcssImport = require("postcss-import");
const purgecss = require("@fullhuman/postcss-purgecss");
const IS_PROD = ["production", "prod"].includes(process.env.NODE_ENV);
let plugins = [];
if (IS_PROD) {
  plugins.push(postcssImport);
  plugins.push(
    purgecss({
      content: [
        "./src/**/*.vue",
        "./public/**/*.html",
        `./node_modules/vuetify/src/**/*.ts`,
        `./node_modules/vuetify/dist/vuetify.css`
      ],
      defaultExtractor (content) {
        const contentWithoutStyleBlocks = content.replace(/<style[^]+?<\/style>/gi, '')
        return contentWithoutStyleBlocks.match(/[A-Za-z0-9-_/:]*[A-Za-z0-9-_/]+/g) || []
      },
        safelist: [ /-(leave|enter|appear)(|-(to|from|active))$/, /^(?!(|.*?:)cursor-move).+-move$/, /^router-link(|-exact)-active$/, /data-v-.*/ ],

        whitelist: [
            'container',
            'row',
            'spacer',
            'aos-animate',
            'col',
            '[type=button]',
            'v-application p',
          ],
          whitelistPatterns: [
            /^v-.*/,
            /^col-.*/,
            /^theme-.*/,
            /^rounded-.*/,
            /^data-aos-.*/,
            /^(red|grey)--text$/,
            /^text--darken-[1-4]$/,
            /^text--lighten-[1-4]$/
          ],
          whitelistPatternsChildren: [
            /^post-content/,
            /^v-input/,
            /^swiper-.*/,
            /^pswp.*/,
            /^v-text-field.*/,
            /^v-progress-linear/
          ]
    })
  );
}

module.exports = {
    plugins:[
        require('cssnano')({
            preset: 'default'
        }),
        require('postcss-pxtorem')({
            remUnit:15, //每个rem对应的px值
            threeVersion:true
        }),
        ...plugins,autoprefixer
    ]
}``

Comments

-2

You are simply missing an include in your main.js (see vuetify docs):

import 'vuetify/dist/vuetify.min.css'

This will ensure that webpack includes the vuetify styles in the bundled CSS for production. This fixed the same issue for me (i.e. it worked locally but not in production).

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.