vitejs / vite

Next generation frontend tooling. It's fast!
http://vitejs.dev
MIT License
67.36k stars 6.06k forks source link

Vue3 + Vite CSS styles are different in development and production #14780

Closed fanatII1 closed 10 months ago

fanatII1 commented 11 months ago

Describe the bug

I have a Vue 3 app bundle by Vite. I have a simple Homepage with styles for the homepage defined in the Home.vue,and global styles defined in the main.css file which is in (src/assets/main.css):

The problem i am facing is, the homepage that i have styled in development looks very different in production(the styling is different)

Here's how the site looks in development: dev image

and here's how it looks in producition: prod image

the repo can be found here: repo link

As you can see the development has the correct styles(perfect grid and elements are not overflowing): I don't know where the problem lies but heres my code.


vite.config.js:

import { fileURLToPath, URL } from 'node:url'

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    vue(),
  ],
  resolve: {
    alias: {
      '@': fileURLToPath(new URL('./src', import.meta.url))
    }
  },
  build: {
    // minify: false,
    cssCodeSplit: false,
    // modulePreload: false,
  }
})```

Home.vue: (dont mind the data fetching and all in the , its just text and images rendered from an api):

```<script setup>
import { ref, computed, onBeforeMount, onMounted } from 'vue';
import router from '../../router';
import { useArticlesStore } from '../../stores/articles.js';
import { client } from '../../contentful';

const articlesStore = useArticlesStore();
const spaceID = import.meta.env.VITE_SPACE_ID;
const environmentID = import.meta.env.VITE_ENVIRONMENT_ID;

const blogPoll = ref([])
const selectedAnswer = ref(null);
const selectedPoll = ref(null);
const latestFourArticles = ref([]);
let categoryVotes = ref(0)

const displayedArticles = computed(() => {
  return articlesStore.searchedArticles.length > 0
    ? articlesStore.searchedArticles
    : articlesStore.articles;
});

function voteCountPercentage(updatedEntry, selectedCategory){
    console.log(selectedCategory)
    let votes = 0;
    if(selectedCategory === 'developers') {
        updatedEntry.Developers.options.forEach(entry => votes += entry.votes)
    }
    else if(selectedCategory === 'gaming') {
        updatedEntry.Gaming.options.forEach(entry => votes += entry.votes)
    }
    else {
        updatedEntry.Tech.options.forEach(entry => votes += entry.votes)
    }
    categoryVotes.value = votes;
}

//here we update the votes of a selected answer by:
//1. getting the selected answer(option) by id
//2. updating its vote number by 1(+1)
//3. and based on the selected answers category(provided on the pollEntry variable(object) e.g Developers, Gaming, Tech), we update the poll answer(option
// * and OPTIONALLY, we set the width of the selected poll(by percentage) for styling purposes
function selectAnswer(answerID, answerIndex, pollID, question, answer, poll) {
  selectedAnswer.value = answerID;
  selectedPoll.value = pollID;
  let selectedCategory;

  //we get the selected topic by using the object answer ...in array
  client.getSpace(spaceID)
 .then((space) => space.getEnvironment('master'))
  .then((environment) => environment.getEntry(environmentID))
  .then((entry) => {
    let pollEntry = entry.fields.poll['en-US'];
    let pollEntryCategoryToUpdate = pollEntry.Developers.question === poll.question ? pollEntry.Developers : pollEntry.Gaming.question === poll.question ? pollEntry.Gaming : pollEntry.Tech;
    let selectedPollEntryToUpdate = pollEntryCategoryToUpdate.options[answerIndex];
    selectedPollEntryToUpdate.votes = selectedPollEntryToUpdate.votes + 1;

    if(pollEntry.Developers.question === pollEntryCategoryToUpdate.question){
        // console.log('developers')
        // console.log(entry.fields.poll['en-US'])
        selectedCategory = 'developers';
        entry.fields.poll['en-US'].Developers.options[answerIndex] = selectedPollEntryToUpdate;
    } else if (pollEntry.Gaming.question === pollEntryCategoryToUpdate.question) {
        selectedCategory = 'gaming';
        entry.fields.poll['en-US'].Gaming.options[answerIndex] = selectedPollEntryToUpdate;
    } else {
        selectedCategory = 'tech';
        entry.fields.poll['en-US'].Tech.options[answerIndex] = selectedPollEntryToUpdate;
    }

    return entry.update()
  })
  .then((entry) => {
    entry.publish();
    console.log(`Entry ${entry.sys.id} updated.`)
    console.log(entry)
    const updatedEntry = entry.fields.poll['en-US'];
    voteCountPercentage(updatedEntry, selectedCategory)
  })

}

