@absolutejs/absolute 0.15.8 → 0.15.10
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/dev/client/errorOverlay.ts +27 -4
- package/dist/dev/client/handlers/react.ts +6 -0
- package/dist/dev/client/handlers/rebuild.ts +8 -2
- package/dist/dev/client/hmrClient.ts +33 -0
- package/dist/index.js +51 -9
- package/dist/index.js.map +6 -6
- package/dist/types/client.d.ts +4 -0
- package/package.json +1 -1
- package/types/client.ts +2 -0
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import type { ErrorOverlayOptions } from '../../../types/client';
|
|
4
4
|
|
|
5
5
|
let errorOverlayElement: HTMLDivElement | null = null;
|
|
6
|
+
let currentOverlayKind: 'compilation' | 'runtime' | null = null;
|
|
6
7
|
|
|
7
8
|
const frameworkLabels: Record<string, string> = {
|
|
8
9
|
angular: 'Angular',
|
|
@@ -26,13 +27,32 @@ const frameworkColors: Record<string, string> = {
|
|
|
26
27
|
vue: '#42b883'
|
|
27
28
|
};
|
|
28
29
|
|
|
29
|
-
|
|
30
|
+
const removeOverlayElement = () => {
|
|
30
31
|
if (errorOverlayElement && errorOverlayElement.parentNode) {
|
|
31
32
|
errorOverlayElement.parentNode.removeChild(errorOverlayElement);
|
|
32
|
-
errorOverlayElement = null;
|
|
33
33
|
}
|
|
34
|
+
errorOverlayElement = null;
|
|
35
|
+
currentOverlayKind = null;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export const hideErrorOverlay = () => {
|
|
39
|
+
const elm = errorOverlayElement;
|
|
40
|
+
if (!elm || !elm.parentNode) {
|
|
41
|
+
removeOverlayElement();
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
elm.style.transition = 'opacity 150ms ease-out';
|
|
45
|
+
elm.style.opacity = '0';
|
|
46
|
+
errorOverlayElement = null;
|
|
47
|
+
currentOverlayKind = null;
|
|
48
|
+
setTimeout(() => {
|
|
49
|
+
if (elm.parentNode) elm.parentNode.removeChild(elm);
|
|
50
|
+
}, 150);
|
|
34
51
|
};
|
|
35
52
|
|
|
53
|
+
export const isRuntimeErrorOverlay = (): boolean =>
|
|
54
|
+
currentOverlayKind === 'runtime';
|
|
55
|
+
|
|
36
56
|
export const showErrorOverlay = (opts: ErrorOverlayOptions) => {
|
|
37
57
|
const message = opts.message || 'Build failed';
|
|
38
58
|
const file = opts.file;
|
|
@@ -43,7 +63,8 @@ export const showErrorOverlay = (opts: ErrorOverlayOptions) => {
|
|
|
43
63
|
const frameworkLabel = frameworkLabels[framework] || framework;
|
|
44
64
|
const accent = frameworkColors[framework] || '#94a3b8';
|
|
45
65
|
|
|
46
|
-
|
|
66
|
+
removeOverlayElement();
|
|
67
|
+
currentOverlayKind = opts.kind || 'compilation';
|
|
47
68
|
|
|
48
69
|
const overlay = document.createElement('div');
|
|
49
70
|
overlay.id = 'absolutejs-error-overlay';
|
|
@@ -63,7 +84,9 @@ export const showErrorOverlay = (opts: ErrorOverlayOptions) => {
|
|
|
63
84
|
accent +
|
|
64
85
|
';color:#fff;opacity:0.95;box-shadow:0 2px 4px rgba(0,0,0,0.2);">' +
|
|
65
86
|
frameworkLabel +
|
|
66
|
-
'</span></div><span style="color:#94a3b8;font-size:13px;font-weight:500;">
|
|
87
|
+
'</span></div><span style="color:#94a3b8;font-size:13px;font-weight:500;">' +
|
|
88
|
+
(opts.kind === 'runtime' ? 'Runtime Error' : 'Compilation Error') +
|
|
89
|
+
'</span>';
|
|
67
90
|
card.appendChild(header);
|
|
68
91
|
|
|
69
92
|
const content = document.createElement('div');
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
Code splitting ensures React lives in a shared chunk that stays cached,
|
|
4
4
|
so dynamic import of the rebuilt entry reuses the same React instance. */
|
|
5
5
|
|
|
6
|
+
import { hideErrorOverlay } from '../errorOverlay';
|
|
6
7
|
import { detectCurrentFramework } from '../frameworkDetect';
|
|
7
8
|
|
|
8
9
|
export const handleReactUpdate = (message: {
|
|
@@ -39,6 +40,11 @@ export const handleReactUpdate = (message: {
|
|
|
39
40
|
import(newUrl + '?t=' + Date.now())
|
|
40
41
|
.then(() => {
|
|
41
42
|
refreshRuntime.performReactRefresh();
|
|
43
|
+
if (window.__ERROR_BOUNDARY__) {
|
|
44
|
+
window.__ERROR_BOUNDARY__.reset();
|
|
45
|
+
} else {
|
|
46
|
+
hideErrorOverlay();
|
|
47
|
+
}
|
|
42
48
|
})
|
|
43
49
|
.catch((err) => {
|
|
44
50
|
console.warn(
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
/* Rebuild, manifest, module-update, and error handlers */
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
hideErrorOverlay,
|
|
5
|
+
isRuntimeErrorOverlay,
|
|
6
|
+
showErrorOverlay
|
|
7
|
+
} from '../errorOverlay';
|
|
4
8
|
|
|
5
9
|
export const handleManifest = (message: {
|
|
6
10
|
data: {
|
|
@@ -29,7 +33,9 @@ export const handleRebuildComplete = (message: {
|
|
|
29
33
|
manifest?: Record<string, string>;
|
|
30
34
|
};
|
|
31
35
|
}) => {
|
|
32
|
-
|
|
36
|
+
if (!isRuntimeErrorOverlay()) {
|
|
37
|
+
hideErrorOverlay();
|
|
38
|
+
}
|
|
33
39
|
if (window.__HMR_MANIFEST__) {
|
|
34
40
|
window.__HMR_MANIFEST__ = message.data.manifest;
|
|
35
41
|
}
|
|
@@ -5,6 +5,7 @@ import '../../../types/client'; // Window global type extensions
|
|
|
5
5
|
|
|
6
6
|
import { hmrState } from '../../../types/client';
|
|
7
7
|
import { detectCurrentFramework } from './frameworkDetect';
|
|
8
|
+
import { hideErrorOverlay, showErrorOverlay } from './errorOverlay';
|
|
8
9
|
import { handleReactUpdate } from './handlers/react';
|
|
9
10
|
import { handleHTMLUpdate, handleScriptUpdate } from './handlers/html';
|
|
10
11
|
import { handleHTMXUpdate } from './handlers/htmx';
|
|
@@ -34,6 +35,31 @@ if (typeof window !== 'undefined') {
|
|
|
34
35
|
}
|
|
35
36
|
}
|
|
36
37
|
|
|
38
|
+
// Catch uncaught runtime errors and show the error overlay
|
|
39
|
+
window.addEventListener('error', function (evt) {
|
|
40
|
+
if (!evt.error) return;
|
|
41
|
+
showErrorOverlay({
|
|
42
|
+
framework: detectCurrentFramework() || undefined,
|
|
43
|
+
kind: 'runtime',
|
|
44
|
+
message:
|
|
45
|
+
evt.error instanceof Error
|
|
46
|
+
? evt.error.stack || evt.error.message
|
|
47
|
+
: String(evt.error)
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
window.addEventListener('unhandledrejection', function (evt) {
|
|
52
|
+
if (!evt.reason) return;
|
|
53
|
+
showErrorOverlay({
|
|
54
|
+
framework: detectCurrentFramework() || undefined,
|
|
55
|
+
kind: 'runtime',
|
|
56
|
+
message:
|
|
57
|
+
evt.reason instanceof Error
|
|
58
|
+
? evt.reason.stack || evt.reason.message
|
|
59
|
+
: String(evt.reason)
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
|
|
37
63
|
// Prevent multiple WebSocket connections
|
|
38
64
|
if (!(window.__HMR_WS__ && window.__HMR_WS__.readyState === WebSocket.OPEN)) {
|
|
39
65
|
// Determine WebSocket URL
|
|
@@ -105,6 +131,7 @@ if (!(window.__HMR_WS__ && window.__HMR_WS__.readyState === WebSocket.OPEN)) {
|
|
|
105
131
|
break;
|
|
106
132
|
|
|
107
133
|
case 'module-update':
|
|
134
|
+
hideErrorOverlay();
|
|
108
135
|
handleModuleUpdate(message);
|
|
109
136
|
break;
|
|
110
137
|
|
|
@@ -113,22 +140,27 @@ if (!(window.__HMR_WS__ && window.__HMR_WS__.readyState === WebSocket.OPEN)) {
|
|
|
113
140
|
break;
|
|
114
141
|
|
|
115
142
|
case 'script-update':
|
|
143
|
+
hideErrorOverlay();
|
|
116
144
|
handleScriptUpdate(message);
|
|
117
145
|
break;
|
|
118
146
|
|
|
119
147
|
case 'html-update':
|
|
148
|
+
hideErrorOverlay();
|
|
120
149
|
handleHTMLUpdate(message);
|
|
121
150
|
break;
|
|
122
151
|
|
|
123
152
|
case 'htmx-update':
|
|
153
|
+
hideErrorOverlay();
|
|
124
154
|
handleHTMXUpdate(message);
|
|
125
155
|
break;
|
|
126
156
|
|
|
127
157
|
case 'svelte-update':
|
|
158
|
+
hideErrorOverlay();
|
|
128
159
|
handleSvelteUpdate(message);
|
|
129
160
|
break;
|
|
130
161
|
|
|
131
162
|
case 'vue-update':
|
|
163
|
+
hideErrorOverlay();
|
|
132
164
|
handleVueUpdate(message);
|
|
133
165
|
break;
|
|
134
166
|
|
|
@@ -195,6 +227,7 @@ if (!(window.__HMR_WS__ && window.__HMR_WS__.readyState === WebSocket.OPEN)) {
|
|
|
195
227
|
if (hmrState.pingInterval) clearInterval(hmrState.pingInterval);
|
|
196
228
|
if (hmrState.reconnectTimeout)
|
|
197
229
|
clearTimeout(hmrState.reconnectTimeout);
|
|
230
|
+
|
|
198
231
|
return;
|
|
199
232
|
}
|
|
200
233
|
|
package/dist/index.js
CHANGED
|
@@ -959,6 +959,7 @@ var devClientDir3 = (() => {
|
|
|
959
959
|
return fromSource;
|
|
960
960
|
return resolve3(import.meta.dir, "./dev/client");
|
|
961
961
|
})();
|
|
962
|
+
var errorOverlayPath = join3(devClientDir3, "errorOverlay.ts").replace(/\\/g, "/");
|
|
962
963
|
var hmrClientPath3 = join3(devClientDir3, "hmrClient.ts").replace(/\\/g, "/");
|
|
963
964
|
var refreshSetupPath = join3(devClientDir3, "reactRefreshSetup.ts").replace(/\\/g, "/");
|
|
964
965
|
var generateReactIndexFiles = async (reactPagesDirectory, reactIndexesDirectory, isDev = false) => {
|
|
@@ -976,13 +977,55 @@ var generateReactIndexFiles = async (reactPagesDirectory, reactIndexesDirectory,
|
|
|
976
977
|
`window.__HMR_FRAMEWORK__ = "react";`,
|
|
977
978
|
`window.__REACT_COMPONENT_KEY__ = "${componentName}Index";`,
|
|
978
979
|
`import '${refreshSetupPath}';`,
|
|
979
|
-
`import '${hmrClientPath3}'
|
|
980
|
+
`import '${hmrClientPath3}';`,
|
|
981
|
+
`import { showErrorOverlay, hideErrorOverlay } from '${errorOverlayPath}';
|
|
982
|
+
`
|
|
983
|
+
] : [];
|
|
984
|
+
const reactImports = isDev ? [
|
|
985
|
+
`import { hydrateRoot, createRoot } from 'react-dom/client';`,
|
|
986
|
+
`import { createElement, Component } from 'react';`
|
|
987
|
+
] : [
|
|
988
|
+
`import { hydrateRoot, createRoot } from 'react-dom/client';`,
|
|
989
|
+
`import { createElement } from 'react';`
|
|
990
|
+
];
|
|
991
|
+
const errorBoundaryDef = isDev ? [
|
|
992
|
+
`
|
|
993
|
+
// Dev-only Error Boundary to catch React render errors`,
|
|
994
|
+
`class ErrorBoundary extends Component {`,
|
|
995
|
+
` constructor(props) {`,
|
|
996
|
+
` super(props);`,
|
|
997
|
+
` this.state = { hasError: false };`,
|
|
998
|
+
` window.__ERROR_BOUNDARY__ = this;`,
|
|
999
|
+
` }`,
|
|
1000
|
+
` static getDerivedStateFromError() {`,
|
|
1001
|
+
` return { hasError: true };`,
|
|
1002
|
+
` }`,
|
|
1003
|
+
` componentDidCatch(error) {`,
|
|
1004
|
+
` showErrorOverlay({`,
|
|
1005
|
+
` framework: 'react',`,
|
|
1006
|
+
` kind: 'runtime',`,
|
|
1007
|
+
` message: error && error.stack ? error.stack : String(error)`,
|
|
1008
|
+
` });`,
|
|
1009
|
+
` }`,
|
|
1010
|
+
` componentDidUpdate(prevProps, prevState) {`,
|
|
1011
|
+
` if (prevState.hasError && !this.state.hasError) {`,
|
|
1012
|
+
` hideErrorOverlay();`,
|
|
1013
|
+
` }`,
|
|
1014
|
+
` }`,
|
|
1015
|
+
` reset() {`,
|
|
1016
|
+
` this.setState({ hasError: false });`,
|
|
1017
|
+
` }`,
|
|
1018
|
+
` render() {`,
|
|
1019
|
+
` if (this.state.hasError) return null;`,
|
|
1020
|
+
``,
|
|
1021
|
+
` return this.props.children;`,
|
|
1022
|
+
` }`,
|
|
1023
|
+
`}
|
|
980
1024
|
`
|
|
981
1025
|
] : [];
|
|
982
1026
|
const content = [
|
|
983
1027
|
...hmrPreamble,
|
|
984
|
-
|
|
985
|
-
`import { createElement } from 'react';`,
|
|
1028
|
+
...reactImports,
|
|
986
1029
|
`import type { ComponentType } from 'react'`,
|
|
987
1030
|
`import { ${componentName} } from '../pages/${componentName}';
|
|
988
1031
|
`,
|
|
@@ -996,6 +1039,7 @@ var generateReactIndexFiles = async (reactPagesDirectory, reactIndexesDirectory,
|
|
|
996
1039
|
` }`,
|
|
997
1040
|
`}
|
|
998
1041
|
`,
|
|
1042
|
+
...errorBoundaryDef,
|
|
999
1043
|
`// Hydration with error handling and fallback`,
|
|
1000
1044
|
`const isDev = ${isDev};`,
|
|
1001
1045
|
`const componentPath = '../pages/${componentName}';
|
|
@@ -1070,7 +1114,7 @@ var generateReactIndexFiles = async (reactPagesDirectory, reactIndexesDirectory,
|
|
|
1070
1114
|
`,
|
|
1071
1115
|
` // Render into the same root container when falling back to client-only`,
|
|
1072
1116
|
` const root = createRoot(container);`,
|
|
1073
|
-
` root.render(createElement(${componentName}, mergedProps));`,
|
|
1117
|
+
` root.render(${isDev ? `createElement(ErrorBoundary, null, createElement(${componentName}, mergedProps))` : `createElement(${componentName}, mergedProps)`});`,
|
|
1074
1118
|
` window.__REACT_ROOT__ = root;`,
|
|
1075
1119
|
` window.__HMR_CLIENT_ONLY_MODE__ = true;`,
|
|
1076
1120
|
` } catch (fallbackError) {`,
|
|
@@ -1116,7 +1160,7 @@ var generateReactIndexFiles = async (reactPagesDirectory, reactIndexesDirectory,
|
|
|
1116
1160
|
` // Use onRecoverableError to catch hydration errors (React 19)`,
|
|
1117
1161
|
` root = hydrateRoot(`,
|
|
1118
1162
|
` container,`,
|
|
1119
|
-
` createElement(${componentName}, mergedProps),`,
|
|
1163
|
+
` ${isDev ? `createElement(ErrorBoundary, null, createElement(${componentName}, mergedProps))` : `createElement(${componentName}, mergedProps)`},`,
|
|
1120
1164
|
` {`,
|
|
1121
1165
|
` onRecoverableError: (error) => {`,
|
|
1122
1166
|
` // Check if this is a hydration error (isHydrationError filters out whitespace-only head mismatches)`,
|
|
@@ -2886,7 +2930,6 @@ var triggerRebuild = async (state, config, onRebuildComplete, filesToRebuild) =>
|
|
|
2886
2930
|
options: {
|
|
2887
2931
|
...config.options,
|
|
2888
2932
|
injectHMR: true,
|
|
2889
|
-
preserveIntermediateFiles: true,
|
|
2890
2933
|
throwOnError: true
|
|
2891
2934
|
}
|
|
2892
2935
|
});
|
|
@@ -3322,8 +3365,7 @@ var devBuild = async (config) => {
|
|
|
3322
3365
|
...config,
|
|
3323
3366
|
options: {
|
|
3324
3367
|
...config.options,
|
|
3325
|
-
injectHMR: true
|
|
3326
|
-
preserveIntermediateFiles: true
|
|
3368
|
+
injectHMR: true
|
|
3327
3369
|
}
|
|
3328
3370
|
});
|
|
3329
3371
|
if (!manifest || Object.keys(manifest).length === 0) {
|
|
@@ -3594,5 +3636,5 @@ export {
|
|
|
3594
3636
|
BUN_BUILD_WARNING_SUPPRESSION
|
|
3595
3637
|
};
|
|
3596
3638
|
|
|
3597
|
-
//# debugId=
|
|
3639
|
+
//# debugId=D00BE7A74B5C034564756E2164756E21
|
|
3598
3640
|
//# sourceMappingURL=index.js.map
|