html style selector remains after webpack postcss processing - javascript

I have added postcss loader with options to my vue js ui library project . I am using postcss loader so that when i import this npm package elsewhere the styles wont conflict. Vue CLI uses PostCSS internally.
my sample html:
<div id="navbackground ">
<h5>Sample h5 text</h5>
</div>
one of my css classes e.g. mycolors.css has following content in it:
#navbackground {
background: red;
}
h4{color:white}
configuration for postcss looks like below
const prefixer = require('postcss-prefixer')
css: {
loaderOptions: {
postcss: {
plugins: [
prefixer({
prefix: 'mystyles-'
})
]
}
}
},
And the css file generated after running web pack build looks like below and it applies prefix.
#mystyles-navbackground {
background: red;
}
h4{color:red}
AS you see from above h4 is NOT transformed with any prefix identifier and also stlyes(e.g. mystyles-navbackground) are not applied on html.
when i looked at the rendered html it has the same class id (navbackground) so it didn't apply the new style name (mystyles-navbackground)
<div id="navbackground ">
<h5>Sample h5 text</h5>
</div>
Do i need to run another loader or plugin to apply the new prefixed style names to html ?

Related

How use my own scss variable file in Quasar template

I want to use my own SCSS fil with variable that I already set with Quasar.
for example in Q-tab
<q-tabs
v-model="selectedTab"
align="left"
indicator-color="transparent"
active-color="$MyOwnVariable"
>
My project is a Vue3 with vite js
I tried to create a quasar.variables.scss in css folder but it doesn't work
Here is I think how it should be set
quasar.config.js
css: [
'app.scss'
]
quasar.variables.scss
$brand-primary: #EAC30D;
app.scss
.brand-primary {
background-color: $brand-primary;
}
YourComponent.vue
<q-btn class="brand-primary" label="Caption" />

Targeting Pure elements in next.js with CSS modules

I'm porting an app from React to Next and I keep getting an error with my css: "ul" is not pure (pure selectors must contain at least one local class or id).
I'm using css modules and am not sure what the workaround is to keep everything in the css module.
for example:
index.js
<div className={styles.container}>
<ul>
<li>Person One</li>
</ul>
</div>
index.module.css
.container{
background-color: pink;
}
ul{
list-style-type: none; //this throws an error
}
If you don't want to use classes as mentioned #Zeeshan's answer, you cannot use the module-based CSS. You will need to use a global stylesheet to target pure elements as selectors. They cannot be component-scoped.
Further, you can only import a global stylesheet in one place (_app.tsx/_app.jsx/_app.js), or you'll receive an error (explained here).
You may break your styles out across many stylesheets, but they all have to be global, so there's probably little benefit from doing so.
To quote directly from this Next.js GitHub discussion forum:
You are receiving this error because you are using html tags directly instead of classnames or ids in a file extension that is probably [filename].module.(css | scss | sass)
File extensions with *.module.(css | scss | sass) are css modules and they can only target elements using classnames or ids and not using tag names. Although this is possible in other frameworks like create-react-app, it is not possible in next-js.
My suggestion is using these html selector css in a separate file that doesn't contain the '.module' in it.
Example: [filename].(css | scss | sass) --> styles.scss
And instead of importing like this
import styles from './styles.module.scss';
import like this
import './styles.scss';
This is actually extremely simple.
You can add a container class to the top element (just like you did), and then use combinators ( ,+,>, etc.) to target pure elements as you wish.
For example:
index.js:
<div className={styles.container}>
<ul>
<li>Person One</li>
</ul>
</div>
index.module.css:
.container {
background-color: pink;
}
.container ul {
list-style-type: none;
}
Try giving a className or id to ul tag and then write your styles accordingly.
for example:
index.js
<div className={styles.container}>
<ul className={styles.container__list}>
<li>Person One</li>
</ul>
</div>
index.module.css
.container {
background-color: pink;
}
.container__list{
list-style-type: none;
}

Vue project can't find image when using <a href> but can find it when using <img>

