@hanzogui/vite-plugin 8.3.0 → 8.3.2
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/dist/cjs/extensions.js +16 -0
- package/dist/cjs/extensions.js.map +1 -0
- package/dist/cjs/here.js +6 -0
- package/dist/cjs/here.js.map +1 -0
- package/dist/cjs/index.js +5 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/loadGui.js +84 -0
- package/dist/cjs/loadGui.js.map +1 -0
- package/dist/cjs/package.json +1 -0
- package/dist/cjs/plugin.js +523 -0
- package/dist/cjs/plugin.js.map +1 -0
- package/dist/esm/extensions.js +13 -0
- package/dist/esm/extensions.js.map +1 -0
- package/dist/esm/here.js +3 -0
- package/dist/esm/here.js.map +1 -0
- package/dist/esm/index.js +2 -2
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/loadGui.js +76 -0
- package/dist/esm/loadGui.js.map +1 -0
- package/dist/esm/plugin.js +518 -0
- package/dist/esm/plugin.js.map +1 -0
- package/package.json +20 -19
- package/src/here.cjs.ts +3 -0
- package/src/here.ts +2 -0
- package/src/index.ts +1 -1
- package/src/plugin.ts +7 -9
- package/types/here.d.ts +2 -0
- package/types/here.d.ts.map +1 -0
- package/types/index.d.ts +1 -1
- package/types/index.d.ts.map +1 -1
- package/types/plugin.d.ts.map +1 -1
- package/dist/cjs/extensions.cjs +0 -28
- package/dist/cjs/index.cjs +0 -20
- package/dist/cjs/loadGui.cjs +0 -101
- package/dist/cjs/plugin.cjs +0 -473
- package/dist/esm/extensions.mjs +0 -3
- package/dist/esm/extensions.mjs.map +0 -1
- package/dist/esm/index.mjs +0 -2
- package/dist/esm/index.mjs.map +0 -1
- package/dist/esm/loadGui.mjs +0 -61
- package/dist/esm/loadGui.mjs.map +0 -1
- package/dist/esm/plugin.mjs +0 -435
- package/dist/esm/plugin.mjs.map +0 -1
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.extensions = void 0;
|
|
4
|
+
exports.extensions = [
|
|
5
|
+
'.ios.js',
|
|
6
|
+
'.native.js',
|
|
7
|
+
'.native.ts',
|
|
8
|
+
'.native.tsx',
|
|
9
|
+
'.js',
|
|
10
|
+
'.jsx',
|
|
11
|
+
'.json',
|
|
12
|
+
'.ts',
|
|
13
|
+
'.tsx',
|
|
14
|
+
'.mjs',
|
|
15
|
+
];
|
|
16
|
+
//# sourceMappingURL=extensions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extensions.js","sourceRoot":"","sources":["../../src/extensions.ts"],"names":[],"mappings":";;;AAAa,QAAA,UAAU,GAAG;IACxB,SAAS;IACT,YAAY;IACZ,YAAY;IACZ,aAAa;IACb,KAAK;IACL,MAAM;IACN,OAAO;IACP,KAAK;IACL,MAAM;IACN,MAAM;CACP,CAAA"}
|
package/dist/cjs/here.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"here.cjs.js","sourceRoot":"","sources":["../../src/here.cjs.ts"],"names":[],"mappings":";;;AAAA,uCAAwC;AAE3B,QAAA,GAAG,GAAG,IAAA,wBAAa,EAAC,UAAU,CAAC,CAAC,IAAI,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";;;AAAA,sDAA2B"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getGuiOptions = getGuiOptions;
|
|
4
|
+
exports.getLoadPromise = getLoadPromise;
|
|
5
|
+
exports.loadGuiBuildConfig = loadGuiBuildConfig;
|
|
6
|
+
exports.ensureFullConfigLoaded = ensureFullConfigLoaded;
|
|
7
|
+
exports.cleanup = cleanup;
|
|
8
|
+
const tslib_1 = require("tslib");
|
|
9
|
+
const StaticWorker = tslib_1.__importStar(require("@hanzogui/static-worker"));
|
|
10
|
+
// use globalThis to share state across vite environments (SSR, client, etc.)
|
|
11
|
+
const LOAD_STATE_KEY = '__hanzogui_load_state__';
|
|
12
|
+
function getLoadState() {
|
|
13
|
+
if (!globalThis[LOAD_STATE_KEY]) {
|
|
14
|
+
;
|
|
15
|
+
globalThis[LOAD_STATE_KEY] = {
|
|
16
|
+
loadPromise: null,
|
|
17
|
+
loadedOptions: null,
|
|
18
|
+
fullConfigLoaded: false,
|
|
19
|
+
fullConfigLoadPromise: null,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
return globalThis[LOAD_STATE_KEY];
|
|
23
|
+
}
|
|
24
|
+
function getGuiOptions() {
|
|
25
|
+
return getLoadState().loadedOptions;
|
|
26
|
+
}
|
|
27
|
+
function getLoadPromise() {
|
|
28
|
+
return getLoadState().loadPromise;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Load just the hanzogui.build.ts config (lightweight)
|
|
32
|
+
* This doesn't bundle the full hanzogui config - call ensureFullConfigLoaded() for that
|
|
33
|
+
*/
|
|
34
|
+
async function loadGuiBuildConfig(optionsIn) {
|
|
35
|
+
const state = getLoadState();
|
|
36
|
+
if (state.loadedOptions)
|
|
37
|
+
return state.loadedOptions;
|
|
38
|
+
if (state.loadPromise)
|
|
39
|
+
return state.loadPromise;
|
|
40
|
+
state.loadPromise = (async () => {
|
|
41
|
+
const options = await StaticWorker.loadGuiBuildConfig({
|
|
42
|
+
...optionsIn,
|
|
43
|
+
platform: 'web',
|
|
44
|
+
});
|
|
45
|
+
state.loadedOptions = options;
|
|
46
|
+
return options;
|
|
47
|
+
})();
|
|
48
|
+
return state.loadPromise;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Ensure the full hanzogui config is loaded (heavy - bundles config + components)
|
|
52
|
+
* Call this lazily when transform/extraction is actually needed
|
|
53
|
+
*/
|
|
54
|
+
async function ensureFullConfigLoaded() {
|
|
55
|
+
const state = getLoadState();
|
|
56
|
+
if (state.fullConfigLoaded)
|
|
57
|
+
return;
|
|
58
|
+
if (state.fullConfigLoadPromise)
|
|
59
|
+
return state.fullConfigLoadPromise;
|
|
60
|
+
// set promise immediately to prevent race conditions
|
|
61
|
+
// (don't await loadGuiBuildConfig before setting this)
|
|
62
|
+
state.fullConfigLoadPromise = (async () => {
|
|
63
|
+
const options = await loadGuiBuildConfig();
|
|
64
|
+
// load full hanzogui config in worker (asynchronous)
|
|
65
|
+
if (!options.disableWatchGuiConfig && !options.disable) {
|
|
66
|
+
await StaticWorker.loadGui({
|
|
67
|
+
components: ['@hanzo/gui'],
|
|
68
|
+
platform: 'web',
|
|
69
|
+
...options,
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
state.fullConfigLoaded = true;
|
|
73
|
+
})();
|
|
74
|
+
return state.fullConfigLoadPromise;
|
|
75
|
+
}
|
|
76
|
+
async function cleanup() {
|
|
77
|
+
await StaticWorker.destroyPool();
|
|
78
|
+
const state = getLoadState();
|
|
79
|
+
state.loadPromise = null;
|
|
80
|
+
state.loadedOptions = null;
|
|
81
|
+
state.fullConfigLoaded = false;
|
|
82
|
+
state.fullConfigLoadPromise = null;
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=loadGui.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loadGui.js","sourceRoot":"","sources":["../../src/loadGui.ts"],"names":[],"mappings":";;;;;;;;AAAA,MAAY,YAAY,4DAA+B;AAGvD,6EAA6E;AAC7E,MAAM,cAAc,GAAG,yBAAyB,CAAA;AAShD,SAAS,YAAY;IACnB,IAAI,CAAE,UAAkB,CAAC,cAAc,CAAC,EAAE,CAAC;QACzC,CAAC;QAAC,UAAkB,CAAC,cAAc,CAAC,GAAG;YACrC,WAAW,EAAE,IAAI;YACjB,aAAa,EAAE,IAAI;YACnB,gBAAgB,EAAE,KAAK;YACvB,qBAAqB,EAAE,IAAI;SAC5B,CAAA;IACH,CAAC;IACD,OAAQ,UAAkB,CAAC,cAAc,CAAC,CAAA;AAC5C,CAAC;AAED;IACE,OAAO,YAAY,EAAE,CAAC,aAAa,CAAA;AACrC,CAAC;AAED;IACE,OAAO,YAAY,EAAE,CAAC,WAAW,CAAA;AACnC,CAAC;AAED;;;GAGG;AACI,KAAK,6BACV,SAA+B;IAE/B,MAAM,KAAK,GAAG,YAAY,EAAE,CAAA;IAC5B,IAAI,KAAK,CAAC,aAAa;QAAE,OAAO,KAAK,CAAC,aAAa,CAAA;IACnD,IAAI,KAAK,CAAC,WAAW;QAAE,OAAO,KAAK,CAAC,WAAW,CAAA;IAE/C,KAAK,CAAC,WAAW,GAAG,CAAC,KAAK,IAAI,EAAE;QAC9B,MAAM,OAAO,GAAG,MAAM,YAAY,CAAC,kBAAkB,CAAC;YACpD,GAAG,SAAS;YACZ,QAAQ,EAAE,KAAK;SAChB,CAAC,CAAA;QAEF,KAAK,CAAC,aAAa,GAAG,OAAO,CAAA;QAC7B,OAAO,OAAO,CAAA;IAChB,CAAC,CAAC,EAAE,CAAA;IAEJ,OAAO,KAAK,CAAC,WAAW,CAAA;AAC1B,CAAC;AAED;;;GAGG;AACI,KAAK;IACV,MAAM,KAAK,GAAG,YAAY,EAAE,CAAA;IAE5B,IAAI,KAAK,CAAC,gBAAgB;QAAE,OAAM;IAClC,IAAI,KAAK,CAAC,qBAAqB;QAAE,OAAO,KAAK,CAAC,qBAAqB,CAAA;IAEnE,qDAAqD;IACrD,uDAAuD;IACvD,KAAK,CAAC,qBAAqB,GAAG,CAAC,KAAK,IAAI,EAAE;QACxC,MAAM,OAAO,GAAG,MAAM,kBAAkB,EAAE,CAAA;QAE1C,qDAAqD;QACrD,IAAI,CAAC,OAAO,CAAC,qBAAqB,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;YACvD,MAAM,YAAY,CAAC,OAAO,CAAC;gBACzB,UAAU,EAAE,CAAC,YAAY,CAAC;gBAC1B,QAAQ,EAAE,KAAK;gBACf,GAAG,OAAO;aACX,CAAC,CAAA;QACJ,CAAC;QACD,KAAK,CAAC,gBAAgB,GAAG,IAAI,CAAA;IAC/B,CAAC,CAAC,EAAE,CAAA;IAEJ,OAAO,KAAK,CAAC,qBAAqB,CAAA;AACpC,CAAC;AAEM,KAAK;IACV,MAAM,YAAY,CAAC,WAAW,EAAE,CAAA;IAChC,MAAM,KAAK,GAAG,YAAY,EAAE,CAAA;IAC5B,KAAK,CAAC,WAAW,GAAG,IAAI,CAAA;IACxB,KAAK,CAAC,aAAa,GAAG,IAAI,CAAA;IAC1B,KAAK,CAAC,gBAAgB,GAAG,KAAK,CAAA;IAC9B,KAAK,CAAC,qBAAqB,GAAG,IAAI,CAAA;AACpC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{ "type": "commonjs" }
|
|
@@ -0,0 +1,523 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.hanzoguiAliases = hanzoguiAliases;
|
|
4
|
+
exports.hanzoguiPlugin = hanzoguiPlugin;
|
|
5
|
+
const tslib_1 = require("tslib");
|
|
6
|
+
const Static = tslib_1.__importStar(require("@hanzogui/static-worker"));
|
|
7
|
+
const static_worker_1 = require("@hanzogui/static-worker");
|
|
8
|
+
const node_crypto_1 = require("node:crypto");
|
|
9
|
+
const node_module_1 = require("node:module");
|
|
10
|
+
const here_ts_1 = require("./here.js");
|
|
11
|
+
const node_path_1 = tslib_1.__importDefault(require("node:path"));
|
|
12
|
+
const loadGui_ts_1 = require("./loadGui.js");
|
|
13
|
+
// Plugin dependencies resolve from the plugin's own location, not the user's project.
|
|
14
|
+
const _pluginRequire = (0, node_module_1.createRequire)(here_ts_1.url);
|
|
15
|
+
const resolve = (name) => _pluginRequire.resolve(name);
|
|
16
|
+
const normalizePath = (value) => value.replace(/\\/g, '/');
|
|
17
|
+
/** what an installed package can hold extractable source in */
|
|
18
|
+
const PACKAGE_EXTENSIONS = /\.(mjs|js|jsx|tsx)$/;
|
|
19
|
+
const CACHE_KEY = '__hanzogui_vite_cache__';
|
|
20
|
+
const CACHE_SIZE_KEY = '__hanzogui_vite_cache_size__';
|
|
21
|
+
const PENDING_KEY = '__hanzogui_vite_pending__';
|
|
22
|
+
function getSharedCache() {
|
|
23
|
+
if (!globalThis[CACHE_KEY]) {
|
|
24
|
+
;
|
|
25
|
+
globalThis[CACHE_KEY] = {};
|
|
26
|
+
}
|
|
27
|
+
return globalThis[CACHE_KEY];
|
|
28
|
+
}
|
|
29
|
+
function getSharedCacheSize() {
|
|
30
|
+
return globalThis[CACHE_SIZE_KEY] || 0;
|
|
31
|
+
}
|
|
32
|
+
function setSharedCacheSize(size) {
|
|
33
|
+
;
|
|
34
|
+
globalThis[CACHE_SIZE_KEY] = size;
|
|
35
|
+
}
|
|
36
|
+
function clearSharedCache() {
|
|
37
|
+
;
|
|
38
|
+
globalThis[CACHE_KEY] = {};
|
|
39
|
+
globalThis[CACHE_SIZE_KEY] = 0;
|
|
40
|
+
}
|
|
41
|
+
// resolves package ids against the user's project root (not the plugin's
|
|
42
|
+
// install location). returns true if the id is resolvable, false if the
|
|
43
|
+
// dep isn't installed, safe to call for optional deps.
|
|
44
|
+
function isInstalled(projectRoot, id) {
|
|
45
|
+
try {
|
|
46
|
+
const req = (0, node_module_1.createRequire)(node_path_1.default.join(projectRoot, 'package.json'));
|
|
47
|
+
req.resolve(id);
|
|
48
|
+
return true;
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
function addIfInstalled(userConf, projectRoot, ids) {
|
|
55
|
+
var _a;
|
|
56
|
+
const root = projectRoot || process.cwd();
|
|
57
|
+
userConf.optimizeDeps || (userConf.optimizeDeps = {});
|
|
58
|
+
(_a = userConf.optimizeDeps).include || (_a.include = []);
|
|
59
|
+
for (const id of ids) {
|
|
60
|
+
if (!userConf.optimizeDeps.include.includes(id) && isInstalled(root, id)) {
|
|
61
|
+
userConf.optimizeDeps.include.push(id);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
// pending extractions map - dedupes concurrent requests for same file
|
|
66
|
+
function getPendingExtractions() {
|
|
67
|
+
if (!globalThis[PENDING_KEY]) {
|
|
68
|
+
;
|
|
69
|
+
globalThis[PENDING_KEY] = new Map();
|
|
70
|
+
}
|
|
71
|
+
return globalThis[PENDING_KEY];
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* returns vite-compatible aliases for hanzogui
|
|
75
|
+
* use this when you need control over alias ordering in your config
|
|
76
|
+
*/
|
|
77
|
+
function hanzoguiAliases(options = {}) {
|
|
78
|
+
const aliases = [];
|
|
79
|
+
if (options.svg) {
|
|
80
|
+
aliases.push({
|
|
81
|
+
find: 'react-native-svg',
|
|
82
|
+
replacement: resolve('@hanzogui/react-native-svg'),
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
if (options.rnwLite) {
|
|
86
|
+
// base package path for subpath imports (package directory, not entry file)
|
|
87
|
+
const rnwlBase = node_path_1.default.dirname(resolve('@hanzogui/react-native-web-lite/package.json'));
|
|
88
|
+
// vite aliases need the esm entry; require.resolve points at cjs.
|
|
89
|
+
const rnwl = normalizePath(node_path_1.default.join(rnwlBase, options.rnwLite === 'without-animated'
|
|
90
|
+
? 'dist/esm/without-animated.js'
|
|
91
|
+
: 'dist/esm/index.js'));
|
|
92
|
+
aliases.push({
|
|
93
|
+
// map deep RNW paths like dist/exports/StyleSheet/preprocess to rnw-lite's flat structure
|
|
94
|
+
// extracts the final path segment (e.g. "preprocess" or "createReactDOMStyle")
|
|
95
|
+
find: /^react-native(?:-web)?\/dist\/(?:exports|modules)\/.*\/([^/]+)$/,
|
|
96
|
+
replacement: `${normalizePath(rnwlBase)}/dist/esm/$1.js`,
|
|
97
|
+
}, {
|
|
98
|
+
find: /^react-native$/,
|
|
99
|
+
replacement: rnwl,
|
|
100
|
+
}, {
|
|
101
|
+
find: /^react-native\/(Libraries\/Utilities\/codegenNativeComponent|Libraries\/Utilities\/codegenNativeCommand)$/,
|
|
102
|
+
replacement: `${rnwlBase}/$1`,
|
|
103
|
+
}, {
|
|
104
|
+
find: 'react-native/package.json',
|
|
105
|
+
replacement: resolve('@hanzogui/react-native-web-lite/package.json'),
|
|
106
|
+
}, {
|
|
107
|
+
find: /^react-native-web$/,
|
|
108
|
+
replacement: rnwl,
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
return aliases;
|
|
112
|
+
}
|
|
113
|
+
function hanzoguiPlugin({ disableResolveConfig, ...hanzoguiOptionsIn } = {}) {
|
|
114
|
+
// extraction ON by default, set disableExtraction: true to opt out
|
|
115
|
+
let shouldExtract = !hanzoguiOptionsIn.disableExtraction;
|
|
116
|
+
let watcher;
|
|
117
|
+
// temporary vxrn native env bridge
|
|
118
|
+
const enableNativeEnv = !!globalThis.__vxrnEnableNativeEnv;
|
|
119
|
+
const extensions = [
|
|
120
|
+
`.web.mjs`,
|
|
121
|
+
`.web.js`,
|
|
122
|
+
`.web.jsx`,
|
|
123
|
+
`.web.ts`,
|
|
124
|
+
`.web.tsx`,
|
|
125
|
+
'.mjs',
|
|
126
|
+
'.js',
|
|
127
|
+
'.mts',
|
|
128
|
+
'.ts',
|
|
129
|
+
'.jsx',
|
|
130
|
+
'.tsx',
|
|
131
|
+
'.json',
|
|
132
|
+
];
|
|
133
|
+
// start loading immediately but don't block
|
|
134
|
+
(0, loadGui_ts_1.loadGuiBuildConfig)(hanzoguiOptionsIn);
|
|
135
|
+
// helper to await load when needed
|
|
136
|
+
const ensureLoaded = async () => {
|
|
137
|
+
const promise = (0, loadGui_ts_1.getLoadPromise)();
|
|
138
|
+
if (promise)
|
|
139
|
+
await promise;
|
|
140
|
+
const options = (0, loadGui_ts_1.getGuiOptions)();
|
|
141
|
+
// update shouldExtract from loaded config (hanzogui.build.ts)
|
|
142
|
+
if (options) {
|
|
143
|
+
shouldExtract = !options.disableExtraction;
|
|
144
|
+
}
|
|
145
|
+
return options;
|
|
146
|
+
};
|
|
147
|
+
// extract plugin state
|
|
148
|
+
const getHash = (input) => (0, node_crypto_1.createHash)('sha1').update(input).digest('base64');
|
|
149
|
+
// use shared cache across environments
|
|
150
|
+
const memoryCache = getSharedCache();
|
|
151
|
+
const cssMap = new Map();
|
|
152
|
+
let config;
|
|
153
|
+
let server;
|
|
154
|
+
const virtualExt = `.hanzogui.css`;
|
|
155
|
+
const getAbsoluteVirtualFileId = (filePath) => {
|
|
156
|
+
if (filePath.startsWith(config.root)) {
|
|
157
|
+
return filePath;
|
|
158
|
+
}
|
|
159
|
+
return normalizePath(node_path_1.default.join(config.root, filePath));
|
|
160
|
+
};
|
|
161
|
+
function isNotClient(environment) {
|
|
162
|
+
return environment?.name && environment.name !== 'client';
|
|
163
|
+
}
|
|
164
|
+
function isNative(environment) {
|
|
165
|
+
return (environment?.name && (environment.name === 'ios' || environment.name === 'android'));
|
|
166
|
+
}
|
|
167
|
+
function invalidateModule(absoluteId) {
|
|
168
|
+
if (!server)
|
|
169
|
+
return;
|
|
170
|
+
const { moduleGraph } = server;
|
|
171
|
+
const modules = moduleGraph.getModulesByFile(absoluteId);
|
|
172
|
+
if (modules) {
|
|
173
|
+
for (const module of modules) {
|
|
174
|
+
moduleGraph.invalidateModule(module);
|
|
175
|
+
module.lastHMRTimestamp = module.lastInvalidationTimestamp || Date.now();
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
const basePlugin = {
|
|
180
|
+
name: 'hanzogui',
|
|
181
|
+
enforce: 'pre',
|
|
182
|
+
configureServer(_server) {
|
|
183
|
+
server = _server;
|
|
184
|
+
},
|
|
185
|
+
async buildEnd() {
|
|
186
|
+
await watcher?.then((res) => {
|
|
187
|
+
res?.dispose();
|
|
188
|
+
});
|
|
189
|
+
},
|
|
190
|
+
async config(_, env) {
|
|
191
|
+
const options = await ensureLoaded();
|
|
192
|
+
if (!options) {
|
|
193
|
+
throw new Error(`No hanzogui options loaded`);
|
|
194
|
+
}
|
|
195
|
+
// start watching config if enabled
|
|
196
|
+
if (!options.disableWatchGuiConfig) {
|
|
197
|
+
watcher = Static.watchGuiConfig({
|
|
198
|
+
components: ['@hanzo/gui'],
|
|
199
|
+
config: './src/hanzogui.config.ts',
|
|
200
|
+
...options,
|
|
201
|
+
}).catch((err) => {
|
|
202
|
+
console.error(` [Gui] Error watching config: ${err}`);
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
return {
|
|
206
|
+
envPrefix: ['GUI_'],
|
|
207
|
+
// A dependency that RENDERS is bundled, not externalised.
|
|
208
|
+
//
|
|
209
|
+
// An externalised package resolves react itself, and under SSR that is a
|
|
210
|
+
// second module instance of the one react in the tree — its dispatcher is
|
|
211
|
+
// null while the app renders, so the package's first hook throws and the
|
|
212
|
+
// whole page fails, not just the subtree. GuiProvider mounts a telemetry
|
|
213
|
+
// client for every app, so these two arrive in apps that never named them.
|
|
214
|
+
//
|
|
215
|
+
// It belongs here rather than in each app's config because every gui app
|
|
216
|
+
// already mounts this plugin, and a list repeated per app is a list the
|
|
217
|
+
// next app forgets.
|
|
218
|
+
ssr: { noExternal: ['@hanzo/event', '@hanzo/observe'] },
|
|
219
|
+
environments: {
|
|
220
|
+
client: {
|
|
221
|
+
define: {
|
|
222
|
+
'process.env.GUI_IS_CLIENT': JSON.stringify(true),
|
|
223
|
+
'process.env.GUI_ENVIRONMENT': '"client"',
|
|
224
|
+
},
|
|
225
|
+
},
|
|
226
|
+
},
|
|
227
|
+
define: {
|
|
228
|
+
// reanimated support
|
|
229
|
+
_frameTimestamp: undefined,
|
|
230
|
+
_WORKLET: false,
|
|
231
|
+
__DEV__: `${env.mode === 'development'}`,
|
|
232
|
+
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || env.mode),
|
|
233
|
+
'process.env.ENABLE_RSC': JSON.stringify(process.env.ENABLE_RSC || ''),
|
|
234
|
+
'process.env.ENABLE_STEPS': JSON.stringify(process.env.ENABLE_STEPS || ''),
|
|
235
|
+
'process.env.IS_STATIC': JSON.stringify(false),
|
|
236
|
+
...(env.mode === 'production' && {
|
|
237
|
+
'process.env.GUI_OPTIMIZE_THEMES': JSON.stringify(true),
|
|
238
|
+
}),
|
|
239
|
+
},
|
|
240
|
+
resolve: disableResolveConfig || enableNativeEnv
|
|
241
|
+
? {}
|
|
242
|
+
: {
|
|
243
|
+
extensions,
|
|
244
|
+
alias: {
|
|
245
|
+
...(options.platform !== 'native' && {
|
|
246
|
+
'react-native/Libraries/Renderer/shims/ReactFabric': resolve('@hanzogui/proxy-worm'),
|
|
247
|
+
'react-native/Libraries/Utilities/codegenNativeComponent': resolve('@hanzogui/proxy-worm'),
|
|
248
|
+
'react-native-svg': resolve('@hanzogui/react-native-svg'),
|
|
249
|
+
...(!options?.useReactNativeWebLite && {
|
|
250
|
+
'react-native': resolve('react-native-web'),
|
|
251
|
+
}),
|
|
252
|
+
}),
|
|
253
|
+
},
|
|
254
|
+
},
|
|
255
|
+
};
|
|
256
|
+
},
|
|
257
|
+
};
|
|
258
|
+
const rnwLitePlugin = {
|
|
259
|
+
name: 'hanzogui-rnw-lite',
|
|
260
|
+
config() {
|
|
261
|
+
if (enableNativeEnv) {
|
|
262
|
+
return {};
|
|
263
|
+
}
|
|
264
|
+
const options = (0, loadGui_ts_1.getGuiOptions)();
|
|
265
|
+
if (!options?.useReactNativeWebLite) {
|
|
266
|
+
return {};
|
|
267
|
+
}
|
|
268
|
+
// react-native-web-lite imports memoize-one internally. the esbuild dep
|
|
269
|
+
// scanner doesn't follow it through the react-native -> rnw-lite alias, so
|
|
270
|
+
// vite discovers it only at request time, re-optimizes mid-load, and full
|
|
271
|
+
// reloads. on slow runners (CI) the in-flight optimized-dep request 504s
|
|
272
|
+
// ("Outdated Optimize Dep") and surfaces as a console error. pre-include
|
|
273
|
+
// it so the first optimize pass is complete and no reload is triggered.
|
|
274
|
+
const include = [];
|
|
275
|
+
if (isInstalled(process.cwd(), 'memoize-one')) {
|
|
276
|
+
include.push('memoize-one');
|
|
277
|
+
}
|
|
278
|
+
return {
|
|
279
|
+
resolve: {
|
|
280
|
+
alias: hanzoguiAliases({ rnwLite: options.useReactNativeWebLite }),
|
|
281
|
+
},
|
|
282
|
+
optimizeDeps: {
|
|
283
|
+
// upstream react-native-web must not be pre-bundled when aliased to lite
|
|
284
|
+
exclude: ['react-native-web'],
|
|
285
|
+
include,
|
|
286
|
+
},
|
|
287
|
+
};
|
|
288
|
+
},
|
|
289
|
+
};
|
|
290
|
+
// extract plugin for optimize mode
|
|
291
|
+
// always included, but checks shouldExtract dynamically after config loads
|
|
292
|
+
const extractPlugin = {
|
|
293
|
+
name: 'hanzogui-extract',
|
|
294
|
+
enforce: 'pre',
|
|
295
|
+
async config(userConf) {
|
|
296
|
+
var _a, _b;
|
|
297
|
+
// wait for config to load to know if we should extract
|
|
298
|
+
const options = await ensureLoaded();
|
|
299
|
+
userConf.optimizeDeps || (userConf.optimizeDeps = {});
|
|
300
|
+
(_a = userConf.optimizeDeps).include || (_a.include = []);
|
|
301
|
+
// inline-style-prefixer is CJS with __esModule and breaks without pre-bundling
|
|
302
|
+
// (reference error: exports is not defined). always include it.
|
|
303
|
+
userConf.optimizeDeps.include.push('inline-style-prefixer');
|
|
304
|
+
// pre-bundle hanzogui packages that use internal hooks (useThemeName, etc.)
|
|
305
|
+
// from sub-entries, vite's dep crawler can otherwise split them into a
|
|
306
|
+
// separate chunk with its own hanzogui copy, producing two ThemeStateContext
|
|
307
|
+
// instances and "Missing theme" errors at runtime.
|
|
308
|
+
//
|
|
309
|
+
// @hanzogui/sheet/controller is the lightweight controller subpath imported
|
|
310
|
+
// by popover/dialog/select; the app imports @hanzogui/sheet (full). if these
|
|
311
|
+
// land in separate optimized chunks they each get their own copy of
|
|
312
|
+
// SheetControllerContext, so the SheetController provider (from /controller)
|
|
313
|
+
// and the Sheet consumer (from the full entry) never match and adapted
|
|
314
|
+
// sheets silently never open. include both so they share one context chunk.
|
|
315
|
+
addIfInstalled(userConf, userConf.root, [
|
|
316
|
+
'@hanzogui/toast',
|
|
317
|
+
'@hanzogui/toast/v2',
|
|
318
|
+
'@hanzogui/sheet',
|
|
319
|
+
'@hanzogui/sheet/controller',
|
|
320
|
+
]);
|
|
321
|
+
// dedupe hanzogui packages so nested resolutions collapse to a single
|
|
322
|
+
// instance. pairs with the include above: include pre-bundles, dedupe
|
|
323
|
+
// prevents duplicate bundling when sub-deps re-resolve them.
|
|
324
|
+
userConf.resolve || (userConf.resolve = {});
|
|
325
|
+
(_b = userConf.resolve).dedupe || (_b.dedupe = []);
|
|
326
|
+
for (const id of [
|
|
327
|
+
'hanzogui',
|
|
328
|
+
'@hanzogui/core',
|
|
329
|
+
'@hanzogui/web',
|
|
330
|
+
'@hanzogui/toast',
|
|
331
|
+
'@hanzogui/sheet',
|
|
332
|
+
]) {
|
|
333
|
+
if (!userConf.resolve.dedupe.includes(id) &&
|
|
334
|
+
isInstalled(userConf.root || process.cwd(), id)) {
|
|
335
|
+
userConf.resolve.dedupe.push(id);
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
if (!shouldExtract)
|
|
339
|
+
return;
|
|
340
|
+
userConf.optimizeDeps.include.push('@hanzogui/core/inject-styles');
|
|
341
|
+
},
|
|
342
|
+
async configResolved(resolvedConfig) {
|
|
343
|
+
config = resolvedConfig;
|
|
344
|
+
},
|
|
345
|
+
async resolveId(source) {
|
|
346
|
+
if (!shouldExtract)
|
|
347
|
+
return;
|
|
348
|
+
if (isNative(this.environment)) {
|
|
349
|
+
return;
|
|
350
|
+
}
|
|
351
|
+
if (isNotClient(this.environment)) {
|
|
352
|
+
return;
|
|
353
|
+
}
|
|
354
|
+
const [validId, query] = source.split('?');
|
|
355
|
+
if (!validId.endsWith(virtualExt)) {
|
|
356
|
+
return;
|
|
357
|
+
}
|
|
358
|
+
const absoluteId = source.startsWith(config.root)
|
|
359
|
+
? source
|
|
360
|
+
: getAbsoluteVirtualFileId(validId);
|
|
361
|
+
if (cssMap.has(absoluteId)) {
|
|
362
|
+
return absoluteId + (query ? `?${query}` : '');
|
|
363
|
+
}
|
|
364
|
+
},
|
|
365
|
+
async load(id) {
|
|
366
|
+
if (!shouldExtract)
|
|
367
|
+
return;
|
|
368
|
+
const options = (0, loadGui_ts_1.getGuiOptions)();
|
|
369
|
+
if (options?.disable) {
|
|
370
|
+
return;
|
|
371
|
+
}
|
|
372
|
+
if (isNative(this.environment)) {
|
|
373
|
+
return;
|
|
374
|
+
}
|
|
375
|
+
if (isNotClient(this.environment)) {
|
|
376
|
+
return;
|
|
377
|
+
}
|
|
378
|
+
const [validId] = id.split('?');
|
|
379
|
+
return cssMap.get(validId);
|
|
380
|
+
},
|
|
381
|
+
transform: {
|
|
382
|
+
order: 'pre',
|
|
383
|
+
async handler(code, id) {
|
|
384
|
+
// ensure hanzogui is loaded before transform
|
|
385
|
+
const options = await ensureLoaded();
|
|
386
|
+
// ensure full config (heavy bundling) is loaded before extraction
|
|
387
|
+
await (0, loadGui_ts_1.ensureFullConfigLoaded)();
|
|
388
|
+
// fully disabled = no extraction AND no debug attrs
|
|
389
|
+
if (options?.disable) {
|
|
390
|
+
return;
|
|
391
|
+
}
|
|
392
|
+
if (isNative(this.environment)) {
|
|
393
|
+
return;
|
|
394
|
+
}
|
|
395
|
+
const [validId] = id.split('?');
|
|
396
|
+
// app source is .tsx; an allowlisted package is whatever it publishes,
|
|
397
|
+
// which for our design system is the jsx-preserving .mjs/.js build
|
|
398
|
+
const pkg = (0, static_worker_1.installedPackageOf)(validId);
|
|
399
|
+
if (pkg
|
|
400
|
+
? !(0, static_worker_1.isExtractable)(validId, options?.extractPackages) ||
|
|
401
|
+
!PACKAGE_EXTENSIONS.test(validId)
|
|
402
|
+
: !validId.endsWith('.tsx')) {
|
|
403
|
+
return;
|
|
404
|
+
}
|
|
405
|
+
const { shouldDisable, shouldPrintDebug } = await (0, static_worker_1.getPragmaOptions)({
|
|
406
|
+
source: code,
|
|
407
|
+
path: validId,
|
|
408
|
+
});
|
|
409
|
+
if (shouldPrintDebug) {
|
|
410
|
+
console.trace(`Current file: ${id} in environment: ${this.environment?.name}, shouldDisable: ${shouldDisable}`);
|
|
411
|
+
console.info(`\n\nOriginal source:\n${code}\n\n`);
|
|
412
|
+
}
|
|
413
|
+
if (shouldDisable) {
|
|
414
|
+
return;
|
|
415
|
+
}
|
|
416
|
+
const isSSR = isNotClient(this.environment);
|
|
417
|
+
// cache key without environment - share compiled JS between SSR/client
|
|
418
|
+
const cacheKey = getHash(`${code}${id}`);
|
|
419
|
+
const pending = getPendingExtractions();
|
|
420
|
+
// helper to format result based on environment
|
|
421
|
+
const formatResult = (entry) => {
|
|
422
|
+
const finalCode = !isSSR && entry.cssImport ? `${entry.js}\n${entry.cssImport}` : entry.js;
|
|
423
|
+
return { code: finalCode, map: entry.map };
|
|
424
|
+
};
|
|
425
|
+
// check cache first
|
|
426
|
+
const cached = memoryCache[cacheKey];
|
|
427
|
+
if (cached) {
|
|
428
|
+
if (process.env.DEBUG_GUI_CACHE) {
|
|
429
|
+
console.info(`[hanzogui-cache] HIT ${this.environment?.name || 'unknown'} ${id.split('/').pop()} key=${cacheKey.slice(0, 8)}`);
|
|
430
|
+
}
|
|
431
|
+
return formatResult(cached);
|
|
432
|
+
}
|
|
433
|
+
// check if another request is already extracting this file
|
|
434
|
+
const pendingExtraction = pending.get(cacheKey);
|
|
435
|
+
if (pendingExtraction) {
|
|
436
|
+
if (process.env.DEBUG_GUI_CACHE) {
|
|
437
|
+
console.info(`[hanzogui-cache] WAIT ${this.environment?.name || 'unknown'} ${id.split('/').pop()} key=${cacheKey.slice(0, 8)}`);
|
|
438
|
+
}
|
|
439
|
+
const result = await pendingExtraction;
|
|
440
|
+
if (result) {
|
|
441
|
+
return formatResult(result);
|
|
442
|
+
}
|
|
443
|
+
return;
|
|
444
|
+
}
|
|
445
|
+
if (process.env.DEBUG_GUI_CACHE) {
|
|
446
|
+
console.info(`[hanzogui-cache] EXTRACT ${this.environment?.name || 'unknown'} ${id.split('/').pop()} key=${cacheKey.slice(0, 8)}`);
|
|
447
|
+
}
|
|
448
|
+
// create extraction promise and store it for deduplication
|
|
449
|
+
const extractionPromise = (async () => {
|
|
450
|
+
let extracted;
|
|
451
|
+
try {
|
|
452
|
+
extracted = await Static.extractToClassNames({
|
|
453
|
+
source: code,
|
|
454
|
+
sourcePath: validId,
|
|
455
|
+
options: options,
|
|
456
|
+
shouldPrintDebug,
|
|
457
|
+
});
|
|
458
|
+
}
|
|
459
|
+
catch (err) {
|
|
460
|
+
if (process.env.DEBUG_GUI_CACHE) {
|
|
461
|
+
console.info(`[hanzogui-cache] ERROR extracting ${id.split('/').pop()}:`, err);
|
|
462
|
+
}
|
|
463
|
+
console.error(err instanceof Error ? err.message : String(err));
|
|
464
|
+
return null;
|
|
465
|
+
}
|
|
466
|
+
if (!extracted) {
|
|
467
|
+
if (process.env.DEBUG_GUI_CACHE) {
|
|
468
|
+
console.info(`[hanzogui-cache] no extraction result for ${id.split('/').pop()}`);
|
|
469
|
+
}
|
|
470
|
+
return null;
|
|
471
|
+
}
|
|
472
|
+
const rootRelativeId = `${validId}${virtualExt}`;
|
|
473
|
+
const absoluteId = getAbsoluteVirtualFileId(rootRelativeId);
|
|
474
|
+
let cssImport = null;
|
|
475
|
+
// store CSS and prepare import (but don't include in cached JS)
|
|
476
|
+
if (extracted.styles) {
|
|
477
|
+
this.addWatchFile(rootRelativeId);
|
|
478
|
+
if (server && cssMap.has(absoluteId)) {
|
|
479
|
+
invalidateModule(rootRelativeId);
|
|
480
|
+
}
|
|
481
|
+
cssImport = `import "${rootRelativeId}";`;
|
|
482
|
+
cssMap.set(absoluteId, extracted.styles);
|
|
483
|
+
}
|
|
484
|
+
// cache the JS separately from CSS import
|
|
485
|
+
const jsCode = extracted.js.toString();
|
|
486
|
+
const cacheEntry = {
|
|
487
|
+
js: jsCode,
|
|
488
|
+
map: extracted.map,
|
|
489
|
+
cssImport,
|
|
490
|
+
};
|
|
491
|
+
// track cache size and clear if too large (64MB)
|
|
492
|
+
const newSize = getSharedCacheSize() + jsCode.length;
|
|
493
|
+
if (newSize > 67108864) {
|
|
494
|
+
clearSharedCache();
|
|
495
|
+
}
|
|
496
|
+
else {
|
|
497
|
+
setSharedCacheSize(newSize);
|
|
498
|
+
}
|
|
499
|
+
memoryCache[cacheKey] = cacheEntry;
|
|
500
|
+
if (process.env.DEBUG_GUI_CACHE) {
|
|
501
|
+
console.info(`[hanzogui-cache] WRITE key=${cacheKey.slice(0, 8)} cacheSize=${Object.keys(memoryCache).length}`);
|
|
502
|
+
}
|
|
503
|
+
return cacheEntry;
|
|
504
|
+
})();
|
|
505
|
+
// store pending promise for deduplication
|
|
506
|
+
pending.set(cacheKey, extractionPromise);
|
|
507
|
+
try {
|
|
508
|
+
const result = await extractionPromise;
|
|
509
|
+
if (result) {
|
|
510
|
+
return formatResult(result);
|
|
511
|
+
}
|
|
512
|
+
return;
|
|
513
|
+
}
|
|
514
|
+
finally {
|
|
515
|
+
// clean up pending map
|
|
516
|
+
pending.delete(cacheKey);
|
|
517
|
+
}
|
|
518
|
+
},
|
|
519
|
+
},
|
|
520
|
+
};
|
|
521
|
+
return [basePlugin, rnwLitePlugin, extractPlugin];
|
|
522
|
+
}
|
|
523
|
+
//# sourceMappingURL=plugin.js.map
|