@gjsify/rolldown-plugin-gjsify 0.64.1-next.245 → 0.64.1-next.247
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/lib/app/browser.js +2 -0
- package/lib/app/gjs.js +2 -0
- package/lib/app/nativescript.js +2 -0
- package/lib/app/node.js +2 -0
- package/lib/index.d.ts +2 -0
- package/lib/index.js +1 -0
- package/lib/plugins/gresource.d.ts +25 -0
- package/lib/plugins/gresource.js +134 -0
- package/package.json +11 -11
package/lib/app/browser.js
CHANGED
|
@@ -32,6 +32,7 @@ import { blueprintTemplateExit } from '../utils/blueprint-template-exit.js';
|
|
|
32
32
|
import { cssAsStringPlugin } from '../plugins/css-as-string.js';
|
|
33
33
|
import { unresolvedWorkspaceImportPlugin } from '../plugins/unresolved-workspace-import.js';
|
|
34
34
|
import { gschemaPlugin } from '../plugins/gschema.js';
|
|
35
|
+
import { gresourcePlugin } from '../plugins/gresource.js';
|
|
35
36
|
import { implicitGlobalAssignPlugin } from '../plugins/implicit-global-assign.js';
|
|
36
37
|
export const setupForBrowser = async (input) => {
|
|
37
38
|
const userExternal = input.userExternal ?? [];
|
|
@@ -145,6 +146,7 @@ export const setupForBrowser = async (input) => {
|
|
|
145
146
|
// replaces the whole global object. This transform runs first and leaves the define
|
|
146
147
|
// nothing to rewrite; the guarded branch stays unreachable on a page either way.
|
|
147
148
|
gschemaPlugin({ mode: 'emit' }),
|
|
149
|
+
gresourcePlugin({ compressed: 'strip' }),
|
|
148
150
|
implicitGlobalAssignPlugin(),
|
|
149
151
|
cssAsStringPlugin(),
|
|
150
152
|
// `order: 'post'` — see app/gjs.ts. The browser target's whole job is to
|
package/lib/app/gjs.js
CHANGED
|
@@ -22,6 +22,7 @@ import { processStubPlugin } from '../plugins/process-stub.js';
|
|
|
22
22
|
import { cssAsStringPlugin } from '../plugins/css-as-string.js';
|
|
23
23
|
import { consoleAssignPlugin } from '../plugins/console-assign.js';
|
|
24
24
|
import { gschemaPlugin } from '../plugins/gschema.js';
|
|
25
|
+
import { gresourcePlugin } from '../plugins/gresource.js';
|
|
25
26
|
import { implicitGlobalAssignPlugin } from '../plugins/implicit-global-assign.js';
|
|
26
27
|
import { shebangPlugin, resolveShebangLine, inputShebangStripPlugin } from '../plugins/shebang.js';
|
|
27
28
|
import { wrapInputWithSideEffects } from '../utils/entry-wrapper.js';
|
|
@@ -203,6 +204,7 @@ export const setupForGjs = async (input) => {
|
|
|
203
204
|
// `globalThis = {…}`, i.e. code that would replace the whole global object if the
|
|
204
205
|
// branch ever ran. Measured; the plugin header carries the artifact diff.
|
|
205
206
|
gschemaPlugin({ mode: 'ignore' }),
|
|
207
|
+
gresourcePlugin({ compressed: 'keep' }),
|
|
206
208
|
implicitGlobalAssignPlugin(),
|
|
207
209
|
// `gi://Ns?version=X&optional` → a guarded import (ADR 0087), claimed `pre`
|
|
208
210
|
// so the externals policy never sees the flagged specifier.
|
package/lib/app/nativescript.js
CHANGED
|
@@ -48,6 +48,7 @@ import { blueprintTemplateExit } from '../utils/blueprint-template-exit.js';
|
|
|
48
48
|
import { platformResolvePlugin, nativescriptSuffixChain, detectNativescriptPlatform, nativescriptPlatformDefines, } from '../plugins/platform-resolve.js';
|
|
49
49
|
import { unresolvedWorkspaceImportPlugin } from '../plugins/unresolved-workspace-import.js';
|
|
50
50
|
import { gschemaPlugin } from '../plugins/gschema.js';
|
|
51
|
+
import { gresourcePlugin } from '../plugins/gresource.js';
|
|
51
52
|
import { implicitGlobalAssignPlugin } from '../plugins/implicit-global-assign.js';
|
|
52
53
|
// Never bundled: an app works only with the ONE core instance the runtime boots, and what
|
|
53
54
|
// this target emits is an ENTRY the NS bundler resolves it for. An optional peer absent from
|
|
@@ -188,6 +189,7 @@ export const setupForNativescript = async (input) => {
|
|
|
188
189
|
// `ReferenceError` in a strict module body, not a gate. `globalThis.window = …`
|
|
189
190
|
// holds the author's intent; the guard and the absence are untouched.
|
|
190
191
|
gschemaPlugin({ mode: 'emit' }),
|
|
192
|
+
gresourcePlugin({ compressed: 'strip' }),
|
|
191
193
|
implicitGlobalAssignPlugin(),
|
|
192
194
|
// NO cssAsStringPlugin — NS ships its own CSS pipeline via
|
|
193
195
|
// @nativescript/core; .css imports are handled by the consuming
|
package/lib/app/node.js
CHANGED
|
@@ -12,6 +12,7 @@ import { gjsImportsEmptyPlugin } from '../plugins/gjs-imports-empty.js';
|
|
|
12
12
|
import { gjsGiNodePlugin, gjsBuiltinModulesNodePlugin } from '../plugins/gjs-gi-node.js';
|
|
13
13
|
import { giOptionalPlugin } from '../plugins/gi-optional.js';
|
|
14
14
|
import { gschemaPlugin } from '../plugins/gschema.js';
|
|
15
|
+
import { gresourcePlugin } from '../plugins/gresource.js';
|
|
15
16
|
import { implicitGlobalAssignPlugin } from '../plugins/implicit-global-assign.js';
|
|
16
17
|
import { unresolvedWorkspaceImportPlugin } from '../plugins/unresolved-workspace-import.js';
|
|
17
18
|
import { nodeNativeExternalPlugin } from '../plugins/node-native-external.js';
|
|
@@ -353,6 +354,7 @@ export const setupForNode = async (input) => {
|
|
|
353
354
|
// `globalThis.window = {…}` is the same statement, the guard is untouched, and
|
|
354
355
|
// nothing defines `window`.
|
|
355
356
|
gschemaPlugin({ mode: 'ignore' }),
|
|
357
|
+
gresourcePlugin({ compressed: 'keep' }),
|
|
356
358
|
implicitGlobalAssignPlugin(),
|
|
357
359
|
// Decides the fate of `@girs/*` before `aliasPlugin` and the default
|
|
358
360
|
// resolver (same composition order as `app/browser.ts`). `emptyGirs` is
|
package/lib/index.d.ts
CHANGED
|
@@ -15,6 +15,8 @@ export { findImplicitGlobalAssignments, rewriteImplicitGlobalAssignments, implic
|
|
|
15
15
|
export type { ImplicitGlobalAssignment } from './plugins/implicit-global-assign.js';
|
|
16
16
|
export { gschemaPlugin, parseGschema, GSCHEMA_PLUGIN } from './plugins/gschema.js';
|
|
17
17
|
export type { GschemaOut, GschemaKey, GschemaPluginOptions } from './plugins/gschema.js';
|
|
18
|
+
export { gresourcePlugin, compileGresource, prepareGresourceXml, gresourceModuleSource, GRESOURCE_PLUGIN, } from './plugins/gresource.js';
|
|
19
|
+
export type { GresourcePluginOptions } from './plugins/gresource.js';
|
|
18
20
|
export { cssAsStringPlugin } from './plugins/css-as-string.js';
|
|
19
21
|
export { textLoaderPlugin } from './plugins/text-loader.js';
|
|
20
22
|
export type { TextLoaderPluginOptions, LoaderKind } from './plugins/text-loader.js';
|
package/lib/index.js
CHANGED
|
@@ -10,6 +10,7 @@ export { giOptionalPlugin, giOptionalShimSource, giOptionalNodeShimSource, giOpt
|
|
|
10
10
|
export { bindConsoleLocally, consoleAssignPlugin, freeConsoleAssignmentInsertion, CONSOLE_LOCAL_BINDING, } from './plugins/console-assign.js';
|
|
11
11
|
export { findImplicitGlobalAssignments, rewriteImplicitGlobalAssignments, implicitGlobalAssignPlugin, IMPLICIT_GLOBAL_ASSIGN_PLUGIN, } from './plugins/implicit-global-assign.js';
|
|
12
12
|
export { gschemaPlugin, parseGschema, GSCHEMA_PLUGIN } from './plugins/gschema.js';
|
|
13
|
+
export { gresourcePlugin, compileGresource, prepareGresourceXml, gresourceModuleSource, GRESOURCE_PLUGIN, } from './plugins/gresource.js';
|
|
13
14
|
export { cssAsStringPlugin } from './plugins/css-as-string.js';
|
|
14
15
|
export { textLoaderPlugin } from './plugins/text-loader.js';
|
|
15
16
|
export { shebangPlugin, GJS_SHEBANG, NODE_SHEBANG, expandEnvTemplate, resolveShebangLine } from './plugins/shebang.js';
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { Plugin } from 'rolldown';
|
|
2
|
+
export declare const GRESOURCE_PLUGIN = "gjsify-gresource";
|
|
3
|
+
export interface GresourcePluginOptions {
|
|
4
|
+
/**
|
|
5
|
+
* `keep`: compile the XML as written (GJS, Node — real GIO inflates).
|
|
6
|
+
* `strip`: drop `compressed="true"` first (browser, NativeScript, ADR 0116 § 2).
|
|
7
|
+
*/
|
|
8
|
+
compressed: 'keep' | 'strip';
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Apply the § 2 rules to the descriptor's text. Returns the XML to compile; throws on a refused
|
|
12
|
+
* option. Comments are blanked first so a commented-out `<file>` neither refuses nor rewrites.
|
|
13
|
+
*/
|
|
14
|
+
export declare function prepareGresourceXml(xml: string, file: string, options: GresourcePluginOptions): string;
|
|
15
|
+
/**
|
|
16
|
+
* Compile `xmlPath` as `glib-compile-resources --sourcedir=<its dir>` would, after the § 2 rules.
|
|
17
|
+
* Returns the compiled bytes and every file they were read from.
|
|
18
|
+
*/
|
|
19
|
+
export declare function compileGresource(xmlPath: string, options: GresourcePluginOptions): Promise<{
|
|
20
|
+
bytes: Uint8Array;
|
|
21
|
+
inputs: string[];
|
|
22
|
+
}>;
|
|
23
|
+
/** The module source: the bytes as base64 and an inline decoder to a `Uint8Array` default export. */
|
|
24
|
+
export declare function gresourceModuleSource(bytes: Uint8Array): string;
|
|
25
|
+
export declare function gresourcePlugin(options: GresourcePluginOptions): Plugin;
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
// `import bytes from './data/<app-id>.data.gresource.xml'` (ADR 0116 §§ 1–2): the app's compiled
|
|
2
|
+
// GResource as a `Uint8Array` default export, for `Gio.Resource.new_from_data(bytes)`.
|
|
3
|
+
//
|
|
4
|
+
// The `.gresource.xml` stays the single source and `glib-compile-resources` stays the compiler, so
|
|
5
|
+
// the embedded bytes are the bytes GNOME loads; base64 is only the transport through a one-file
|
|
6
|
+
// bundle, as in `adwaita-app/scripts/build-icon-gresource.mjs`. ADR 0116 decides the host tool over
|
|
7
|
+
// an in-JS GVDB writer ("What this does not decide": a JS replacement for glib-compile-resources).
|
|
8
|
+
//
|
|
9
|
+
// § 2 per file: `prefix`, `alias`, nested and `../` paths, `xml-stripblanks`, `json-stripblanks` go
|
|
10
|
+
// through unchanged. `compressed="true"` is dropped for the browser and NativeScript (`strip`),
|
|
11
|
+
// because those targets have no synchronous inflate; GIO answers `lookup_data` and `get_info` with
|
|
12
|
+
// the same data either way. `preprocess="to-pixdata"` is refused, naming the file and line.
|
|
13
|
+
//
|
|
14
|
+
// The decoder is emitted inline instead of calling `atob`/`Uint8Array.fromBase64`: GJS has neither
|
|
15
|
+
// global without an injected register, and the module must evaluate the same on all four targets.
|
|
16
|
+
import { Buffer } from 'node:buffer';
|
|
17
|
+
import { execFile } from 'node:child_process';
|
|
18
|
+
import { mkdtemp, readFile, rm, writeFile } from 'node:fs/promises';
|
|
19
|
+
import { tmpdir } from 'node:os';
|
|
20
|
+
import { dirname, join } from 'node:path';
|
|
21
|
+
import { promisify } from 'node:util';
|
|
22
|
+
const execFileAsync = promisify(execFile);
|
|
23
|
+
export const GRESOURCE_PLUGIN = 'gjsify-gresource';
|
|
24
|
+
const SUFFIX = /\.gresource\.xml$/;
|
|
25
|
+
const TOOL = 'glib-compile-resources';
|
|
26
|
+
function lineOf(xml, index) {
|
|
27
|
+
return xml.slice(0, index).split('\n').length;
|
|
28
|
+
}
|
|
29
|
+
function attr(tag, name) {
|
|
30
|
+
return new RegExp(`\\s${name}\\s*=\\s*(?:"([^"]*)"|'([^']*)')`)
|
|
31
|
+
.exec(tag)
|
|
32
|
+
?.slice(1)
|
|
33
|
+
.find((v) => v !== undefined);
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Apply the § 2 rules to the descriptor's text. Returns the XML to compile; throws on a refused
|
|
37
|
+
* option. Comments are blanked first so a commented-out `<file>` neither refuses nor rewrites.
|
|
38
|
+
*/
|
|
39
|
+
export function prepareGresourceXml(xml, file, options) {
|
|
40
|
+
const source = xml.replace(/<!--[\s\S]*?-->/g, (c) => c.replace(/[^\n]/g, ' '));
|
|
41
|
+
for (const m of source.matchAll(/<file\b([^>]*)>([\s\S]*?)<\/file>/g)) {
|
|
42
|
+
const preprocess = (attr(m[1], 'preprocess') ?? '').split(',').map((p) => p.trim());
|
|
43
|
+
if (preprocess.includes('to-pixdata')) {
|
|
44
|
+
throw new Error(`${file}:${lineOf(source, m.index)}: '${m[2].trim()}' uses preprocess="to-pixdata", which GLib ` +
|
|
45
|
+
'deprecated and the web and NativeScript cannot decode; ship the PNG as it is (ADR 0116 § 2)');
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
if (options.compressed === 'keep')
|
|
49
|
+
return xml;
|
|
50
|
+
let out = '';
|
|
51
|
+
let last = 0;
|
|
52
|
+
for (const m of source.matchAll(/<file\b[^>]*>/g)) {
|
|
53
|
+
out += xml.slice(last, m.index);
|
|
54
|
+
out += xml.slice(m.index, m.index + m[0].length).replace(/\scompressed\s*=\s*(?:"[^"]*"|'[^']*')/, '');
|
|
55
|
+
last = m.index + m[0].length;
|
|
56
|
+
}
|
|
57
|
+
return out + xml.slice(last);
|
|
58
|
+
}
|
|
59
|
+
async function compileResources(args) {
|
|
60
|
+
try {
|
|
61
|
+
const { stdout } = await execFileAsync(TOOL, args, { maxBuffer: 64 * 1024 * 1024 });
|
|
62
|
+
return stdout;
|
|
63
|
+
}
|
|
64
|
+
catch (err) {
|
|
65
|
+
const e = err;
|
|
66
|
+
if (e?.code === 'ENOENT') {
|
|
67
|
+
throw new Error(`${TOOL} not found; embedding a .gresource.xml needs it on the build host for every target ` +
|
|
68
|
+
'(ADR 0116). Install it via your distro (package: glib2-devel / libglib2.0-dev).');
|
|
69
|
+
}
|
|
70
|
+
throw new Error(`${TOOL} failed${e?.code !== undefined ? ` (exit ${e.code})` : ''}: ${String(e?.stderr ?? '')}`);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Compile `xmlPath` as `glib-compile-resources --sourcedir=<its dir>` would, after the § 2 rules.
|
|
75
|
+
* Returns the compiled bytes and every file they were read from.
|
|
76
|
+
*/
|
|
77
|
+
export async function compileGresource(xmlPath, options) {
|
|
78
|
+
const xml = await readFile(xmlPath, 'utf8');
|
|
79
|
+
const prepared = prepareGresourceXml(xml, xmlPath, options);
|
|
80
|
+
const sourcedir = dirname(xmlPath);
|
|
81
|
+
const tmp = await mkdtemp(join(tmpdir(), 'gjsify-gresource-'));
|
|
82
|
+
try {
|
|
83
|
+
let descriptor = xmlPath;
|
|
84
|
+
if (prepared !== xml) {
|
|
85
|
+
descriptor = join(tmp, 'resources.gresource.xml');
|
|
86
|
+
await writeFile(descriptor, prepared);
|
|
87
|
+
}
|
|
88
|
+
const target = join(tmp, 'resources.gresource');
|
|
89
|
+
const deps = await compileResources([`--sourcedir=${sourcedir}`, '--generate-dependencies', descriptor]);
|
|
90
|
+
await compileResources([`--sourcedir=${sourcedir}`, `--target=${target}`, descriptor]);
|
|
91
|
+
const bytes = new Uint8Array(await readFile(target));
|
|
92
|
+
return { bytes, inputs: deps.split('\n').filter((l) => l !== '') };
|
|
93
|
+
}
|
|
94
|
+
finally {
|
|
95
|
+
await rm(tmp, { recursive: true, force: true });
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
const B64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
|
|
99
|
+
/** The module source: the bytes as base64 and an inline decoder to a `Uint8Array` default export. */
|
|
100
|
+
export function gresourceModuleSource(bytes) {
|
|
101
|
+
const b64 = Buffer.from(bytes.buffer, bytes.byteOffset, bytes.byteLength).toString('base64');
|
|
102
|
+
return [
|
|
103
|
+
`const s = ${JSON.stringify(b64)};`,
|
|
104
|
+
`const a = ${JSON.stringify(B64)};`,
|
|
105
|
+
'const t = new Uint8Array(128);',
|
|
106
|
+
'for (let i = 0; i < 64; i++) t[a.charCodeAt(i)] = i;',
|
|
107
|
+
'const b = new Uint8Array((s.length / 4) * 3 - (s.endsWith("==") ? 2 : s.endsWith("=") ? 1 : 0));',
|
|
108
|
+
'for (let i = 0, j = 0; i < s.length; i += 4) {',
|
|
109
|
+
' const v = (t[s.charCodeAt(i)] << 18) | (t[s.charCodeAt(i + 1)] << 12) | (t[s.charCodeAt(i + 2)] << 6) | t[s.charCodeAt(i + 3)];',
|
|
110
|
+
' b[j++] = v >> 16;',
|
|
111
|
+
' if (j < b.length) b[j++] = (v >> 8) & 255;',
|
|
112
|
+
' if (j < b.length) b[j++] = v & 255;',
|
|
113
|
+
'}',
|
|
114
|
+
'export default b;',
|
|
115
|
+
].join('\n');
|
|
116
|
+
}
|
|
117
|
+
export function gresourcePlugin(options) {
|
|
118
|
+
return {
|
|
119
|
+
name: GRESOURCE_PLUGIN,
|
|
120
|
+
async load(id) {
|
|
121
|
+
if (!SUFFIX.test(id))
|
|
122
|
+
return null;
|
|
123
|
+
const { bytes, inputs } = await compileGresource(id, options);
|
|
124
|
+
// The native engine's context may predate `addWatchFile`/`info`; a build must not
|
|
125
|
+
// fail over bookkeeping (rolldown-native `NativePluginContext`).
|
|
126
|
+
const ctx = this;
|
|
127
|
+
for (const f of [id, ...inputs])
|
|
128
|
+
ctx.addWatchFile?.(f);
|
|
129
|
+
const code = gresourceModuleSource(bytes);
|
|
130
|
+
ctx.info?.(`${id}: ${bytes.byteLength} B compiled, ${code.length} B embedded (ADR 0116)`);
|
|
131
|
+
return { code, moduleType: 'js' };
|
|
132
|
+
},
|
|
133
|
+
};
|
|
134
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gjsify/rolldown-plugin-gjsify",
|
|
3
|
-
"version": "0.64.1-next.
|
|
3
|
+
"version": "0.64.1-next.247",
|
|
4
4
|
"description": "Rolldown / Rollup / Vite plugin orchestrator for GJS, Node, and Browser targets",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
@@ -63,12 +63,12 @@
|
|
|
63
63
|
],
|
|
64
64
|
"license": "MIT",
|
|
65
65
|
"dependencies": {
|
|
66
|
-
"@gjsify/console": "0.64.1-next.
|
|
67
|
-
"@gjsify/resolve-npm": "0.64.1-next.
|
|
68
|
-
"@gjsify/rolldown-plugin-deepkit": "0.64.1-next.
|
|
69
|
-
"@gjsify/rolldown-plugin-pnp": "0.64.1-next.
|
|
70
|
-
"@gjsify/utils": "0.64.1-next.
|
|
71
|
-
"@gjsify/vite-plugin-blueprint": "0.64.1-next.
|
|
66
|
+
"@gjsify/console": "0.64.1-next.247",
|
|
67
|
+
"@gjsify/resolve-npm": "0.64.1-next.247",
|
|
68
|
+
"@gjsify/rolldown-plugin-deepkit": "0.64.1-next.247",
|
|
69
|
+
"@gjsify/rolldown-plugin-pnp": "0.64.1-next.247",
|
|
70
|
+
"@gjsify/utils": "0.64.1-next.247",
|
|
71
|
+
"@gjsify/vite-plugin-blueprint": "0.64.1-next.247",
|
|
72
72
|
"@rollup/pluginutils": "^5.4.0",
|
|
73
73
|
"acorn": "^8.17.0",
|
|
74
74
|
"acorn-typescript": "^1.4.13",
|
|
@@ -78,7 +78,7 @@
|
|
|
78
78
|
"sass": "^1.101.0"
|
|
79
79
|
},
|
|
80
80
|
"peerDependencies": {
|
|
81
|
-
"@gjsify/lightningcss-native": "0.64.1-next.
|
|
81
|
+
"@gjsify/lightningcss-native": "0.64.1-next.247",
|
|
82
82
|
"rolldown": "^1.1.4"
|
|
83
83
|
},
|
|
84
84
|
"peerDependenciesMeta": {
|
|
@@ -90,8 +90,8 @@
|
|
|
90
90
|
}
|
|
91
91
|
},
|
|
92
92
|
"devDependencies": {
|
|
93
|
-
"@gjsify/cli": "0.64.1-next.
|
|
94
|
-
"@gjsify/unit": "0.64.1-next.
|
|
93
|
+
"@gjsify/cli": "0.64.1-next.247",
|
|
94
|
+
"@gjsify/unit": "0.64.1-next.247",
|
|
95
95
|
"@types/node": "^25.9.2",
|
|
96
96
|
"rolldown": "^1.1.4",
|
|
97
97
|
"typescript": "^6.0.3"
|
|
@@ -104,5 +104,5 @@
|
|
|
104
104
|
"win32": "supported"
|
|
105
105
|
}
|
|
106
106
|
},
|
|
107
|
-
"gitHead": "
|
|
107
|
+
"gitHead": "0865008d02b3a10af8152061095378aabe6b9d5d"
|
|
108
108
|
}
|