Vue 2 component styles without Vue loader - javascript

Considering that there is single file component (as shown in the guide),
<style>
.example {
color: red;
}
</style>
<template>
<div class="example">hi</div>
</template>
How can the same thing be done without Vue loader in non-modular ES5/ES6 environment?
Considering that the style is scoped,
<style scoped>
.example {
color: red;
}
</style>
Is there a way to implement scoped CSS in non-modular environment, too? If there's none, is there a way to implement it in modular environment (Webpack), but without Vue loader and custom .vue format?

Instead of using the template instance in the Vue component, you can harness a 'closer-to-the-compiler alternative' with the render function without the need for the Vue Loader or compiler. You can add any additional attributes with the second parameter in the createElement function and this will give you a lot of flexibility on top of just styles.
See the Render Functions section in the guide for more info and the full options allowed in the data obj:
https://v2.vuejs.org/v2/guide/render-function
https://v2.vuejs.org/v2/guide/render-function#The-Data-Object-In-Depth
Note: The caveat here is that the style will only apply to the component it is declared in, so it might not be able to used across multiple components of the same class like CSS would be. Not sure if thats also what you want to achieve.
An example from the docs catered to this use case:
Vue.component('example', {
// render function as alternative to 'template'
render: function (createElement) {
return createElement(
// {String | Object | Function}
// An HTML tag name, component options, or function
// returning one of these. Required.
'h2',
// {Object}
// A data object corresponding to the attributes
// you would use in a template. Optional.
{
style: {
color: 'red',
fontSize: '28px',
},
domProps: {
innerHTML: 'My Example Header'
}
},
// {String | Array}
// Children VNodes. Optional.
[]
)}
});
var example = new Vue({
el: '#yourExampleId'
});

It can be achieved putting the scope manually, as vue-loader does automatically.
This is the example of the documentation. Adding some kind of ID, "_v-f3f3eg9" in this case, to scope the class only for that element.
<style>
.example[_v-f3f3eg9] {
color: red;
}
</style>
Vue.component('my-component', {
template: '<div class="example" _v-f3f3eg9>hi</div>'
});

I use Rollup (+ Bublé) + Vue.js all the time. It's pretty simple and fast.
The Rollup config is like:
import vue from 'rollup-plugin-vue';
import resolve from 'rollup-plugin-node-resolve';
import buble from 'rollup-plugin-buble';
const pkg = require('./package.json');
const external = Object.keys(pkg.dependencies);
export default {
external,
globals: { vue: 'Vue' },
entry: 'src/entry.js',
plugins: [
resolve(),
vue({ compileTemplate: true, css: true }),
buble({ target: { ie: 9 }})
],
targets: [
{ dest: 'dist/vue-rollup-example.cjs.js', format: 'cjs' },
{ dest: 'dist/vue-rollup-example.umd.js', format: 'umd' }
]
};
I've made a boilerplate repo:
git clone https://github.com/jonataswalker/vue-rollup-example.git
cd vue-rollup-example
npm install
npm run build

Related

Solved - Vue dynamically add style to :active pseudo class

