Fetching data from an API works locally but not live - javascript

First time building a site with Nuxt.js and I'm requesting data from an API that works great locally but when I access the site through Netlify, none of the code seems to run. I'm assuming this has something to do with my misunderstanding of how static sites work.
What I'm trying to do is check if there is a browser cookie, if not create one and fetch the API to get the user's general location and check their city against an array of cities in NY. If there is a match then close the v-banner. If there is already a browser cookie then close the v-banner.
Abridged index.vue:
<template>
<v-app v-bind:class="{ alertOpen: alertOpen }">
<v-main>
<v-banner
class="state-alert"
transition="slide-y-transition"
v-bind:class="{ alertOpen: alertOpen }"
>
By our calculations, it looks like you might be visiting our website from outside of New York. Unfortunately at this time, we can't sell our Granola outside of New York. If you are buying a gift for someone with a New York address then please proceed.
<template>
<v-btn
icon
color="alert"
v-on:click="alertOpen = false"
>
<v-icon>mdi-close</v-icon>
</v-btn>
</template>
</v-banner>
</v-main>
</v-app>
</template>
<script>
let nyList = ['Albany', 'Amsterdam', 'Auburn', 'Batavia', 'Beacon', 'Binghamton', 'Buffalo', 'Canandaigua', 'Cohoes', 'Corning', 'Cortland', 'Dunkirk', 'Elmira', 'Fulton', 'Geneva', 'Glen Cove', 'Glens Falls', 'Gloversville', 'Hornell', 'Hudson', 'Ithaca', 'Jamestown', 'Johnstown', 'Kingston', 'Lackawanna', 'Little Falls', 'Lockport', 'Long Beach', 'Mechanicville', 'Middletown', 'Mount Vernon', 'New Rochelle', 'New York', 'Newburgh', 'Niagara Falls', 'North Tonawanda', 'Norwich', 'Ogdensburg', 'Olean', 'Oneida', 'Oneonta', 'Oswego', 'Peekskill', 'Plattsburgh', 'Port Jervis', 'Poughkeepsie', 'Rensselaer', 'Rochester', 'Rome', 'Rye', 'Salamanca', 'Saratoga Springs', 'Schenectady', 'Sherrill', 'Syracuse', 'Tonawanda', 'Troy', 'Utica', 'Watertown', 'Watervliet', 'White Plains', 'Yonkers'];
export default ({
head() {
return {
script: [{
body: true
}]
}
},
data() {
return {
geoData: [],
alertOpen: true
}
},
async fetch() {
const locationCookie = this.$cookies.get('location-cookie');
if(!locationCookie) {
console.log('no cookie');
this.$cookies.set('location-cookie', 'true', {
path: '/',
maxAge: 31556952
});
this.geoData = await fetch(
'https://ipgeolocation.abstractapi.com/v1/?api_key=1eef312cdda9428cac26815c9d3bdd26'
).then(res => res.json());
var vm = this;
compareCity(this.geoData.city);
function compareCity(city) {
var i;
for(i = 0; i < nyList.length; i++) {
if(nyList[i].toLowerCase().replace(/\s/g, '') == city.toLowerCase().replace(/\s/g, '')) {
console.log(city);
vm.alertOpen = false;
}
}
}
} else {
console.log('yes cookie');
this.alertOpen = false;
}
}
});
</script>
Not sure if ya'll also need to see the nuxt.config.js:
export default {
mode: "universal",
// Global page headers (https://go.nuxtjs.dev/config-head)
head: {
title: 'homemade-crunch',
meta: [
{ charset: 'utf-8' },
{ name: 'viewport', content: 'width=device-width, initial-scale=1' },
{ hid: 'description', name: 'description', content: '' }
],
link: [
{ rel: "preconnect", href: "https://app.snipcart.com" },
{ rel: "preconnect", href: "https://cdn.snipcart.com" },
{ rel: 'stylesheet', href: 'https://cdn.snipcart.com/themes/v3.0.23/default/snipcart.css', defer: true },
{ rel: 'stylesheet', href: 'https://fonts.googleapis.com/css2?family=Anton&family=Open+Sans&display=swap' }
],
script: [
{ src: "https://cdn.snipcart.com/themes/v3.0/default/snipcart.js", defer: true }
]
},
// Global CSS (https://go.nuxtjs.dev/config-css)
css: [
],
// Plugins to run before rendering page (https://go.nuxtjs.dev/config-plugins)
plugins: [
'#plugins/vuetify'
],
// Auto import components (https://go.nuxtjs.dev/config-components)
components: true,
// Modules for dev and build (recommended) (https://go.nuxtjs.dev/config-modules)
buildModules: [],
// Modules (https://go.nuxtjs.dev/config-modules)
modules: [
'vue-scrollto/nuxt',
'cookie-universal-nuxt'
],
// Build Configuration (https://go.nuxtjs.dev/config-build)
build: {
},
server: {
port: 3333,
host: '0.0.0.0'
}
}
The git repo: https://github.com/mat148/Homemade-crunch
and live site: https://www.homemadecrunch.com/
Let me know if I've forgotten something or done something silly.
Any help would be greatly appreciated.
Thank you!