I have this Vue project. All I've done is run vue create foo and removed all the pre-created code that comes in the src folder when you run that command. I then added an image to the src folder and created my own App.vue, this is all I've written in it.
<template>
<div>
<img alt="Vue logo" src="./foo.png">
<a href="./foo.png" download>foo</a>
</div>
</template>
<script>
export default {
}
</script>
When I then try it out with npm run serve the website displays the image perfectly fine, but the download link does not work. It says the server doesn't have the requested file or something.
Vue loader automatically transforms img src attributes in templates into webpack module requests, but by default it doesn't do the same for links.
If you need to link directly to a file, you can put it in the public/ directory to bypass webpack (using a path relative to that directory -- i.e. for a file in public/foo/bar.jpg you'd use <a href="/foo/bar.jpg">)
Alternatively, you can leave the file where it is, and tell webpack to transform <a href> urls into module requests, just as it does image src urls, by changing the transformAssetUrls options:
/* Add to vue.config.js */
module.exports = {
chainWebpack: config => {
config.module
.rule("vue")
.use("vue-loader")
.loader("vue-loader")
.tap(options => {
// modify the options...
options = Object.assign(options, {
transformAssetUrls: {
a: "href"
}
});
return options;
});
}
}

How to Use css selectors in jest unit testing while using css modules

I'm using css modules in my react project and using web pack for bundling. While using Jest for testing, as the jest will try to import css files like normal JS files got the below error,
SyntaxError: Unexpected token .
The solution that I found is to use "identity-obj-proxy" to mock scss/css files.But now I cannot use css selectors to test components.For example
Test
it('renders 2 children', () => {
expect(component.find('.mockyApp').children().length).toBe(2);
});
render method
render() {
if (this.state.host) {
return (
<div className={style.mockyApp}>
<div className={style.sidePage}>
<SideBar clickHandler={this.setPage} selected={this.state.page}/>
</div>
<div className={style.mainPage}>
{this.renderComponent()}
</div>
</div>
);
}
// ... .. rest of render method
}
I'm using import style from './mocky.scss'; to import styles and using the style object for class names. Before using css-modules the above test used to work.Now my question is how will I be able to test using css selectors and what change needs to be done to make this work?. Googling didn't help
I don't think there exists a good solution for this problem yet.
Few ways you can still test it:
1) Add a static class name just for testing:
<div className={`${style.mockyApp} mockyApp`}>
<div className={style.sidePage}>
<SideBar clickHandler={this.setPage} selected={this.state.page}/>
</div>
<div className={style.mainPage}>
{this.renderComponent()}
</div>
</div>
2) Use a data attribute to target that element.
Component
<div className={`${style.mockyApp} mockyApp`} data-jest="mockyApp">
<div className={style.sidePage}>
<SideBar clickHandler={this.setPage} selected={this.state.page}/>
</div>
<div className={style.mainPage}>
{this.renderComponent()}
</div>
</div>
Render
it('renders 2 children', () => {
expect(component.find('[data-jest=mockyApp]').children().length).toBe(2);
});
Both ways work but they include adding stuff to the DOM which gets shipped to production, which means more bytes being sent to your users.
If you are going with the second approach, you can consider writing a Babel plugin that strips out all data-jest attributes from the DOM in the transpilation process.

In Vue.js, is there a way to keep component templates out of JavaScript strings?

