How to make Axios use Fetch instead of XMLHttpRequest - xmlhttprequest

I am beginner in the PWA and I try to get my code to call an API and then store it in the browser's cache. But I see that axios uses the XMLHttpRequest and not the fetch API, so I can't cache my API call.
I use workbox for the service worker and vue cli.
my service-worker.js :
workbox.setConfig({
debug: false,
});
workbox.precaching.precacheAndRoute([]);
//image in cache
workbox.routing.registerRoute(
/\.(?:png|gif|jpg|jpeg|svg)$/,
workbox.strategies.staleWhileRevalidate({
cacheName: 'images',
plugins: [
new workbox.expiration.Plugin({
maxEntries: 60,
maxAgeSeconds: 30 * 24 * 60 * 60, // 30 Days
}),
],
}),
);
//network request in cache
workbox.routing.registerRoute(
new RegExp('http://api.giphy.com/v1/gifs/'),
workbox.strategies.networkFirst({
cacheName: 'api',
}),
);
//js and css in cache
workbox.routing.registerRoute(
/\.(?:js|css)$/,
workbox.strategies.staleWhileRevalidate(),
);
//webfont in cache
workbox.routing.registerRoute(
new RegExp('https://fonts.(?:googleapis|gstatic).com/(.*)'),
workbox.strategies.cacheFirst({
cacheName: 'googleapis',
plugins: [
new workbox.expiration.Plugin({
maxEntries: 30,
}),
],
}),
);
my registerServiceWorker.js :
import { register } from 'register-service-worker'
if (process.env.NODE_ENV === 'production') {
register(`${process.env.BASE_URL}service-worker.js`, {
ready () {
console.log(
'App is being served from cache by a service worker.\n'
)
},
registered () {
console.log('Service worker has been registered.')
},
cached () {
console.log('content in cached');
},
updatefound () {
console.log('New content is downloading.')
},
updated () {
console.log('New content is available; please refresh.')
},
offline () {
},
error (error) {
console.error('Error during service worker registration:', error)
}
})
}
and my call API :
import Vue from 'vue';
import CONSTANTS from '../constants/constants';
import exception_manager from 'exception_manager';
export default {
getGiphy() {
return Vue.axios.get(`${CONSTANTS.SERVER_ADDRESS}search?q=cat&api_key=${CONSTANTS.API_KEY}&limit=9`).catch(error => {
exception_manager.handleException(error, 'GiphyService.js', 8, window, CONSTANTS.ERROR_SERVER_ADDRESS);
});
}
}
I think that's really the story with the xmlhttprequest, but I'm not sure.
On the other hand, js, css and images files are well cached

Your RegExp route inside of the service worker looks for http://api.giphy.com/v1/gifs/, which is an http: URL. Service workers will only intercept secure requests, which means https: (or http://localhost).
Make sure that you're using https: in your client-side Vue code, and adjust your Workbox configuration to use https: as well.

Related

How to call methods in Vue app $refs.components or Vuex $store from registerServiceWorker.js?

I'm working on a Vue PWA scaffolded out with Vue CLI, which by default uses register-service-worker package to expose the serviceWorker lifecycle methods in registerServiceWorker.js:
ready () {
console.log(
'App is being served from cache by a service worker.'
)
},
registered () {
console.log('Service worker has been registered.')
},
cached () {
console.log('Content has been cached for offline use.')
},
updatefound () {
console.log('New content is downloading.')
},
updated () {
console.log('New content is available; please refresh.')
},
offline () {
console.log('No internet connection found. App is running in offline mode.')
},
error (error) {
console.error('Error during service worker registration:', error)
}
registerServiceWorker.js is imported into main.js:
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store/index'
import './registerServiceWorker'
Vue.config.productionTip = false
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
The question is, how do I access scope to call methods in my Vuex $store or App.vue $refs.components from the scope of registerServiceWorker.js, e.g.
updated () {
// Something like
this.$store.commit('showUpdateNotification')
// OR
this.$refs.updateNotification.show()
}
I know I can setup additional eventListeners in my app to do this, but seems better to make use of registerServiceWorker.js?
Import the Vuex store in your registerServiceWorker.js file.
ie.
/* eslint-disable no-console */
import { register } from 'register-service-worker'
import appConfig from './app.config.json'
import store from './store'
if (process.env.NODE_ENV === 'production') {
register(`${appConfig.router.baseUrl}service-worker.js`, {
ready() {
console.log(
'App is being served from cache by a service worker.'
)
},
cached() {
console.log('Content has been cached for offline use.')
},
updated() {
console.log('New content is available; please refresh.')
store.commit('showUpdateNotification')
},
offline() {
console.log(
'No internet connection found. App is running in offline mode.'
)
},
error(error) {
console.error('Error during service worker registration:', error)
},
})
}

nuxtjs/proxy url axios after dist

when I ty yarn dev In server rendering Proxy is working fine. fetching data from API site api.server.com/api
But after yarn generate axios request is calling self server
current.example.com/api.
Why it is not working in dist html?
Is Proxy working only in server side? Please, help.
I have NuxtJS config:
/*
** Nuxt.js modules
*/
modules: [
'#nuxtjs/axios',
'#nuxtjs/proxy'
],
axios: {
proxy: true // Can be also an object with default options
},
proxy: {
'/api/': {
target: 'http://api.server.com/api',
pathRewrite: {'^/api/': ''}
},
changeOrigin: true
},
plugins axios.js
import axios from 'axios'
export default axios.create({
baseURL: '/api/',
responseType: 'json'
})
here I called that API like below index.vue
<script>
import axios from '~/plugins/axios'
export default {
mounted() {
this.loaded();
},
methods: {
loaded(){
const location = axios.get('/contact/contact_session.php').then((response) => {
console.log(response);
}).catch((err) => {
});
},
}
}
</script>
The proxy.js module only works in the development environment, in the production environment you must configure your web-server, preferably nginx, the proxy that takes your requests for example from the path "/ api / ..." and redirects it to the server you need.