function fetchArticle(id) {
    router.push(`/read-article/${id}`)
}

onBeforeMount(() => {
    articlesStore.clearSearchArticles();
})

//fetch all articles from CMS
onMounted(async () => {
    const art = await articlesStore.fetchAllArticles();
    const pollQuestions = articlesStore.pollQuestions.poll;
    const { Developers, Gaming, Tech } = pollQuestions;

    const poll = [Developers, Gaming, Tech];
    blogPoll.value = poll;
    const fourArticles = art.filter((article) => article.id > 1);
    latestFourArticles.value = fourArticles
})
</script>

<template>
  <Navbar/>  
  <main id="home-wrapper">
    <!-- LATEST 5 ARTICLES / Top of the month -->
    <section id="latest-articles">
        <div class="main-latest">
          <div class="overlay"></div>
          <img :src="articlesStore.articles[0].img" alt="" class="article-image">
          <p class="title main-title">{{ articlesStore.articles[0].title }}</p>  
        </div>
        <div class="sub-latest" v-if="articlesStore.articles.length  > articlesStore.articles.length - 1">
            <div class="sub-article" v-for="(article, index) in latestFourArticles">
                <div class="overlay"></div>
                <img :src="article.img ? article.img : ''" alt="" class="latest-article-img">
                <p class="title">{{ article.title }}</p> 
                <p class="article-date">{{ article.date }}</p>
            </div>
        </div>
    </section>

    <div id="heading-wrapper">
       <h2 id="new-articles-heading">New Articles</h2>
       <div class="heading-underline"></div>
    </div>

    <!-- NEW ARTICLES -->
    <section class="all-new-articles">
      <div class="new-article" v-for="article in displayedArticles" @click="fetchArticle(article.id)">
        <img :src="article.img" alt="" class="new-article-img">
        <p class="new-article-title"><span class="span-new-article-title">{{ article.title }}</span></p>
        <p class="date">{{ article.date }}</p>
        <p
          :class="{
            category: true,
            developers: article.category === 'Developers',
            gaming: article.category === 'Gaming',
            tech: article.category === 'Tech'
          }"
        >
          {{ article.category }}
        </p>
      </div>
    </section>

    <div id="heading-wrapper">
       <h2 id="new-articles-heading">POLL'S</h2>
       <div class="heading-underline"></div>
    </div>

    <!-- POLL -->
    <section id="poll">
        <div class="poll-area" v-for="(poll, index) in blogPoll">
            <p class="poll-question">{{ poll.question }}</p>
            <div class="opt" v-for="answer, answerIndex in poll.options" @click="selectAnswer(answer.id, answerIndex,  poll.id, poll.question, answer.answer, poll)">
              <div
               id="percentage"
               v-if="answer.id === selectedAnswer && poll.id === selectedPoll"
               :style="{ 'width' : answer.votes * 100 / categoryVotes + '%' }"
               >
            </div>
              <p class="option-name">{{ answer.answer }}</p>
            </div>
        </div>
    </section>
  </main>
</template>

<style lang="scss" scoped>
#home-wrapper {
    height: 100%;
    overflow: scroll;
}

#home-wrapper::-webkit-scrollbar {
    width: 3px;
    background-color: none;
}

#home-wrapper::-webkit-scrollbar-thumb {
    background-color: #ed1d3c41;
    border-radius: 2px;
}

#latest-articles {
    height: 55%;
    display: flex;
}

.article-image {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.main-latest {
    position: relative;
    width: 50%;
    cursor: pointer;
    transition: .4s;
    overflow: hidden;
}

.main-latest:hover, .main-latest img {
    transform: scale(1.008);
}

.overlay{
    position: absolute;
    left: 0;
    top: 0;
    width: 100%;
    height: 100%;
    background: #ed1d3b;
    background: -webkit-linear-gradient(181deg, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0) 50%, #ed1d3cad 100%);
    background: linear-gradient(181deg, rgba(255, 255, 255, 0) 0%, rgba(255, 255, 255, 0) 50%, #ed1d3cad);
    z-index: 2;
}

.sub-latest{
    display: grid;
    grid-template-columns: 50% 50%;
    grid-template-rows: 50% 50%;
    height: 100%;
    width: 50%;
    overflow: hidden;
    cursor: pointer;
}

.sub-article{
    position: relative;
    overflow: hidden;
    transition: .4s;
}

.sub-article:hover, .sub-article img {
    transform: scale(1.02);
}

.title{
    position: absolute;
    bottom: 0;
    z-index: 3;
    margin: 0 0 5% 3%;
    font-weight: 600;
    font-size: 1.15rem;
    color: #fff;
}

.article-date{
    position: absolute;
    bottom: 0;
    z-index: 3;
    margin: 0 0 1% 3%;
    font-size: 0.7rem;
    color: #fff;
}

.main-title{
    font-size: 2.5rem;
}

#heading-wrapper{
    display: flex;
    justify-content: center;
    align-items: center;
    flex-direction: column;
}

.heading-underline {
    height: 5px;
    width: 15%;
    background-color: #ed1d3b;
}

.all-new-articles {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(300px, 350px));
    grid-auto-rows: 100%;
    justify-content: center;
    gap: 2%;
    height: 40%;
    max-height: 850px;
    margin: 3% 0;
    overflow: scroll;
}