I decided to move my logic from the index.vue to a javascript file

Related

Multiple NuxtJS og:image Meta Tags

In the specification of Open Graph protocol - Arrays it is documented that multiple versions of the type og:image may be arranged.
We use on components basis this structure in NuxtJS ssr:
export default {
data() {
return {
title: 'Home page'
}
},
head() {
return {
title: this.title,
meta: [
{
hid: 'description',
name: 'description',
content: 'Home page description'
}
// And others...
]
}
}
}
The goal is to have multiple nodes of the tag <meta property="og:image" content="https://example.com/rock.jpg" /> generated by NuxtJS Meta. The thinking is, since these are dynamic pages, to build an array and merge them into the meta array.
export default {
data() {
return {
title: 'Home page'
}
},
head() {
return {
title: this.title,
meta: [
{
hid: 'description',
name: 'description',
content: 'Home page description'
}
// And others...
...this.getMetaOgImages
]
}
},
computed: {
getMetaOgImages() {
const tempArr = []
// this.images comes from map state vuex-store
this.images.forEach(image => {
tempArr.push(
{
hid: 'og:image',
property: 'og:image',
content: image.url
},
{
hid: 'og:image:secure_url',
property: 'og:image:secure_url',
content: image.url
}
)
})
return tempArr
}
}
}
The computed property contains all urls, but in the browser (in the generated <meta> tags) only the first element is present.
It seems to me that vue-meta filters out the other elements because they are considered duplicates.
Can anyone confirm this or does anyone have experience with outputting multiple elements?
According to the specification this is valid and should not be a problem.

PWA - Frontend doesn't update even after a hard refresh

