Skip to content

Conversation

@cconard96
Copy link
Contributor

@cconard96 cconard96 commented Dec 12, 2025

Checklist before requesting a review

  • I have read the CONTRIBUTING document.
  • I have performed a self-review of my code.

Description

Modern code deserves modern solutions.
Only affects Vue code at this time and is not completely done by this PR due to the number of changes.

  • Adjusts ESlint CI check to also cover Vue files
  • Adds restricted syntax to catch jQuery usage
  • Adds Axios as a replacement for AJAX requests and add lint rule to prohibit direct fetch/XMLHttpRequest. Axios is based on fetch but with some helpful functionality added like automatic JSON parsing and cleaner error handling.
  • Fixes unrelated ESLint issues now caught by CI in .vue files

Additional PRs can address the remaining $.each and $(selector|HTML) usages.

@cconard96 cconard96 changed the title Prohibit jQuery in Vue code Start prohibiting jQuery in Vue code Dec 13, 2025
"selector": "CallExpression[callee.object.name='$'][callee.property.name=/^(ajax|get|post)$/]",
"message": "Use axios for HTTP requests instead of jQuery AJAX methods."
},
// {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To be uncommented in later PRs

customfielddefinitions_id: custom_fields_id,
action: 'purge_field'
}, {
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Axios defaults to JSON while jQuery defaulted to "application/x-www-form-urlencoded". To avoid needing to change server code, the content type is manually changed in each request. JSON would likely be better in the future, which is why this header isn't added in the axios instance.

});
// Add axios interceptors
axiosInstance.interceptors.request.use((config) => {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Near-copy of the jQuery ajaxSend and ajaxComplete handlers for recording requests sent by Axios.

all_menus.value = menus;
});
}
const fuzzy_search = $('#fuzzysearch');
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Replaced by wrapping the component in a Teleport which makes Vue automatically "teleport" the component to another place in the DOM.

@cconard96 cconard96 marked this pull request as ready for review December 15, 2025 20:32
Comment on lines +36 to +52
const instance = axios.create({
baseURL: CFG_GLPI.root_doc,
headers: {
'X-Requested-With': 'XMLHttpRequest',
'X-Glpi-Csrf-Token': window.getAjaxCsrfToken(),
}
});

export function useAJAX() {
return {
ajaxGet: (url, config = {}) => instance.get(url, config),
ajaxPost: (url, data = {}, config = {}) => instance.post(url, data, config),
ajaxPut: (url, data = {}, config = {}) => instance.put(url, data, config),
ajaxDelete: (url, config = {}) => instance.delete(url, config),
axiosInstance: instance,
};
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMHO, we should reexport the axios object itself, to be able to use it with import axios from './axios'; in our modules. Developers would just have to know that we have a specific import location for this module, and that it defines some common default values, but would be able to use it the same way as in any other project using it.

Defaults can be configured with

axios.defaults.baseURL = CFG_GLPI.root_doc;
axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
axios.defaults.headers.post['X-Glpi-Csrf-Token'] = window.getAjaxCsrfToken();

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there are separate concerns here between Vue code and our regular ES modules. This composable will evolve with the Vue ecosystem and state management in mind. I am not sure it is something that should be started in this PR for code outside Vue.

Perhaps with GLPI 12 we can consider bundling our own plain ES module code together and then decide how to handle Axios in that context. f there is a ES script that re-exports Axios, it wouldn't be reliably usable everywhere as there are still non-module scripts loaded and inline on the page which would not have access. Even if the module had a side-effect of putting Axios on the window, it may not be available by the time the non-modules run.

Keeping the separation of Vue=Axios and everything else=jQuery AJAX may make it easier for other developers to understand as well in the short-term.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could keep it only for vue modules. My concern is about having specific methods naming that requires developers to learn how they behave while they probably already know how to properly use axios.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this could eventually be replaced with the composable from VueUse which is a widely used set of utilities. I was just waiting for there to be more than one or two things I knew we could use it for before proposing adding it instead of having simple implementations of what is needed currently.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants