@peachy/plugin-resources 0.0.10 → 0.0.11

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.md CHANGED
@@ -2,11 +2,19 @@
2
2
 
3
3
  Allow you to import files as resources.
4
4
 
5
+ > NOTE: In dev mode, your resources will NOT be watched for changes and live-reloaded.
6
+
5
7
  ## Usage
6
8
 
7
- You will need to have peachy installed.
9
+ You will need to have `peachy` installed.
10
+
11
+ ### Configuration
12
+
13
+ Then you will need to create a peachy configuration file. There are two ways to do this:
8
14
 
9
- Then, you need to create a `peachy.config.ts` file in the root of your project.
15
+ #### 1. Use `peachy.config.ts`
16
+
17
+ You can create a `peachy.config.ts` file in the root of your project.
10
18
 
11
19
  ```ts
12
20
  // peachy.config.ts
@@ -14,16 +22,30 @@ Then, you need to create a `peachy.config.ts` file in the root of your project.
14
22
  import { defineConfig } from "@peachy/core";
15
23
 
16
24
  export default defineConfig({
17
- package: {
18
- name: "dev.peachy.Example"
19
- },
25
+ applicationId: "dev.peachy.Example",
20
26
  resources: {
21
27
  icons: true,
22
- }
28
+ },
23
29
  });
24
30
  ```
25
31
 
26
- TODO: enable this by default, skip generation if there's no resources/icons
32
+ #### 2. Use a field in `package.json`
33
+
34
+ You can also add a special `peachy` field in your existing package.json
35
+
36
+ ```json
37
+ // package.json
38
+ {
39
+ "peachy": {
40
+ "applicationId": "dev.peachy.Example",
41
+ "resources": {
42
+ "icons": true
43
+ }
44
+ }
45
+ }
46
+ ```
47
+
48
+ ### Initialization
27
49
 
28
50
  In your code, make sure to initialize your code to use the given name in your `peachy.config.ts` file.
29
51
 
@@ -31,7 +53,7 @@ In your code, make sure to initialize your code to use the given name in your `p
31
53
  import Gtk from "gi://Gtk?version=4.0";
32
54
 
33
55
  const app = new Gtk.Application({
34
- // IMPORTANT: match this with the one in `peachy.config.ts`
56
+ // IMPORTANT: match this with the one in the configuration file
35
57
  application_id: "dev.peachy.Example",
36
58
  flags: Gtk.ApplicationFlags.FLAGS_NONE,
37
59
  });
@@ -43,7 +65,6 @@ app.run([]);
43
65
 
44
66
  Then you can start importing resources/icons.
45
67
 
46
-
47
68
  ### Importing Files
48
69
 
49
70
  When you need to import a resource, you can directly import them. Currently, only SVG files are supported.
@@ -64,6 +85,22 @@ You can use the imported resource anywhere that accepts a `Gio.Resource` like `G
64
85
 
65
86
  Icons in `data/icons` folder will be automatically configured and registered as Themed Icons, so you can use them just by referencing their name.
66
87
 
88
+ If your icons are in a different folder, you can specify the path in the configuration file.
89
+
90
+ ```ts
91
+ // peachy.config.ts
92
+
93
+ import { defineConfig } from "@peachy/core";
94
+
95
+ export default defineConfig({
96
+ applicationId: "dev.peachy.Example",
97
+ resources: {
98
+ // specify the path to your icons folder
99
+ icons: "./path/to/icons",
100
+ },
101
+ });
102
+ ```
103
+
67
104
  #### 1. Put your icons in `data/icons` folder.
68
105
 
69
106
  ```
@@ -80,3 +117,34 @@ const button = new Gtk.Button({
80
117
  icon_name: "right-symbolic",
81
118
  });
82
119
  ```
