VueJS 2 Apps compiled in 1 - vue.js

We are building an app using VueJS as our front end. But we sort of have 2 apps in one. The ecommerce side that the public sees, then we have a admin panel that our employees can use to add products, users, etc.
I am wondering the best way to style each of these sections differently. The ecommerce side we want to use 1 stylesheet (scss) and then our admin panel use another stylesheet. The problem we are running into is that when it all compiles both are added to both sides of the app. So because our admin is loaded second all of our color variables are show on the ecommerce public side of the app.
We have pulled the main.scss out of main.js and created main.scss & main-admin.scss, we are then importing these files into their respective page-template files which we though was going to deouple the 2. But that isnt working, any suggestion on the best way to accomplish this?

You can import your stylesheets dynamically in the script tag like this:
<script setup>
import { ref, watchEffect } from "vue";
const theme = ref(2);
watchEffect(() => {
import(`./assets/base${theme.value}.css`);
});
</script>

Related

Vue-Router add new route dynamically when there is a new component

I need to create a fully modular Vue project and I can't figure out how do I add or remove routes when there is a new component or a component is deleted.
Now I statically type all the routes that are available in my Sidebar menu. Let's say there are 10 menus in my sidebar, it means that I should type 10 routes in my routes.js file.
But I need this project to be modular. By saying modular what I mean is, I need to give the component list to the project, I think that I should do that with a .json file and let's say this file says that it has only 5 component available, then the related routes will be dynamically created in the routes.js file, and when one of them is deleted, the related route should be removed from the routes list as well. That is what I want.
I want to do that because I develop a single frontend with Vue for more than one device. These devices may have different options and menus, when the device and the frontend matches, only the available menus will be put in the sidebar, so I can't type all the routes statically as I've been doing the whole time.
Any advice would be appreciated.
You can loop through a list of routes and use the router.addRoute function to dynamically add them to your router instance (requires vue-router 3.5.0+), instead of loading them by default. You could do this from the created() hook of your main layout for example.
// app.vue
<template>
<router-view />
</template>
<script>
export default {
created() {
let routes = loadRoutes(); // insert your own function to get the correct routes here
routes.forEach(route => this.$router.addRoute(route))
},
};
</script>
If you need to be able to switch between different layouts on the same device (like a shared terminal for managers and employees) you can reset the routes array by creating a new router instance, or removeRoute (if you use v4.0+).

Vue including global styles without repeating the styles for each component

I have an app and would like to include some global styles that I can use anywhere in the app like this:
.btn {
...
}
In webpack I already have this for _variables.scss to include things like $my-color: $fff and that is wired up like this in my loaderOptions:
{
additionalData: `#import "#/styles/_variables.scss";`
}
Obviously for some global styles I could do the same thing, however, this will cause my styles like .btn to load as many times as components that I have.
Logically it would seem best to just go into my root Vue component and add global <style lang="scss"></style>.
However, I am upgrading a legacy jQuery app and it is being piecemealed and instead of one root app component, I have several roots for parts that have been converted to Vue. I don't have a central place to load these styles.
For instance I have searchBar and checkout apps that are instantiated using Vue.extend (so they are all part of the same instance). There aren't just two apps, there are quite a few. If I include the global styles in the root of any of them it... feels... icky...
Is there any way around this or should I set the global styles in a random app with a TODO to refactor once everything is ported over?
Ideally I would do the same thing I'm doing with the _variables.scss but having the styles duplicated for each component is a non starter for me.
In this scenario you do not need to worry about how webpacks CSS loaders are working.
You can simply go into your main.js and import '#/styles/globals.scss' to load the styles globally.

Gridsome: How to add Vue.use(MyPlugin) for a single page only?

I have added ReCaptcha plugin using Vue.use(ReCaptcha, {some options}) in Gridsome main.js which is displaying on all pages.
How to add plugin for a particular page only in gridsome?
I've never used ReCaptcha or Gridsome before, but generally, if you install a plugin using npm, then the simplest way to use it on a single page would be to import the plugin to the specific component rendered on the route you want to use it on. i.e
/* === MyComponent.vue === */
<script>
import plugin from 'packageName';
// or
import { pluginExport } from 'packageName';
export Default{
// You can then use the plugin/pluginExport here
}
From there you should be able to use the package in that specific component as you normally would if you implemented it app-wide with Vue.use. In some cases, depending on how the plugin is meant to be used, you may need to register the imported plugin Module as a child component in the components object. Like this vuejs QR Code generator for example.

Why router link have diferent behavior in mobil view?

When I use router links in desktop view works fine but in mobile view the links lack the "/" to work, any idea to make it work for mobile (I mean when max-width change) (bootstraps makes all the jobs). I think a parameter or something to keep it working if bootstraps changes to a copy the menu adapted to mobile screen. In that swap of styles bootstrap stripes the "/" to the links with router vue link to. Any advice, suggerence or sample link will appretiated.
You should read this.
Vue Router Child, Trailing slash
Also to prevent this you can use strict in vue-router as follows
const route1 = { template: '<div>Route 1 (strict)</div>' }
const route2 = { template: '<div>Route 2 (no strict)</div>' }
Check the fiddle link
http://jsfiddle.net/L7hscd8h/9377/

Is it possible to make a distributable Vue widget with Single File Components?

This might be a bit of an odd question, but I'll try to explain.
I'm looking to build a vue based video player widget for a client's Drupal website. The idea is to create something he can just drop in, like a JQuery plugin. However, I'd really like to leverage Vue's Single File Components (with Webpack) so I can keep everything all bundled together.
My first thought would be to use the Vue CLI, npm build and then reach into the dist/ folder and pull out the following to drop in:
<link href=/static/css/app.cf6f127cf50f4c0b2424d30fdc56c3a4.css rel=stylesheet>
<div id="my-widget"></div>
<script type=text/javascript src=/static/js/manifest.e12c1c4a9566f686d69f.js></script>
<script type=text/javascript src=/static/js/vendor.47037dd92c40b3f38949.js></script>
<script type=text/javascript src=/static/js/app.3f1bab5cc5b1be1127b2.js></script>
Although this feels off, is there a better way to achieve this? Keep in mind his website is NOT a Vue app, but I want this widget to be built LIKE a Vue app.
I don't know if I understand 100 percent, as far as I know, it is possible. It doesn't matter how you bundle your app. It is a matter of architecture. You can use vue.js partly, like widget.
First when you set Vue instance, just set element with your target element.
new Vue({
el: '#my-widget'
});
If you want your client to set element himself, make some functions to create vue widget. (considering multiple vue instance or state sharing blah blah...)
// you can provide simple function like this (I'm sure it needs to be more.)
const Widget = {
createWidget(el) {
new Vue({
el: el
});
}
};
// on client side
Widget.createWidget('#his-widget');
On bundling, if you want your widget to be bundled together with client's Drupal website. Let him import your widget like other libraries. You can build your widget with npm run build in vue-cli and then give it to him so that he can include it.
Thanks to #yuriy636 for answering my question. The CLI 3.0 allows to build as a library or a web component. docs
Also I found the following article which goes into more depth
https://vuejsdevelopers.com/2018/05/21/vue-js-web-component/