Serving SVG content from static/assets folder in Nuxt - vue.js

I have a lot of SVGs in my site and they have lots of paths so I don't want to clutter my code with them, but display the full code in the browser.
In PHP there's a magic function called file_get_contents('path')
Is there an alternative to this in Nuxt? So far the only option is to serve it as a regular img tag which prohibits all styling.

Check out the #nuxtjs/svg module (NPM). Using that module you can import your svgs in your script and use them like components in your template.
<template>
<NuxtLogo class="logo" />
</template>
<script>
import NuxtLogo from "~/assets/nuxt.svg?inline";
export default {
components: { NuxtLogo },
};
</script>
<style scoped>
.logo {
fill: #fff;
}
</style>

Related

Vue.js (v3): How to have a unique data-v-* hash for each component instance

I have the following code:
blah-foo.vue:
<template>
<div>Hello {{ name }}</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
export default defineComponent({
props: {
name: {
type: String,
}
},
});
</script>
<style scoped>
div {
color: white;
}
</style>
and App.vue:
<template>
<blah-foo
name="Alice"
></blah-foo>
<blah-foo
name="Bob"
></blah-foo>
</template>
The result in my browser is the following:
<div data-v-73bdd40c>Hello Alice</div>
<div data-v-73bdd40c>Hello Bob</div>
Is there any way I could tell the vue loader to generate an unique data-v-* attribute for each of them ?
What is happening in production is that since the component blah-foo is called on many different lazy-loaded pages, I end up having many times
div[data-v-73bdd40c] {
color: white;
}
all overriding each other.
That isn't a problem in itself, it just does seem very disgraceful (code wise) after having loaded a few pages when inspecting elements.
That is not possible with vue-loader. And it shouldn't be done anyway.
The whole point of the data-v-xxx attribute is to identify the components in the DOM so vue can apply to them the correct scoped css.
If it ever applied uniq data-v attributes, it would not be able to apply the correct css.
I understand your problem is that, on production, you see in the css inspector several times the css code, right?
My guess is that it's related with sourcemaps, which may mess with the css inspector. But I can't help more without additional details on your project configurations.
Even if your component is used on several pages, its module will be fetched and loaded only once. You don't have the scoped css loaded several times, it's just an inspector problem.

Vite Plugin SSR - critical style generation (VUE.js)

I'm using vite-plugin-ssr + vue-router and I want to implement critical styling.
My project has a pages folder which has the following structure:
pages/SomePage/index.vue
<template>
<div class="TestPage">
TestPage Content
</div>
</template>
<script>
export default {
name: "TestPage"
}
</script>
<style lang="css" src="./critical.css"/>
pages/SomePage/critical.css
.TestPage {
background: red;
}
I want the styles from the critical.css file to go into the <head/> tag as internal ~ <style> .SomePage {background: blue;} </style> for each route.
I tried to get inspired by the rollup-plugin-critical idea, but my knowledge is apparently not enough, because a positive result could not be achieved.
How can this be implemented?

Rendering a vue2leaflet map in jsfiddle via CDN

I am trying to render a Leaflet map using Vue2Leaflet in a jsfiddle so I can get help with a specific problem but I can't even get it to render properly in the trivial case. I have already looked up how to load libraries via CDN in jsfiddle and a far as I can tell, I am doing it right. There are also no errors in the console. But the map will not render.
This is the jsfiddle: https://jsfiddle.net/iboates/bywzgf1q/3/
Vue2Leaflet also requires the vue-client-only library. I have it working in my local codebase but maybe it has something to do with why it isn't working in jsfiddle. I am also loading this library via a CDN.
I've also looked at other jsfiddles using Vue with custom libraries loaded via CDN and I don't see what is being done differently.
Apparently StackOverflow requires that a jsfiddle link requires code in the post as well, which is a bit weird to me since the code is literally contained in a link which can also execute it, but here it goes:
HTML:
<div id="app">
<client-only>
<l-map id="map" ref="map">
<l-tile-layer
:attribution="'x'"
:url="'https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png'"
/>
<!-- <l-geo-json
:geojson="geojsonData"
/> -->
</l-map>
</client-only>
</div>
JS:
import { LMap, LTileLayer } from "./vue2-leaflet";
new Vue({
el: "#app",
components: {
LMap,
LTileLayer,
ClientOnly
},
data: {
geojsonData: {
type: "FeatureCollection",
features: []
}
},
mounted() {
}
})
CSS
#app {
background-color: black;
height: 500px;
width: 500px;
}
#map {
height: 500px;
width: 500px;
}
There are multiple errors in your fiddle.
First of all, Vue is not installed. In addition, you try to import Vue-Leaflet like in a Webpack / Rollup build system and not the way you can use it from a CDN.
To begin with, install your CDN (Vue, Leaflet CSS, Leaflet js, Vue-Leaflet):
https://cdn.jsdelivr.net/npm/vue#2.6.12/dist/vue.js
https://unpkg.com/leaflet#1.7.1/dist/leaflet.css
https://unpkg.com/leaflet#1.7.1/dist/leaflet.js
https://unpkg.com/vue2-leaflet#2.6.0/dist/vue2-leaflet.min.js
Then, add your components the CDN-way (check official documentation: https://vue2-leaflet.netlify.app/quickstart/#if-imported-by-cdn
):
components: {
'l-map': window.Vue2Leaflet.LMap,
'l-tile-layer': window.Vue2Leaflet.LTileLayer
}
Check working fiddle: https://jsfiddle.net/scpta4jq/1/

