Vue WebApp - Load latest build - vue.js

I'm building a Vue.js application using Vuexy BootstrapVue template, deployed in a Docker container.
I am finding that when we deploy updates to our web app, that the User has to do a hard-refresh in their browser to load the latest version of the app, otherwise they'll be navigating around a cached version.
Is there a way for me to force a client browser to load the latest version for a User?
Either on every load, or every few hours?
(I've tagged Bootstrap-Vue for transparency, but don't actually know if it has any bearing on this issue)

You are facing the cache problem and there is multiple ways to handle this.
Cache Control
You can control the cache with the header with max-age or no-store, no-cache to simple disable it, like this question/answer: How do we control web page caching, across all browsers?
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control
https://csswizardry.com/2019/03/cache-control-for-civilians/
Cache busting
Aappending a version (example: 1.0.0) to query string of the script tag:
<script src="path/to/your/app.min.js?v=1.0.0"
and change that version for every build.
Hashing the script file
You can also use some webpack/rollup config to build the script with a hash, like app.bf43112.js
webpack
const config = {
output: {
path: PATHS.build,
filename: "[name].[contenthash].js",
},
};
Rollup
const isProduction = process.env.NODE_ENV === 'production';
export default {
output: {
sourcemap: true,
format: 'iife',
name: 'app',
file: isProduction ? 'bundle[hash].js' : 'public/build/bundle.js',
}
};
Reference: Hashed file names using Rollup
Service Worker
Another solution, that I never tested, but sounds a good method.. is creating a service worker to control how retrieve the js file:
https://developers.google.com/web/ilt/pwa/caching-files-with-service-worker
You can do things like deleting the cache, responding the cache with a response that you manually fetch with js, etc.

Related

Vue Cli 404 on wwwroot/index.html error using PWA

I've just moved an app over to the vue cli, but i'm having an issue with getting the PWA to work. When its trying to load it up theres an console error
Uncaught (in promise) bad-precaching-response: bad-precaching-response :: [{"url":"/wwwroot/index.html?WB_REVISION=xxxxxxx","status":404}]
Thing is i'm not really sure where this error is commminng from. The actual sire loads fine, and all the asserts are ok, but thw PWA index.html seems to be loading from the wrong place. its in /index.html not /wwwrooot/html. I'm not sure why its trying to load from here. This is what the vue.config looks like
pwa: {
name: 'app Portal',
themeColor: '#CC0001',
msTileColor: '#CC0001',
appleMobileWebAppCapable: 'yes',
appleMobileWebAppStatusBarStyle: 'black',
workboxOptions: {
exclude: /\.cshtml$/,
/*
docs: https://developers.google.com/web/fundamentals/primers/service-workers/lifecycle#skip_the_waiting_phase
a new service worker does not serve pages until the old one releases control
this is called the waiting phase
skipWaiting means the new one immediately takes control. this may cause issues with people still using your application
*/
skipWaiting: true,
},
},
``
Any ideas why the PWA seems to be loading the index.html from the wrong place?
I use the pwa webpack config navigatefallback to fix this issue please see: https://developers.google.com/web/tools/workbox/modules/workbox-webpack-plugin#generateSW-navigateFallback
Also pwa can fail with history mode enabled on the vue Router:
here are some questions that i think will get you in the right direction:
PWA doesn't load when router is in history mode (Vue CLI 3 based project)
and
Vue Router History Mode with PWA in Offline Mode

Vue + SWPrecacheWebpackPlugin - app.js is not cached

I'm trying to implement a service worker for my website. I used SWPrecacheWebpackPlugin with vue and registering and so on works well. Somehow it doesn't cache all files, in this case I guess the most important app.js file.
When I'm online the file structure built by vue looks like the following:
But when I check the cache the app.js file is missing and in offline mode i just get a white page.
So obivously the service-worker is up and running and is even caching some stuff, but not the relevant app.js file.
My webpack config looks like the following:
new SWPrecacheWebpackPlugin({
cacheId: 'xxx',
filename: 'service-worker.js',
staticFileGlobs: ['dist/**/*.{js,html,css}'],
minify: true,
stripPrefix: 'dist/'
})
I have actually no idea what I am missing.
Update:
The app.js file was too big and wasn't cached by the PlugIn. No warning, no error, nothing...

what is the most reasonable way apply webpack to a full-stack node app?

