Vuetify CSS 在我为生产构建时丢失

Vuetify CSS missing when i build for production

我们从某人那里购买了一个用 Vue 编写的 Web 应用程序,我们正在开发它 change/improve。我们添加的一件事是 Vuetify,因此我们可以使用 Vuetify 元素,并且在开发模式下一切都运行良好,但是当我们为生产构建时,缺少 Vuetify 元素的 CSS。

我已经在网上搜索过了,并且已经尝试了大家的建议,但没有成功。

任何人都知道可能出了什么问题以及为什么 npm 运行 build 会缺少一些 CSS?

奇怪的是 Vue 元素的所有 UI 功能都运行良好,只是缺少 CSS。

请参阅下面的代码示例。

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"
  }
}

很难理解哪里缺少了什么。如果您认为缺少,请尝试从 cdn 将 css 添加到 HTML 文件并检查工作情况。

<link href="https://cdn.jsdelivr.net/npm/vuetify@2.x/dist/vuetify.min.css" rel="stylesheet">

我看到你使用的是webpack来编译代码。所以,这也可能与 webpack 配置有关。在你的 webpack 规则中,你有 css 和 scss 的规则吗?因为 vuetify 文件在 scss.

当我做这些类型的马戏团时,我的 webpack 配置如下。

--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'`,
          ];
        }
      },
    }),
  ],
}

检查一下你的postcss.config.js,看看是不是跟purgecss有关。 您必须配置白名单以忽略 vuetify 样式。 这里有一个示例供您参考:

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
    ]
}``

您只是缺少 main.js 中的一个包含(请参阅 vuetify docs):

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

这将确保 webpack 在捆绑的 CSS 中包含 vuetify 样式以用于生产。这为我解决了同样的问题(即它在本地有效但在生产中无效)。