.all-new-articles::-webkit-scrollbar {
    width: 0;
    background-color: none;
}

.all-new-articles::-webkit-scrollbar-thumb {
    background-color: #ed1d3c41;
    border-radius: 2px;
}

.new-article{
    height: 100%;
    background-color: #0f1010;
    color: #fff;
    border: 1px solid #ed1d3b;
    -webkit-box-shadow: 0 0 11px 1.5px #ed1d3b;
    -moz-box-shadow: 0 0 11px 1.5px #ed1d3b;
    box-shadow: 0 0 11px 1.5px #ed1d3b;
    cursor: pointer;
    transition: .4s;
}

.new-article:hover {
    transform: scale(1.04);
}

.latest-article-img{
    display: block;
    height: 100%;
    width: 100%;
    object-fit: cover;
    margin-bottom: 5%;
}

.new-article-title, .date, .category {
    padding-left: 3%;
    line-height: 2.5;
    font-size: 1.05rem;
    font-weight: 600;
}

.category {
    padding-left: 0;
    display: inline;
}

.developers, .gaming, .tech {
    padding: 2%;
    margin-left: 3%;
}

.developers {
    background-color: #ed1d3b;
    -webkit-box-shadow: 0 0 11px 1.5px #ed1d3b;
    -moz-box-shadow: 0 0 11px 1.5px #ed1d3b;
    box-shadow: 0 0 11px 1.5px #ed1d3b;
}

.gaming {
    background-color: #f10de2;
    -webkit-box-shadow: 0 0 11px 1.5px #f10de2;
    -moz-box-shadow: 0 0 11px 1.5px #f10de2;
    box-shadow: 0 0 11px 1.5px #f10de2;
}

.tech {
    background-color: #5d00f9;
    -webkit-box-shadow: 0 0 11px 1.5px #5d00f9;
    -moz-box-shadow: 0 0 11px 1.5px #5d00f9;
    box-shadow: 0 0 11px 1.5px #5d00f9;
}

#poll {
    height: 100%;
    max-height: 600px;
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(300px, 350px));
    grid-auto-rows: 100%;
    gap: 3.5%;
    justify-content: center;
    margin: 3% 0;
}
.poll-area {
    max-width: 320px;
    height: 100%;
    max-height: 700px;
    padding-bottom: 1%;
    background-color: #0f1010;
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    border-radius: 10px;
}

.poll-question {
    border-top-left-radius: 10px;
    border-top-right-radius: 10px;
    background: #242526;
    padding: 2%;
    color: #fff;
    font-size: 1.65rem;
    text-align: center;
    font-weight: 600;
}

.opt {
    position: relative;
    margin: 4.2% 4.2% 0;
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 5%;
    color: #fff;
    font-weight: 600;
    border: 1px solid #ed1d3b;
    -webkit-box-shadow: 0 0 11px 1.5px #ed1d3b;
    -moz-box-shadow: 0 0 11px 1.5px #ed1d3b;
    box-shadow: 0 0 11px 1.5px #ed1d3b;
    cursor: pointer;
    transition: .4s;
    height: 10%;
}

.opt:hover {
    transform: scale(1.02);
}

.option-name {
    position: absolute;
    z-index: 3;
}

#percentage {
    position: absolute;
    left: 0;
    top: 0;
    height: 100%;
    background: #ed1d3b;
    z-index: 2;
}

@media screen and (max-width: 1024px) {
    .all-new-articles {
        height: 50%;
    }
    .developers, .gaming, .tech {
    padding: 0% 2%;
    margin-left: 3%;
}
}