Below is the configuration of our nuxt and nuxt-pwa configuration.
Nuxt pwa is recognising a new version available and we prompt user to do a hard refresh/reload.
And on reload - new UI also starts to work.
However, if we open the site in a new tab. A spinner gets shown & the latest frontend fails to load. And again, a hard refresh is required.
our frontend redirects to /dashboard on visiting localhost:8080 by default and this is getting loaded from serviceworker with cached data.
Please help us resolve this since this has been a critical issue for us.
Spinner seen on new tab opening :
export default {
ssr: false,
target: 'static',
head: {
titleTemplate: '',
title: 'NocoDB',
meta: [
{ charset: 'utf-8' },
{ name: 'viewport', content: 'width=device-width, initial-scale=1' },
{ hid: 'description', name: 'description', content: process.env.npm_package_description || '' }
],
link: [
{ rel: 'icon', type: 'image/x-icon', href: './favicon-32.png' }
]
},
plugins: [
// plugins
],
buildModules: [
'#nuxtjs/vuetify',
'#nuxtjs/pwa'
],
modules: [
// Doc: https://axios.nuxtjs.org/usage
'#nuxtjs/axios',
'vue-github-buttons/nuxt',
'#nuxtjs/toast'
],
axios: {
baseURL: process.env.NC_BACKEND_URL || (process.env.NODE_ENV === 'production' ? '..' : 'http://localhost:8080')
},
router: {
mode: 'hash',
base: process.env.NODE_ENV === 'production' ? './' : '',
middleware: ['auth']
},
vuetify: {
defaultAssets: {
icons: false
},
optionsPath: '#/config/vuetify.options.js',
treeShake: true,
customVariables: ['./config/variables.scss']
},
build: {
parallel: true,
plugins: [
new MonacoEditorWebpackPlugin({
languages: ['sql', 'json', 'javascript'],
features: ['!gotoSymbol']
})
],
extend(config, { isDev, isClient }) {
if (isDev) {
config.devtool = isClient ? 'source-map' : 'inline-source-map'
}
config.externals = config.externals || {}
config.externals['#microsoft/typescript-etw'] = 'FakeModule'
return config
}
},
pwa: {
workbox: {
assetsURLPattern: /\/_nuxt\//,
config: { debug: true }
},
icon: {
publicPath: './'
},
manifest: {
name: 'NocoDB',
start_url: '../?standalone=true',
theme_color: '#ffffff'
}
}
}
Lighthouse report :
Github issue reference : https://github.com/nuxt-community/pwa-module/issues/501
You need to set service worker which clears cache based on versions.
Setup service-worker.js as below. and update LATEST_VERSION on changes you deploy.
// service-worker.js
importScripts("https://storage.googleapis.com/workbox-cdn/releases/4.3.1/workbox-sw.js");
workbox.core.setCacheNameDetails({ prefix: 'pwa' })
//Change this value every time before you build to update cache
const LATEST_VERSION = 'v1.0.1'
self.addEventListener('activate', (event) => {
console.log(`%c ${LATEST_VERSION} `, 'background: #ddd; color: #0000ff')
if (caches) {
caches.keys().then((arr) => {
arr.forEach((key) => {
if (key.indexOf('pwa-precache') < -1) {
caches.delete(key).then(() => console.log(`%c Cleared ${key}`, 'background: #333; color: #ff0000'))
} else {
caches.open(key).then((cache) => {
cache.match('version').then((res) => {
if (!res) {
cache.put('version', new Response(LATEST_VERSION, { status: 200, statusText: LATEST_VERSION }))
} else if (res.statusText !== LATEST_VERSION) {
caches.delete(key).then(() => console.log(`%c Cleared Cache ${LATEST_VERSION}`, 'background: #333; color: #ff0000'))
} else console.log(`%c Great you have the latest version ${LATEST_VERSION}`, 'background: #333; color: #00ff00')
})
})
}
})
})
}
})
workbox.core.skipWaiting();
workbox.core.clientsClaim();
self.__precacheManifest = [].concat(self.__precacheManifest || [])
// workbox.precaching.suppressWarnings()
workbox.precaching.precacheAndRoute(self.__precacheManifest, {})
Don't know for nuxt, but for angular we need to bump the version element of ngsw-config.json on each deploy (1, 2, 3, ...) and also call SwUpdate.checkForUpdate() on startup. Only then the new version of the app will be retrieved from the server.

Add RTL condition in head with Nuxt Js i18n

I would like to add a condition as follows
if(app.i18n.locale == 'ar')
I use Arabic with English in this project. If the current language is Arabic, bootstrap-rtl.css is added in the head, and if the current language en is called bootstrap.css, I have tried more than one method and did not succeed.
Add a file in plugins folder for example direction-control.js
export default ({ app }, inject) => {
const dir = () =>
app.i18n.locales.find((x) => x.code === app.i18n.locale)?.dir;
inject('dir', dir);
};
While your nuxt.config.js will need similar code to this
plugins: [
'~/plugins/direction-control', // your plugins file name
// other plugins
],
modules: [
[
'nuxt-i18n',
{
locales: [
{
code: 'en',
file: 'en.json',
dir: 'ltr',
name: 'English',
},
{
code: 'ar',
file: 'ar.json',
dir: 'rtl', // that will be passed to your app
name: 'عربي',
},
],
langDir: 'translations/',
defaultLocale: 'ar',
},
],
],
Now it's time to get dir
export default {
mounted() {
console.log(this.$dir()); // logs your direction 'ltr' or 'rtl'
console.log(this.$i18n.locale);
if (this.$i18n.locale == "ar") {
// make some action
}
},
}
or inside template like this
<template>
<div :dir="$dir()">
<Nuxt />
</div>
</template>

