How to use asset URLs in style binding with Vite - css

I want to show a background image from my assets folder. When I use an image tag, the image is shown properly, so the image is well placed, but throws a 404 when I use the background-image style. Any idea about what is happening?. I am using Vue 3 with TypeScript and Vite 2.
This does not resolve the URL:
<div style="background-image: url(./assets/img/header.png)"
></div>
But this does:
<img src="./assets/img/header.png" alt="Header" />

The URL needs to be resolved with import in <script>. #vue/compiler-sfc does not automatically resolve the URLs in <div>.style, but it does for <img>.src, which is why your second example works correctly.
Solution
Use the import keyword in a <script> block to expose the resolved image URL to the template:
<script setup>
import imagePath from '#/assets/logo.svg'
</script>
<template>
<div class="logo" :style="{ backgroundImage: `url(${imagePath})` }"></div>
</template>
<style>
.logo {
height: 400px;
width: 400px;
}
</style>
demo

This is due to vite can't handle alias by default, so we need to set up an alias in vite config file.
there is no need to setup the import image in script tag.
just put the below code in vite.config.js file
import { defineConfig } from "vite";
import vue from "#vitejs/plugin-vue";
import path from "path";
export default defineConfig({
plugins: [vue()],
resolve: {
alias: {
"#": path.resolve(__dirname, "/src"),
"~#": path.resolve(__dirname, "/src"),
},
},
});

Related

How do I use PrimeVue in CustomElements?

I have a Vue 3 custom Element in which I want to use PrimeVue & PrimeFlex etc.
So I first create a Component, use the .ce.vue extension for the sfc mode and use the combination of defineCustomElement and customElements.define to compile it to a web component. Finally I use it in the index.html to see if it works in the Browser.
It works to some extent but not completely. For example, I am unsure about how to translate app.use(PrimeVue) for my case.
//customElement.ce.vue
<template>
<div>Test</div>
<AutoComplete field="name" />
</template>
<script lang="ts">
import { defineComponent } from "vue";
import AutoComplete from "primevue/autocomplete";
export default defineComponent({
name: "customElement",
props: {
msg: String,
},
components: { AutoComplete },
setup: () => {
console.log(JSON.stringify(theme));
return { PrimeVue };
},
styles: [],
});
</script>
<style scoped lang="scss"></style>
//main.ts
import { createApp, defineCustomElement } from "vue";
import App from "./App.vue";
//PrimeVue
import PrimeVue from "primevue/config";
import "/node_modules/primeflex/primeflex.css";
import "primevue/resources/primevue.min.css";
import "primevue/resources/themes/saga-blue/theme.css";
//CustomElement
import customElement from "#/components/customElement.ce.vue";
const customElementWC = defineCustomElement(customElement);
customElements.define("custom-element", customElementWC);
//Setup VueApplication for testing/reference, this works as expected.
const app = createApp(App);
app.use(PrimeVue);
app.mount("#app");
//index.html (for testing)
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width,initial-scale=1.0" />
<link rel="icon" href="<%= BASE_URL %>favicon.ico" />
<title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
<noscript>
<strong
>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work
properly without JavaScript enabled. Please enable it to
continue.</strong
>
</noscript>
<div id="app"></div> //test app
<custom-element /> //the custom Web Component
<!-- built files will be auto injected -->
</body>
</html>
So I can see that the PrimeVue-Autocomplete is being shown, but the styles are not working.
So the question is:
How can I use all of PrimeVue in a custom Component?
Or in other words: How do I setup a Vue 3 CustomElement with PrimeVue?
So I have found a workaround (not a proper solution).
The way to make most of it work is to import the styles and js/ts modules in the component(s) itself.
The main styles make the most sense to import in the root component of the web component.
The reason why it has to be there is, due to:
https://github.com/vuejs/vue-cli/issues/6033 and
https://github.com/vuejs/core/issues/4662
that web components can't use plugins, or at least I don't know how. In other words there is no app.use() method.
I still couldn't properly import primeflex so I had to use the cdn link. I think it is possible to use an internal import, and I will update the answer when I find out how.
To use a specific PrimeVue component, simply import and register it as the documentation describes.
<template>
<Button />
</template>
<script lang="ts">
import Button from "primevue/button";
import { defineComponent } from "vue";
export default defineComponent({
components: { Button },
});
</script>
<style>
#import url("https://unpkg.com/primeflex#3.1.0/primeflex.css");
</style>
<style lang="scss" src="#/assets/scss/globals.scss"></style>
<style src="primevue/resources/primevue.min.css"></style>
<style src="primevue/resources/themes/tailwind-light/theme.css"></style>
//main.ts
import { defineCustomElement } from "vue";
import App from "./App.ce.vue";
customElements.define("custom-element", defineCustomElement(App));
Limitation:
Due to the missing plugin support (or my lack of knowledge of it) the lines:
import PrimeVue from 'primevue/config';
app.use(PrimeVue);
are not possible. Unfortunately, I can't fully grasp the impact that might have.

Vue <script setup>, unable to use defineProps and defineEmits without importing it

As per the official documentation,
defineProps and defineEmits are compiler macros only
usable inside <script setup>. They do not need to be
imported and are compiled away when <script setup> is
processed.
The problem definition
I'm not able to use defineProps and defineEmits in <script setup> without importing it. Please refer to the error screenshot attached below.
The vue code which I'm executing
<!-- HelloWorld.vue -->
<template>
<h1>{{ props.message }}</h1>
</template>
<script setup>
// import { defineProps } from 'vue';
const props = defineProps({
message: {
type: String,
required: true,
}
});
</script>
The environment details for reference:
vue
^3.2.6 (3.2.19)
vue-cli
#vue/cli 5.0.0-beta.4
node:
v14.16.1
npm
6.14.12
We can resolve this issue with one of the below solutions.
Create Vue project with Vite. Follow this link for more information.
yarn create vite <project-name> --template vue
Add below rules in your eslint configuration file. Follow this link for more information.
// .eslintrc.js
module.exports = {
extends: ['plugin:vue/base'],
rules: {
'vue/script-setup-uses-vars': 'error',
}
}

