Sails js send 404 status for missing static files - express

I have my sails app set to serve static files from a custom directory
module.exports.http = {
customMiddleware: function(app) {
app.use('/', express.static(process.cwd() + '/public'));
},
middleware: {
xframe: require('lusca').xframe('SAMEORIGIN'),
order: [
'xframe',
'startRequestTimer',
'cookieParser',
'customMiddleware',
'session',
'myRequestLogger',
'bodyParser',
'handleBodyParserError',
'compress',
'methodOverride',
'poweredBy',
'$custom',
'router',
'www',
'favicon',
'404',
'500'
]
}
};
and my frontend app get served using the route
'/*': {
view: 'index',
skipAssets: true,
skipRegex: /(^\/api\/.*$)|^\/csrfToken$/
}
but I've noticed that if I request a file that doesn't exist i.e /css/whataloadofrubbish.css it just hangs when it should send a 404. Not sure what I'm missing.

Ah compared to another app and found my notFound.js find was wrong

Related

How can one add custom http headers to Nuxt __page__ ( not static asset ! ) in Nuxt dev server?

https://github.com/hyperbotauthor/vue-chessground/tree/main/test
My problem is that I have to add custom headers to my Nuxt page in order that SharedArrayBuffer may work.
I know how to add custom headers to assets served from the static folder and to the production server:
render: {
static: {
setHeaders(res) {
res.setHeader('Cross-Origin-Embedder-Policy', 'require-corp')
res.setHeader('Cross-Origin-Opener-Policy', 'same-origin')
},
},
dist: {
setHeaders(res) {
res.setHeader('Cross-Origin-Embedder-Policy', 'require-corp')
res.setHeader('Cross-Origin-Opener-Policy', 'same-origin')
}
}
},
However in dev server these headers are not added to the Nuxt pages served from the pages folder.
If I hand write an HTML page in the static folder, then SharedArrayBuffer will work on that page. But not on the Nuxt page.
Is there any way to make Nuxt dev server add headers to Vue rendered pages?
EDIT:
If I include the hand written, in separation working HTML in an iframe from the Vue page, then it again won't work.
EDIT:
I opened an issue at Nuxt:
https://github.com/nuxt/nuxt.js/issues
You also need to add the headers to the response for pages as well. Try testing using Postman or something similar to view response headers, when you try to load the static resources, as well as the nuxt pages.
Setting render: { static: ... } in nuxt.config.ts worked for the static resources.
To set up middleware for the server creating the initial html pages you can do:
// middleware/setSameOriginHeader.ts
export default function (req: any, res: any, next: any) {
res?.setHeader('Cross-Origin-Embedder-Policy', 'require-corp')
res?.setHeader('Cross-Origin-Opener-Policy', 'same-origin')
}
// nuxt.config.ts
export default {
ssr: false,
...
// middleware to set headers on pages
serverMiddleware: ['~/middleware/setSameOriginHeaders.ts'],
// set headers on resources in static dir
render: {
static: {
setHeaders(res: any) {
res.setHeader('Cross-Origin-Embedder-Policy', 'require-corp')
res.setHeader('Cross-Origin-Opener-Policy', 'same-origin')
}
}
},
...
}

Nuxt.js env Property, understanding and how to use it?

following https://nuxtjs.org/api/configuration-env
I have been trying to set up my apiUrl in nuxt.config.js once for the whole project, like:
export default {
env: {
apiUrl: process.env.MY_REMOTE_CMS_API_URL || 'http://localhost:1337'
}
}
adding this in nuxt.config.js, I'd expect (and would like) to have apiUrl accessible everywhere in the project.
In particular, it is needed for the 3 following cases:
with axios, to generate static pages from dynamic urls (in nuxt.config.js)
generate: {
routes: function () {
return axios.get(apiUrl + '/posts')
.then((res) => {
return res.data.filter(page => {
return page.publish === true;
}).map(page => {
return {
route: '/news/' + page.slug
}
})
})
}
},
with apollo, to get data via graphql (in nuxt.config.js)
apollo: {
clientConfigs: {
default: {
httpEndpoint: apiUrl + '/graphql'
}
}
},
in every layout, page and components, as the base url of media:
<img :src="apiUrl + item.image.url" />
As you might see, only thing I need is to 'print' the actual base url of the cms.
I have also tried to access it with process.env.apiUrl, with no success.
The only way I was able to make it has been to create an extra plugin/apiUrl.js file, which injects the api url, and seems wrong to me as I am now setting the apiUrl twice in my project.
I asked this question in the past, but in a way less clear way. I was suggested to use dotenv, but from the docs it looks like adding an additional layer of complication that might not be necessary for a simpler setup.
Thanks.
I think dotenv module really is what you need.
This is my setup:
Project root has a .env file that contains
BASE_URL=https://www.myapi.com
require('dotenv').config() at top of nuxt.config.js
#nuxtjs/dotenv installed and added to buildModules of nuxt.config.js
env: { BASE_URL: process.env.BASE_URL} added to nuxt.config.js
axios: { baseURL: process.env.BASE_URL } added to nuxt.config.js (optional)
You should have access to your .env throughout the project. (process.env.BASE_URL)
I haven't used apollo, but you should be able to set the apollo endpoint with process.env.BASE_URL + '/graphql'
As of Nuxt 2.13, #nuxtjs/dotenv is not required anymore. Read here
The concept that I was missing is that you set up the same named variable in your server / pipeline, so that you have your (always local / never pushed) .env file and a same name variable remotely, not added to your repo (where the value can be the same or different)