Trying to set Vue Meta page title using string + variable

I'm using Vue Meta as part of a blog application within a project using Nuxt JS 2.4.5
I'm having some trouble trying to set the title + a variable from data () and I'm not sure what I'm missing
I've tried multiple attempts at getting it to work, moving code around, using this setting it manually, nothing seems to work...
<script>
import BlogsFromJson from '~/static/articles/blogs.json';
export default {
head: {
title: 'My Website: Blog: ' + this.myBlogTitle, // or something else
meta: [
{ hid: 'description', name: 'description', content: 'Read the latest news and articles from Flex Repay UK.' }
]
},
data () {
return {
title: this.$route.params.title,
blog: BlogsFromJson,
myBlogTitle: 'some title'
}
}
}
</script>
I've tried setting a variable within data () and using it statically.
Doing this should give me My Website: Blog: some title
What could I be missing here?
Try to use function instead of object for head.
Change
head: {
...
},
to
head () {
return {
...
}
}
Instead of defining metaInfo as an object, define it as a function and access this as usual:
Post.vue:
<template>
<div>
<h1>{{{ title }}}</h1>
</div>
</template>
your script
<script>
export default {
name: 'post',
props: ['title'],
data () {
return {
description: 'A blog post about some stuff'
}
},
metaInfo () {
return {
title: this.title,
meta: [
{ vmid: 'description', name: 'description', content: this.description }
]
}
}
}
</script>
PostContainer.vue:
<template>
<div>
<post :title="title"></post>
</div>
</template>
<script>
import Post from './Post.vue'
export default {
name: 'post-container',
components: { Post },
data () {
return {
title: 'Example blog post'
}
}
}
</script>
metaInfo() {
return {
title: this.pageTitle,
}
}

vue.js Uncaught SyntaxError: Identifier has already been declared

I have two demos for same library under repo, with demo.
The main difference is that, one is for browser use and the other is for node use.
However browser one will have error
index.js:1 Uncaught SyntaxError: Identifier 'HeaderComp' has already been declared
What is the main cause?
Update:
Please keep in mind I do not declare a variable twice! I also tried to add console log at the top to ensure the script is executed once!
var HeaderComp = {
name: 'HeaderComp',
template: `
Back
{{ r.title }}
`,
mixins: [VueTopDown.VueTopDownItem],
computed: {
routes () {
return [
{ href: '/page', title: 'Page' },
{ href: '/hello-vue', title: 'HelloVue' }
]
}
}
}
var FooterComp = {
name: 'FooterComp',
template: `{{ vueFooter }}`,
mixins: [VueTopDown.VueTopDownItem],
data () {
return {
vueFooter: 'This is Vue Footer'
}
}
}
var ContentComp = {
name: 'ContentComp',
template: ``,
mixins: [VueTopDown.VueTopDownItem],
computed: {
innerHTML () {
var root = document.createElement('div')
root.innerHTML = this[VTDConstants.OUTER_HTML]
return root.querySelector('*').innerHTML
}
}
}
var HelloVue = {
template: `Hello Vue`,
props: ['clazz'],
inheritAttrs: false
}
var Page = {
template: ``,
props: ['clazz', 'innerHTML'],
inheritAttrs: false
}
var router = new VueRouter([
{ path: '/hello-vue', component: HelloVue },
{ path: '/page', component: Page },
{ path: '*', redirect: '/page' }
])
var inst = new Vue({
router,
mixins: [VueTopDown.VueTopDown],
components: {
HeaderComp: HeaderComp,
FooterComp,
ContentComp
},
data () {
return {
[VueTopDown.VTDConstants]: {
'header': HeaderComp,
'footer': FooterComp,
'.content': ContentComp
}
}
}
})
inst.$mount('#app')
Also keep in mind that similar code works fine in node environment but fails in browser!
Doesn't occur if commenting out inst.$mount('#app')
Expect
The expected behavior of browser should be same as that of node.

Categories

Resources