Webpack workbox Serviceworker API Precache index.html - javascript

I'm in the process of turning a, what was called, "PWA" into an actual PWA. I have successfully gotten a serviceworker attached to the application and now I wanna know how to precache the entire application so that internet connection is "never" needed to open the application if it has already been cached in the browser.
To my mind the StaleWhileRevalidate strategy SHOULD be the best option here, but I have been bested by, either, my own ability to read documentation or workbox-webpack's horrible attempt at documentation (it's most likely the former, rather than the latter)
I have my webpack.common.js file which is my general webpack config entry point for all types of builds.
'use strict';
const helpers = require('./helpers');
const path = require('path');
const VueLoaderPlugin = require('vue-loader/lib/plugin')
const WorkboxPlugin = require('workbox-webpack-plugin')
module.exports = {
entry: {
polyfill: '#babel/polyfill',
main: path.resolve(__dirname, '../src/main.js'),
vendor: path.resolve(__dirname, '../src/vendor.js')
},
module: {
rules: [{
test: /\.(vue|Vue)$/,
loader: 'vue-loader',
include: [helpers.root('src')]
},
{
test: /\.html$/,
use: [
{
loader: 'html-loader',
}
]
},
{
test: /\.ico$/,
use: {
loader: 'file-loader',
options: {
name: '[name].[hash].[ext]',
outputPath: 'assets/img/icons'
}
}
},
{
test: /\.svg$/,
use: [{
loader: 'svg-sprite-loader',
options: {
spriteFilename: 'sprites.svg',
runtimeCompat: true
}
},
{
loader: 'svgo-loader',
options: {
removeTitle: true,
removeUselessStrokeAndFill: true
}
}
]
}
]
},
plugins: [
new VueLoaderPlugin(),
new WorkboxPlugin.GenerateSW({
exclude: ['./static/1pixel.png'],
maximumFileSizeToCacheInBytes: 6291456,
clientsClaim: true,
skipWaiting: true,
runtimeCaching: [
{
handler: 'CacheFirst',
urlPattern: /\.(?:js|css|html)$/,
options: {
cacheName: 'static-assets-cache',
cacheableResponse: {
statuses: [200]
}
}
}
]
})
]
};
so far I have gotten to the point where I can exclude an image file from the cache, but that's about as far as I have gotten. I want to achieve the following:
I open the application WITH internet connection. Get everything loaded, cached and ready to go. I then close the tab the application was loaded in, but my phone in my pocket and go about my business. I then later want to open the application again, but now WITHOUT internet connection. This should be possible since the application should live in the cache. However. I can see in my applications cache all of my fonts, image assets, polyfill and stores (js) have been cached, but not the index.html file. And I guess that is why my application refuses to load after a tab in the browser is disposed.
TL;DR - How do I precache the index.html so that the application will load even after a browsertab has been disposed or the browser timed out the session that my PWA lives in?

My current solution was to add:
{
handler: 'CacheFirst',
urlPattern: './index.html',
options: {
cacheName: 'index-assets-cache',
cacheableResponse: {
statuses: [200]
}
}
}
To my runtimeCaching object. I also fixed my manifest.json config to comply with the standards defined by Chrome and Safari. This way I can install the PWA as an app on the phone, which fixes my problem when the app is installed on the phone.
The problem still persists in a normal browser on a phone. After login and load of all files and precaching I cannot close the tab and open it again from an offline state. So this is not a complete answer.

Related

Webpack/Javascript - Browser keeps refreshing when I do "npm run build-dev"