How do I cache other routes for offline browsing?

I am setting up a Progressive Web App supporting offline browsing.
I have already set up offline browsing for my main route ('domainsample.com/') and it responds 200 even if offline.
But when I navigate to other routes ('domainsample.com/about') I receive a No Internet Page error.
Here is a sample I deployed in Heroku the URL: https://pwa-hehe.herokuapp.com
I used Vue CLI 3 to set up the project and Node.js and Express.js to run my dist folder in the server.
// server.js
const express = require('express')
const path = require('path')
const history = require('connect-history-api-fallback')
const app = express()
const staticFileMiddleware = express.static(path.join(__dirname + '/dist'))
app.use(staticFileMiddleware)
app.use(history({
disableDotRule: true,
verbose: true
}))
app.use(staticFileMiddleware)
app.get('/', function (req, res) {
res.render(path.join(__dirname + '/dist/'))
})
var server = app.listen(process.env.PORT || 3000, function () {
var port = server.address().port
console.log("App now running on port", port)
})
// manifest.json
{
"name": "pwa-offline",
"short_name": "pwa-offline",
"icons": [
{
"src": "./img/icons/android-chrome-192x192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "./img/icons/android-chrome-512x512.png",
"sizes": "512x512",
"type": "image/png"
}
],
"start_url": "./index.html",
"display": "standalone",
"background_color": "#000000",
"theme_color": "#4DBA87"
}
// service-worker.js
/**
* Welcome to your Workbox-powered service worker!
*
* You'll need to register this file in your web app and you should
* disable HTTP caching for this file too.
*
*
* The rest of the code is auto-generated. Please don't update this file
* directly; instead, make changes to your Workbox build configuration
* and re-run your build process.
*
*/
importScripts("https://storage.googleapis.com/workbox-cdn/releases/3.6.3/workbox-sw.js");
importScripts(
"/precache-manifest.d3f1ce5d8331bddc555348f44cfba9d8.js"
);
workbox.core.setCacheNameDetails({prefix: "pwa-offline"});
/**
* The workboxSW.precacheAndRoute() method efficiently caches and responds to
* requests for URLs in the manifest.
*
*/
self.__precacheManifest = [].concat(self.__precacheManifest || []);
workbox.precaching.suppressWarnings();
workbox.precaching.precacheAndRoute(self.__precacheManifest, {});
There's a simpler solution that doesn't involve using InjectManifest.
Simply add this to your vue.config.js file:
pwa: {
workboxOptions: {
navigateFallback: 'index.html'
}
}
It will automatically add the necessary code to your service worker:
workbox.routing.registerNavigationRoute(workbox.precaching.getCacheKeyForURL("index.html"));
I had the same problem and I found the solution here: https://github.com/vuejs/vue-cli/issues/717#issuecomment-382079361
To anyone who is also using the vue/cli-pligin-pwa and vue-cli 3, I have solved this problem.
The vue/cli-pligin-pwa does its job in caching your js files for offline use of your web app.
but since you're using a Single Page App, you'll have to set a some kind of fallback.
The request for the page e.g.(sample.com/about) will be a navigation request and it will serve the cached page for /index.html
Source: https://developers.google.com/web/tools/workbox/modules/workbox-routing#how_to_register_a_navigation_route
So what I did is, I made a custom service worker by entering this line of code in my
vue.config.js file
// vue.config.js
module.exports = {
pwa: {
// configure the workbox plugin
workboxPluginMode: 'InjectManifest',
workboxOptions: {
swSrc: 'public/service-worker.js'
}
}
}
and now, create a service-worker.js in your public folder directory, and write up the the generated line of codes from vue/cli-pligin-pwa and add the line :
workbox.routing.registerNavigationRoute('/index.html');
//service-worker.js
self.__precacheManifest = [].concat(self.__precacheManifest || []);
workbox.precaching.suppressWarnings();
workbox.precaching.precacheAndRoute(self.__precacheManifest, {});
workbox.routing.registerNavigationRoute('/index.html');
// install new service worker when ok, then reload page.
self.addEventListener("message", msg => {
if (msg.data.action == 'skipWaiting') {
self.skipWaiting()
}
})
The problem is that your service worker is not aware of which assets to cache. What is the value of self.__precacheManifest? (probably the web manifest file).
You would need to configure workbox in order to have some assets for the precacheAndRoute method, as this will instruct the service worker on which files to cache and when. Something like:
workbox.precaching.precacheAndRoute([
'/styles/example.ac29.css',
'/app/offlinePage.js',
'/app/offlinePage.html',
// ... other entries ...
]);
Per default a service worker does not know which assets or HTTP responses to cache, therefore we have to define and implement a caching strategy according to our requirements.
I wrote an article about service workers and the available caching strategies. Have a look at it if you want to deepen the topic.