120
+
121
+ ### Bundle resources
122
+
123
+ If you have resources that you want to always be bundled in your application, you can "bundle" them.
124
+
125
+ These files can be read by objects that uses "Automatic resources" such as
126
+ [Gtk.Application](https://gnome.pages.gitlab.gnome.org/gtk/gtk4/class.Application.html#automatic-resources) and
127
+ [Adw.Application](https://gnome.pages.gitlab.gnome.org/libadwaita/doc/main/class.Application.html).
128
+
129
+ A few use cases are given below:
130
+
131
+ - The `gtk/help-overlay.ui` file will be used to display application help.
132
+ - The `style.css` file will be automatically loaded and applied to your application.
133
+
134
+ ```ts
135
+ // peachy.config.ts
136
+
137
+ import { defineConfig } from "@peachy/core";
138
+
139
+ export default defineConfig({
140
+ applicationId: "dev.peachy.Example",
141
+ resources: {
142
+ bundle: [
143
+ // this assumes that the file is located at `gtk/help-overlay.ui`
144
+ "gtk/help-overlay.ui",
145
+ // if you have a file located elsewhere, you can specify the path and alias it will be available at
146
+ { path: "./path/to/style.css", alias: "style.css" },
147
+ ],
148
+ },
149
+ });
150
+ ```
package/dist/index.d.mts CHANGED
@@ -2,12 +2,17 @@ import { Plugin } from "rolldown";
2
2
 
3
3
  //#region src/types.d.ts
4
4
  interface ResourcesPluginOptions {
5
- setRunnerEnv(key: string, value: string): void;
5
+ setRunnerEnv(this: void, key: string, value: string): void;
6
6
  applicationId?: string;
7
7
  prod: boolean;
8
8
  outdir: string;
9
9
  iconsPath?: string | false;
10
+ bundle?: BundledResource[];
10
11
  }
12
+ type BundledResource = string | {
13
+ alias?: string;
14
+ path: string;
15
+ };
11
16
  //#endregion
12
17
  //#region src/plugins/index.d.ts
13
18
  declare function resourcesPlugin(config: ResourcesPluginOptions): Plugin[];
package/dist/index.mjs CHANGED
@@ -1,10 +1,10 @@
1
1
  import { basename, dirname, join, relative, resolve } from "node:path";
2
- import path from "path";
3
2
  import fs from "fs/promises";
4
- import { access, mkdir, mkdtempDisposable, readFile, readdir, stat, writeFile } from "node:fs/promises";
3
+ import path from "path";
5
4
  import { exactRegex, prefixRegex } from "rolldown/filter";
6
- import { tmpdir } from "node:os";
5
+ import { access, mkdir, mkdtempDisposable, readFile, readdir, stat, writeFile } from "node:fs/promises";
7
6
  import { exec } from "node:child_process";
7
+ import { tmpdir } from "node:os";
8
8
  import { promisify } from "node:util";
9
9
 
10
10
  //#region src/constants.ts
@@ -67,8 +67,7 @@ async function loadIcons(prefix, path$1) {
67
67
  const id = relative(process.cwd(), fullName);
68
68
  collectedAssets.set(fullName, {
69
69
  internalResourceId: id,
70
- resourceId: getResourceId(prefix, id),
71
- path: fullName
70
+ resourceId: getResourceId(prefix, id)
72
71
  });
73
72
  }
74
73
  return collectedAssets;
@@ -82,8 +81,8 @@ function getFilePath(path$1, alias) {
82
81
  return ` <file${attrs}>${path$1}</file>`;
83
82
  }
84
83
  function generateGResourceXML(prefix, assets, icons) {
85
- const files = [...assets.values()].map(({ internalResourceId }) => getFilePath(internalResourceId)).join("\n");
86
- const iconFiles = icons ? [...icons.values()].map(({ internalResourceId }) => getFilePath(internalResourceId, basename(internalResourceId))).join("\n") : "";
84
+ const files = Array.from(assets).map(([id, { internalResourceId }]) => getFilePath(id, internalResourceId)).join("\n");
85
+ const iconFiles = icons ? Array.from(icons).map(([id, { internalResourceId }]) => getFilePath(id, basename(internalResourceId))).join("\n") : "";
87
86
  return `<?xml version="1.0" encoding="UTF-8"?>
88
87
  <gresources>
89
88
  <gresource prefix="${prefix}">
@@ -95,6 +94,21 @@ ${iconFiles}
95
94
  </gresources>`;
96
95
  }
97
96
 
97
+ //#endregion
98
+ //#region src/utilities/bundle.ts
99
+ function addBundledResources(collectedResources, prefix, bundle = []) {
100
+ for (const bundledResource of bundle) {
101
+ const resourcePath = typeof bundledResource == "string" ? bundledResource : bundledResource.path;
102
+ const resourceAlias = typeof bundledResource == "object" ? bundledResource.alias : null;
103
+ const id = path.resolve(process.cwd(), resourcePath);
104
+ const internalResourceId = resourceAlias ?? resourcePath;
105
+ collectedResources.set(id, {
106
+ internalResourceId,
107
+ resourceId: getResourceId(prefix, internalResourceId)
108
+ });
109
+ }
110
+ }
111
+
98
112
  //#endregion
99
113
  //#region src/utilities/icons.ts
100
114
  async function getIconsPath(iconsPath) {
@@ -114,7 +128,7 @@ async function collectIcons(baseIconsPath, prefix) {
114
128
  /**
115
129
  * This plugin configures a GRESOURCES overlay for development purposes.
116
130
  */
117
- function resourcesPluginOverlay({ prefix, prod, outdir, setRunnerEnv, iconsPath: baseIconsPath }) {
131
+ function resourcesPluginOverlay({ prefix, prod, outdir, setRunnerEnv, iconsPath: baseIconsPath, bundle }) {
118
132
  if (prod) return null;
119
133
  const collectedResources = /* @__PURE__ */ new Map();
120
134
  const devResourcesOverlay = path.join(outdir, "_peachy_resources");
@@ -130,7 +144,6 @@ function resourcesPluginOverlay({ prefix, prod, outdir, setRunnerEnv, iconsPath:
130
144
  const resourceId = getResourceId(prefix, path$1);
131
145
  collectedResources.set(path$1, {
132
146
  resourceId,
133
- path: path$1,
134
147
  internalResourceId: getInternalResourceId(path$1)
135
148
  });
136
149
  return generateImportCode(importType, resourceId, false);
@@ -148,6 +161,7 @@ function resourcesPluginOverlay({ prefix, prod, outdir, setRunnerEnv, iconsPath:
148
161
  },
149
162
  async writeBundle() {
150
163
  await fs.mkdir(devResourcesOverlay, { recursive: true });
164
+ addBundledResources(collectedResources, prefix, bundle);
151
165
  const currentPaths = new Set(Array.from(collectedResources.values()).map((r) => r.internalResourceId));
152
166
  const existing = await fs.readdir(devResourcesOverlay, {
153
167
  recursive: true,
@@ -160,7 +174,7 @@ function resourcesPluginOverlay({ prefix, prod, outdir, setRunnerEnv, iconsPath:
160
174
  if (currentPaths.has(relativePath) || relativePath === GRESOURCE_ICONS_PATH) continue;
161
175
  await fs.unlink(fullPath);
162
176
  }
163
- for (const [, { path: filePath, internalResourceId }] of collectedResources) {
177
+ for (const [filePath, { internalResourceId }] of collectedResources) {
164
178
  const linkPath = path.join(devResourcesOverlay, internalResourceId);
165
179
  try {
166
180
  await fs.lstat(linkPath);
@@ -174,10 +188,38 @@ function resourcesPluginOverlay({ prefix, prod, outdir, setRunnerEnv, iconsPath:
174
188
  };
175
189
  }
176
190
 
191
+ //#endregion
192
+ //#region src/plugins/loader.ts
193
+ /**
194
+ * This plugin injects some code that loads and registers our application's
195
+ * GResource
196
+ */
197
+ function resourcesPluginLoader({ gresourcePath }) {
198
+ return {
199
+ name: "@peachy/plugin-resources#loader",
200
+ resolveId: {
201
+ filter: { id: exactRegex(GRESOURCE_LOADER) },
202
+ handler(id) {
203
+ return id;
204
+ }
205
+ },
206
+ load: {
207
+ filter: { id: exactRegex(GRESOURCE_LOADER) },
208
+ handler() {
209
+ return [
210
+ `import Gio from "gi://Gio";`,
211
+ `const resource = Gio.Resource.load("${gresourcePath}");`,
212
+ `resource._register();`
213
+ ].join("\n");
214
+ }
215
+ }
216
+ };
217
+ }
218
+
177
219
  //#endregion
178
220
  //#region src/plugins/prod/index.ts
179
221
  const exec$1 = promisify(exec);
180
- function resourcesPluginGenerateXML({ prefix, gresourceName, gresourcePath, prod, iconsPath }) {
222
+ function resourcesPluginGenerateXML({ prefix, gresourceName, gresourcePath, prod, iconsPath, bundle }) {
181
223
  if (!prod) return null;
182
224
  const collectedResources = /* @__PURE__ */ new Map();
183
225
  return {
@@ -191,7 +233,6 @@ function resourcesPluginGenerateXML({ prefix, gresourceName, gresourcePath, prod
191
233
  const resourceId = getResourceId(prefix, path$1);
192
234
  collectedResources.set(path$1, {
193
235
  resourceId,
194
- path: path$1,
195
236
  internalResourceId: getInternalResourceId(path$1)
196
237
  });
197
238
  return generateImportCode(importType, resourceId, true);
@@ -199,9 +240,12 @@ function resourcesPluginGenerateXML({ prefix, gresourceName, gresourcePath, prod
199
240
  },
200
241
  async generateBundle() {
201
242
  const collectedIcons = await collectIcons(iconsPath ?? false, prefix);
243
+ addBundledResources(collectedResources, prefix, bundle);
202
244
  if (collectedResources.size === 0 && collectedIcons.size === 0) return;
203
245
  const xmlPath = join((await mkdtempDisposable(join(tmpdir(), "peachy-resource-build"))).path, "gresources.xml");
204
- await writeFile(xmlPath, generateGResourceXML(prefix, collectedResources, collectedIcons));
246
+ const xml = generateGResourceXML(prefix, collectedResources, collectedIcons);
247
+ await writeFile(xmlPath, xml);
248
+ console.log("xml", xml);
205
249
  await mkdir(dirname(gresourcePath), { recursive: true });
206
250
  await exec$1(`glib-compile-resources --sourcedir=${process.cwd()} --target=${gresourcePath} ${xmlPath}`, { env: { ...process.env } });
207
251
  this.emitFile({
@@ -234,34 +278,6 @@ function resourcesPluginResolve() {
234
278
  };
235
279
  }
236
280
 
237
- //#endregion
238
- //#region src/plugins/loader.ts
239
- /**
240
- * This plugin injects some code that loads and registers our application's
241
- * GResource
242
- */
243
- function resourcesPluginLoader({ gresourcePath }) {
244
- return {
245
- name: "@peachy/plugin-resources#loader",
246
- resolveId: {
247
- filter: { id: exactRegex(GRESOURCE_LOADER) },
248
- handler(id) {
249
- return id;
250
- }
251
- },
252
- load: {
253
- filter: { id: exactRegex(GRESOURCE_LOADER) },
254
- handler() {
255
- return [
256
- `import Gio from "gi://Gio";`,
257
- `const resource = Gio.Resource.load("${gresourcePath}");`,
258
- `resource._register();`
259
- ].join("\n");
260
- }
261
- }
262
- };
263
- }
264
-
265
281
  //#endregion
266
282
  //#region src/plugins/index.ts
267
283
  function resourcesPlugin(config) {
@@ -1,4 +1,4 @@
1
- //#region src/types/global.d.ts
1
+ //#region src/modules.d.ts
2
2
  declare module "*.svg" {
3
3
  const content: string;
4
4
  export default content;
package/package.json CHANGED
@@ -1,33 +1,33 @@
1
1
  {
2
2
  "name": "@peachy/plugin-resources",
3
- "version": "0.0.10",
4
- "type": "module",
3
+ "version": "0.0.11",
5
4
  "description": "Import resources in your app",
6
- "main": "./src/index.ts",
5
+ "license": "MIT",
6
+ "author": "",
7
+ "files": [
8
+ "dist"
9
+ ],
10
+ "type": "module",
7
11
  "exports": {
8
12
  ".": {
9
13
  "import": "./dist/index.mjs",
10
14
  "types": "./dist/index.d.mts"
11
15
  },
12
- "./types": {
13
- "types": "./dist/types/global.d.mts"
16
+ "./modules": {
17
+ "types": "./dist/modules.d.mts"
14
18
  }
15
19
  },
16
- "author": "",
17
- "license": "MIT",
18
20
  "devDependencies": {
19
21
  "@types/node": "^25.0.9",
20
22
  "rolldown": "1.0.0-beta.60",
21
23
  "tsdown": "0.20.0-beta.4",
22
- "typescript": "^5.9.3"
24
+ "typescript": "^5.9.3",
25
+ "@peachy/internal-utilities": "0.0.0"
23
26
  },
24
27
  "peerDependencies": {
25
28
  "rolldown": "1.0.0-beta.58"
26
29
  },
27
- "files": [
28
- "dist"
29
- ],
30
30
  "scripts": {
31
- "build": "tsdown src/index.ts src/types/global.d.ts --dts"
31
+ "build": "tsdown src/index.ts src/modules.d.ts --dts"
32
32
  }
33
33
  }
package/src/index.ts DELETED
@@ -1 +0,0 @@
1
- export * from "./plugins";