I have two different projects (or repo) on the server. one of them is wroten with vue.js (SPA) and another is created by static site generator (mkdoc).
then I add PWA to my SPA project (from here) and a strange thing happened🙁. in my project, I navigate to example.com/help but it shown a 404 page while /help route is for my mddoc project!
in other words:
SPA Project domain: example.com
mkdoc Project domain: example.com/help
so I searched on the web and thought about this problem and I realized why this problem happens!
I think that's because of the service worker in PWA! the service worker cached all the files and assets of the project.
now I think to solve this problem I should prevent cache the /help route! but I couldn't understand how to config PWA in vue.config.js vue cli.
really I don't know that can we exclude one route and prevent to cache with the service worker or not!?
how can I fix this problem!?
vue.config.js
module.exports = {
publicPath: '/',
css: {
loaderOptions: {
sass: {
prependData: `
#import "#/assets/styles/_boot.scss";
`
}
}
},
pwa: {
name: "app",
themeColor: "#004581",
msTileColor: "white",
appleMobileWebAppCapable: "yes",
appleMobileWebAppStatusBarStyle: "white",
iconPaths: {
favicon32: 'img/icons/favicon-32x32.png',
favicon16: 'img/icons/favicon-16x16.png',
appleTouchIcon: 'img/icons/apple-touch-icon-180x180.png',
maskIcon: 'img/icons/safari-pinned-tab.svg',
msTileImage: 'img/icons/mstile-144x144.png',
},
// configure the workbox plugin
workboxPluginMode: "GenerateSW",
workboxOptions: {
importWorkboxFrom: "local",
navigateFallback: "/",
ignoreUrlParametersMatching: [/help*/],
// Do not precache images
exclude: [/\.(?:png|jpg|jpeg|svg)$/],
// Define runtime caching rules
runtimeCaching: [
{
// Match any request that ends with .png, .jpg, .jpeg or .svg.
urlPattern: /\.(?:png|jpg|jpeg|svg)$/,
// Apply a cache-first strategy.
handler: "CacheFirst",
options: {
// Use a custom cache name.
cacheName: "images",
// Only cache 10 images.
expiration: {
maxEntries: 10
}
}
}
]
}
}
};
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.\n' +
'For more details, visit https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-pwa'
);
},
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);
}
});
}
If you want to exclude specific route or routes from service worker you should add navigateFallbackDenylist to workboxOptions.
navigateFallbackDenylist: [/help*/],
Related
I've built a website with Nextjs (using version 12.1.4). For SEO purposes I would like to make a permanent redirect for my www version of the site to my non-www. Normally this could easily be done with nginx or an .htaccess file with apache. However, static websites hosted on Digitalocean are not running apache or nginx so an .htaccess file won’t do. I've read that this should be possible using Nextjs redirects.
I've tried the following 3 redirects:
redirects: async () => [
{
source: '/:path*',
has: [
{
type: 'host',
value: 'www',
},
],
destination: '/:path*',
permanent: true,
},
],
---------------------------------------------------
redirects: async () => [
{
source: '/:path*/',
has: [
{
type: 'host',
value: 'www',
},
],
destination: '/:path*/',
permanent: true,
},
],
------------------------------------------------------
redirects: async () => [
{
source: '/:path*',
has: [{ type: 'host', value: 'https://www.cvtips.nl/' }],
destination: 'https://cvtips.nl/:path*',
permanent: true,
},
],
All of them don't seem to redirect to the non-www version. I don't know if it is relevant, but I do use trailingSlash: true in the config.
Next thing I tried is adding a middleware file. I both tried adding it at the root and calling it middleware.js and inside the pages folder calling it _middleware.js.
This is the code I use for the redirect:
--> https://github.com/vercel/next.js/discussions/33554
import { NextRequest, NextResponse } from 'next/server';
export function middleware(req: NextRequest) {
const host = req.headers.get('host');
const wwwRegex = /^www\./;
// This redirect will only take effect on a production website (on a non-localhost domain)
if (wwwRegex.test(host) && !req.headers.get('host').includes('localhost')) {
const newHost = host.replace(wwwRegex, '');
return NextResponse.redirect(`https://${newHost}${req.nextUrl.pathname}`, 301);
}
return NextResponse.next();
}
Also does not work at all... Doesn't do anything I believe.
How can I redirect a Nextjs website from www to non-www?
I'm trying to setup navigation guards in my Nuxt app to redirect users to the login screen if they are not authenticated via Firebase Authentication. When the user attempts to navigate my router middleware is redirecting them successfully, but on page load they are not being redirected.
I did realize that the middleware is not even being fired on page load. I found a recommendation to try a plugin to handle the redirect on page load, but it is not working. Calling router.push from within the plugin does not redirect the user.
Here are a few notes on my setup. This is being deployed to firebase hosting directly as a SPA with no SSR. It's using the Nuxt-Firebase module with Firebase Authentication service.
// nuxt.config.js
target: "server", // server here works when I deploy to firebase, but I also tried static
ssr: false,
middleware: ["auth"],
plugins: [
"~/plugins/auth.js",
],
modules: [
[
"#nuxtjs/firebase",
{
services: {
auth: {
initialize: {
onAuthStateChangedMutation:
"authData/ON_AUTH_STATE_CHANGED_MUTATION",
onAuthStateChangedAction: "authData/ON_AUTH_STATE_CHANGED_ACTION",
subscribeManually: false,
},
},
},
},
],
],
};
Here's a sample plugin I thought might solve this, but calling handleLoggedOut appears to do nothing on page load.
// --- plugin to redirect user --- /plugins/auth.js ---
export default function (context, inject) {
const auth = {
handleLoggedOut: () => {
console.log("logout handled");
context.redirect("/login");
},
};
inject("auth", auth);
}
// --- store actions --- /store/authData.js ---
actions: {
async ON_AUTH_STATE_CHANGED_ACTION(
{ commit, state, dispatch },
{ authUser, claims }
) {
if (authUser) {
// logged in
}
else {
// attempting to redirect here does not work
this.$auth.handleLoggedOut()
}
}
I'm new to Nuxt and I can't seem to find an example that solves my issue.
Any help would be greatly appreciated, thank you!
Code seems fine, But you can just use the this.$fire.auth.signOut() and you can remove the auth plugin.
Example:
// --- store actions --- /store/authData.js ---
actions: {
async signOut({ commit }, payload) {
try {
await this.$fire.auth.signOut();
// This is just a guard to avoid navigation guard error (NavigationDuplicated),
// you can remove the if block
if (!payload) {
this.$router.push('/login')
}
commit(ON_AUTH_STATE_CHANGED_MUTATION, { authUser: null})
} catch(err) {
console.log(err)
}
},
async ON_AUTH_STATE_CHANGED_ACTION(
{ commit, state, dispatch },
{ authUser, claims }
) {
if (authUser) {
// logged in
}
else {
// attempting to redirect here does not work
return dispatch('signOut')
}
}
}
The solution for redirecting users to the login on page load was to put this in my auth middleware:
export default function ({ redirect, store, route }) {
// https://nuxtjs.org/docs/internals-glossary/context#redirect
if (!store || !store.getters || !store.getters["authData/isLoggedIn"]) {
window.onNuxtReady(() => {
window.$nuxt.$router.push("/login");
});
}
}
I'm making a plain, static site (HTML/CSS/JS) with Webpack that I intend to eventually deploy to s3. I have my final HTML files exported to the root of my dist folder like, index.html, foo.html, bar.html.
When I go to localhost:9000, my index loads as expected. For foo and bar I have to type the file extension like /foo.html and /bar.html for those pages to load. Is there a setting that I'm missing that will allow me to simply type /foo and /bar in the browser and have the intended pages load?
One way I found for individual pages, is to specify a proxy using devServer.proxy. For /foo and /bar, this would look like that:
const path = require("path");
module.exports = {
...
devServer: {
static: {
directory: path.resolve(__dirname, 'dist')
},
port: 3000,
open: false,
hot: true,
proxy: {
'/foo': {
target: 'http://localhost:3000/foo.html',
pathRewrite: { '^/foo': '' }
},
'/bar': {
target: 'http://localhost:3000/bar.html',
pathRewrite: { '^/bar': '' }
}
}
}
}
Check the DevServer documentation for more options.
In addition to Nikolai's answer, in case you need your local dev server to serve urls w/o extensions in router history mode, just use the following:
historyApiFallback: {
rewrites: [
{ from: /^\/$/, to: '/views/landing.html' },
{ from: /^\/subpage/, to: '/views/subpage.html' },
{ from: /./, to: '/views/404.html' },
],
},
Source: https://webpack.js.org/configuration/dev-server/#devserverhistoryapifallback
I am using glue to spin up the hapi server so I gave the json object with connection and registration details.
I have 10 routes and i need to use authentication strategy for all the 10 routes, So followed the below steps
1) I have registered the xyz custom auth plugin
2) Defined the strategy server.auth.strategy('xyz', 'xyz', { });
3) At every route level I am enabling auth strategy
auth: {
strategies: ['xyz'],
}
How can I give below line to glue configuration object itself.
server.auth.strategy('xyz', 'xyz', { });
Glue.compose(ServerConfig, { relativeTo: baseDir }, (err, server) => {
internals.server = server;
})
One more question here is, in this line server.auth.strategy('xyz', 'xyz', { from json file}); I am reading the JSON data from a config file. When I change the data in this JSON file I dont want to restart the server manually to load the modified data. Is there any plugin or custom code to achieve this?
I figured out a general workaround for when you want to do setup that Glue does not directly support (AFAIK) and you also don't want to keep adding to index.js.
Create a plugins folder where your manifest.js is located.
Create a file plugins/auth.js (in this case). Here you will have a register callback with access to the server object and you can make setup calls that go beyond what Glue does declaratively.
Add a plugin item to manifest.js pointing to your plugin file.
in manifest.js:
register: {
plugins: [
{
plugin: './plugins/auth',
},
]
}
in plugins/auth.js:
module.exports = {
name: 'auth',
async register (server) {
await server.register([
require('#hapi/cookie'),
]);
server.auth.strategy('session', 'cookie', {
cookie: {
name: 'sid-example',
password: '!wsYhFA*C2U6nz=Bu^%A#^F#SF3&kSR6',
isSecure: false
},
redirectTo: '/login',
validateFunc: async (request, session) => {
const account = await users.find(
(user) => (user.id === session.id)
);
if (!account) {
return { valid: false };
}
return { valid: true, credentials: account };
}
});
server.auth.default('session');
},
};
(auth setup code is from the Hapi docs at enter link description here)
This is the way I have found where I can call things like server.auth.strategy() sort-of from manifest.js.
Note: Auth is not a great example for this technique as there is a special folder for auth strategies in lib/auth/strategies.
I'm currently working on an app with a server that uses Hapi, and I am running into a problem whenever I try to load a .jade file. Here is the current code for my index.js file:
var Hapi = require('hapi');
var internals = {};
internals.main = function() {
var options = {
views: {
engines: { jade: 'jade' },
path: '../app',
compileOptions: {
pretty: true
}
}
};
this._server = new Hapi.createServer('localhost', 8000, options);
this._server.route({
method: 'GET',
path: '/',
handler: function(request, reply) {
reply.view('index')
}
});
// Start server.
this._server.start()
};
internals.main();
The file has a series of local scripts and CSS files that are in the app directory, but when the page index.jade is loaded, it does not see those local files. Is there something I need to add/modify in my options, or is this location of local scripts and style files a problem with jade compilation using Hapi?
I was looking for a similar solution, while trying to setup a single page application with angular.js and hapi.js
I have found that adding the configuration below to your server routes will help to make CSS, JS, ... files in '/public' directory visible to the application.
server.route({
method: "GET",
path: "/public/{path*}",
handler: {
directory: {
path: "./public",
listing: false,
index: false
}
}
});
Hope it helps.