vue/cli-plugin-pwa: server requests (with axios) aren’t cached by the service worker - vue.js

I’m unsuccessfully trying to add PWA to the project. Server requests aren’t cached by the service worker. Request addresses aren’t added to Cache Storage. Accordingly, the offline mode doesn’t work.
Project config:
vue spa
requests to the server using axios library
server responses don’t contain cache-control header
pwa is implemented using the standard vue plugin: vue /
cli-plugin-pwa
PWA config in vue.config.js:
module.exports = {
publicPath: '/',
pwa: {
name: 'Old Vehicles',
manifestOptions: {
name: "Old Vehicles",
display: "standalone",
scope: "/",
start_url: "/"
},
workboxPluginMode: 'GenerateSW',
workboxOptions: {
navigateFallback: '/index.html',
runtimeCaching: [{
urlPattern: new RegExp('^http'),
handler: 'NetworkFirst',
options: {
networkTimeoutSeconds: 2,
cacheName: 'api-cache',
cacheableResponse: {
statuses: [0, 200],
},
},
}]
}
}
};
PS And also this: developer console in browser -> Application tab -> Installability -> "Page does not work offline". The service worker successfully connected (excepting request caching), the manifest is identified. Why does it show such a message?

I'm currently learning about PWA too. What I read about this issue:
Axios is using behind the lines XHR requests and not fetch requests.
Because workers run separately from the main thread, service workers are independent of the application they are associated with, consequences : synchronous XHR and localStorage cannot be used in a service worker
So I guess you may need to use standard fetch requests.

