vite-ssr-middleware
v0.2.1
Published
"Middleware support for plugin vite-ssr"
Downloads
51
Readme
Vite-SSR-Middleware
This plugin adds Nuxt like middleware feature to Vite-SSR only for Vue.
Installation
This package requires vite-ssr
and vue-router@next
as peer dependency.
Download it from npm (p)npm install vite-ssr-middleware
or yarn add vite-ssr-middleware
.
Usage
Usage is simple, there is no need to register this package like vueApp.use()
.
Creating Middleware
A middleware can have 3 arguments, 2 of them are necessary and 1 is optional.
First parameter is unique name to middleware string
Second parameter is handler (context, properties) => boolean | Promise<boolean>
Third parameter is optional object, which can be defined in root handler object
Every middleware has to return boolean
. If middleware returns true
chaining will continue.
If middleware returns false
chaining will stop.
Return false
to use next()
and redirect()
inside middlewares. If returned value is true
and next()
or redirect()
is used vue-router
will throw error.
import { defineMiddleware } from 'vite-ssr-middleware';
import { useStore } from '../stores/mainStore';
// context is Vite-SSR context. Simply return type of useContext() from vite-ssr.
// Properties are empty object by default and can be customized in root handler.
export const authMiddleware = defineMiddleware('auth', (context, properties) => {
// Vite-SSR 0.12.0 available context values
const {
next, // from vue-router
to, // from vue-router
from, // from vue-router
isClient,
request,
redirect,
initialState,
url,
writeResponse,
response
} = context;
// Check if middleware runs on client side.
// import.meta.env.SSR can be used here.
if (isClient) {
// we are going to talk about this later.
const store = useStore(properties.pinia);
if (store.auth) return true; // continue chaining
// if user not signed in
next('/login');
return false; // Stop chaining because NEXT is used.
}
// if not client, it is server
const authorization = request.headers.authorization;
const isOK = CheckUserTokenAndReturnFalseOrTrue(authorization);
if (isOk) return true; // token is correct, return true to continue chaining
// In server side we have to use redirect() function and next() together.
// on server side redirect() handles navigation but if next() is not called after,
// it does not work and stuck on same page.
redirect('/login');
next();
return false; // return false and stop chaining because next is used.
});
Creating Middleware Handler
There are 2 middleware handlers. One is simple and the other one is needed to be handled.
Handlers need vite-ssr
context, vue-router
guard arguments and all middlewares as array.
And can take properties
as argument. properties
can be accessible from any middleware.
Simple Handler
import { viteSSR } from 'vite-ssr';
import { middlewareHandler } from 'vite-ssr-middleware';
import App from './App.vue';
import { routes } from './routes';
// Store example with pinia
import { createPinia } from 'pinia';
// Import middlewares
import { authMiddleware } from '../middlewares/authMiddleware';
export default viteSSR(App, { routes }, (context) => {
const { app, router } = context;
const pinia = createPinia();
app.use(pinia);
// middlewareHandler must be used inside router.beforeEach
const handler = middlewareHandler(context, [authMiddleware], {
// this property is accessible in each middleware
pinia
});
router.beforeEach(handler);
//...
});
A Little Complex Handler
This handler is to create a handler function. Handler function will return true
or false
.
If handler function returns true
it means a middleware returned false
and blocked chaining.
Basically in this tutorial if false
is returned from middleware it means next()
or redirect()
is called. You can use it for your own purpose
If handler returns false
it means none of middlewares called next()
, so we have to call it manually.
import { viteSSR } from 'vite-ssr';
import { createMiddlewareHandler } from 'vite-ssr-middleware';
import App from './App.vue';
import { routes } from './routes';
// Store example with pinia
import { createPinia } from 'pinia';
// Import middlewares
import { authMiddleware } from '../middlewares/authMiddleware';
export default viteSSR(App, { routes }, (context) => {
const { app, router } = context;
const pinia = createPinia();
app.use(pinia);
// middlewareHandler must be used inside router.beforeEach
// I pass pinia as property here because some middlewares need it.
const handler = createMiddlewareHandler(context, [authMiddleware], {
pinia
});
router.beforeEach(async (to, from, next) => {
// if any one of middlewares returned false, isNextHandled = true
// in this tutorial, return false means NEXT is used.
// you can customize this for your own purpose.
const isNextHandled = await handler({ to, from, next });
if (isNextHandled) return;
next();
});
//...
});
Defining Middlewares for Routes
To define middleware for routes we have to use middlewares
array inside of route.meta
.
Middlewares array can store the value
of middleware and name
of it as string.
This package does not remove middleware duplications!!!!
import { RouteRecordRaw } from 'vue-router';
import { authMiddleware } from '../middlewares/authMiddleware';
const routes = [
{
path: '/settings',
component: () => import('./Settings.vue'),
meta: {
middlewares: [authMiddleware]
}
},
{
path: '/topsecret',
component: () => import('./SecretPage.vue'),
meta: {
middlewares: ['auth'] // name of the middleware (first parameter)
}
}
];
Typed Custom Properties
You can create your own types for properties inside middlewares.
middlewares.d.ts
This file should ALWAYS!
import something or export something. If no import or export provided this will break all types.
//or import something
import { App } from 'vue';
declare module 'vite-ssr-middleware' {
interface CustomProperties {
propertyForMiddleware: string;
}
}
// a garbage type just to make this file as a module.
export type Integer = number;
Importing Middlewares Dynamically
Thanks to vite's import.meta.globEager
function we can import files inside a directory so we won't import middlewares by hand.
I am assuming that we have a directory called middlewares
and every file inside of this folder has default
export which is middleware.
Check: Glob Import
import { viteSSR } from 'vite-ssr/vue';
import { middlewareHandler, Middleware } from 'vite-ssr-middleware';
import App from './App.vue';
import { routes } from './routes';
import type { Middleware } from 'vite-ssr-middleware';
export default viteSSR(App, { routes }, (context) => {
const { router } = context;
// glob import will return an object of imports.
// key is path and value is exported data.
/**
* Example: {
* './middlewares/authMiddleware.ts': {
* default: middlewareData,
* },
* './middlewares/loggerMiddleware.ts': {
* default: loggerMiddlewareData,
* },
* }
*/
const midwareGlob = import.meta.globEager('./middlewares/*.ts');
const middlewares: Middleware[] = Object.keys(midwareGlob).map((key) => midwareGlob[key].default);
const handler = middlewareHandler(context, middlewares);
router.beforeEach(handler);
});
authMiddleware.ts
export default defineMiddleware('auth', () => true);
loggerMiddleware.ts
export default defineMiddleware('logger', () => true);
Vite Plugin Pages Example
If you are using vite-plugin-pages we cannot import middlewares and directly use them. But this library supports name of middlewares so we can use them.
<!-- I have to use prettier-ignore thanks to prettier :) -->
<!-- prettier-ignore -->
<route lang="yaml"> <!-- OR json or json5 -->
meta:
middlewares:
- auth
- logger
</route>
Notes
Middlewares are called by array queue.
Use handler inside of viteSSR
function.