Currently just a BootstrapVue VueJS frontend project I have, I have 4 playing cards that I would ideally like to keep on one line/row (as it does locally), but stacks when I view it in production (using Heroku, if it makes a difference)
Currently the code for this is like:
<div
flex-wrap="nowrap"
class="row d-flex nowrap mt-3"
justify-content="space-between"
width="100vw"
>
<b-container>
<b-row>
<b-col>
<PlayingCard/>
</b-col>
....etc for the other cards....
</b-row>
</b-container>
</div>
I've played around a lot with different classes and justify-contents and all that stuff, but continually get different local vs prod results. And I can confirm the code on Heroku is up to date because it redeploys with each new commit and I've added some new features since attempting to fix this styling issue and those appear properly.
Styling issues like that are most commonly due to scoping issues of your CSS. If you inspect the element locally you will likely see that only the local styling has been applied, while if you inspect the element in production, you will see that either the selector contains more CSS (due to identical selectors in two different components), or another selector is applied altogether.
You are getting this problem, because in dev-mode it only loads the CSS of the components you are viewing. In production mode, all the CSS of all components is combined.
To solve the problem, you have several options:
You can use the scoped attribute on your style tag. Vue will automatically add a data-attribute on your component, and scope the styling using that data attribute. This does commonly not work nicely with things like popups that are moved out of their previous location.
<template>
<div>
<!-- something here -->
</div>
</template>
<script>
export default {
//...
}
</script>
<style scoped>
button {
// This only styles the buttons in this component, rather than every button in the application
}
</style>
If you need to style sub-components as well, you can just use a class on your root element and style everything relative to that. You would need to make that class a unique name in your application, but if you just use the name of your component that shouldn't be a problem.
<template>
<div class="comp-card">
<!-- something here -->
</div>
</template>
<script>
export default {
name: 'Card'
}
</script>
<style lang="scss">
.comp-card {
button {
// All buttons that are descendants of our component are now styled.
}
}
</style>
I see two issues with the given code, addressing these may not resolve your issue, but may remove some interference.
Bootstrap provides the class .flex-nowrap for applying flex: nowrap – it should be noted that nowrap is the default behaviour of flexbox, and this may not be needed anyway.
Some attributes in your div appear to be style declarations, and ought to be in the [style] attribute as shown below, or a <style> tag if using SFCs
<div
class="row d-flex mt-3"
style="justify-content: space-between; width: 100vw"
>
Caching of applicable files can vary between local and production environments.
Browsers accessing production servers may cache older versions of files and make it appear that the change was not made. The server may have newer files than what the browser is using.
UI changes in production might be issue of CSS Optimization in build process of vue cli.
Did you try to serve/run build locally if it works then it might issue on production site/cache/browser etc. Try local build with serve or any other tool to verify.
If css optimization issue in build then re-configure build config with underlying tool like webpack or vite etc whichever used.
Related
I am trying to use vue-masonry-wall in my NuxtJS (v2.15.7) app to give it a masonry layout. According to the docs, the vue-masonry-wall package is "SSR friendly". It states to simply add :ssr="{columns: 2}" to masonry so that during SSR, it will be loaded in 2 columns.
I tried this in my code (codesandbox here). But, during SSR, nothing is loaded.
Anyone got any idea on what is happening and why I can't see any of the items? It works fine in client-mode.
Code example:
<vue-masonry-wall :items="items" :options="{width: 300, padding: 12}" :ssr="{columns: 2}" #append="append">
<template v-slot:default="{item}">
<div class="item">
<h5>{{item.title}}</h5>
<p>{{item.content}}</p>
</div>
</template>
</vue-masonry-wall>
One option is to run it just on the client side, so:
1- if loaded as plugin, globally: name the plugin file ending with ".client", for instance: 'vue-masonry-wall.client.js'
2- if used as module, you can wrap it with the tag.
I'm trying to make use of the #extend of sass so that I don't mix markup and html together. As explained in this article.
In short, instead of writing
<div class="alert alert-primary>This is an alert!</div>
You'd instead write something like
<div class="banner">This is an alert!</div>
.banner {
#extend .alert;
#extend .alert-primary;
}
Such that styling and content stay nicely separated.
The problem: When using this with webpack (sass-loader) and components (e.g. Vue.js or Angular), I run into a problem where including a bootstrap partial will now result in the complete compilation of the entire bootstrap file into css.
This results into a class .btn[data-v-3614b62c] and another .btn[data-v-45ac961c] etc. for every component that uses the partial bootstrap/scss/_buttons.scss and that for all classes defined in that partial.
Even if I don't use it.
In the long run, this will be detrimental for the application since its size will increase rapidly and I image the browser will slow down with that many css classes to parse.
The question(s): How do I make sure sass doesn't duplicate the entire imported partial?
Can I enable some kind of tree shaking where it only includes the classes I use?
Do I have to change my file structure so that sass understands I only need certain classes inside the partial rather than everything?
Code example
This is a vue component using bootstrap
<template>
<form class="form">
<input type="text" class="input">
<button class="button-submit">Send</button>
<button class="button-cancel">Cancel</button>
</form>
</template>
<style lang="scss" scoped>
#import "node_modules/bootstrap/scss/functions";
#import "node_modules/bootstrap/scss/variables";
#import "node_modules/bootstrap/scss/mixins";
#import "node_modules/bootstrap/scss/root";
#import "node_modules/bootstrap/scss/buttons";
.form {
.button-submit {
#extend .btn;
#extend .btn-primary;
}
.button-cancel {
#extend .btn;
#extend .btn-danger;
}
}
</style>
This will result in the entire partial _buttons.scss to be compiled into css instead of only .form .button-submit and .form .button-cancel.
Live example
https://codesandbox.io/embed/musing-feynman-8w2kx.
To see the problem I have:
Right click on the example to the right and click Inspect
In the Elements tab, navigate to #document > html > head
At the bottom you'll have several style elements
Two of them will contain all the button css where only the [data-v-######] attribute is different and at the end are my couple of lines code.
Note that the same happens for production builds. The css is then simply bundled up in a single file, but duplicates are still around.
If you are #importing the same CSS rules into different components, then you will get the same rules duplicated across all modules. That's just how it works.
You should only be #importing modules that define abstract declarations like variables, mixins, functions, etc, not actual styles.
The only way you can de-duplicate the styles globally is if you use something like mini-css-extract-plugin to extract and combine all the CSS into a single file and then run it through something like cssnano which will discard duplicate rules (although with scoped CSS, this probably won't work).
Modules are typically built independently of other modules and there isn't a simple way to know if a rule has been declared already by a previous module. In development you may be using style-loader which operates on a per-module basis and injects styles into the webpage on demand; there's just no way it can work out which styles should be injected in case some particular style has already been injected by another component.
It just gets messy; keep it simple by not duplicating styles in the first place.
If you really want to use #extend, then make a separate .scss file which is the only module that #imports the bootstrap styles, and define all your extensions in there.
For a project where Vue is dropped in, is using style or similar available to components?
Vue.component('vue-sup', {
template: '<div>Sup</div>',
style: '* { color: blue; }'
})
I tried adding the styles inside the template like:
<div>
<style>
.here{}
</style>
<div>Sup</div>
</div>
which didn't work because the template parser detected a tag with side effects
Vue's implementation of scoped css is entirely a feature of vue-loader, and thus only works with compilation. Scoped css momentarily made a debut into Html 5 but saw almost no adoption and was dropped entirely as far as I know. There is the anticipation that "Shadow DOM" may be supported broadly and could be use to add scoped css, but adoption is not there yet either.
So at this point you can add unique classes or ids obviously to a parent container and scope your css that way, but is understandably not what you are asking for nor is it always practical.
The best alternative is a pollyfill. There are several that are available. Here is one by Sam Thorogood and another by Thomas Park but if you do a quick search you will likely discover more.
I came across the same problem and I'm able to insert styling inside Vue template
by creating a component that will dynamically insert a <style> tag on the DOM. This might be impractical like #skribe said but it allows me to have separate CSS from JS without using .vue extension.
You can take a look at this
I'm trying to create a standard user status widget for my Aurelia app, and I'm not sure what I'm doing wrong. As a starting point I followed the docs, but my results aren't what they tell me to expect and I'm not getting errors either in build nor in the browser.
Relevant files are as follows:
<!-- nav-bar.html -->
<template bindable='router'>
<require from="./user-status "></require>
<!-- various nav buttons -->
<p class="navbar-collapse collapse navbar-text">
Test <user-status></user-status>
</p>
user-status.html
<template>
${status}
</template>
user-status.js
export default class UserStatusCustomElement {
constructor() {
this.status = 'Be sure to drink your Ovaltine!';
}
}
if I change the require in nav-bar.html to look for ./user-status.html it appears to have an effect (additional aurelia-looking attributes are added to the user-status element in the rendered html) but does not render the message (one assumes b/c it's not picking up the class and rendering as an html-only thing). If I leave as-is, it doesn't error but those attributes are not added and nothing is rendered, even static text.
I played around with your code and found that removing default from the user-status.js module fixed the problem. I suspect the reason has something to do with how Aurelia utilizes module-loaders (System.js, webpack, ...) when importing modules. Unfortunately I don't know enough about the internals of Aurelia to give a more in-depth answer.
I know that Aurelia is a framework for an SPA but I need to open multiple pages at the same time inside the browser.
I want to host each page (view/viewmodel) within a draggable div and have more than one open at the same time. They will be selected by the User from a menu.
I have looked at viewPorts but cannot see how they will help in this problem.
Is there another way to do this?
Yes, there is a way to do this.
You say pages, but basically they are components. Every component has a HTML (view) and JS (view-model) file. They can be included as custom-elements.
So if you want multiple possible components on one page, all you need to do is create one component that has a placeholder for those views.
Probably, you would want something looking like this:
running Gist example
<template>
<require from="./page1"></require>
<require from="./page2"></require>
<page1></page1>
<hr>
<page2></page2>
</template>
You can create loop for all elements you want to display, if you need multiple instances of the same page, and put a repeat.for on the elements:
HTML:
<template>
<require from="./page1"></require>
<require from="./page2"></require>
<page1 repeat.for="i of page1instances"></page1>
<hr>
<page2 repeat.for="i of page2instances"></page2>
</template>
JS:
export class App {
const page1Instances = 4;
}
Making them drag&droppable works like every other element, there are many solutions for that to be found. Just make the <page1> and <page2> draggable.