Contributing to SQIP
March 2, 2026 · View on GitHub
:+1::tada: First off, thanks for taking the time to contribute! :tada::+1:
Atom Dev Team - CONTRIBUTING.md
Development Setup
SQIP uses a monorepo pattern to manage its many dependencies via npm workspaces. Lerna is used only for publishing and changelog generation.
Requirements
- Node.js >= 20
- npm (comes with Node.js)
Installation and repo setup
npm will automatically setup the monorepo workspaces for you:
npm install
Directory structure
SQIP is organized in packages. They are located in the packages directory. Each package is released as a separate NPM package.
All packages should follow the same directory structure to allow proper TS builds.
Relevant files and directories:
.
├── Dockerfile
├── lerna.json
├── package.json
├── packages
│ ├── sqip
│ │ ├── README.md
│ │ ├── __tests__
│ │ ├── dist
│ │ ├── node_modules
│ │ ├── package.json
│ │ └── src
│ ├── ...
└── package-lock.json
Developing
If not specified differently, all commands are executed from the project root directory.
A npm run will give you a first overview of all available scripts.
Building the source
To build/transpile the source of all packages via TypeScript, execute:
npm run build
You can watch for changes as well:
npm run build:watch
Create a new plugin
To build a new SQIP plugin is pretty simple:
- Make sure the SQIP repository is checked out at master with the latest status and you ran
npm install. - Create a new directory under
packages/for your plugin (e.g.packages/sqip-plugin-my-amazing-plugin). - Use the following template to rocket-start your new plugin:
import { SqipPlugin } from 'sqip'
export default class MyAmazingPlugin extends SqipPlugin {
static get cliOptions() {
// Make options available to the CLI.
return [
{
name: 'bar',
alias: 'b',
type: String,
description: 'Set replacement value for "foo"',
defaultValue: 'bar'
}
]
}
constructor({ pluginOptions }) {
/**
* Will enhance your plugin instance with the following:
* this.metadata: Object with width, height and type
* this.sqipConfig: The configuration passed to SQIP by the user
*/
super(...arguments)
// Set your options
this.options = {
// Inject default options
bar: 'bar',
...pluginOptions
}
}
async apply(imageBuffer) {
console.log('Incoming image:', imageBuffer)
// Check for correct format for your plugin
if (this.metadata.type !== 'svg') {
throw new Error('The plugin needs a svg image as input.')
}
// Read plugin options
const { bar } = this.options
// Do some transformation
const svg = imageBuffer.toString()
const newSvg = svg.replace('foo', bar)
// Hint: Consider to use https://www.npmjs.com/package/buffer-replace for replacements instead of this hack
// Return new svg as buffer
return Buffer.from(newSvg)
}
}
Add dependencies to a package
To add a dependency to a specific package, use npm's workspace flag:
npm install the-dependency-i-badly-need -w sqip-plugin-my-amazing-plugin
Testing
This project uses eslint for linting and Vitest for unit and e2e tests.
- Run
npm run lintto lint all packages - Run
npm run testto lint and test all packages
Watching and executing specific tests
Run a specific test file and watch for changes:
npx vitest packages/sqip/__tests__/unit/sqip.test.ts
Unit tests
- Run
npm run test:unitto execute unit tests in all packages - Run
npm run test:unit:watchto execute unit tests in all packages and rerun if code changes
End-to-end tests
- Run
npm run test:e2eto execute end-to-end tests in all packages. Will build the packages before execution. - Run
npm run test:e2e:watchto execute end-to-end tests in all packages and rerun if code changes
Hint: When watching end-to-end tests, you need to rebuild the source after each of your changes. You can use npm run build:watch for this.
Code style
This project uses prettier to format its source code. Your committed code will be automatically linted and transformed via husky.
See .prettierrc for the configuration details.
Commit conventions
To keep the automated release and changelog engine running, every commit should follow the conventional commits guidelines originally introduced by angular.
You may use Commitizen to ease up creating commit messages with the conventional commits guidelines. It is fully integrated into the project.
After merging into our master branch, this will allow semantic release to decide what kind of version to release. An automated changelog will also be created.