Nuxt JS LocalStorage in Universal mode not working - vue.js

I'm working on a Nuxt JS application which utilises LocalStorage. When compiling in SPA mode it functions correctly, however I need to switch my project to universal mode to get my SEO meta titles and descriptions to work when generating my project, after switching I get an error on a few pages which utilise LocalStorage:
localStorage is not defined
Has anyone got any suggestions to fix this?

You don't have localStorage because there is no such thing in Node.js environment. You also don't have window and document objects.
https://ssr.vuejs.org/guide/universal.html#access-to-platform-specific-apis
Nuxt.js uses Vue SSR under the hood.
However, you still have a store (Vuex). And it will be synchronized between node and browser.

I needed data to persist between sessions for GDPR. You can use the mounted life cycle event and wait for window.localStorage to be available. Then assign it to a data property and add a v-if in a wrapper tag so the page doesn't start rendering before localeStorage is available. I'm doing this with a static nuxt build:
<div v-if="localStorageReady">
Awesome stuff here...
</div>
data() {
return {
localStorageReady: false,
}
},
mounted() {
if (window.localStorage) {
this.localStorageReady = true
}
}

Related

How to use Vue hooks inside a custom plugin?

I am writing custom plugin and need to create CSS custom properties from inside of it. In SPA mode everything is fine, but SSR mode is where the troubles coming. What I need is just to put my method inside of a mounted() hook. Is it possible?
export default {
install(app, options) {
createCSSVariables()
function createCSSVariables(options) {
const root = document.documentElement // this can't be working on server side :(
root.style.setProperty('--font-family', options.font_family)
root.style.setProperty('---accent', options.colors.accent)
}
}
}
I am using nuxt and could just use 'client' flag in plugin, but since it is for UI library, this will not help much - in this scenario all the elements would flicker right after mount

How to refer other html file to load in production mode of application that are developed using electron?

I have problem in building electron application, which is made using electron.js and vue.js.
The development is almost done, so I need to build it and make production.
Basically, my project has license system, so when the program starts, users should activate it by entering license key. I wrote this part inside activate.html. So, inside public folder, there are two html files, one is default index.html, and the other is activate.html
Inside activate.html, when activation is success, startMain() javascript function is called. Inside this function, the program is navigated to main program, especially to index.html. This html file is Vue application, and then main program is started.
All this process is working fine in the development mode. But when it
comes to production, this is not working anymore. I probably know why this
happens, this is just because index.html is not available in
production mode when all these are built up.
Alternatively, I tried to load localhost:8080 inside
startMain(). But also this works fine in development mode, but unluckily, we don't have localhost server on production mode, so this
doesn't solve the problem.
This is startMain() inside activate.html
function startMain() {
window.__static = "index.html";
// Alternatively, we can use location.href on development mode.
// window.location.href = "http://localhost:8080/";
}
This is background.js ( electron main engine)
function createWindow() {
// Create the browser window.
win = new BrowserWindow({
width: 1400,
height: 900,
titleBarStyle: "hiddenInset"
});
win.setMenuBarVisibility(false);
if (isDevelopment) {
// Load the url of the dev server if in development mode
// win.loadURL(process.env.WEBPACK_DEV_SERVER_URL);
win.loadURL(`file://${process.cwd()}/public/activate.html`);
// if (!process.env.IS_TEST) win.webContents.openDevTools()
} else {
createProtocol("app");
// Load the index.html when not in development
win.loadFile("activate.html");
}
win.on("closed", () => {
win = null;
});
}
What I want is to make it run correctly in production mode.
Specifically, when the user finishes activation flow ( activate.html),
it should start main program ( index.html )
Please help me with this issue. I welcome any comments.
I built this application using vue-cli-plugin-electron-builder package
In Vue usually you use vue-router to switch between views. You set the BrowserWindow.location the first time, in background.js, but after that you are in the Vue app and you make router calls like this:
router.replace({ name: "index" }).catch(() => { });
It's hard to guess what to do in your case, without seeing the rest of your activate.html. You need to define router in your App and probably want to convert your activate.html into an activate.vue component and make it the proper first page of your App.
I think the cli-plugin boilerplate will call main.js where you will define your app and bootstraps it. You add router there:
import router from "./router";
window.$app = new Vue({
router,
In your bootstrap function you can also call something like router.replace({ name: "activate"}) to start your app with your activate vue component.

Dynamically decide when to use vue router

I have a big web application which I am building with vuejs and laravel.
Along the way, I have to switch between
<router-link></router-link> and <a></a> tags
so I build a template that I have a link on it I want it to automatically detect if vue <router-view></router-view>
is available otherwise just use the normal href tag
The below code is the function I have assigned to the click function but it turns out not to be working
try {
this.$router.push("/cart");
} catch (error) {
window.location.href = "/cart";
}
}
My question is
is there any way I can dynamically detect the presence of vue router and as well decide on which tag to use.
Either
window.location.href
or
this.$router.push()

Load AJAX in Framework7, vue

I'm very new to Framework7, and want to build a fairly simple mobile app -- a list of places, detail pages of those places (where some murals are displayed), and a map and about page. My current plan is to publish it via PhoneGap Build, since that seems like a fast and easy way to deploy.
I created my app using the phonegap-framework7-vue template. Perhaps overkill for such a simple app, but seems better than building it from scratch.
I want to load a list of places via AJAX (eventually via sqlite), and can't figure out how/when to do this, and how to access the main app. My Murals.vue file has the template and the following script, but doesn't load because app.request is undefined. I've tried "framework7", "Framework7", and moving it outside of the mounted() call, but feel like I'm just guessing. Any suggested? Thanks!
<script>
import F7List from "framework7-vue/src/components/list";
let dataURL = 'https://jsonplaceholder.typicode.com/posts'; // returns some json
export default {
name: 'Murals',
components: {F7List},
mounted() { // when the Vue app is booted up, this is run automatically.
app.request.get(dataURL, function (data) {
console.log(data);
});
},
data () {
return {
title: 'Murals'
};
}
};
</script>
You're code is almost right !
To access to F7 app instance with vue, you have to use this.$f7.request rather the app.request

How to fetch data before mounting the root Vue instance?

TL;DR: What is a good way to do async stuff before starting the app?
vue-devtools does not work correctly if I wait for async stuff to finish before creating / mounting the root Vue instance.
I'm new to Vue.js and I'm developping a back office app where nothing is accessible unless the user is logged. Except for the sign in / sign up pages of course.
So on page load I do something like this:
// Set up store and router ...
router.beforeEach(function (to, from, next) {
/* redirect to auth if store.state.auth.isLogged is false */
}
// Dispatch an action that send a request to the API to get the connected user
// (or null if the user is not logged)
store.dispatch('getAuth').then(user) {
// Mount the app one the request is done and the mutation for isLogged is done
new Vue({
el: '#app',
router,
store,
// ...
});
}
And in my index.html I have a pure HTML/CSS loading page that waits for the vue app to mount.
So this works fine, on load, the app check if the user is logged and once this is done, it redirects to the auth pag if needed.
My problem is mainly with vue-devtools, it seems that if the root Vue instance is not mounted on page load, I can't inspect components from the vue-devtools, but the vuex & events inspection works. Plus the extension icon on chrome is grayed out ("Vue.js not detected") whereas it kind of works.
Am I doing something wrong? Or is it a problem with the devtools?
What you are doing is fine. There is a refresh button at the top right of the Vue dev tools. Click it and your asynchronously loaded Vue instance should be detected.