I am trying to get more familiar with using webpack. I have converted everything to be able to load modules, and plugins. Everything loads fine when I run "npm run build-prod", when I use liveServer, HTML and everything loads properly. However when I run "npm run build-dev", it auto pops up my index.html file and starts reloading the page nonstop, and doesn't apply any CSS. The reloading issue makes me think I am using npm run build-dev wrong.
I am pretty new to webpacks, but to my understanding, the point of running "npm run build-dev", it will compile everything using my loaders and plugins without minifying everything, so I can edit and make changes in real time. Or is my understanding completely wrong.
const path = require("path");
const webpack = require("webpack");
const HtmlWebPackPlugin = require("html-webpack-plugin");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
module.exports = {
entry: "./src/client/index.js",
mode: "development",
devtool: "source-map",
stats: "verbose",
output: {
filename: "main.js",
path: path.resolve(__dirname, "dist"),
},
module: {
rules: [
{
test: "/.js$/",
exclude: /node_modules/,
loader: "babel-loader",
},
{
test: /\.scss$/,
use: ["style-loader", "css-loader", "sass-loader"],
},
],
},
plugins: [
new HtmlWebPackPlugin({
template: "./src/client/views/index.html",
filename: "./index.html",
}),
new CleanWebpackPlugin({
// Simulate the removal of files
dry: true,
// Write Logs to Console
verbose: true,
// Automatically remove all unused webpack assets on rebuild
cleanStaleWebpackAssets: true,
protectWebpackAssets: false,
}),
],
};
Here is my full repo, but without the .env variables holding my API keys.
Just a friendly advice: It feels like you started doing something complex without getting the basics right.
Why don't you try some of the examples first?
The webpack website is quite rich of those: https://webpack.js.org/guides/getting-started/
Never figured out what the issue was, but when I ran it on my Mac instead of Windows, I couldn't reproduce the issue. I tried on both Chrome and FireFox without any plug-in.

how can I bundle multiple libraries with webpack and use them in a browser

Webpack describes a multi-main entry feature that seems to do exactly this, it bundles several libs into one file. The problem is that when I load that file only the last library on the list is available.
I've created a small demo on github.
There are 2 libraries each exporting a single symbol, only lib2.d2 is accessible from the test.html that loads the bundled JS. If you look in the bundle file you can see the code from lib1 but it's not exported in any way that I can find.
The webpack config is below. I suspect the problem is that there's no way to supply 2 library names when there's out only output and so the last one over-writes the earlier ones.
const path = require('path');
module.exports = {
entry: ['./js/lib1.js', './js/lib2.js'],
module: {
rules: [
{
test: /\.js$/,
use: 'babel-loader',
exclude: /node_modules/,
},
],
},
resolve: {
extensions: ['.tsx', '.ts', '.js'],
},
output: {
library: {
name: 'MyLibrary',
type: 'umd',
},
filename: 'lib.js',
path: path.resolve(__dirname, 'dist'),
},
"optimization": {
"minimize": false,
usedExports: true,
},
mode: "development",
};
If you're curious why I would want to do this, I'm doing some development on wix.com. The only way to push JS files up to their server is copy/paste one at a time. Bundling a bunch of stuff into one file will save me some pain. My current work-around is to output to multiple files and then cat them all together with something export const exportLib1 = lib1 for each one. That gives me a JS file that I can import and access each one but there must be an easier way.

Trying to save configuration settings to a JSON file on a user's computer from the web browser using a React App that has webpack?

I am working on a social media app for a friend at their request which should allow them to create categories and then write hashtags that correspond to those categories. Afterwards they can just select them as opposed to spending the time typing them all out every single time.
Given the constant updating nature of the project I had set myself for a react web-app and thought I could store the categories and hashtags made in a .JSON file and then any time they added a new category / hashtag, I could just write to that .JSON file.
problem is, using "fs" gets me this error Cannot find module "fs" and the solutions about externals or target Node or other methods invariably results in Uncaught ReferenceError: require is not defined on the .JSX file that makes the reference to fs
I have linked my webpack below. I want to save to a .JSON file on the local computer's file system so I do not have to deal with/pay for some sort of online storage space. I do not want to use the download command because I do not want to open up that dialogue box and would rather have the file be written to a static location in the background. Likewise, I thought a webpage would be a good way to implement the app because when it is built they can just download from github and open the index.html in their preferred browser. If there is another alternative which is less of a headache I am all for listening to suggestions.
var path = require('path')
const mode = process.env.NODE_ENV
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const webpack = require('webpack')
module.exports = {
mode: 'development',
entry: path.join(__dirname,'./index.js'),
output:{
path: path.resolve(__dirname, 'build'),
filename: 'bundle.js',
},
devServer:{
publicPath: '/build/',
port:8080,
hot: true,
},
plugins: [ new MiniCssExtractPlugin(), new webpack.HotModuleReplacementPlugin() ],
module:{
rules: [
{
test: /\.jsx?$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['#babel/preset-env','#babel/preset-react']
}
}
},
{
test: /\.s[ac]ss$/i,
use: [
// Creates `style` nodes from JS strings
//'style-loader',
MiniCssExtractPlugin.loader,
// Translates CSS into CommonJS
'css-loader',
// Compiles Sass to CSS
'sass-loader',
],
}
]
}
}
edited for additional clarity