@media screen and (max-width: 768px) {
    .main-latest {
        display: none;
    }

    .sub-latest {
        width: 100%;
    }

    #new-articles-heading {
        font-size: 1.9rem;
    }

    /* #poll {
        height: 40%;
    } */

    .poll-question {
        font-size: 0.9rem;
    }

    .option-name {
        font-size: 0.7rem;
    }
}

@media screen and (max-width: 425px) {

    .new-article-title {
        font-size: 0.9rem;
    }

    .title {
        font-size: 1.05rem !important;
        bottom: 3.5%;
    }

    .developers, .gaming{
        padding: 0;
        padding-left: 2%;
        margin-left: 3%;
        margin-bottom: 10%;
    }

    .menu {
        display: none;
    }
}

@media screen and (max-width: 1024px) {
    #poll {
        height: 55%;
    }

    .poll-area {
        max-height: 450px;
        margin: 0 auto;
    }

    .poll-question {
        font-size: 1.2rem;
    }

    .main-title {
        font-size: 1.8rem;
    }
}

@media screen and (min-width: 1025px) {
    #poll {
        height: 55%;
    }
    .poll-area {
        max-width: 385px;
    }
}

</style>```

main.css: (in src/assets/main.css)
```* {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

html{
  font-size: 16px;
}

body {
  height: 100vh;
  overflow: hidden;
  font-family: Roboto,sans-serif;
}

#app{
  height: 100%;
  background-color: #000;
  overflow: scroll;
}

#app::-webkit-scrollbar {
  width: 0.1px;
  background-color: none;
}

#app::-webkit-scrollbar-thumb {
  background-color: #ed1d3c41;
  border-radius: 2px;
}

/* STYLES APPLICABLE TO NAVIGAITON PAGES DISPLAY ARTICLES */
#heading-wrapper{
  display: flex;
  justify-content: center;
  align-items: center;
  flex-direction: column;
}

@media screen and (max-width: 768px) {
  #heading-wrapper {
    margin: 7.5% auto;
  }
}

#new-articles-heading{
  color: #fff;
  font-size: 2.5rem;
  text-align: center;
  margin: 2% 0 0.5% 0;
}

#new-articles-heading-read {
  color: #fff;
  font-size: 2.5rem;
  text-align: center;
  margin: 2% 0 0.5% 0;
}

@media screen and (max-width: 1024px) {
  #new-articles-heading{
    font-size: 1.9rem;
  }

  #new-articles-heading-read {
    font-size: 1.55rem;
  }
}

.heading-underline {
  height: 5px;
  width: 15%;
  background-color: #ed1d3b;
}

.all-new-articles {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 350px));
  grid-auto-rows: 100%;
  justify-content: center;
  gap: 2%;
  height: 40%;
  max-height: 850px;
  padding: 0 5%;
  margin: 1% 0;
}

@media screen and (max-width: 1024px) {
  .all-new-articles {
    height: 50%;
  }
}

@media screen and (max-width: 768px) {
  .rtc-paragraph {
    margin: 5% 0 !important;
  }

  .rtc-img-wrapper {
    max-height: 450px !important;
  }
}

.new-article{
  height: 100%;
  display: flex;
  flex-direction: column;
  justify-content: space-evenly;
  background-color: #0f1010;
  color: #fff;
  border: 1px solid #ed1d3b;
  -webkit-box-shadow: 0 0 11px 1.5px #ed1d3b;
  -moz-box-shadow: 0 0 11px 1.5px #ed1d3b;
  box-shadow: 0 0 11px 1.5px #ed1d3b;
  cursor: pointer;
  overflow: hidden;
  transition: .4s;
}

.new-article:hover {
  transform: scale(1.04);
}

.new-article-img{
  display: block;
  height: 60%;
  width: 100%;
  object-fit: cover;
  margin-bottom: 5%;
}

.new-article-title, .date, .category {
  padding-left: 3%;
  line-height: 2.35;
  font-size: 1.05rem;
  font-weight: 600;
}

.category {
  padding-left: 0;
  display: inline;
  width: 31%;
}

.developers, .gaming, .tech {
  padding-left: 2%;
  margin-left: 3%;
}

.developers, {
  background-color: #ed1d3b;
  -webkit-box-shadow: 0 0 11px 1.5px #ed1d3b;
  -moz-box-shadow: 0 0 11px 1.5px #ed1d3b;
  box-shadow: 0 0 11px 1.5px #ed1d3b;
}

.gaming {
  background-color: #f10de2;
  -webkit-box-shadow: 0 0 11px 1.5px #f10de2;
  -moz-box-shadow: 0 0 11px 1.5px #f10de2;
  box-shadow: 0 0 11px 1.5px #f10de2;
}