I just worked through the Guide on Vue.js's website, and I have a bad feeling about templates for components. It seems strange to me that they are specified in strings; sure, maybe this works for very short templates, but once you get to multiline templates, you need to start escaping your new lines and it just feels wrong to have html in javascript strings to begin with. Not to mention that syntax highlighting or any other nice IDE features are useless with HTML in JS strings.
Two alternatives that are detailed in the docs are using inline templates, or X-templates, but both of these options are discouraged.
The only other alternative seems to be Single File Components, which seems like a good option, but they are in the Advanced section and in the docs, it is said that for small and medium sized apps, simply using Vue.component should be enough. Furthermore, Single File Components look like they're more difficult to integrate into a project, requiring tapping into the project's build system (the docs talk about Webpack and Browserify).
So I'm confused. Do I just need to accept that my component code is going to look as messy as this example, pulled straight from the docs?
Vue.component('currency-input', {
template: '\
<span>\
$\
<input\
ref="input"\
v-bind:value="value"\
v-on:input="updateValue($event.target.value)"\
>\
</span>\
',
......
Given that you are starting a new project, you can use vue-hackernews-2.0 as boilerplate, where you see lot of components already coded with webpack integration for both dev and prod env. This is also developed by core vue team and recommended in official docs.
You can see there are different files for each component and one component looks like following having clear separation of HTML, JS and CSS part:
<template>
<li v-if="comment" class="comment">
<div class="by">
<router-link :to="'/user/' + comment.by">{{ comment.by }}</router-link>
{{ comment.time | timeAgo }} ago
</div>
<div class="text" v-html="comment.text"></div>
<div class="toggle" :class="{ open }" v-if="comment.kids && comment.kids.length">
<a #click="open = !open">{{
open
? '[-]'
: '[+] ' + pluralize(comment.kids.length) + ' collapsed'
}}</a>
</div>
<ul class="comment-children" v-show="open">
<comment v-for="id in comment.kids" :id="id"></comment>
</ul>
</li>
</template>
<script>
export default {
name: 'comment',
props: ['id'],
data () {
return {
open: true
}
},
computed: {
comment () {
return this.$store.state.items[this.id]
}
},
methods: {
pluralize: n => n + (n === 1 ? ' reply' : ' replies')
}
}
</script>
<style lang="stylus">
.comment-children
.comment-children
margin-left 1.5em
.comment
border-top 1px solid #eee
position relative
.by, .text, .toggle
font-size .9em
margin 1em 0
.by
color #999
a
color #999
text-decoration underline
.text
overflow-wrap break-word
a:hover
color #ff6600
pre
white-space pre-wrap
.toggle
background-color #fffbf2
padding .3em .5em
border-radius 4px
a
color #999
cursor pointer
&.open
padding 0
background-color transparent
margin-bottom -0.5em
</style>
This uses webpack for build and adds working config as well which I myself am using in production without any issue.
You can use <template>...</template> or <script type="text/x-template">...</script>, and specify the selector in template attribute for that.
<template id="myComponent">
<div>
<h1>Hello!</h1>
<p><slot></slot></p>
</div>
</template>
Vue.component('myComponent', {
template: '#myComponent'
})
Simple working example here: http://codepen.io/anon/pen/dNWrZG?editors=1010
Also, the build process of single file components is not that difficult. You can check the webpack-simple template: https://github.com/vuejs-templates/webpack-simple, the vue-loader will do everything for you.
Once you feel comfortable with webpack, you can take a look at the full webpack template: https://github.com/vuejs-templates/webpack
From my experiences, if the template is very short, use inline mode is OK. If not, x-template also allows you to get rid of escaping line breaks. I don't see why you think these approaches are discouraged. Can you provide more information?
However, if you insist to embed long template inline, you can still do that without escaping. The answer is ES6 template literals - string wrapped within ``:
template: `
<span>
$
<input
ref="input"
v-bind:value="value"
v-on:input="updateValue($event.target.value)"
>
</span>
`,
On the other hand, I really think vue-cli is a great tool. Webpack is something worth learning.
This is not really a direct answer (It's editor Specific) but i just thought i should share, but if you're using Visual Studio Code as your editor, Then you can keep your templates as part of your component and still get Syntax highlighting.
Thanks to this awesome extension
angular-2-inline
It was Originally meant for Angular 2, but it works for all ES6 Template strings (Provided the key of Template String is "template").
Single File components are the Recommended way, but they can become a burden when you're not building a Full-fledged SPA and you're just using Vue to enhance some HTML templates Here and there, and you don't want to get Involved with Webpack.
Don't believe it? I'm currently using it.
Thanks to #danidee answer I was able to track an Atom extension to properly do syntax highlighting for "backticked" HTML strings. However as he indicates it will only work when the template is declared inside the very component definition (and I want to separate template in another .js file). So I did this and it's a more ellegant solution, I think:
COMPONENT DEFINITION
/* template definition */
import { csFooterView } from './csfooter-view.js?v6';
/* component definition */
const csfooter = {
name: 'csfooter',
props: ['projectName'],
data: function() {
return {
copyrightCompany: 'CSDev'
}
},
template: csFooterView.template
};
/* exports */
export { csfooter };
TEMPLATE DEFINITION
/**
* VUE Footer Component
* Template
*/
/* template definition */
const csFooterView = {
template: `
<footer class="footer bg-warning p-4 m-auto">
<p>{{ copyrightCompany }} (c) 2020 - {{ projectName }}</p>
</footer>
`
};
export { csFooterView }
ATOM SCREENSHOT WITH HTML SYNTAX HIGHLIGHTING IN THE .JS FILE
Link to Atom extension

Categories

Resources