import compiled sass as string in vue

I'm trying to build a simple mail editor in vue (and vuex). Once everything is edited out of some input, i'd like to inline some scss files into the resulting html, using juice.
If i try to import one css using webpack raw-loader,
import css from '!raw-loader!./../assets/sass/test.css';
then i can pass the css value to juice
let result=juice.inlineContent(html,css)
and then injecting with v-html (see below) in one of my component to render the email.
Whitout using the raw-loader, the css will be applied to everything, beeing imported.
If i try to use the raw-loader with a scss file, it's not compiled - rightly - properly.
import css from '!raw-loader!./../assets/sass/main.scss';
I'm quite new to vue and webpack, so, is there something/somewhere i can dig in to understand a way to preprocess a scss file and then pass it as a string to vue, without applying it as style in vue?
I've also tried to scope some css to a component in which i use a v-html tag (and where the inlined html should go)
<template>
<div v-html="render" />
</template>
<script>
import { mapGetters } from "vuex";
export default {
computed: {
...mapGetters(["render"]),
},
};
</script>
<style lang="scss" scoped>
table {
border: 1px solid red;
}
</style>
At first in the value (the getters) ther's no table, but when i add it to the component (with the editor) the style it's not rendered at all, as if the component is not re-rendered. That's the reason i decided to inline the css before injecting in the DOM, instead of doing it after some action - like a click on a button.
I've also tried using >>> but with no luck. I know this is not the main question, just a "side quest", but i'm just learning
import css from '!raw-loader!sass-loader!./../assets/sass/main.scss';
It first compile the sass and then import it as a row string... easy peasy

What does the name: 'app' line do in this Vue.js CLI code?

What function does the name: 'app' have in the following Vue.js CLI code?
I understand that the export default is used for
"creating JavaScript modules to export functions, objects, or
primitive values from the module so they can be used by other programs
with the import statement" (docs)
and I understand the module to be what is in the template element, but I don't see where it is being imported.
<template>
<div id="app">
<img src="./assets/logo.png">
<router-view></router-view>
</div>
</template>
<script>
export default {
name: 'app'
}
</script>
<style>
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
Nor do I see what name: 'app' does exactly since if I change the name, the Vue.js. code still works, until when you change this in non-CLI Vue.js, e.g.
new Vue({
el: '#app',
...
});
If you change the '#app' then the code won't reference the element and it won't work anymore.
The name Attribute of a Vue component is not really required in projects generated with the vue cli webpack template. In your case, the component name is set elsewhere (since you use vue-router: in src/router/index.js), hence it is not technically required in the export default of the *.vue file.
If you generated your vue cli webpack template without vue-router you wouldn't have to supply the component name either, because your <script> block would look like this:
<script>
import Hello from './components/Hello'
export default {
...
components: {
Hello
}
}
</script>
The components: {Hello} is a shorthand for components: {'Hello': Hello} in EcmaScript 6. This is where the component name would be set in this case.
That being said, setting the component name in the export default object of your *.vue file is considered good style, because your components will be named consistently across the project and thus be easier to debug. If you changed the import Hello from .... to something like import HelloComponent from .... it would show up as HelloComponent in things like vue-devtools and warning messages. You would also now have to reference it as <hello-component></hello-component> in your <template>. Since you want your component names to be consistent, especially when writing components that you intend to be reusable, you should set the name property in your vue component once and for all.