Caching entire folder in service worker - sw-precache

I have a build folder which is generated via webpack, any idea how i can cache the entire folder, i tried the following but to no avail
self.addEventListener('install', e => {
e.waitUntil(
caches.open('notes').then(cache => {
return cache.addAll([
'./build/*',
])
.then(() => self.skipWaiting());
}))
});
self.addEventListener('activate', event => {
event.waitUntil(self.clients.claim());
});
self.addEventListener('fetch', event => {
event.respondWith(
caches.match(event.request).then(response => {
return response || fetch(event.request);
})
);
});
Any help on how i can cache the entire build folders' file. I am not using the webpack plugin, just written my on SW.

cache.addAll() takes as its parameter an array of URLs. './build/*' isn't an array of URLs, and that sort of wildcard pattern has no meaning when run inside of a service worker on users' browsers.
What you really want to do use a wildcard pattern that gets evaluated at build time, locally on the same machine that's performing your Webpack build, which will have access to the local files in your build/ directory and can generate a full list of them. You need to express that intent within your Webpack build process, not within the cache.addAll() run from your service worker.
There are a few Webpack plugins, like sw-precache-webpack-plugin and offline-plugin, that automate the process of expanding wildcards at build time and injecting the resulting list of files (along with versioning information, which is also super-important) into a service worker file, which in turn gets run in your users' browsers. You mention that you don't want to use a plugin and instead write your own service worker, but I'd recommend at least looking at the source for those plugins (or for the sw-precache project) since you're almost certainly going to end up following a similar approach.

Related

Vue WebApp - Load latest build

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.

Webpack can not resolve module

I need some guidance. I am experiencing an issue where webpack throws an error that it can not find a module . I was trying to add a require statement of a package(included as dependency). I got it working in another project where I don't need webpack. The code looks basically as follows:
context.subscriptions.push(
vscode.commands.registerCommand("vstodo.helloWorld", () => {
vscode.window.showInformationMessage(
"test"
);
const sfdx = require('sfdx-node');
sfdx.auth.web.login({
setdefaultdevhubusername: true,
setalias: 'HubOrg'
})
.then(() => {
// Display confirmation of source push
console.log('Source pushed to scratch org');
});
}));
My webpack config can be found here
I uploaded a simplified version of the repository here Repository
containing all the configuration files for rollup and webpack.
If I leave out the part starting at the require statement everything works again.
Any help on how to tackle this would be much appreciated, thanks
The vscode extension page has a short troubleshooting guide about this: https://code.visualstudio.com/api/working-with-extensions/bundling-extension#webpack-critical-dependencies.
They suggest the following solutions:
Try to make the dependency static so that it can be bundled.
Exclude that dependency via the externals configuration. Also make sure that those JavaScript files aren't excluded from the packaged extension, using a negated glob pattern in .vscodeignore, for example !node_modules/mySpecialModule.

How to Manage Staging and Production Environments in a React Native App

I got a react-native app already ready and works but the app points on a prod api so to avoid problems I wanted that she points on a rest api, so how can I reconfigure it, I have only an environment file.js that contains the URL api, and this file is called in the API service
I tried react-native config but didn't know how to make it work,
All I want is to duplicate that env file because he contains all necessary URLs, so I want to have file named envProd and another named envStaging they should be similar the only different part is the URL of my api , so when I want to run the app i precise which file I want to choose to run with
If the API URL's are the only difference, you don't need to create two separate config files. Instead, you can make use of the inbuild __DEV__ global variable in JavaScript to determine if you're using React Native packager (dev mode) or not (production).
Ref: https://facebook.github.io/react-native/docs/javascript-environment.html
So, something like below.
var apiURL = __DEV__ == true ? 'development.api.com' : 'prod.api.com';
I am finding switching environments quite hard to manage.
__DEV__ is awesome for local disabling stuff when in development. Won't work for any of the builds though.
For staging vs production seems that configuring react-native-config is the best. Unfortunately, next to being somewhat hard to configure binaries need to get recompiled separately for each environment. This means - one update - two build with uploads to whatever provider you use. It can get more complex if you use something like codepush too.
possible solution
Create a hidden feature in your app that allows to toggle the environment from the within the app. This way you can have one build, give it to testers. They switch env to staging and later you only need to promote it as a production build.
This could be something like tap 10 times on an empty space somewhere - the more creative you get the better :)
Good luck
const _Environments = {
production: {
API_BASE: 'https://api.test.com/',
USERNAME: 'admin',
PASSWORD: '1234',
},
development: {
API_BASE: 'https://dev.api.test.com/',
USERNAME: 'admin',
PASSWORD: '1234',
},
};
function getEnvironment() {
// Insert logic here to get the current platform (e.g. staging, production, etc)
var platform = __DEV__ ? 'development' : 'production';
// ...now return the correct environment
return _Environments[platform];
}
export const Environment = getEnvironment();
Try this. using yargs you can replace static import content with dynamic scripts.

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.

webserver with specified root folder via gulp task

I've take a look at a few gulp server instances (currently using gulp-webserver) but I can't seem to find where to set the root folder for the server per the params I see here See code below:
gulp.task('webserver', function() {
gulp.src(debugFolder)
.pipe(webserver({
directoryListing: true
}));
});
I'm not sure what the gulp.src param does as it's not the root. The root is the folder that holds the gulp script. Am I missing something on this module or is there another module that will do this? Trying to keep things clean and simple.
Please don't use gulp-webserver for it, since it's not a Gulp plugin and has been blacklisted by the community. I'd suggest you to use BrowserSync, which does exactly what you need and is a lot more standalone. Check out this documentation or my little writeup here. It would work like this:
var browserSync = require('browser-sync');
gulp.task('webserver', function() {
browserSync({
server: {
baseDir: "./app/"
}
});
});
And it's able to do a lot more!