The other answer is misleading.
Assuming the service worker is successfully registered/etc, any (https) network request on the main thread (or web worker threads) will be sent via the service worker.
Axios is part of the main thread, not the service worker thread.
XHR in the main thread are the same as any other method (eg js: fetch(), html: , css: url())...all requests will trigger the 'fetch' event in the service worker (presumably to be cached).
The problem is quite likely to be because the network requests in the main thread are http, not https.
If possible, upgrade the server serving the resources from http to https, and change the URLs used on the main thread. It will not be possible to 'rewrite' the protocol in the service worker.
If you cannot change the code on the main thread for some reason (eg legacy app with no source), then it should be possible to get the server that is sending the document that causes the request (ie the js file with fetch('http://.../')/XHR, the html file with <img src="http://.../">, the css file with url(http://.../)) to add a header:
Content-Security-Policy: upgrade-insecure-requests
More info: https://github.com/w3c/ServiceWorker/issues/813
and https://w3c.github.io/webappsec-upgrade-insecure-requests/#goals

Related

Vuejs Issue with the second request having 300ms overhead

I started learning Vuejs and I saw a strange behavior with the HTTP request to my web server. I'm using axios to make requests.
I just installed the vue-cli version 3.11 without using the webpack, and I added the config file vue.config.js next to package.json with the following content to proxy my web server
module.exports = {
devServer: {
port: 8081,
proxy: "http://127.0.0.1:8080"
}
};
Then using axios I'm trying to do a GET request by clicking a button
axios.get(API_URL, {
headers: {
Accept: "application/json",
"Content-Type": "application/json",
"Cache-Control": "no-cache"
}
}).then(response => {});
My web server based on Python and bottle where the API request of fetching users takes between 5ms and 16ms to be processed.
By opening the browser inspector I saw that on the second request I'm getting an overhead around 300ms, please see below:
Request and Response parameters
Anyone has an opinion about this behavior? I searched a bit for vue-cli 3 issues or CORS headers but I did not find anything helpful. Thank you.

Vue Cli 3 blocks CORS even after headers change

I'm running locally both a Vue Cli 3 app and a Google Cloud Function (CF).
I have changed the response headers in CF as follows:
res.set('Access-Control-Allow-Origin', "*")
res.set('Access-Control-Allow-Methods', 'GET, POST')
and it serves me well when I call the CF from a browser.
For some reason, the same call is CORS blocked when invoked inside the Vue app.
I tried with Firefox (CORS enabled by settings as well as using a plugin).
I also added the following to vue.config.js as described here:
// vue.config.js
module.exports = {
devServer: {
proxy: 'http://localhost:8010', //<-- my CFs are running on 8010
}
}
Not sure how to proceed as the whole point of CFs is to not have any servers running (including a proxy).
Any pointers are much appreciated, cheers.
Problem was with the local Cloud Function emulator.
Got it working when I altered the Cloud Function headers in the live environment.
// Set CORS headers for preflight requests
function setCorsHeaders(req, res){
res.set('Access-Control-Allow-Origin', CLIENT_URL);
res.set('Access-Control-Allow-Credentials', 'true');
if (req.method === 'OPTIONS') {
// Send response to OPTIONS requests
res.set('Access-Control-Allow-Methods', 'GET,POST');
res.set('Access-Control-Allow-Headers', 'Content-Type');
res.set('Access-Control-Max-Age', '3600');
res.status(204).send('');
}
}

Lyft-API - GET from Localhost

I have been trying to figure out how to get this Vue project to work with the Lyft API. I have been able to get an Auth Token successfully created from the three-legged procedure, but I am unable to get the available drive types https://api.lyft.com/v1/ridetypes endpoint from the localhost:8080. It does work on Postman.
It keeps stating:
Access to XMLHttpRequest at
'https://api.lyft.com/v1/ridetypes?lat=37.7752315&lng=-122.418075'
from origin 'http://localhost:8080' has been blocked by CORS policy:
Response to preflight request doesn't pass access control check: No
'Access-Control-Allow-Origin' header is present on the requested
resource.
I had tried doing a proxy using a vue.config.js file:
module.exports = {
devServer: {
proxy: {
'/lyftapi': {
target: 'https://api.lyft.com/v1',
ws: true,
changeOrigin: true
}
}
}
}
I been around other parts of Stack Overflow, and this is the closest thing to my problem, but no answers.
CORS error in Lyft API started recently
Any suggestions?
Axios Get Call
axios.get('/ridetypes', {
baseURL: 'https://api.lyft.com/v1',
headers: {
'Authorization': this.lyftToken,
},
params: {
lat: lat.toString(),
lng: long.toString()
}
})
If it means anything, I am able to make successful GET calls to retrieve Uber products, but not so much the Auth Token (unless its from Postman).
Lyft-API has disabled CORS, this means that browsers will block calls to api.lyft.com.
Vue won't be able to do anyting about this as this is a browser security policy.
Luckily there is nothing from stoping you to make this call from your own server.
One solution is to forward the request and response using your own server. You make a call to your server, the server makes a call to lyft, waits for the response and then responds your request.
This is not a vue only solution.

How to ask to the service worker to ignore requests matching a specific URL pattern in Polymer?

My application is built on Polymer v2 and uses the Firebase Auth service for authentication. Actually, I use the login-fire element. For a better experience on mobile devices, I choose to sign-in with redirect.
In the "network" tab of the DevTool (in Chrome) I see that a request containing the /__/auth/handler? pattern is sent for requesting Google authentication (for example, if the provider used is Google).
With the service workers enabled, this request is caught and the response is the login page of my application. No login attempted, the response comes from the service worker and I get a Network Error from Firebase API because of a timeout.
When I deploy the app without service workers the authentication process is working and I can reach the app.
I tried many ways to config the service workers to ignore all requests to a URL with the /auth/ pattern but I failed.
See the last version of my config file bellow.
sw-precache-config.js
module.exports = {
globPatterns: ['**\/*.{html,js,css,ico}'],
staticFileGlobs: [
'bower_components/webcomponentsjs/webcomponents-loader.js',
'images/*',
'manifest.json',
],
clientsClaim: true,
skipWaiting: true,
navigateFallback: 'index.html',
runtimeCaching: [
{
urlPattern: /\/auth\//,
handler: 'networkOnly',
},
{
urlPattern: /\/bower_components\/webcomponentsjs\/.*.js/,
handler: 'fastest',
options: {
cache: {
name: 'webcomponentsjs-polyfills-cache',
},
},
},
{
urlPattern: /\/images\//,
handler: 'cacheFirst',
options: {
cacheableResponse: {
statuses: [0, 200],
},
},
},
],
};
Do you have a better solution? Do you notice what I missed?
Thank you for your help.
You can add this to your sw-precache-config.js file
navigateFallbackWhitelist: [/^(?!\/auth\/)/],
You should only whitelist the paths of your application. This should be known to you.
So everything you do not whitelist, will not be served from the serviceworker.
navigateFallbackWhitelist: [/^\/news\//,/^\/msg\//, /^\/settings\//],
With this example, only news/*, msg/*,settings/* will be delivered.
/auth/*,/api/*,... will not be caught.

How to serve data for AJAX calls in a Vue.js-CLI project?

I have a Vue.js CLI project working.
It accesses data via AJAX from localhost port 8080 served by Apache.
After I build the project and copy it to a folder served by Apache, it works fine and can access data via AJAX on that server.
However, during development, since the Vue.js CLI website is being served by Node.js which is serving on a different port (8081), I get a cross-site scripting error) and want to avoid cross-site scripting in general.
What is a way that I could emulate the data being provided, e.g. some kind of server script within the Vue.js-CLI project that would serve mock data on port 8081 for the AJAX calls during the development process, and thus avoid all cross-site scripting issues?
Addendum
In my config/index.js file, I added a proxyTable:
dev: {
env: require("./dev.env"),
port: 8081,
autoOpenBrowser: true,
assetsSubDirectory: "static",
assetsPublicPath: "/",
proxyTable: {
"/api": {
target: "http://localhost/data.php",
changeOrigin: true
}
},
And now I make my AJAX call like this:
axios({
method: 'post',
url: '/api',
data: {
smartTaskIdCode: 'activityReport',
yearMonth: '2017-09',
pathRewrite: {
"^/api": ""
}
}
But now I see in my JavaScript console:
Error: Request failed with status code 404
Addendum 2
Apparent axios has a problem with rerouting, so I tried it with vue-resource but this code is showing an error:
var data = {
smartTaskIdCode: 'pageActivityByMonth',
yearMonth: '2017-09'
}
this.$http.post('/api', data).then(response => {
this.pageStatus = 'displaying';
this.activity = response.data['activity'];
console.log(this.activity);
}, response => {
this.pageStatus = 'displaying';
console.log('there was an error');
});
The webpack template has its own documentation, and it has a chapter about API proxying during development:
http://vuejs-templates.github.io/webpack/proxy.html
If you use that, it means that you will request your data from the node server during development (and the node server will proxy< the request to your real backend), and the real backend directly in production, so you will have to use different hostnames in each environment.
For that, you can define an env variable in /config/dev.env.js & /config.prod.env.js