Introducing Plugin Preloader
As the upgrade team, one of our most significant challenges is the initial setup of each project, as many of the tools we utilize for inspection need distinct and customized configurations. This is due to the countless methods in which JavaScript/TypeScript projects can be constructed.
In today’s demonstration, we will introduce you to our new open source project called plugin-preloader and show you how you can use it to simplify your workflow if you encounter similar issues as we do.
plugin-preloader is a powerful and flexible JavaScript library written in TypeScript and designed to streamline the development workflow by automating the preloading and processing of the code.
With its ability to integrate various plugins, plugin-preloader provides an efficient and customizable solution for managing Babel and ESLint plugins.
Use case
We have a blog post that explains how we use es6-plato to create a comprehensive static code analysis report for each project. The report is produced by examining the project’s source code and offering a visual representation of code complexity along with various other metrics.
In order to generate the report, es6-plato must parse the project’s source code. This is where the plugin-preloader
becomes valuable. It allows us to install all the necessary Babel and ESLint plugins by simply specifying the paths to their respective configurations, eliminating the need for manual installation.
This feature is implemented in our fork of the es6-plato library. As we deal with multiple projects, this approach can save us a lot of time and effort.
Installation
To install the library, run the following command:
npm install plugin-preloader
Usage example
Let’s take a look at a project whose primary objective is to analyze other projects. To accomplish this, it must process the source code of the project being examined.
An example without usage of plugin-preloader
Let’s consider the following project structure:
Main executable file:
const babel = require("@babel/core");
const fs = require("fs");
async function getAST(filePath, config) {
const fileContent = (await fs.promises.readFile(filePath)).toString();
return await babel.parse(fileContent, config);
}
async function main(pathToTargedProject, configPath) {
const config = require(configPath);
// For the purpose of this example, we can skip the implementation of the getTargetProjectFiles function
const targetProjectFiles = await getTargetProjectFiles(pathToTargedProject);
const asts = await Promise.all(
targetProjectFiles.map((filePath) => getAST(filePath, config))
);
console.log(asts);
}
module.exports = main;
In order to be able to inspect TypeScript projects, we need to install the @babel/plugin-transform-typescript
plugin. We need to be sure that it was added to the package.json
file:
{
"dependencies": {
"@babel/core": "7.21.8",
"@babel/plugin-transform-typescript": "7.21.3"
}
}
And add it to the Babel configuration:
module.exports = {
plugins: ["@babel/plugin-transform-typescript"]
};
With that new setup ready, we can now move on and try to run this tool on a React project. Once again, we need to install the @babel/preset-react
plugin and ensure that it was stored in the package.json
file:
{
"dependencies": {
"@babel/core": "7.21.8",
"@babel/plugin-transform-typescript": "7.21.3",
"@babel/preset-react": "7.18.6"
}
}
We have to also modify the Babel configuration. As we no longer need the @babel/plugin-transform-typescript
plugin, we can remove it from the configuration:
module.exports = {
presets: ["@babel/preset-react"]
};
From the previous code samples, you can see the pattern: in order to inspect a project, we need to install the required plugins and modify the Babel configuration.
In some cases we don’t need to use some installed Babel plugins and just modify the configuration.
An example using plugin-preloader
Now let’s take a look at how plugin-preloader
can save us time and effort.
Changes we need to make to the main executable file:
const babel = require("@babel/core");
const fs = require("fs");
// add the plugin-preloader library
const preload = require("plugin-preloader");
// rest of the code
async function main(pathToTargedProject, configPath) {
const config = require(configPath);
// add the preload function call with the desired configuration, it can be babel and/or eslint
preload({ babel: config });
// rest of the code
}
module.exports = main;
Changes we need to make to the Babel configuration file:
module.exports = {
presets: [["@babel/preset-react", undefined, undefined, "7.18.6"]]
};
And changes we need to make to the package.json
file:
{
"dependencies": {
"@babel/core": "7.21.8",
"plugin-preloader": "7.18.6"
}
}
As you can see from these snippets, the project requires Babel plugins to parse the code. This is where the plugin-preloader
proves useful.
By specifying the path to the plugin’s configuration, plugin-preloader
allows you to install and use all necessary plugins dynamically and removes the need for manual installation. It offers the preload
function that works seamlessly with standard Babel and ESLint configurations, ensuring that each plugin, preset, parser, or extend is processed and installed with the latest version.
To use a specific version for Babel plugins and presets, add a fourth element in the plugin/preset definition array item, bypassing the second and third elements (plugin configuration arguments) - ["@babel/preset-react", undefined, undefined, "7.18.6"]
. For ESLint plugins, extends, and parsers, use an array instead of a string, and the desired version is specified in the second element of the array - ["plugin:@typescript-eslint/recommended", "3.0.0"]
. From this point on, we can modify our Babel configuration based on the target project and not worry about installing the required pluginsm, plugin-preloader
will take care of that for us.
To more effectively demonstrate the usage of this library, we have created an example project. You can find it in the example folder.
Output
After successfully executing the preload function, the desired plugins, presets, parsers, and extends will be installed in the node_modules
folder. It is important to note that these installed packages will not be added to the package.json or package-lock.json files. This is by design, as plugin-preloader
aims to provide a temporary installation of the required plugins for the current session without affecting the project’s main dependencies. This approach ensures that the installed packages are solely used for the purpose they were preloaded for, such as code analysis or linting, without cluttering your project’s dependencies.
Once you are done with the specific task, the installed packages can be easily removed by running a clean-up process, such as deleting the node_modules
folder and reinstalling the project dependencies using npm prune
or yarn install
. This keeps your project’s dependency list clean and focused on its core requirements.
Known issues
The library is still in its early stages of development, and we are working on improving it. We are aware of the following issues , and we are working on resolving them.
Conclusion
In conclusion, the plugin-preloader library offers a useful solution for handling Babel and ESLint plugins in JavaScript and TypeScript projects. By automating the installation of plugins, presets, parsers, and extends, it streamlines the development workflow, saving you time and effort.
By integrating this library into your projects, you can eliminate manual installation steps and focus on what truly matters — creating software.