HIGHLIGHT: This is a solved problem.
Edit: Solved the problem using #Amaarockz's advice!
I haven't had much experience in CSS variables & complicated :style structures, but turned out they're great!
Original question:
I have a menu built with Vue.js (and Vuetify), data passed in from the backend like:
[
{
id: 13241243,
color: "#123456",
activeColor: "#abcdef",
text: "Asadpyqewri"
},
{
id: 742378104,
color: "#234567",
activeColor: "#bcdefa",
text: "Iudaofqepr"
}
]
Menu looks like:
<v-btn-toggle>
<v-btn v-for="item in items" :key="item.id" :color="item.color">
{{item.text}}
</v-btn>
</v-btn-toggle>
Problem
I want to know, how can I dynamically make the items in a different color when they have :active pseudo-class?
What I've tried:
Write something in "style" attribute of list items:
Failed, as I can't add a selector in <element style="">, only styles.
Use an attribute like "active-color" defined by Vuetify:
Failed, such things don't exist.
Dynamically add colors to the "v--btn-active" class, which Vuetify adds automatically:
Failed, I can't find a way to do this seperately for each button.
Watch when the :active pseudo-class appears, add style in the listener:
Somehow MutationObserver didn't work for me.
getElementsByClassName[0] keeps getting "null". I tried writing that in windows.onload, nothing changed.
One time it returned the correct node, and I was able to watch the class mutation. But I can't reproduce that even though nothing changed in the code.
mounted(){
window.onload = function(){
const targetNodes = document.getElementsByClassName('asdff');
var a = targetNodes.item(0);
//"targetNodes" is a HTMLCollection with 3 elements, but "a" is null.
}
}
Add one different class to every button, and write seperate CSS for them using JavaScript:
Perhaps doable, but code's going to be extremely ugly & difficult to maintain.
Besides, it's hard to overwrite Vuetify's default style outsides <element style>; you have to add !important.
Last two attempts are what I think more hopeful. Is there any way to work through?
Try using pseudo class like
Vue.component('pseudo', {
data() {
return {
msg: 'Hover on me',
}
},
props: {
color: {
type: String,
},
text: {
type: String,
}
},
computed: {
cssAttrs() {
return {
'--color': this.color,
'--text': JSON.stringify(this.text),
}
}
},
template: `<button class="content" :style="cssAttrs">{{msg}}</button>`,
});
var vm = new Vue({
el: '#app',
});
.content {
color: red;
}
.content:focus {
content: var(--text);
color: var(--color);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<pseudo color="blue" text="Changing!!"></pseudo>
</div>

Webpack 5 & Vue 3 - CSS Tree Shake

I'm developing a UI component library using Vue 3, SCSS and Webpack 5. The library consists of serval components (button, input, form etc) having a scoped SCSS each.
After installing the library in my main project (also built with Vue 3 & Webpack 5), I'm importing only a single component (button) into it. However, after the build finished (CSS build) I see other components's CSS are included in the build as well. I should mention The JS tree shaking do working.
I want to reduce my bundle size to include only the CSS of the imported components.
An example for button component in my build file:
var script$4 = defineComponent({
name: "SButton",
props: {
stype: {
type: String,
default: "primary"
},
type: {
type: String,
default: "button"
}
}
});
const _withId$4 = /*#__PURE__*/withScopeId("data-v-7a74475b");
const render$4 = /*#__PURE__*/_withId$4((_ctx, _cache, $props, $setup, $data, $options) => {
return (openBlock(), createBlock("button", {
class: ["s-button", _ctx.stype],
type: _ctx.type
}, [
renderSlot(_ctx.$slots, "default")
], 10 /* CLASS, PROPS */, ["type"]))
});
var css_248z$6 = "html {\n --sbutton-general-icon-padding: 9px;\n --sbutton-general-icon-width: 36px;\n --sbutton-general-icon-height: 36px;\n --sbutton-width: 100%;\n --sbutton-min-height: 56px;\n --sbutton-line-height: 32px;\n}\n#media (min-width: 992px) {\n html {\n --sbutton-general-icon-padding: 7px;\n --sbutton-general-icon-width: 32px;\n --sbutton-general-icon-height: 32px;\n --sbutton-width: auto;\n --sbutton-min-height: 46px;\n --sbutton-line-height: 22px;\n }\n}";
styleInject(css_248z$6);

How to properly write a vuepress plugin?

I am trying to write a Vuepress plugin to make use of App Level enhancement and install a Vue plugin. But I can't seem to get this to work. Can you please take a look at the code below and see what is wrong?
{.vuepress/config.js}
module.exports = {
plugins: [
require('./builder.plugin.js')
]
}
{.vuepress/builder.plugin.js}
module.exports = (option, ctx) => {
return {
enhanceAppFiles: [{
name: 'builder-plugin',
content: `export default ({ Vue }) => {
Vue.component('b-header', {
name: 'b-header',
template: '<div id="header"><slot /></div>'
})
}`
}]
}
}
{README.md}
# Introduction
<b-header>Test from component</b-header>
The final error I get is:
Unknown custom element: <b-header> - did you register the component correctly? For recursive components, make sure to provide the "name" option.
I actually found the answer. The above did not work because I was mixing client site code with runtime code by using a plugin.
The trick was to use enhanceAPP hook.
ref: https://vuepress.vuejs.org/guide/basic-config.html#theme-configuration

Instantiate Vue.js components from existing HTML?

I'm trying to make Vue.js instantiate it's components from existing HTML templates and I cannot find any reasonable information on doing that. I'm using non-JavaScript backend framework and Vue.js added in as a normal .js file in the view stack.
Let's say I have the HTML structure looking like this:
<div id="vueApp">
<div class="vueComponent">...</div>
<div class="vueComponent">...</div>
<div class="vueComponent">...</div>
</div>
Then I'm trying to enable it with JavaScript like this (mixing jQuery and Vue for safety):
<script>
// declare Vue component
Vue.component('irrelevantName', {
template: '.vueComponent',
data: function() {
return { something: false }
}
});
// launch Vue app
jQuery(document).ready(function() {
var vueApp = new Vue({
el: '#vueApp',
created: function() {
// TODO: some method that will read/parse the component data, do binding, whatever
}
});
});
</script>
This kind of approach worked perfectly for whenever I had a precisely declared and pointed <template> tag within the HTML structure and the component was supposed to be just a single one. In this case though I'm trying to instantiate n ones identified by a CSS class.
I am aware that one possible approach would be passing all the component data as hidden <input> with JSON-ized array/Collection data, and then asking vueApp to create single-template-driven components on the fly from this data, though that seems a bit tedious approach.
Any suggestions?
Thanks in advance!
I believe you might be thinking about this the wrong way. Vue binds to a single element, so if you want multiple elements to be manipulated, what you can do is create a new Vue instance around div#vueApp and create the components inside of that with Vue templates, like so:
Vue.component('vue-comp', {
data: function () {
return {
something: false
}
},
template: '<div class="vue-comp"></div>'
})
let vueApp = new Vue({
el: '#vueApp',
created: function() {
}
});
div#vueApp {
padding: 1rem;
background: #CD545b;
display: inline-block;
}
div.vue-comp {
height: 50px;
width: 50px;
margin: 0 1rem;
background: #236192;
display: inline-block;
}
<script src="https://unpkg.com/vue"></script>
<div id="vueApp">
<vue-comp></vue-comp>
<vue-comp></vue-comp>
<vue-comp></vue-comp>
</div>

Inject varables in css, html, js with Webpack

I have problem, that in my project I use constants, variables in css, html, js and if I wanna something change some constants I need find it in html or css or js, that take long time. And wonder if it possible have separate js file with variables and constants, and inject value from that to html, js, css (sass). Pseudocode below. I wanna know, is even possible do with webpack, if yes, how or where I should look?
document.getElementById(${=name}).style.color = 'white';
.box {
width: ${=width}
}
<div class="box box_${=id}">
Some text
</div>
const css = {
width: '250px',
};
const html = {
id: '2'
};
const js = {
id: 'haha',
};
You can use a webpack plugin for doing all replacement.
for instance:
https://github.com/jamesandersen/string-replace-webpack-plugin
It can replace in any files you want...
for JS (for instance) you would have something like:
module: {
loaders: [
// configure replacements for file patterns
{
test: /.js$/,
loader: StringReplacePlugin.replace({
replacements: [
{
pattern: /DEFAULT_WIDTH/ig,
replacement: function () {
return '100px';
}
}
]})
}
]
},

Categories

Resources