Webpack is importing modules from my machine's global `node_modules`. How do I get it to only import from my project's `node_modules`?

I'm migrating a project from using Grunt to using Webpack. This project uses jQuery. I noticed that the bundled code was working fine, even though I hadn't yet added jQuery to package.json, which seemed strange.
Looking at the output of webpack --mode=development --display-modules, I saw:
[../../../../../../../node_modules/jquery/dist/jquery.js] /Users/rothomas/node_modules/jquery/dist/jquery.js 274 KiB {index} [built]
That is: it seems at some point I ran npm install --global jquery, and Webpack is importing that jQuery. I don't want this to happen, because my teammates/server won't have jQuery installed in $HOME.
The obvious solution is for me to just remove jQuery from my $HOME/node_modules (no idea how it got there anyway), which will cause Webpack to fail until I add it to package.json, as expected.
But I'd like to know:
Why does Webpack use $HOME/node_modules? I understand this is the default behavior of Node package resolvers, but it seems very error-prone since I imagine many other developers keep their projects nested under $HOME.
How can I specify the scope within which Webpack should be trying to resolve modules?
(I looked at Webpack's documentation on resolvers, but it's not very clear to me.)
Here is my current Webpack config:
const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
function pathTo(filepath) {
return path.join(__dirname, filepath);
}
module.exports = function (env, argv) {
return {
entry: {
'index': [
pathTo('src/scripts/index.js'),
pathTo('src/scss/index.scss'),
]
},
module: {
rules: [
{
exclude: /node_modules/,
loader: 'babel-loader',
options: {
presets: [
'#babel/env'
]
},
test: /\.js$/,
},
{
test: /\.(scss|css|sass)$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
},
{
loader: 'css-loader',
options: {
url: false,
},
},
{
loader: 'sass-loader',
options: {
sassOptions: {
outputStyle: 'expanded',
},
},
},
],
},
],
},
output: {
filename: '[name].js',
path: pathTo('web'),
},
plugins: [
new MiniCssExtractPlugin()
],
}
}
The problem is that your app is located inside the directory that has your global node_modules directory.
Webpack (and for that matter all node resolvers) will keep searching up your tree until it finds a directory that has a node-modules directory. then it will check in there for jquery. It continues doing this until it either finds what it's looking for, or if it reaches the root of your filesystem.

I am having a problem building my Node app with webpack

Let me describe my problem. I have developed a Node.js application with ES6, it is a REST API using several Node modules especially from google-cloud because I am using Google Cloud Vision and Translate APIs.
Until now there is no problem, everything works as expected, but things got wrong when I wanted to run it as a service on a Windows Server. I found a way to do it here using the Node module "node-windows".
I made the service script like in that post and the service got installed and shown in the Windows services list, but when I click to start it stops immediately.
After some analyzing I remembered that I am using ES6 that needs to be transpiled to ES5 to work like a standard Node script, so I thought that building my whole app with webpack will solve that for me, but not exactly, I got my bundle.js generated with webpack without any error (just some warnings), then when I try to run it with node ./bundle.js it returns errors like :
Error: The include '/protos/google/cloud/vision/v1/image_annotator.proto' was not found.
Though I made a rule in my webpack config file to support .proto files.
This is my webpack.config.js :
module.exports = {
target: "node",
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader"
}
},
{
test: /\.json$/,
exclude: /node_modules/,
use: {
loader: "json-loader"
}
},
{
test: /\.proto$/,
use: {
loader: "pbf-loader"
}
},
{
test: /\.html$/,
use: {
loader: "html-loader"
}
}
]
}
};
At this level, I have no idea how to make those google-cloud .proto files to be integrated in my bundel.js, can someone please guide me ? thanks.
This is the code from grpc.js inside the #google-cloud module that tries to resolve the .proto files paths:
GoogleProtoFilesRoot.prototype.resolvePath = function (originPath, includePath) {
originPath = path.normalize(originPath);
includePath = path.normalize(includePath);
// Fully qualified paths don't need to be resolved.
if (path.isAbsolute(includePath)) {
if (!fs.existsSync(includePath)) {
throw new Error('The include `' + includePath + '` was not found.');
}
return includePath;
}
if (COMMON_PROTO_FILES.indexOf(includePath) > -1) {
return path.join(googleProtoFilesDir, includePath);
}
return GoogleProtoFilesRoot._findIncludePath(originPath, includePath);
};

Categories

Resources