Middleware
Basic Concepts of Middleware
- Definition: Middleware consists of functions executed before a page is rendered, with access to the context object.
- Purpose: Used for authentication, data preloading, permission control, etc.
- Types: Global middleware, single-page middleware, and group middleware.
Creating Middleware
- Create File: Create a middleware file in the
middlewarefolder. - Write Logic: Implement the middleware logic in the file.
Example Code
Create auth.js in the middleware folder:
// middleware/auth.js
export default function ({ store, redirect }) {
if (!store.getters['auth/isAuthenticated']) {
return redirect('/login');
}
}Using Middleware
- Global Middleware: Configure global middleware in
nuxt.config.js. - Single-Page Middleware: Specify middleware in a page file.
- Group Middleware: Apply middleware to a group of pages.
Example Code
Global Middleware:
// nuxt.config.js
export default {
middleware: ['auth'],
};Single-Page Middleware:
// pages/about.vue
export default {
middleware: 'auth',
};Group Middleware:
// nuxt.config.js
export default {
router: {
middleware: ['auth'],
},
};Middleware Parameters
Middleware functions receive a context object with the following properties:
req: Node.js request object.res: Node.js response object.store: Vuex store instance.redirect: Redirect method.app: Vue application instance.route: Current route object.
Example Code
// middleware/auth.js
export default function ({ store, redirect }) {
if (!store.getters['auth/isAuthenticated']) {
return redirect('/login');
}
}Complex Logic
- Combining Multiple Middleware: Specify multiple middleware using an array.
- Conditional Logic: Execute different middleware based on conditions.
// nuxt.config.js
export default {
middleware: ['auth', 'admin'],
};Error Handling
- Catching Errors: Capture and handle errors within middleware.
// middleware/auth.js
export default function ({ store, redirect, error }) {
if (!store.getters['auth/isAuthenticated']) {
error({ statusCode: 401, message: 'Unauthorized' });
}
}Example Project Structure
project/
├── middleware/
│ ├── auth.js
│ └── admin.js
├── pages/
│ ├── index.vue
│ ├── about.vue
│ └── login.vue
├── store/
│ └── auth.js
└── nuxt.config.jsCombining Multiple Middleware
In real-world applications, you may need to combine multiple middleware to handle complex logic, such as authenticating users and then checking their permissions.
// middleware/auth.js
export default function ({ store, redirect }) {
if (!store.getters['auth/isAuthenticated']) {
return redirect('/login');
}
}
// middleware/admin.js
export default function ({ store, redirect }) {
if (!store.getters['auth/isAdmin']) {
return redirect('/dashboard');
}
}Using These Middleware in Pages or Groups:
// nuxt.config.js
export default {
router: {
middleware: ['auth', 'admin'],
},
};Dynamic Middleware
Dynamic middleware allows you to conditionally apply middleware based on certain criteria, achieved by dynamically specifying middleware names in pages or groups.
// pages/admin.vue
export default {
middleware: ['auth', 'admin'],
};Asynchronous Middleware
Middleware can be asynchronous, allowing you to use the await keyword to wait for asynchronous operations to complete.
// middleware/auth.js
export default async function ({ store, redirect }) {
const isAuthenticated = await store.dispatch('auth/checkAuthentication');
if (!isAuthenticated) {
return redirect('/login');
}
}Error Handling in Middleware
Proper error handling in middleware is critical to ensure application stability and a good user experience.
// middleware/auth.js
export default function ({ store, redirect, error }) {
if (!store.getters['auth/isAuthenticated']) {
error({ statusCode: 401, message: 'Unauthorized' });
}
}Using Vuex Middleware
You can use Vuex middleware to handle more complex logic, such as modifying the Vuex store’s state within middleware.
// middleware/auth.js
export default async function ({ store, redirect }) {
const isAuthenticated = await store.dispatch('auth/checkAuthentication');
if (!isAuthenticated) {
store.commit('auth/setAuthenticationStatus', false);
return redirect('/login');
}
}Middleware Order
The execution order of middleware is important, as it affects the final page rendering result. Ensure middleware is defined in the correct order.
// nuxt.config.js
export default {
router: {
middleware: ['auth', 'admin'],
},
};Testing Middleware
Write tests to ensure middleware behaves as expected.
// tests/unit/middleware/auth.test.js
import { shallowMount, createLocalVue } from '@vue/test-utils';
import Vuex from 'vuex';
import authMiddleware from '~/middleware/auth';
const localVue = createLocalVue();
localVue.use(Vuex);
describe('Auth Middleware', () => {
let store;
let context;
beforeEach(() => {
store = new Vuex.Store({
getters: {
'auth/isAuthenticated': () => true,
},
});
context = {
store,
redirect: jest.fn(),
error: jest.fn(),
};
});
it('should redirect to login if not authenticated', async () => {
store.getters['auth/isAuthenticated'] = () => false;
await authMiddleware(context);
expect(context.redirect).toHaveBeenCalledWith('/login');
});
it('should not redirect if authenticated', async () => {
await authMiddleware(context);
expect(context.redirect).not.toHaveBeenCalled();
});
});Plugins
Nuxt.js plugins are a way to extend Vue and Nuxt functionality, allowing you to run custom code when the application starts. Plugins can be used to register global components, configure third-party libraries, add custom directives, and more.
Creating Plugins
- Create File: Create a plugin file in the
pluginsfolder. - Write Logic: Implement the plugin logic in the file.
Example Code
Create axios.js in the plugins folder:
// plugins/axios.js
import Vue from 'vue';
import axios from 'axios';
// Set base URL
axios.defaults.baseURL = 'https://api.example.com/';
// Add request interceptor
axios.interceptors.request.use(
function (config) {
// Do something before sending the request
return config;
},
function (error) {
// Handle request errors
return Promise.reject(error);
}
);
// Add response interceptor
axios.interceptors.response.use(
function (response) {
// Do something with response data
return response;
},
function (error) {
// Handle response errors
return Promise.reject(error);
}
);
// Mount Axios to Vue prototype
Vue.prototype.$axios = axios;Using Plugins
- Register Plugin: Register the plugin in
nuxt.config.js.
Example Code
// nuxt.config.js
export default {
plugins: ['~/plugins/axios'],
};Plugin Parameters
Plugin functions receive a context object with the following properties:
app: Vue application instance.router: Vue Router instance.store: Vuex store instance.$axios: Axios instance.$nuxt: Nuxt instance.
// plugins/axios.js
export default function ({ app, $axios }) {
// Access app and $axios here
}Global Components
- Register Global Components: Register global components in a plugin.
// plugins/global-components.js
import Vue from 'vue';
import MyComponent from '~/components/MyComponent.vue';
Vue.component('my-component', MyComponent);Global Directives
- Register Global Directives: Register global directives in a plugin.
// plugins/global-directives.js
import Vue from 'vue';
Vue.directive('focus', {
inserted(el) {
el.focus();
},
});Global Filters
- Register Global Filters: Register global filters in a plugin.
// plugins/global-filters.js
import Vue from 'vue';
Vue.filter('capitalize', function (value) {
if (!value) return '';
value = value.toString();
return value.charAt(0).toUpperCase() + value.slice(1);
});Third-Party Libraries
- Configure Third-Party Libraries: Configure third-party libraries in a plugin.
// plugins/vuelidate.js
import Vue from 'vue';
import Vuelidate from 'vuelidate';
Vue.use(Vuelidate);Complex Logic
- Combining Multiple Plugins: Specify multiple plugins using an array.
- Conditional Logic: Execute different plugins based on conditions.
// nuxt.config.js
export default {
plugins: ['~/plugins/axios', '~/plugins/global-components'],
};Testing Plugins
- Write Unit Tests: Write unit tests to verify plugin behavior.
// tests/unit/plugins/axios.test.js
import axios from 'axios';
import { shallowMount, createLocalVue } from '@vue/test-utils';
const localVue = createLocalVue();
describe('Axios Plugin', () => {
beforeEach(() => {
localVue.prototype.$axios = axios;
});
it('should have a default baseURL', () => {
expect(localVue.prototype.$axios.defaults.baseURL).toBe('https://api.example.com/');
});
});Example Project Structure
project/
├── plugins/
│ ├── axios.js
│ ├── global-components.js
│ ├── global-directives.js
│ └── global-filters.js
├── components/
│ └── MyComponent.vue
└── nuxt.config.js