i've been studying up on webpack for a couple of weeks now, and i've seen many examples of front end setups, and probably just this one setup for a backend.
i'm trying to setup a react app with a node back-end (e.g. express, koa, hapi, etc) where i would need at least one transpilation step for the back-end (e.g. babel, coffeescript, etc), and i think it would be nice to use webpack there for consistency vs adding another build mechanism to the mix (e.g. gulp, grunt, etc).
it would also be great if i could make changes to the backend and have the server restart automatically (watch style).
i'm wondering if the best way to do that is to basically have two distinct project setups with their own package.json and webpack.config files. maybe nest the back-end one under a server folder in the top level project folder, and use one or more script directives in the top level package.json file to control the two.
i guess i might have to proxy one server to the other to avoid CORS issues as well.
looking for any guidance from those more webpack battle tested than i for a decent setup.
regards,
tony.
Easiest way is to split this into two tasks: a build step that outputs to a folder (e.g. 'server'), then watch the output folder for changes and restart server task.
1. Build task
This can be in the same webpack.config as client building code - you can export an array and webpack will watch all of them.
Example webpack.config.js (top half is for server)
module.exports = [
{
name: 'server code, output to ./server',
entry: './index.js',
output: {
filename: './server/index.js'
},
target: 'node'
},
{
name: 'client side, output to ./public',
entry: './app.js',
output: {
filename: './public/app.js'
}
}
];
2.Watch Step
For the watch step, nodemon monitor changes and restart. Otherwise you could add a watch task to your server.js manually using something like fs.watch or node-watch.

E2E Testing for AngularJS App on another computer

I'm developing single page application on AngularJS for learning. My project is located on Apache HTTP Server on another computer, I use WinSCP synchronisation while developing so that it is always the last version of my work.
Halfway through (actually, when I has already finished the biggest part the application), I realized that I don't have any tests and I should learn how to test what I do not just manually. I decided to try writing E2E tests for my AngularJS application using Karma Test Runner.
I installed Karma via npm, initialized it (karma init test/karma.conf.js), but what happens now?
I tried karma start test/karma.conf.js it launches Chrome (as I stated in config) and says that
Karma - connected
Chrome 26.0 (Windows) is idle
even though in conf file there are specified my test file:
files = [
'test/first_test.js'
];
And that's what inside it:
describe('my app', function() {
browser().navigateTo('/');
it('should then be.', function() {
expect(browser().location().url()).toBe('/login');
});
});
Thanks in advance!
EDIT: I realized, it's not just 'Chrome is idle', there's also console log error:
Uncaught ReferenceError: browser is not defined
Any ideas? I'm so confused right now.
Browser is only defined inside of beforeEach. Try this:
describe('my app', function() {
beforeEach(function(){
browser().navigateTo('/');
});
it('should then be.', function() {
expect(browser().location().url()).toBe('/login');
});
});
Alright, looks like I solved it myself.
I should have added
ANGULAR_SCENARIO,
ANGULAR_SCENARIO_ADAPTER,
to the files property of karma config file. After that, I progressed a little bit, but still got a lot of troubles, but essentially the main was that I got error that resumeBootstrap was undefined. My app was using AngularJS 1.0.4, but it looks like Karma's Adapters are for 1.0.6+ only. Upgrading app to 1.0.6 helped with resumeBootstrap.
Regarding testing the app on external server:
proxies = {
'/': 'http://another.internal/app/'
};
and don't forget to change links to CSS and JS files in app's index.html from local (css/style.css) to web (//another.internal/app/css/style.css).

Is it possible to add a request parameter to dojo module requests via dojo's AMD loader

Is it possible to modify request urls used by the dojo AMD loader before a request is sent to the server for an AMD module? I would like to append a request parameter with a version number.
The problem we are trying to solve is that we want our javascript files to be cached by the browser unless the application's version is updated. I think we should be able to do that if we can add a version number to the requested URL.
The paths config property seems to work for individual modules, and cacheBust can be used for all modules. Example jsfiddle.
<script>
var dojoConfig = {
paths: {
// version a single file by using path with version number
"aa": "mylib-aa.js?v=1.0",
// standard path, no explicit versioning
"bb": "mylib-bb"
},
// use v=1.0 for ALL loaded modules
cacheBust: "v=1.0",
waitSeconds: 10
};
</script>
<script src="https://ajax.googleapis.com/ajax/libs/dojo/1.8.3/dojo/dojo.js"></script>
<script>
require(["aa", "bb"], function () {});
</script>
Giving:
"NetworkError: 404 Not Found - https://ajax.googleapis.com/ajax/libs/dojo/1.8.3/dojo/mylib-aa.js?v=1.0.js&v=1.0"
"NetworkError: 404 Not Found - https://ajax.googleapis.com/ajax/libs/dojo/1.8.3/dojo/mylib-bb.js?v=1.0"
The hiccup for the paths approach is the trailing ".js", but for the purposes of versioning I don't think that's an issue as the URL is still unique in the way you want it to be.