@meng-xi/vite-plugin 0.0.4 → 0.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README-en.md +249 -70
- package/README.md +343 -143
- package/dist/common/index.cjs +1 -1
- package/dist/common/index.d.cts +84 -1
- package/dist/common/index.d.mts +84 -1
- package/dist/common/index.d.ts +84 -1
- package/dist/common/index.mjs +1 -1
- package/dist/factory/index.cjs +1 -1
- package/dist/factory/index.d.cts +71 -6
- package/dist/factory/index.d.mts +71 -6
- package/dist/factory/index.d.ts +71 -6
- package/dist/factory/index.mjs +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +4 -5
- package/dist/index.d.mts +4 -5
- package/dist/index.d.ts +4 -5
- package/dist/index.mjs +1 -1
- package/dist/logger/index.cjs +1 -1
- package/dist/logger/index.d.cts +1 -1
- package/dist/logger/index.d.mts +1 -1
- package/dist/logger/index.d.ts +1 -1
- package/dist/logger/index.mjs +1 -1
- package/dist/plugins/index.cjs +1 -1
- package/dist/plugins/index.d.cts +213 -8
- package/dist/plugins/index.d.mts +213 -8
- package/dist/plugins/index.d.ts +213 -8
- package/dist/plugins/index.mjs +1 -1
- package/dist/shared/vite-plugin.B5wW4CiL.mjs +36 -0
- package/dist/shared/vite-plugin.Ba9646wL.cjs +1 -0
- package/dist/shared/vite-plugin.C3ejdBNf.mjs +1 -0
- package/dist/shared/{vite-plugin.B3PARlU9.d.cts → vite-plugin.CLr0ttuO.d.cts} +16 -0
- package/dist/shared/{vite-plugin.B3PARlU9.d.mts → vite-plugin.CLr0ttuO.d.mts} +16 -0
- package/dist/shared/{vite-plugin.B3PARlU9.d.ts → vite-plugin.CLr0ttuO.d.ts} +16 -0
- package/dist/shared/vite-plugin.CXlzkIgT.cjs +36 -0
- package/dist/shared/vite-plugin.CawoITTT.cjs +1 -0
- package/dist/shared/vite-plugin.DSb6XzBn.mjs +1 -0
- package/package.json +72 -72
- package/dist/shared/vite-plugin.C7isVPKg.mjs +0 -1
- package/dist/shared/vite-plugin.D6NYITpX.cjs +0 -1
- package/dist/shared/vite-plugin.D8HTI0Ni.cjs +0 -2
- package/dist/shared/vite-plugin.Dd2ogbSe.mjs +0 -2
- package/dist/shared/vite-plugin.DqWt65U-.cjs +0 -1
- package/dist/shared/vite-plugin.HZb-1B5l.mjs +0 -1
- package/dist/shared/vite-plugin.UkE7CdSe.d.cts +0 -43
- package/dist/shared/vite-plugin.UkE7CdSe.d.mts +0 -43
- package/dist/shared/vite-plugin.UkE7CdSe.d.ts +0 -43
package/README-en.md
CHANGED
|
@@ -2,60 +2,72 @@
|
|
|
2
2
|
|
|
3
3
|
<div align="center">
|
|
4
4
|
<a href="https://github.com/MengXi-Studio/vite-plugin">
|
|
5
|
-
<img alt="
|
|
5
|
+
<img alt="MengXi Studio Logo" width="215" src="https://github.com/MengXi-Studio/vite-plugin/blob/master/packages/docs/src/public/logo.png">
|
|
6
6
|
</a>
|
|
7
7
|
<br>
|
|
8
8
|
<h1>@meng-xi/vite-plugin</h1>
|
|
9
|
+
<p>A toolkit providing practical plugins for Vite, also a complete plugin development framework</p>
|
|
9
10
|
|
|
10
11
|
[](LICENSE) [](https://www.npmjs.com/package/@meng-xi/vite-plugin)
|
|
11
12
|

|
|
12
13
|
|
|
13
14
|
</div>
|
|
14
15
|
|
|
15
|
-
|
|
16
|
-
> - Extends Vite build process functionality, providing automated processing solutions for common build tasks.
|
|
17
|
-
> - All plugins support detailed configuration options, allowing customization based on project needs to meet different usage scenarios.
|
|
18
|
-
> - Plugins provide error handling mechanisms to ensure build processes can catch errors, improving build reliability.
|
|
19
|
-
> - Export core components like BasePlugin, Logger, Validator, allowing developers to build custom plugins based on the same infrastructure.
|
|
16
|
+
## Features
|
|
20
17
|
|
|
21
|
-
|
|
18
|
+
- **Ready to Use** - Provides practical plugins for file copying, router generation, version management, icon injection
|
|
19
|
+
- **Plugin Development Framework** - Exports core components like BasePlugin, Logger, Validator for building custom plugins
|
|
20
|
+
- **Complete Lifecycle** - Supports initialization, config resolution, destroy lifecycle management with automatic hook composition
|
|
21
|
+
- **Type Safe** - Complete TypeScript type definitions with configuration validators ensuring parameter correctness
|
|
22
|
+
- **Flexible Configuration** - All plugins support detailed configuration to meet diverse scenario requirements
|
|
23
|
+
- **Safe Execution** - Built-in error handling strategies (throw / log / ignore) for unified exception management
|
|
22
24
|
|
|
23
|
-
|
|
25
|
+
## Documentation
|
|
24
26
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
### Installation
|
|
27
|
+
View full documentation: [https://mengxi-studio.github.io/vite-plugin/](https://mengxi-studio.github.io/vite-plugin/)
|
|
28
28
|
|
|
29
|
-
|
|
29
|
+
## Installation
|
|
30
30
|
|
|
31
31
|
```bash
|
|
32
|
-
#
|
|
33
|
-
npm install @meng-xi/vite-plugin
|
|
32
|
+
# npm
|
|
33
|
+
npm install @meng-xi/vite-plugin -D
|
|
34
34
|
|
|
35
|
-
#
|
|
36
|
-
yarn add @meng-xi/vite-plugin
|
|
35
|
+
# yarn
|
|
36
|
+
yarn add @meng-xi/vite-plugin -D
|
|
37
37
|
|
|
38
|
-
#
|
|
39
|
-
pnpm add @meng-xi/vite-plugin
|
|
38
|
+
# pnpm
|
|
39
|
+
pnpm add @meng-xi/vite-plugin -D
|
|
40
40
|
```
|
|
41
41
|
|
|
42
|
-
|
|
42
|
+
## Quick Start
|
|
43
43
|
|
|
44
|
-
|
|
44
|
+
### Using Built-in Plugins
|
|
45
45
|
|
|
46
46
|
```typescript
|
|
47
47
|
import { defineConfig } from 'vite'
|
|
48
|
-
import { copyFile, injectIco } from '@meng-xi/vite-plugin'
|
|
48
|
+
import { copyFile, generateRouter, generateVersion, injectIco } from '@meng-xi/vite-plugin'
|
|
49
49
|
|
|
50
50
|
export default defineConfig({
|
|
51
51
|
plugins: [
|
|
52
|
-
// Copy
|
|
52
|
+
// Copy files
|
|
53
53
|
copyFile({
|
|
54
54
|
sourceDir: 'src/assets',
|
|
55
55
|
targetDir: 'dist/assets'
|
|
56
56
|
}),
|
|
57
57
|
|
|
58
|
-
//
|
|
58
|
+
// Generate router config (uni-app)
|
|
59
|
+
generateRouter({
|
|
60
|
+
pagesJsonPath: 'src/pages.json',
|
|
61
|
+
outputPath: 'src/router.config.ts'
|
|
62
|
+
}),
|
|
63
|
+
|
|
64
|
+
// Generate version
|
|
65
|
+
generateVersion({
|
|
66
|
+
format: 'datetime',
|
|
67
|
+
outputType: 'both'
|
|
68
|
+
}),
|
|
69
|
+
|
|
70
|
+
// Inject website icon
|
|
59
71
|
injectIco({
|
|
60
72
|
base: '/assets'
|
|
61
73
|
})
|
|
@@ -63,24 +75,34 @@ export default defineConfig({
|
|
|
63
75
|
})
|
|
64
76
|
```
|
|
65
77
|
|
|
66
|
-
|
|
78
|
+
### Accessing Plugin Instance
|
|
79
|
+
|
|
80
|
+
All built-in plugins return an object with a `pluginInstance` property for accessing internal state:
|
|
67
81
|
|
|
68
82
|
```typescript
|
|
69
|
-
import {
|
|
83
|
+
import type { PluginWithInstance } from '@meng-xi/vite-plugin/factory'
|
|
84
|
+
import type { GenerateRouterOptions } from '@meng-xi/vite-plugin'
|
|
85
|
+
|
|
86
|
+
const routerPlugin = generateRouter({ watch: true }) as PluginWithInstance<GenerateRouterOptions>
|
|
87
|
+
|
|
88
|
+
// Access plugin internals via pluginInstance
|
|
89
|
+
console.log(routerPlugin.pluginInstance?.options)
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Developing Custom Plugins
|
|
93
|
+
|
|
94
|
+
```typescript
|
|
95
|
+
import { BasePlugin, createPluginFactory } from '@meng-xi/vite-plugin'
|
|
96
|
+
import type { BasePluginOptions, PluginWithInstance } from '@meng-xi/vite-plugin/factory'
|
|
70
97
|
import type { Plugin } from 'vite'
|
|
71
98
|
|
|
72
|
-
interface MyPluginOptions {
|
|
99
|
+
interface MyPluginOptions extends BasePluginOptions {
|
|
73
100
|
path: string
|
|
74
|
-
enabled?: boolean
|
|
75
|
-
verbose?: boolean
|
|
76
|
-
errorStrategy?: 'throw' | 'log' | 'ignore'
|
|
77
101
|
}
|
|
78
102
|
|
|
79
103
|
class MyPlugin extends BasePlugin<MyPluginOptions> {
|
|
80
104
|
protected getDefaultOptions() {
|
|
81
|
-
return {
|
|
82
|
-
path: './default'
|
|
83
|
-
}
|
|
105
|
+
return { path: './default' }
|
|
84
106
|
}
|
|
85
107
|
|
|
86
108
|
protected validateOptions(): void {
|
|
@@ -96,69 +118,226 @@ class MyPlugin extends BasePlugin<MyPluginOptions> {
|
|
|
96
118
|
this.logger.info(`Plugin started with path: ${this.options.path}`)
|
|
97
119
|
}
|
|
98
120
|
}
|
|
121
|
+
|
|
122
|
+
protected destroy(): void {
|
|
123
|
+
super.destroy()
|
|
124
|
+
// Custom cleanup logic, e.g. close connections, stop watchers
|
|
125
|
+
}
|
|
99
126
|
}
|
|
100
127
|
|
|
101
128
|
export const myPlugin = createPluginFactory(MyPlugin)
|
|
102
129
|
```
|
|
103
130
|
|
|
104
|
-
## Plugin
|
|
131
|
+
## Plugin Development Framework
|
|
105
132
|
|
|
106
|
-
###
|
|
133
|
+
### BasePlugin Core Concepts
|
|
107
134
|
|
|
108
|
-
|
|
135
|
+
`BasePlugin` is the base class for all plugins, providing complete lifecycle management and development conventions:
|
|
109
136
|
|
|
110
|
-
|
|
137
|
+
#### Lifecycle
|
|
111
138
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
139
|
+
| Phase | Method | Description |
|
|
140
|
+
| ----------------- | ------------------ | -------------------------------------------------------------- |
|
|
141
|
+
| Initialization | `constructor` | Merge options, initialize logger and validator |
|
|
142
|
+
| Config Resolution | `onConfigResolved` | Called when Vite config is resolved |
|
|
143
|
+
| Hook Registration | `addPluginHooks` | Register Vite plugin hooks |
|
|
144
|
+
| Destroy | `destroy` | Automatically called during `closeBundle` for resource cleanup |
|
|
118
145
|
|
|
119
|
-
|
|
146
|
+
#### Automatic Hook Composition
|
|
120
147
|
|
|
121
|
-
|
|
148
|
+
The `toPlugin()` method automatically composes the following hooks:
|
|
122
149
|
|
|
123
|
-
**
|
|
150
|
+
- **configResolved** - Base class `onConfigResolved` runs first, then subclass hook
|
|
151
|
+
- **closeBundle** - Subclass hook runs first, then base class `destroy`
|
|
124
152
|
|
|
125
|
-
|
|
126
|
-
- `url`: Complete URL for the icon
|
|
127
|
-
- `link`: Custom complete link tag HTML
|
|
128
|
-
- `icons`: Custom icon array
|
|
129
|
-
- `verbose`: Whether to output detailed logs, default is `true`
|
|
130
|
-
- `enabled`: Whether to enable the plugin, default is `true`
|
|
131
|
-
- `copyOptions`: Icon file copying configuration
|
|
153
|
+
> Subclasses don't need to manually register `closeBundle` hooks for cleanup — just override the `destroy()` method.
|
|
132
154
|
|
|
133
|
-
|
|
155
|
+
#### Required Methods
|
|
134
156
|
|
|
135
|
-
|
|
157
|
+
| Method | Description |
|
|
158
|
+
| ------------------------ | --------------------- |
|
|
159
|
+
| `getPluginName()` | Return plugin name |
|
|
160
|
+
| `addPluginHooks(plugin)` | Add Vite plugin hooks |
|
|
136
161
|
|
|
137
|
-
|
|
138
|
-
2. Clone the code: Clone the forked project to your local machine.
|
|
162
|
+
#### Optional Methods
|
|
139
163
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
164
|
+
| Method | Default Behavior | Description |
|
|
165
|
+
| -------------------------- | ----------------- | ------------------------------------------- |
|
|
166
|
+
| `getDefaultOptions()` | Returns `{}` | Provide plugin default options |
|
|
167
|
+
| `validateOptions()` | No validation | Validate configuration parameters |
|
|
168
|
+
| `getEnforce()` | `undefined` | Plugin execution order (`'pre'` / `'post'`) |
|
|
169
|
+
| `onConfigResolved(config)` | Store config | Config resolved callback |
|
|
170
|
+
| `destroy()` | Unregister logger | Cleanup logic when plugin is destroyed |
|
|
171
|
+
|
|
172
|
+
#### Built-in Properties
|
|
173
|
+
|
|
174
|
+
| Property | Type | Description |
|
|
175
|
+
| ------------ | ------------------------ | ----------------------------- |
|
|
176
|
+
| `options` | `Required<T>` | Merged complete configuration |
|
|
177
|
+
| `logger` | `PluginLogger` | Plugin logger |
|
|
178
|
+
| `validator` | `Validator<T>` | Configuration validator |
|
|
179
|
+
| `viteConfig` | `ResolvedConfig \| null` | Resolved Vite configuration |
|
|
180
|
+
|
|
181
|
+
#### Error Handling Strategy
|
|
182
|
+
|
|
183
|
+
Control error behavior via the `errorStrategy` configuration option:
|
|
184
|
+
|
|
185
|
+
- `'throw'` (default) - Log error and throw exception, halting the build
|
|
186
|
+
- `'log'` - Log error but don't throw, continue execution
|
|
187
|
+
- `'ignore'` - Log error but don't throw, continue execution
|
|
188
|
+
|
|
189
|
+
Wrap error-prone operations with `safeExecute` / `safeExecuteSync`:
|
|
190
|
+
|
|
191
|
+
```typescript
|
|
192
|
+
const result = await this.safeExecute(async () => {
|
|
193
|
+
return await someAsyncOperation()
|
|
194
|
+
}, 'Execute async operation')
|
|
143
195
|
```
|
|
144
196
|
|
|
145
|
-
|
|
197
|
+
### createPluginFactory
|
|
146
198
|
|
|
147
|
-
|
|
148
|
-
|
|
199
|
+
Create plugin factory functions with optional normalizer support:
|
|
200
|
+
|
|
201
|
+
```typescript
|
|
202
|
+
// Basic usage
|
|
203
|
+
const myPlugin = createPluginFactory(MyPlugin)
|
|
204
|
+
|
|
205
|
+
// With normalizer (supports shorthand string config)
|
|
206
|
+
const myPlugin = createPluginFactory(MyPlugin, opt => (typeof opt === 'string' ? { path: opt } : opt))
|
|
207
|
+
|
|
208
|
+
// Usage with shorthand
|
|
209
|
+
myPlugin('./custom-path')
|
|
149
210
|
```
|
|
150
211
|
|
|
151
|
-
|
|
212
|
+
### Logger
|
|
152
213
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
214
|
+
Global singleton log manager providing independent log control for each plugin:
|
|
215
|
+
|
|
216
|
+
```typescript
|
|
217
|
+
import { Logger } from '@meng-xi/vite-plugin/logger'
|
|
218
|
+
|
|
219
|
+
// Create logger (usually called automatically by BasePlugin)
|
|
220
|
+
Logger.create({ name: 'my-plugin', enabled: true })
|
|
221
|
+
|
|
222
|
+
// Unregister plugin log config (automatically called on plugin destroy)
|
|
223
|
+
Logger.unregister('my-plugin')
|
|
224
|
+
|
|
225
|
+
// Destroy singleton (for test scenarios)
|
|
226
|
+
Logger.destroy()
|
|
156
227
|
```
|
|
157
228
|
|
|
158
|
-
|
|
229
|
+
Log output format:
|
|
159
230
|
|
|
160
|
-
```bash
|
|
161
|
-
git push origin feature/your-feature
|
|
162
231
|
```
|
|
232
|
+
ℹ️ [@meng-xi/vite-plugin:my-plugin] Info message
|
|
233
|
+
✅ [@meng-xi/vite-plugin:my-plugin] Success message
|
|
234
|
+
⚠️ [@meng-xi/vite-plugin:my-plugin] Warning message
|
|
235
|
+
❌ [@meng-xi/vite-plugin:my-plugin] Error message
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
## Built-in Plugins
|
|
239
|
+
|
|
240
|
+
### copyFile
|
|
241
|
+
|
|
242
|
+
Copy files or directories to specified locations after Vite build is completed.
|
|
243
|
+
|
|
244
|
+
| Option | Type | Default | Description |
|
|
245
|
+
| ----------- | ------- | ------- | ------------------------------------------ |
|
|
246
|
+
| sourceDir | string | - | Source directory path (required) |
|
|
247
|
+
| targetDir | string | - | Target directory path (required) |
|
|
248
|
+
| overwrite | boolean | true | Whether to overwrite existing files |
|
|
249
|
+
| recursive | boolean | true | Whether to recursively copy subdirectories |
|
|
250
|
+
| incremental | boolean | true | Whether to enable incremental copying |
|
|
251
|
+
|
|
252
|
+
### generateRouter
|
|
253
|
+
|
|
254
|
+
Automatically generate router configuration files based on uni-app project's `pages.json`.
|
|
255
|
+
|
|
256
|
+
| Option | Type | Default | Description |
|
|
257
|
+
| -------------------- | ------------------------------------------------- | ---------------------- | ------------------------------------------------ |
|
|
258
|
+
| pagesJsonPath | string | 'src/pages.json' | Path to pages.json file |
|
|
259
|
+
| outputPath | string | 'src/router.config.ts' | Output file path |
|
|
260
|
+
| outputFormat | 'ts' \| 'js' | 'ts' | Output file format |
|
|
261
|
+
| nameStrategy | 'path' \| 'camelCase' \| 'pascalCase' \| 'custom' | 'camelCase' | Route name strategy |
|
|
262
|
+
| customNameGenerator | (path: string) => string | - | Custom route name generator function |
|
|
263
|
+
| includeSubPackages | boolean | true | Whether to include sub-package routes |
|
|
264
|
+
| watch | boolean | true | Whether to watch changes and auto-regenerate |
|
|
265
|
+
| metaMapping | Record\<string, string\> | - | Mapping from page style fields to meta |
|
|
266
|
+
| exportTypes | boolean | true | Whether to export type definitions |
|
|
267
|
+
| preserveRouteChanges | boolean | true | Whether to preserve user modifications to routes |
|
|
268
|
+
|
|
269
|
+
### generateVersion
|
|
270
|
+
|
|
271
|
+
Automatically generate version numbers during the Vite build process.
|
|
272
|
+
|
|
273
|
+
| Option | Type | Default | Description |
|
|
274
|
+
| ------------ | --------------------------------------------------------------------- | ----------------- | ------------------------------ |
|
|
275
|
+
| format | 'timestamp' \| 'date' \| 'datetime' \| 'semver' \| 'hash' \| 'custom' | 'timestamp' | Version format |
|
|
276
|
+
| customFormat | string | - | Custom format template |
|
|
277
|
+
| semverBase | string | '1.0.0' | Semantic version base |
|
|
278
|
+
| outputType | 'file' \| 'define' \| 'both' | 'file' | Output type |
|
|
279
|
+
| outputFile | string | 'version.json' | Output file path |
|
|
280
|
+
| defineName | string | '**APP_VERSION**' | Global variable name to inject |
|
|
281
|
+
| hashLength | number | 8 | Hash length (1-32) |
|
|
282
|
+
| prefix | string | - | Version number prefix |
|
|
283
|
+
| suffix | string | - | Version number suffix |
|
|
284
|
+
| extra | Record\<string, unknown\> | - | Extra info (JSON file only) |
|
|
285
|
+
|
|
286
|
+
### injectIco
|
|
287
|
+
|
|
288
|
+
Inject website icon links into the head of HTML files during the Vite build process.
|
|
289
|
+
|
|
290
|
+
| Option | Type | Default | Description |
|
|
291
|
+
| ----------- | ------ | ------- | ------------------------------- |
|
|
292
|
+
| base | string | '/' | Base path for icon files |
|
|
293
|
+
| url | string | - | Complete URL for the icon |
|
|
294
|
+
| link | string | - | Custom complete link tag HTML |
|
|
295
|
+
| icons | Icon[] | - | Custom icon array |
|
|
296
|
+
| copyOptions | object | - | Icon file copying configuration |
|
|
297
|
+
|
|
298
|
+
`Icon` interface definition:
|
|
299
|
+
|
|
300
|
+
| Property | Type | Required | Description |
|
|
301
|
+
| -------- | ------ | -------- | ------------------ |
|
|
302
|
+
| rel | string | Yes | Icon relation type |
|
|
303
|
+
| href | string | Yes | Icon URL |
|
|
304
|
+
| sizes | string | No | Icon sizes |
|
|
305
|
+
| type | string | No | Icon MIME type |
|
|
306
|
+
|
|
307
|
+
## Sub-path Exports
|
|
308
|
+
|
|
309
|
+
Support importing modules on demand to reduce bundle size:
|
|
310
|
+
|
|
311
|
+
```typescript
|
|
312
|
+
// Full import
|
|
313
|
+
import { copyFile, BasePlugin, Logger } from '@meng-xi/vite-plugin'
|
|
314
|
+
|
|
315
|
+
// Module-level import
|
|
316
|
+
import { BasePlugin, createPluginFactory } from '@meng-xi/vite-plugin/factory'
|
|
317
|
+
import { Logger } from '@meng-xi/vite-plugin/logger'
|
|
318
|
+
import { copyFile, generateRouter } from '@meng-xi/vite-plugin/plugins'
|
|
319
|
+
import { Validator, readFileContent, writeFileContent } from '@meng-xi/vite-plugin/common'
|
|
320
|
+
|
|
321
|
+
// Type imports (on-demand type definitions from sub-paths)
|
|
322
|
+
import type { PluginWithInstance, PluginFactory, BasePluginOptions } from '@meng-xi/vite-plugin/factory'
|
|
323
|
+
import type { GenerateVersionOptions, InjectIcoOptions, Icon } from '@meng-xi/vite-plugin/plugins'
|
|
324
|
+
import type { DateFormatOptions } from '@meng-xi/vite-plugin/common'
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
## Changelog
|
|
328
|
+
|
|
329
|
+
See [GitHub Releases](https://github.com/MengXi-Studio/vite-plugin/releases)
|
|
330
|
+
|
|
331
|
+
## Contributing
|
|
332
|
+
|
|
333
|
+
Contributions are welcome! Please follow these steps:
|
|
334
|
+
|
|
335
|
+
1. Fork the repository
|
|
336
|
+
2. Create a feature branch: `git checkout -b feature/your-feature`
|
|
337
|
+
3. Commit changes: `git commit -m "feat: your feature description"`
|
|
338
|
+
4. Push to branch: `git push origin feature/your-feature`
|
|
339
|
+
5. Create a Pull Request
|
|
340
|
+
|
|
341
|
+
## License
|
|
163
342
|
|
|
164
|
-
|
|
343
|
+
[MIT](LICENSE)
|