The vue pwa offline event doesn't fire

I just create a new vue application with pwa from the #vue/cli.
When I switch to offline mode or refresh the page in offline mode,
I do expect to see the message: "No internet connection found. App is running in offline mode." because in registerServiceWorker.ts has the event.
/* eslint-disable no-console */
import { register } from 'register-service-worker'
if (process.env.NODE_ENV === 'production') {
register(`${process.env.BASE_URL}service-worker.js`, {
ready () {
console.log(
'App is being served from cache by a service worker.\n' +
'For more details'
)
},
registered () {
console.log('Service worker has been registered.')
},
cached () {
console.log('Content has been cached for offline use.')
},
updatefound () {
console.log('New content is downloading.')
},
updated () {
console.log('New content is available; please refresh.')
},
offline () {
console.log('No internet connection found. App is running in offline mode.')
},
error (error) {
console.error('Error during service worker registration:', error)
}
})
}

Service worker not caching https responses

I have a service worker for a vue pwa. Its able to cache assets but I cant figure out how to cache http responses. According to this tutorial I am supposed to see api-cache in Cache Storage list
vue.config.vue
module.exports = {
pwa: {
workboxPluginMode: "InjectManifest",
workboxOptions: {
swSrc: "./src/sw.js",
swDest: "service-worker.js",
navigateFallback: "/index.html",
runtimeCaching: [
{
urlPattern: new RegExp(
"^https://<api>.<domain>.co.za/"
),
handler: "networkFirst",
options: {
networkTimeoutSeconds: 2000,
cacheName: "api-cache",
cacheableResponse: {
statuses: [0, 200]
}
}
}
]
}
}
};
registerServiceWorker.js
/* eslint-disable no-console */
import { register } from 'register-service-worker'
if (process.env.NODE_ENV === 'production') {
register(`${process.env.BASE_URL}service-worker.js`, {
ready () {
console.log(
'App is being served from cache by a service worker.'
)
},
registered (registration) {
setInterval(() => {
registration.update();
}, 1000 * 60 * 60);
console.log('Service worker has been registered.')
},
cached () {
console.log('Content has been cached for offline use.')
},
updatefound () {
console.log('New content is downloading.')
},
updated (registration) {
document.dispatchEvent(
new CustomEvent('swUpdated', { detail: registration })
);
console.log('New content is available; please refresh.')
},
offline () {
console.log('No internet connection found. App is running in offline mode.')
},
error (error) {
console.error('Error during service worker registration:', error)
}
})
}
It might well be that the package #ionic/vue is the reason.
If you can, I would suggest to try to implement your PWA with workbox. It is a set of node libraries, therefore you can embed in your Vue app.
In the same article suggested in the comments, I give also an Overview about Workbox.
Some articles related to using Workbox with Vue PWA:
https://www.blog.plint-sites.nl/adding-workbox-to-a-vue-cli-pwa/
https://www.telerik.com/blogs/offline-first-vue-apps-with-hoodie-workbox

Cant mock axios api call with axios-mock-adapter in Storybook with Vuejs

Been trying to use storybook with my VueJS project and Im stuck with mocking api calls.
I tried using axios-mock-adapter without luck.
My storybook file code is:
import { storiesOf } from '#storybook/vue';
import { action } from '#storybook/addon-actions';
import { withKnobs, boolean } from '#storybook/addon-knobs';
import axios from 'axios';
import MockAdapter from 'axios-mock-adapter';
import fileUpload from './fileUpload.vue';
const mock = new MockAdapter(axios);
mock
.onPost('https://s3.amazonaws.com')
.reply(200, []);
storiesOf('Common|File CSV Upload', module)
.addDecorator(withKnobs)
.add('Default', () => ({
components: { fileUpload },
data: () => ({
}),
template: `
<v-flex>
<file-upload></file-upload>
</v-flex>`,
methods: {
action: action('file upload'),
},
}));
Am I using it right?
My strong recommendation is to use storybook-addon-mock for mocking (axios) API calls in Storybook.
It is nicley integrated into Storybook, setup in the different stories is easy and the data can be alteresd in the corresponding panel.
These 4 steps are needed:
Add the additional dependency: yarn add storybook-addon-mock
adapt the config and add in .storybook/main.js:
module.exports = {
addons: [
...
'storybook-addon-mock',
],
configure the behaviour and add mock data for general/ repeating API calls in .storybook/preview.js. These are mocks that will be available in every story.
export const parameters: Parameters = {
mockAddonConfigs: {
globalMockData: [
{
url: 'api/token',
method: 'POST',
status: 200,
response: () => '1234567abcdefg',
},
],
refreshStoryOnUpdate: true, // This re-render the story if there's any data changes
// disable: true, // This disables the panel from all the stories
}
in your story file add:
export default {
title: 'components/myComponentName',
component: MyComponent,
parameters: {
mockData: [
{
url: '/api/myendpoint/',
method: 'GET',
status: 200,
delay: 500,
response: () => 'some content',
},
{
url: '/api/myendpoint/',
method: 'POST',
status: 200,
delay: 1000,
response: {
data: 'some response',
},
},
],
},
Hint: Have a look into the different responses - function, string, etc to match them with the real response. There can be a pitfall with the data entry, that can be avoided with response: () => 'some content'