@rsbuild/plugin-image-compress 1.0.0-alpha.9 → 1.0.1

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/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2023-present Bytedance, Inc. and its affiliates.
3
+ Copyright (c) 2024 Rspack Contrib
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -1,19 +1,78 @@
1
- <p align="center">
2
- <a href="https://rsbuild.dev" target="blank"><img src="https://github.com/web-infra-dev/rsbuild/assets/7237365/84abc13e-b620-468f-a90b-dbf28e7e9427" alt="Rsbuild Logo" /></a>
1
+ # @rsbuild/plugin-image-compress
2
+
3
+ An Rsbuild plugin to compress images via [@napi-rs/image](https://www.npmjs.com/package/@napi-rs/image) and [SVGO](https://www.npmjs.com/package/svgo).
4
+
5
+ With the image compression plugin, image assets used in the project can be compressed to reduce the output size without affecting the visual appearance of the image.
6
+
7
+ <p>
8
+ <a href="https://npmjs.com/package/@rsbuild/plugin-image-compress">
9
+ <img src="https://img.shields.io/npm/v/@rsbuild/plugin-image-compress?style=flat-square&colorA=564341&colorB=EDED91" alt="npm version" />
10
+ </a>
11
+ <img src="https://img.shields.io/badge/License-MIT-blue.svg?style=flat-square&colorA=564341&colorB=EDED91" alt="license" />
3
12
  </p>
4
13
 
5
- # Rsbuild
14
+ ## Usage
15
+
16
+ Install:
17
+
18
+ ```bash
19
+ npm add @rsbuild/plugin-image-compress -D
20
+ ```
21
+
22
+ Add plugin to your `rsbuild.config.ts`:
23
+
24
+ ```ts
25
+ // rsbuild.config.ts
26
+ import { pluginImageCompress } from "@rsbuild/plugin-image-compress";
27
+
28
+ export default {
29
+ plugins: [pluginImageCompress()],
30
+ };
31
+ ```
32
+
33
+ ## Options
34
+
35
+ The plugin accepts an array of compressor configuration options, each of which can be either a string or an object. The string can be the name of a built-in compressor and its default configuration enabled.
36
+ Or use the object format configuration and specify the compressor in the `use` field. The remaining fields of the object will be used as compressor configuration options.
37
+
38
+ By default, the plugin will enable `jpeg`, `png`, `ico` image compressors, which are equivalent to the following two examples:
39
+
40
+ ```js
41
+ pluginImageCompress(["jpeg", "png", "ico"]);
42
+ ```
43
+
44
+ ```js
45
+ pluginImageCompress([{ use: "jpeg" }, { use: "png" }, { use: "ico" }]);
46
+ ```
47
+
48
+ The default configuration can be overridden by specifying a configuration option.
49
+ For example, to allow the jpeg compressor to recognize new extension name and to set the quality of the png compressor.
50
+
51
+ ```js
52
+ pluginImageCompress([
53
+ { use: "jpeg", test: /\.(?:jpg|jpeg|jpe)$/ },
54
+ { use: "png", minQuality: 50 },
55
+ "ico",
56
+ ]);
57
+ ```
58
+
59
+ The default `png` compressor is lossy.
60
+ If you want to replace it with a lossless compressor, you can use the following configuration.
6
61
 
7
- The Rspack-based build tool. It's fast, out-of-the-box and extensible.
62
+ ```js
63
+ pluginImageCompress(["jpeg", "pngLossless", "ico"]);
64
+ ```
8
65
 
9
- ## Documentation
66
+ The list of configuration options will eventually be converted to the corresponding bundler loader configuration, so compressors follow the same bottom-to-top matching rule.
10
67
 
11
- https://rsbuild.dev/
68
+ For example, the `png` compressor will take precedence over the `pngLossless` compressor for the following configuration:
12
69
 
13
- ## Contributing
70
+ ```js
71
+ pluginImageCompress(["jpeg", "pngLossless", "ico", "png"]);
72
+ ```
14
73
 
15
- Please read the [Contributing Guide](https://github.com/web-infra-dev/rsbuild/blob/main/CONTRIBUTING.md).
74
+ For more information on compressors, please visit [@napi-rs/image](https://image.napi.rs/docs).
16
75
 
17
76
  ## License
18
77
 
19
- Rsbuild is [MIT licensed](https://github.com/web-infra-dev/rsbuild/blob/main/LICENSE).
78
+ [MIT](./LICENSE).
package/dist/index.cjs CHANGED
@@ -5,7 +5,6 @@ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
6
  var __getProtoOf = Object.getPrototypeOf;
7
7
  var __hasOwnProp = Object.prototype.hasOwnProperty;
8
- var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
9
8
  var __export = (target, all) => {
10
9
  for (var name in all)
11
10
  __defProp(target, name, { get: all[name], enumerable: true });
@@ -27,10 +26,6 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
27
26
  mod
28
27
  ));
29
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
30
- var __publicField = (obj, key, value) => {
31
- __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
32
- return value;
33
- };
34
29
 
35
30
  // src/index.ts
36
31
  var src_exports = {};
@@ -40,7 +35,7 @@ __export(src_exports, {
40
35
  pluginImageCompress: () => pluginImageCompress
41
36
  });
42
37
  module.exports = __toCommonJS(src_exports);
43
- var import_node_assert2 = __toESM(require("assert"));
38
+ var import_node_assert2 = __toESM(require("assert"), 1);
44
39
 
45
40
  // src/minimizer.ts
46
41
  var import_node_buffer2 = require("buffer");
@@ -48,7 +43,7 @@ var import_node_buffer2 = require("buffer");
48
43
  // src/shared/codecs.ts
49
44
  var import_node_buffer = require("buffer");
50
45
  var import_image = require("@napi-rs/image");
51
- var import_svgo = __toESM(require("svgo"));
46
+ var import_svgo = __toESM(require("svgo"), 1);
52
47
  var jpegCodec = {
53
48
  handler(buf, options) {
54
49
  return (0, import_image.compressJpeg)(buf, options);
@@ -103,8 +98,7 @@ var codecs_default = codecs;
103
98
  var IMAGE_MINIMIZER_PLUGIN_NAME = "@rsbuild/plugin-image-compress/minimizer";
104
99
  var ImageMinimizerPlugin = class {
105
100
  constructor(options) {
106
- __publicField(this, "name", IMAGE_MINIMIZER_PLUGIN_NAME);
107
- __publicField(this, "options");
101
+ this.name = IMAGE_MINIMIZER_PLUGIN_NAME;
108
102
  this.options = options;
109
103
  }
110
104
  async optimize(compiler, compilation, assets) {
@@ -134,7 +128,11 @@ ${cause.message}` : cause.message;
134
128
  if (info?.minimized || !matchObject(opts, fileName)) {
135
129
  return;
136
130
  }
137
- const { source: inputSource } = compilation.getAsset(name);
131
+ const asset = compilation.getAsset(name);
132
+ if (!asset) {
133
+ return;
134
+ }
135
+ const { source: inputSource } = asset;
138
136
  const eTag = cache.getLazyHashedEtag(inputSource);
139
137
  const cacheItem = cache.getItemCache(name, eTag);
140
138
  let result = await cacheItem.getPromise();
@@ -176,7 +174,7 @@ ${cause.message}` : cause.message;
176
174
  };
177
175
 
178
176
  // src/shared/utils.ts
179
- var import_node_assert = __toESM(require("assert"));
177
+ var import_node_assert = __toESM(require("assert"), 1);
180
178
  var withDefaultOptions = (opt) => {
181
179
  const options = typeof opt === "string" ? { use: opt } : opt;
182
180
  const { defaultOptions } = codecs_default[options.use];
@@ -0,0 +1,38 @@
1
+ import { RsbuildPlugin } from '@rsbuild/core';
2
+ import { JpegCompressOptions, PngQuantOptions, PNGLosslessOptions } from '@napi-rs/image';
3
+ import { Config } from 'svgo';
4
+
5
+ type OneOrMany<T> = T | T[];
6
+ interface CodecBaseOptions {
7
+ jpeg: JpegCompressOptions;
8
+ png: PngQuantOptions;
9
+ pngLossless: PNGLosslessOptions;
10
+ ico: Record<string, unknown>;
11
+ svg: Config;
12
+ }
13
+ interface BaseCompressOptions<T extends Codecs> {
14
+ use: T;
15
+ test?: OneOrMany<RegExp>;
16
+ include?: OneOrMany<RegExp>;
17
+ exclude?: OneOrMany<RegExp>;
18
+ }
19
+ type FinalOptionCollection = {
20
+ [K in Codecs]: BaseCompressOptions<K> & CodecBaseOptions[K];
21
+ };
22
+ type Codecs = keyof CodecBaseOptions;
23
+ type OptionCollection = {
24
+ [K in Codecs]: K | FinalOptionCollection[K];
25
+ };
26
+ type Options = OptionCollection[Codecs];
27
+
28
+ type PluginImageCompressOptions = Options[];
29
+ declare const DEFAULT_OPTIONS: Codecs[];
30
+ interface IPluginImageCompress {
31
+ (...options: Options[]): RsbuildPlugin;
32
+ (options: Options[]): RsbuildPlugin;
33
+ }
34
+ declare const PLUGIN_IMAGE_COMPRESS_NAME = "rsbuild:image-compress";
35
+ /** Options enable by default: {@link DEFAULT_OPTIONS} */
36
+ declare const pluginImageCompress: IPluginImageCompress;
37
+
38
+ export { DEFAULT_OPTIONS, type IPluginImageCompress, PLUGIN_IMAGE_COMPRESS_NAME, type PluginImageCompressOptions, pluginImageCompress };
package/dist/index.d.ts CHANGED
@@ -1,11 +1,38 @@
1
- import type { RsbuildPlugin } from '@rsbuild/core';
2
- import type { Codecs, Options } from './types';
3
- export type PluginImageCompressOptions = Options[];
4
- export declare const DEFAULT_OPTIONS: Codecs[];
5
- export interface IPluginImageCompress {
1
+ import { RsbuildPlugin } from '@rsbuild/core';
2
+ import { JpegCompressOptions, PngQuantOptions, PNGLosslessOptions } from '@napi-rs/image';
3
+ import { Config } from 'svgo';
4
+
5
+ type OneOrMany<T> = T | T[];
6
+ interface CodecBaseOptions {
7
+ jpeg: JpegCompressOptions;
8
+ png: PngQuantOptions;
9
+ pngLossless: PNGLosslessOptions;
10
+ ico: Record<string, unknown>;
11
+ svg: Config;
12
+ }
13
+ interface BaseCompressOptions<T extends Codecs> {
14
+ use: T;
15
+ test?: OneOrMany<RegExp>;
16
+ include?: OneOrMany<RegExp>;
17
+ exclude?: OneOrMany<RegExp>;
18
+ }
19
+ type FinalOptionCollection = {
20
+ [K in Codecs]: BaseCompressOptions<K> & CodecBaseOptions[K];
21
+ };
22
+ type Codecs = keyof CodecBaseOptions;
23
+ type OptionCollection = {
24
+ [K in Codecs]: K | FinalOptionCollection[K];
25
+ };
26
+ type Options = OptionCollection[Codecs];
27
+
28
+ type PluginImageCompressOptions = Options[];
29
+ declare const DEFAULT_OPTIONS: Codecs[];
30
+ interface IPluginImageCompress {
6
31
  (...options: Options[]): RsbuildPlugin;
7
32
  (options: Options[]): RsbuildPlugin;
8
33
  }
9
- export declare const PLUGIN_IMAGE_COMPRESS_NAME = "rsbuild:image-compress";
34
+ declare const PLUGIN_IMAGE_COMPRESS_NAME = "rsbuild:image-compress";
10
35
  /** Options enable by default: {@link DEFAULT_OPTIONS} */
11
- export declare const pluginImageCompress: IPluginImageCompress;
36
+ declare const pluginImageCompress: IPluginImageCompress;
37
+
38
+ export { DEFAULT_OPTIONS, type IPluginImageCompress, PLUGIN_IMAGE_COMPRESS_NAME, type PluginImageCompressOptions, pluginImageCompress };
package/dist/index.js CHANGED
@@ -1,25 +1,11 @@
1
- import { createRequire } from 'module';
2
- var require = createRequire(import.meta['url']);
3
-
4
- var __defProp = Object.defineProperty;
5
- var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
6
- var __publicField = (obj, key, value) => {
7
- __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
8
- return value;
9
- };
10
-
11
- // ../../node_modules/.pnpm/@modern-js+module-tools@2.54.6_eslint@9.6.0_typescript@5.5.2/node_modules/@modern-js/module-tools/shims/esm.js
12
- import { fileURLToPath } from "url";
13
- import path from "path";
14
-
15
1
  // src/index.ts
16
- import assert2 from "assert";
2
+ import assert2 from "node:assert";
17
3
 
18
4
  // src/minimizer.ts
19
- import { Buffer as Buffer3 } from "buffer";
5
+ import { Buffer as Buffer2 } from "node:buffer";
20
6
 
21
7
  // src/shared/codecs.ts
22
- import { Buffer as Buffer2 } from "buffer";
8
+ import { Buffer } from "node:buffer";
23
9
  import {
24
10
  Transformer,
25
11
  compressJpeg,
@@ -62,7 +48,7 @@ var icoCodec = {
62
48
  var svgCodec = {
63
49
  async handler(buf, options) {
64
50
  const result = svgo.optimize(buf.toString(), options);
65
- return Buffer2.from(result.data);
51
+ return Buffer.from(result.data);
66
52
  },
67
53
  defaultOptions: {
68
54
  test: /\.svg$/
@@ -81,8 +67,7 @@ var codecs_default = codecs;
81
67
  var IMAGE_MINIMIZER_PLUGIN_NAME = "@rsbuild/plugin-image-compress/minimizer";
82
68
  var ImageMinimizerPlugin = class {
83
69
  constructor(options) {
84
- __publicField(this, "name", IMAGE_MINIMIZER_PLUGIN_NAME);
85
- __publicField(this, "options");
70
+ this.name = IMAGE_MINIMIZER_PLUGIN_NAME;
86
71
  this.options = options;
87
72
  }
88
73
  async optimize(compiler, compilation, assets) {
@@ -112,14 +97,18 @@ ${cause.message}` : cause.message;
112
97
  if (info?.minimized || !matchObject(opts, fileName)) {
113
98
  return;
114
99
  }
115
- const { source: inputSource } = compilation.getAsset(name);
100
+ const asset = compilation.getAsset(name);
101
+ if (!asset) {
102
+ return;
103
+ }
104
+ const { source: inputSource } = asset;
116
105
  const eTag = cache.getLazyHashedEtag(inputSource);
117
106
  const cacheItem = cache.getItemCache(name, eTag);
118
107
  let result = await cacheItem.getPromise();
119
108
  try {
120
109
  if (!result) {
121
110
  const input = inputSource.source();
122
- const buf = await codec.handler(Buffer3.from(input), opts);
111
+ const buf = await codec.handler(Buffer2.from(input), opts);
123
112
  result = { source: new RawSource(buf) };
124
113
  await cacheItem.storePromise(result);
125
114
  }
@@ -154,7 +143,7 @@ ${cause.message}` : cause.message;
154
143
  };
155
144
 
156
145
  // src/shared/utils.ts
157
- import assert from "assert";
146
+ import assert from "node:assert";
158
147
  var withDefaultOptions = (opt) => {
159
148
  const options = typeof opt === "string" ? { use: opt } : opt;
160
149
  const { defaultOptions } = codecs_default[options.use];
package/package.json CHANGED
@@ -1,13 +1,7 @@
1
1
  {
2
2
  "name": "@rsbuild/plugin-image-compress",
3
- "version": "1.0.0-alpha.9",
4
- "description": "Image compress plugin for Rsbuild",
5
- "homepage": "https://rsbuild.dev",
6
- "repository": {
7
- "type": "git",
8
- "url": "https://github.com/web-infra-dev/rsbuild",
9
- "directory": "packages/plugin-image-compress"
10
- },
3
+ "version": "1.0.1",
4
+ "repository": "https://github.com/rspack-contrib/rsbuild-plugin-image-compress",
11
5
  "license": "MIT",
12
6
  "type": "module",
13
7
  "exports": {
@@ -17,30 +11,52 @@
17
11
  "require": "./dist/index.cjs"
18
12
  }
19
13
  },
20
- "main": "./dist/index.cjs",
14
+ "main": "./dist/index.js",
15
+ "module": "./dist/index.mjs",
21
16
  "types": "./dist/index.d.ts",
22
17
  "files": [
23
18
  "dist"
24
19
  ],
20
+ "simple-git-hooks": {
21
+ "pre-commit": "npx nano-staged"
22
+ },
23
+ "nano-staged": {
24
+ "*.{js,jsx,ts,tsx,mjs,cjs}": [
25
+ "biome check --write --no-errors-on-unmatched"
26
+ ]
27
+ },
25
28
  "dependencies": {
26
29
  "@napi-rs/image": "^1.9.2",
27
30
  "svgo": "^3.3.2"
28
31
  },
29
32
  "devDependencies": {
30
- "@types/node": "18.x",
31
- "typescript": "^5.5.2",
32
- "@rsbuild/core": "1.0.0-alpha.9"
33
+ "@biomejs/biome": "^1.8.3",
34
+ "@playwright/test": "^1.44.1",
35
+ "@rsbuild/core": "1.0.0-alpha.9",
36
+ "@types/node": "^20.14.1",
37
+ "nano-staged": "^0.8.0",
38
+ "playwright": "^1.44.1",
39
+ "simple-git-hooks": "^2.11.1",
40
+ "tsup": "^8.0.2",
41
+ "typescript": "^5.5.2"
33
42
  },
34
43
  "peerDependencies": {
35
- "@rsbuild/core": "^1.0.0-alpha.9"
44
+ "@rsbuild/core": "1.x"
45
+ },
46
+ "peerDependenciesMeta": {
47
+ "@rsbuild/core": {
48
+ "optional": true
49
+ }
36
50
  },
37
51
  "publishConfig": {
38
52
  "access": "public",
39
- "provenance": true,
40
53
  "registry": "https://registry.npmjs.org/"
41
54
  },
42
55
  "scripts": {
43
- "build": "modern build",
44
- "dev": "modern build --watch"
56
+ "build": "tsup",
57
+ "dev": "tsup --watch",
58
+ "lint": "biome check .",
59
+ "lint:write": "biome check . --write",
60
+ "test": "playwright test"
45
61
  }
46
62
  }
@@ -1,13 +0,0 @@
1
- import type { Rspack } from '@rsbuild/core';
2
- import type { FinalOptions } from './types';
3
- export declare const IMAGE_MINIMIZER_PLUGIN_NAME: "@rsbuild/plugin-image-compress/minimizer";
4
- export interface MinimizedResult {
5
- source: Rspack.sources.RawSource;
6
- }
7
- export declare class ImageMinimizerPlugin {
8
- name: string;
9
- options: FinalOptions;
10
- constructor(options: FinalOptions);
11
- optimize(compiler: Rspack.Compiler, compilation: Rspack.Compilation, assets: Record<string, Rspack.sources.Source>): Promise<void>;
12
- apply(compiler: Rspack.Compiler): void;
13
- }
@@ -1,8 +0,0 @@
1
- import type { Codec, Codecs } from '../types';
2
- export declare const jpegCodec: Codec<'jpeg'>;
3
- export declare const pngCodec: Codec<'png'>;
4
- export declare const pngLosslessCodec: Codec<'pngLossless'>;
5
- export declare const icoCodec: Codec<'ico'>;
6
- export declare const svgCodec: Codec<'svg'>;
7
- declare const codecs: Record<Codecs, Codec<any>>;
8
- export default codecs;
@@ -1,2 +0,0 @@
1
- import type { FinalOptions, Options } from '../types';
2
- export declare const withDefaultOptions: (opt: Options) => FinalOptions;
@@ -1,33 +0,0 @@
1
- import type { Buffer } from 'node:buffer';
2
- import type { JpegCompressOptions, PNGLosslessOptions, PngQuantOptions } from '@napi-rs/image';
3
- import type { Config as SvgoConfig } from 'svgo';
4
- export type OneOrMany<T> = T | T[];
5
- export interface WebpTransformOptions {
6
- quality?: number;
7
- }
8
- export interface CodecBaseOptions {
9
- jpeg: JpegCompressOptions;
10
- png: PngQuantOptions;
11
- pngLossless: PNGLosslessOptions;
12
- ico: Record<string, unknown>;
13
- svg: SvgoConfig;
14
- }
15
- export interface BaseCompressOptions<T extends Codecs> {
16
- use: T;
17
- test?: OneOrMany<RegExp>;
18
- include?: OneOrMany<RegExp>;
19
- exclude?: OneOrMany<RegExp>;
20
- }
21
- export type FinalOptionCollection = {
22
- [K in Codecs]: BaseCompressOptions<K> & CodecBaseOptions[K];
23
- };
24
- export type FinalOptions = FinalOptionCollection[Codecs];
25
- export interface Codec<T extends Codecs> {
26
- handler: (buf: Buffer, options: CodecBaseOptions[T]) => Promise<Buffer>;
27
- defaultOptions: Omit<FinalOptionCollection[T], 'use'>;
28
- }
29
- export type Codecs = keyof CodecBaseOptions;
30
- export type OptionCollection = {
31
- [K in Codecs]: K | FinalOptionCollection[K];
32
- };
33
- export type Options = OptionCollection[Codecs];