.tech {
  background-color: #5d00f9;
  -webkit-box-shadow: 0 0 11px 1.5px #5d00f9;
  -moz-box-shadow: 0 0 11px 1.5px #5d00f9;
  box-shadow: 0 0 11px 1.5px #5d00f9;
}

/*STYLES FOR THE READ ARTICLES PAGE ARE DEFINED HERE BECAUSE THE RICH TEXT EDITOR OF THE CMS MUST HAVE ITS STYLES GLOBAL TO THE HTML PAGE*/
.article-content {
  max-width: 1550px;
  margin: 0 auto;
}

.rtc-paragraph {
  margin: 1% 0;
}

.rtc-img-wrapper {
  height: 750px;
  max-height: 525px;
  width: 95%;
  margin: 2% auto;
}

.rtc-img{
  display: block;
  height: 100%;
  width: 100%;
  margin: 0 auto;
  object-fit: cover;
}

@media screen and (max-width: 425px) {
  .rtc-img-wrapper {
    max-height: 360px;
  }
}```

### Reproduction

https://github.com/fanatII1/testing-blog

### Steps to reproduce

_No response_

### System Info

```shell
System:
    OS: Windows 10 10.0.22621
    CPU: (4) x64 AMD Athlon Gold 3150U with Radeon Graphics     
    Memory: 937.69 MB / 5.88 GB
  Binaries:
    Node: 18.12.1 - C:\Program Files\nodejs\node.EXE
    Yarn: 1.22.19 - ~\AppData\Roaming\npm\yarn.CMD
    npm: 8.19.2 - C:\Program Files\nodejs\npm.CMD
  npmPackages:
    @vitejs/plugin-vue: ^4.4.0 => 4.4.0 
    vite: ^4.4.11 => 4.5.0

Used Package Manager

npm

Logs

No response

Validations

fanatII1 commented 11 months ago

here are the logs:


[13:30:49.894] Cloning github.com/fanatII1/testing-blog (Branch: main, Commit: 84ebe88)
[13:30:50.155] Cloning completed: 260.745ms
[13:30:51.236] Restored build cache
[13:30:51.301] Running "vercel build"
[13:30:51.737] Vercel CLI 32.4.1
[13:30:52.354] Installing dependencies...
[13:30:53.112] 
[13:30:53.112] up to date in 429ms
[13:30:53.113] 
[13:30:53.113] 9 packages are looking for funding
[13:30:53.113]   run `npm fund` for details
[13:30:53.122] Detected `package-lock.json` generated by npm 7+
[13:30:53.122] Running "npm run build"
[13:30:53.552] 
[13:30:53.553] > fanatii-tech-blog@0.0.0 build
[13:30:53.553] > vite build
[13:30:53.553] 
[13:30:53.906] vite v4.5.0 building for production...
[13:30:53.986] transforming...
[13:30:56.511] ✓ 35 modules transformed.
[13:30:56.833] rendering chunks...
[13:30:56.842] computing gzip size...
[13:30:56.861] dist/index.html                   0.42 kB │ gzip:   0.28 kB
[13:30:56.861] dist/assets/index-55c5a7eb.css    8.35 kB │ gzip:   1.97 kB
[13:30:56.861] dist/assets/index-47f846bd.js   513.13 kB │ gzip: 124.44 kB
[13:30:56.861] 
[13:30:56.861] (!) Some chunks are larger than 500 kBs after minification. Consider:
[13:30:56.862] - Using dynamic import() to code-split the application
[13:30:56.862] - Use build.rollupOptions.output.manualChunks to improve chunking: https://rollupjs.org/configuration-options/#output-manualchunks
[13:30:56.862] - Adjust chunk size limit for this warning via build.chunkSizeWarningLimit.
[13:30:56.862] ✓ built in 2.95s
[13:30:56.953] Build Completed in /vercel/output [5s]
[13:30:57.050] Deploying outputs...
[13:30:58.021] Deployment completed
[13:30:59.561] Uploading build cache [7.50 MB]...
[13:31:00.558] Build cache uploaded: 996.931ms```
sapphi-red commented 11 months ago

The reproduction looks identical between dev and after build on my machine. dev bnmixrvyjgithub-bw1z--5173--09144545 local-corp webcontainer io_ build + preview bnmixrvyjgithub-bw1z--4173--09144545 local-corp webcontainer io_

github-actions[bot] commented 11 months ago

Hello @fanatII1. Please provide a minimal reproduction using a GitHub repository or StackBlitz. Issues marked with need reproduction will be closed if they have no activity within 3 days.