grunt-connect middleware for testing file uploads - gruntjs

How can I use grunt-connect with livereload to test uploading files to a server?
I'm using Yeoman and angular-seed for my project. One of the requirements is the ability to upload files to the server. Rather than setting up some external server for the project, I'd like to be able to keep everything contained in my current setup.
This solution adds middleware directly into Gruntfile.js for grunt-connect.
First it loads connect bodyParser which makes it easier to parse the uploaded file and form elements.
Next it sets an endpoint at '/upload'. This will be the route used during development and testing. This middleware returns a basic response with file properties.
Finally, the static routes that Yeoman automatically configures are appended to the list of middleware, which is returned back to grunt-connect.

Configuration property for adding a file upload handler to grunt-connect.
livereload: {
options: {
open: true,
base: [ '.tmp', '<%= yeoman.app %>' ],
middleware: function (connect, options) {
var middlewares = [
connect().use(connect.bodyParser({ uploadDir: '.tmp' })),
connect().use('/upload', function(req, res, next) {
/*
console.log(req.files); // files properties
console.log(req.body); // form properties
*/
res.setHeader('Content-Type', 'application/json');
// response with basic file stats
res.end(JSON.stringify({
'size': req.files.file.size,
'path' : req.files.file.path,
'other' : null }));
})
];
// add the static paths in options.base
options.base.forEach(function (base) {
middlewares.push(connect.static(base));
});
return middlewares;
}
}
}

Related

Next Js: Middleware is ignored for a directory with re-writes

I have a file system like this
Pages
secure/
_middleware.ts
protectedResource.tsx
_app.tsx
_document.tsx
index.tsx
I have next configured like this
module.exports = {
...
async rewrites() {
return [
{
source: '/protectedResource',
destination: '/secure/protectedResource'
}
]
}
}
The rewrite works correctly, when accessing http://localhost:3000/protectedResource the user sees the correct route. The middleware from the 'secure' directory, however, is not invoked during the request pipeline. Aside from moving the middleware to the pages directory, how can I resolve this?

Exposing Storybook via NextJS route

I have a NextJS app and am using Storybook to develop my components.
After looking through all the NextJS routing documentation, I can't find a way to route to my storybook from within NextJS. Only access pages within the /pages directory.
What I would like to do it to have my StoryBook available at /styleguide from within my Next app thought all environments.
Is someone able to help?
Short answer: No, you can not do that.
But you can always redirect the url /styleguide to another domain where Storybook is running, for example styleguide.example.com. Here, an example based on the official documentation:
// next.config.js
module.exports = {
async redirects() {
return [
{
source: '/styleguide',
destination: 'https://styleguide.example.com',
permanent: true,
},
]
},
}
If your URL's would have any parameters for it's origin that you would want to append to the redirects destination, NextJS provides a feature to do just that.
// next.config.js
module.exports = {
async redirects() {
return [
{
source: '/styleguide/:pageId/:slug',
destination: 'https://styleguide.example.com/:pageId/:slug',
permanent: true,
},
]
},
}

Nextjs and workbox integration

Requirement: I am trying to use service worker and cache static files so as to have a benefit to reduce HTTP requests and make the site performance better. 
Down the lane I would switch to offline, caching images, api's etc.
I have seen the plugins:
https://github.com/hanford/next-offline and
https://www.npmjs.com/package/next-pwa
It seems to work. Although I was trying to find out if there were examples of (nextjs + workbox).
Next js do have an example for https://github.com/vercel/next.js/tree/canary/examples/with-next-offline. But I would like just using workbox for this.
Anyone got any working examples? Even a basic one would do.
Currently am not using a custom server. Just using the inbuilt builder of nextjs (https://nextjs.org/docs/getting-started#manual-setup)
I figured out an answer on my own:
Reference: https://developers.google.com/web/tools/workbox/reference-docs/latest/module-workbox-build#.generateSW
I have done runtime caching for my app here and added the workbox file into the base file:
// Use the window load event to keep the page load performant
useEffect(() => {
window.addEventListener("load", () => {
const serviceWorkerScope = `/${country}/workbox-worker.js`
navigator.serviceWorker
.register(serviceWorkerScope)
.then(() => {
logger.info(`Service worker registered at ${serviceWorkerScope}`)
})
.catch(error => {
logger.error("Error in serviceWorker registration: ", error)
})
})
})
I have added comments,
// File to generate the service worker.
require("dotenv").config()
const workboxBuild = require("workbox-build")
const { COUNTRY: country, NODE_ENV } = process.env
const urlPattern = new RegExp(`/${country}\/static|_next\/.*/`)
// https://developers.google.com/web/tools/workbox/reference-docs/latest/module-workbox-build#.generateSW
const buildSW = () => {
return workboxBuild.generateSW({
swDest: "public/workbox-worker.js",
clientsClaim: true,
mode: NODE_ENV,
skipWaiting: true,
sourcemap: false,
runtimeCaching: [
{
urlPattern: urlPattern,
// Apply a cache-first strategy.
handler: "CacheFirst",
options: {
cacheName: "Static files caching",
expiration: {
maxEntries: 50,
maxAgeSeconds: 15 * 60, // 15minutes
},
},
},
],
})
}
buildSW()

Setting cache-control header for static file serving on nextjs default server

I am using the default nextjs server to run my nextjs program by this command next start.
However, I am not able to change the cache-control header for the files under the public folder.
Is there any method to set the cache-control header without setting the Custom Server?
There is undocumented feature or bug, but it works. More info can be found here https://nextjs.org/docs/api-reference/next.config.js/headers
Add config to you next.config.js file for example:
async headers() {
return [
{
source: '/:all*(svg|jpg|png)',
locale: false,
headers: [
{
key: 'Cache-Control',
value: 'public, max-age=9999999999, must-revalidate',
}
],
},
]
},
Per this bug report and discussion the Next devs believe static file serving should only be used as a developer convenience, not in production, and hence they don't consider it a priority to add such features.
However, in the issue comments somebody has suggested a workaround using Express to detect requests that will end up serving static files. For example, if the Next.js route handler is the handler() method you can do this to set a one-year cache policy for *.woff font files:
// this is a hack to make the cache headers friendlier..
server.get('*.woff2?', (req, res) => {
res.setHeader('Cache-Control', 'public,max-age=31536000');
return handler(req, res);
});
I'm using Express as a custom server for Next.js, and this is how I set "Cache-Control" header for static files:
const express = require("express");
const server = express();
...
server.use(express.static(__dirname + "/public", { maxAge: "365d" }));
server.use(function (req, res, next) {
if (req.url.match(".js|.css|.woff|.jpg|.png|.gif|.ttf")) {
res.setHeader("Cache-Control", "public,max-age=31536000"); // 365 days
}
next();
});

__dirname is not defined within API routes

I have a Next.js API route which needs to access a local file, but __dirname is not defined when I use it within an API route.
Is it possible to get the current directory from within a Next route?
In order to access the root directory, or any directory for that matter, you can used next.config.js to set a webpack alias. Example:
// Inside next.config.js
module.exports = {
webpack: (config) => {
config.resolve.alias = {
...config.resolve.alias,
'~': __dirname,
};
}
Now ~, when used to path to resources, will resolve to the value of __dirname.
Alternatively you could use next.js's client env if you're on next.js 8+. Example:
// inside next.config.js
module.exports = {
env: {
ROOT: __dirname,
}
}
Now using process.env.ROOT gives you access to __dirname.

Resources