Unable to remove Aurelia routing's preceding hashtag

I've run into an issue that I can't seem to resolve.
It should be possible to remove the preceding hashtag in routes by executing the steps provided in RouterConfiguration -> Options-> Push State.
I've executed all these steps, see the code below.
app.ts RouterConfiguration options
public configureRouter(config: RouterConfiguration, router: Router) {
config.options.pushState = true;
config.options.root = '/';
config.map([
{
route: 'login',
name: 'login',
moduleId: 'pages/auth/login',
nav: false,
title: 'Login',
settings: {
allow_anonymous: true
}
}
]);
...
index.html head
<head>
<meta charset="utf-8">
<base href="/">
...
config.js
System.config({
baseURL: "/",
...
My login route still only works using localhost:9000/#/login whereas localhost:9000/login can't be found.
I've also tried implementing this in a fresh Aurelia JSPM skeleton application to no avail...
Any idea why this is happening and what I might be doing wrong?
For BrowserSync (as described by #Bryandh), you need to configure it to always fallback to your index.html. Depending on your project, you may have some task file(e.g. a Gulp serve task, which is used throughout Aurelia) which needs to be changed.
As an example, I took Aurelia's skeleton navigation project. It has a sub directory skeleton-esnext which uses Gulp and JSPM to run the application. In the file build/tasks/serve.js is a serve task which needs to be adjusted as follows:
var historyFallback = require('connect-history-api-fallback');
gulp.task('serve', ['build'], function(done) {
browserSync({
online: false,
open: false,
port: 9000,
server: {
baseDir: ['.'],
middleware: [function(req, res, next) {
res.setHeader('Access-Control-Allow-Origin', '*');
next();
}, historyFallback()]
}
}, done);
});
The important part is the historyFallback() middleware. This is provided automatically by BrowserSync. If you serve your app with this task now (gulp serve or gulp watch), you can directly access your routes, e.g. http://localhost:9000/users. There will be no more 404 as you get directed to index.html which bootstraps Aurelia and handles the route /users.
For my views that are being dynamically loaded into the router-view container, with index as the root, I was able to get my project's URLs to look like the following (which I believe is what you're asking for):
http://localhost:2112/
http://localhost:2112/jobs
http://localhost:2112/discussion
I didn't need to alter as much code as you shared in order to get this to work. The first thing I did was to establish a base reference in my root html file.
For me, this was index.html.
<base href="/" />
Then, I set the push state to true inside the configureRouter() method
configureRouter(config, route) {
...
config.options.pushState = true;
...
}

hapi single page application using inert plugin doesn't serve up api route

I am trying to build a single page application using hapi and inert.
my example code is here: https://github.com/7seven7lst/hapi-inert-test
and the base of the project is built from the answer here nodejs hapi single page
Basically I would like to both server static file and api json data to front end. I know how to do this in express, but haven't figure out how with hapi. the delimma is : if I use hapi only, it doesn't serve up static file, and if i use hapi+inert, it wont' serve up api route.
solutions????
The documentation says that the route handler chooses the route from most specific to least specific. So you can pre-fix your api routes with something like /api/v1/ and then everything else that doesn't begin with /api/v1/ will get routed to static files dished up by inert.
Hapi.js Routing Documentation:
When determining what handler to use for a particular request, hapi searches paths in order from most specific to least specific. That means if you have two routes, one with the path /filename.jpg and a second route /filename.{ext} a request to /filename.jpg will match the first route, and not the second. This also means that a route with the path /{files*} will be the last route tested, and will only match if all other routes fail.
'use strict'
const Hapi= require('Hapi')
// Config
var config= {
connection: {port: 3000, host: 'localhost'}
}
const server= new Hapi.Server()
server.connection(config.connection)
const plugins= [
// https://github.com/hapijs/inert
{ register: require('inert'), options: {} },
]
function setupRoutes() {
// Sample API Route
server.route({
method: 'GET',
path: '/api/v1/Person/{name}',
handler: function (req, reply) {
reply('Hello, '+ encodeURIComponent(req.params.name)+ '!')
}
})
// Web Server Route
server.route({
method: 'GET',
path: '/{files*}',
// https://github.com/hapijs/inert#the-directory-handler
handler: {directory: {path: '../html_root', listing: false, index: true } }
})
}
server.register(plugins, (err)=> {
if (err) {throw err}
// Initialize all routes
setupRoutes()
// Start the Server
server.start((err)=> {
if (err) {throw err}
server.log('info', `Server running at: ${server.info.uri}`)
})
})