SassError: File to import not found or unreadable: style.scss

I am trying to setup a vuejs project from scratch. I am getting this error when I import "style.scss" in the component. Here's the component (Login.vue) where I import the style.scss
<template>
<div class="container">
<div class="card">
<h1>This is login page</h1>
</div>
</div>
</template>
<script>
export default {
name: "Login"
};
</script>
<style lang="scss">
#import 'style.scss';
</style>
Here is my folder structure. style.scss is under /src and the component Login.vue is under /src/views:
I even tried changing the import to
#import '/style.scss'; //and
#import '../style.scss';
Here's my webpack configuration of sass-loader
{
test: /\.scss$/,
use: [
'vue-style-loader',
'css-loader',
'sass-loader'
]
}
Your file name is "styles" not "style".
Try one of those three file path options you listed above. I'm pretty sure either #import '/styles.scss'; or #import '../styles.scss'; should work for you.

How to import css file from node_modules in Vue-component

I want to connect this toastr-library into my component:
my-component.vue
<script>
import toastr from 'toastr';
export default {
mounted(){
toastr.success('Hello from toastr!');
}
}
</script>
<template>
<div>
Template for my-component.vue here.
</div>
</template>
<style>
/* HOW TO IMPORT `toastr.css` FROM NODE_MODULES HERE?
</style>
How to connect library's css from node_modules directory?
As #LinusBorg suggested here in vue-loader discussion thread, you can use src-attribute inside <style>-tag:
my-component.vue
<script>
import toastr from 'toastr';
export default {
mounted(){
toastr.success('Hello from toastr!');
}
}
</script>
<template>
<div>
Template for my-component.vue here.
</div>
</template>
<style src='toastr/build/toastr.min.css'></style>

VueJS 2 + ASP.NET MVC 5

I'm very new with VueJS.
I have to build a single page application inside a ASP.NET MVC5.
I follow this tutorial and works very well -> TUTORIAL
But when i create a .vue page to test VueJS2 Routes, the browser does not understand "Import", i read that i have to use a transpiler like Babel, someone know how i solve it?
App.VUE
<template>
<div id="app">
{{msg}}
</div>
</template>
<script>
export default {
name: 'app',
data () {
return {
msg: 'Welcome to Your Vue.js App'
}
}
}
</script>
App.JS
import Vue from 'vue'
import App from './App.vue'
new Vue({
el: '#app',
router,
render: h => h(App),
data: {
message: 'Hello Vue! in About Page'
}
});
_Layout.cshtml
<div class="container-fluid">
#RenderBody()
<div id="app">
{ { message } }
</div>
</div>
<script src="~/Scripts/essential/jquery-3.1.1.min.js"></script>
<script src="~/Scripts/essential/bootstrap.min.js"></script>
<script src="~/Scripts/essential/inspinia.js"></script>
<script src="~/Scripts/essential/vue.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue-router/2.0.1/vue-router.js"></script>
<script src="~/Scripts/app.js"></script>
<script src="~/Scripts/plugin/metisMenu/jquery.metisMenu.js"></script>
<script src="~/Scripts/plugin/pace/pace.min.js"></script>
<script src="~/Scripts/plugin/slimscroll/jquery.slimscroll.min.js"></script>
Thanks a lot!!
Welcome to Vue.js development! Yes, you are correct, you need something to translate the import statements into JavaScript that the browsers can handle. The most popular tools are webpack and browserify.
You are also using a .vue file, which needs to be converted (with vue-loader) before the browser can pick it up. I am going to lay out how to do this, and set up webpack, which involves a few steps. First, the HTML we're working with looks something like this:
<html>
<head>
</head>
<body>
<div class="container-fluid">
<div id="app">
{ { message } }
</div>
</div>
<script src="./dist.js"></script>
</body>
</html>
Our goal is to use webpack to bundle / compile App.vue and app.js into dist.js. Here is a webpack.config.js file that can help us do that:
module.exports = {
entry: './app.js',
output: {
filename: 'dist.js'
},
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader'
}
]
}
}
This configuration says, "start in app.js, replace import statements as we come across them, and bundle it into a dist.js file. When webpack sees a .vue file, use the vue-loader module to add it to dist.js."
Now we need to install the tools / libraries that can make this happen. I recommend using npm, which comes with Node.js. Once you have npm installed, you can put this package.json file in your directory:
{
"name": "getting-started",
"version": "1.0.0",
"scripts": {
"build": "webpack"
},
"dependencies": {
"css-loader": "^0.28.7",
"vue": "^2.4.2",
"vue-loader": "^13.0.4",
"vue-resource": "^1.3.3",
"vue-router": "^2.7.0",
"vue-template-compiler": "^2.4.2",
"webpack": "^3.5.5"
}
}
And do the following:
Run npm install to get all of the packages.
Run npm run-script build to generate your dist.js file via webpack.
Note in the example for this question, router is undefined in app.js, but here is a fixed-up file:
import Vue from 'vue'
import VueRouter from 'vue-router'
import App from './App.vue'
var router = new VueRouter();
new Vue({
el: '#app',
router,
render: h => h(App),
data: {
message: 'Hello Vue! in About Page'
}
});
That should be it! Let me know if you have any questions.

Resources