👍🎉 First off, thanks for taking the time to contribute! 🎉👍
Atom Dev Team - CONTRIBUTING.md
SQIP uses a monorepo pattern to manage its many dependencies via npm workspaces. Lerna is used only for publishing and changelog generation.
- Node.js >= 20
- npm (comes with Node.js)
npm will automatically setup the monorepo workspaces for you:
npm installSQIP 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.
.
├── Dockerfile
├── lerna.json
├── package.json
├── packages
│ ├── sqip
│ │ ├── README.md
│ │ ├── __tests__
│ │ ├── dist
│ │ ├── node_modules
│ │ ├── package.json
│ │ └── src
│ ├── ...
└── package-lock.json
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.
To build/transpile the source of all packages via TypeScript, execute:
npm run buildYou can watch for changes as well:
npm run build:watchTo 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)
}
}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-pluginThis 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
Run a specific test file and watch for changes:
npx vitest packages/sqip/__tests__/unit/sqip.test.ts- 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
- 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.
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.
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.