@dev-to/react-loader 0.1.0 → 0.3.0

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.
@@ -1 +1 @@
1
- {"version":3,"file":"ReactLoader.d.ts","sourceRoot":"","sources":["../src/ReactLoader.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ReactLoader.d.ts","sourceRoot":"","sources":["../src/ReactLoader.tsx"],"names":[],"mappings":"AAAA,OAAc,EAQZ,KAAK,SAAS,EACf,MAAM,OAAO,CAAA;AAGd,OAAO,EAML,KAAK,wBAAwB,EAC9B,MAAM,sBAAsB,CAAA;AAkD7B;;GAEG;AAEH,eAAO,MAAM,yBAAyB,iCAA6B,CAAA;AACnE,eAAO,MAAM,qBAAqB,6BAAyB,CAAA;AAyC3D,kCAAkC;AAClC,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,MAAM,EACd,gBAAgB,CAAC,EAAE,MAAM,GACxB,OAAO,CAAC,wBAAwB,CAAC,CAyBnC;AAED,yCAAyC;AACzC,wBAAsB,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,wBAAwB,iBAcxF;AAED;;GAEG;AAEH,MAAM,WAAW,0BAA0B;IACzC,OAAO,EAAE,IAAI,CAAA;IACb,QAAQ,EAAE,MAAM,CAAA;CACjB;AAED,MAAM,WAAW,yBAAyB;IACxC,OAAO,EAAE,KAAK,CAAA;IACd,KAAK,EAAE;QACL,OAAO,EAAE,MAAM,CAAA;QACf,IAAI,EAAE,qBAAqB,GAAG,sBAAsB,CAAA;QACpD,aAAa,CAAC,EAAE,MAAM,CAAA;QACtB,WAAW,CAAC,EAAE,MAAM,CAAA;QACpB,UAAU,CAAC,EAAE;YACX,KAAK,EAAE,MAAM,CAAA;YACb,KAAK,EAAE,MAAM,EAAE,CAAA;SAChB,CAAA;KACF,CAAA;CACF;AAED,MAAM,MAAM,oBAAoB,GAAG,0BAA0B,GAAG,yBAAyB,CAAA;AAEzF;;;GAGG;AACH,wBAAsB,iBAAiB,CACrC,MAAM,EAAE,MAAM,EACd,aAAa,EAAE,MAAM,EACrB,gBAAgB,CAAC,EAAE,MAAM,GACxB,OAAO,CAAC,oBAAoB,CAAC,CAgE/B;AAED;;;GAGG;AACH,wBAAsB,0BAA0B,CAC9C,MAAM,EAAE,MAAM,EACd,aAAa,EAAE,MAAM,EACrB,gBAAgB,CAAC,EAAE,MAAM,GACxB,OAAO,CACR;IAAE,OAAO,EAAE,IAAI,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,GACjC;IAAE,OAAO,EAAE,KAAK,CAAC;IAAC,WAAW,EAAE,gBAAgB,CAAA;CAAE,CACpD,CAgBA;AAYD,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;IAC5B,UAAU,CAAC,EAAE;QACX,KAAK,EAAE,MAAM,CAAA;QACb,KAAK,EAAE,MAAM,EAAE,CAAA;KAChB,CAAA;CACF;AAED,MAAM,WAAW,gBAAgB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAC3F,wFAAwF;IACxF,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,kEAAkE;IAClE,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,oDAAoD;IACpD,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,cAAc,EAAE,CAAC,CAAA;IACjB,OAAO,CAAC,EAAE,SAAS,CAAA;IACnB,mFAAmF;IACnF,aAAa,CAAC,EAAE,gBAAgB,GAAG,IAAI,CAAA;IACvC,sBAAsB;IACtB,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,GAAG,gBAAgB,KAAK,SAAS,CAAA;CAC7D;AA2mBD;;GAEG;AACH,wBAAgB,WAAW,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACrF,KAAK,EAAE,gBAAgB,CAAC,CAAC,CAAC,2CAqD3B"}
package/dist/index.js CHANGED
@@ -34,8 +34,7 @@ function isBridgeContract(value) {
34
34
  const paths = value['paths'];
35
35
  const events = value['events'];
36
36
  if (!isRecord(paths) || 'string' != typeof paths['reactRuntime']) return false;
37
- if (!isRecord(events) || 'string' != typeof events['fullReload']) return false;
38
- return true;
37
+ return !(!isRecord(events) || 'string' != typeof events['fullReload']);
39
38
  }
40
39
  function resolveContract(initModule) {
41
40
  const moduleRecord = isRecord(initModule) ? initModule : {};
@@ -0,0 +1,751 @@
1
+ (function(root, factory) {
2
+ if ('object' == typeof exports && 'object' == typeof module) module.exports = factory(require("React"));
3
+ else if ('function' == typeof define && define.amd) define([
4
+ "React"
5
+ ], factory);
6
+ else if ('object' == typeof exports) exports["DevToReactLoader"] = factory(require("React"));
7
+ else root["DevToReactLoader"] = factory(root["React"]);
8
+ })(globalThis, (__rspack_external_react)=>(()=>{
9
+ "use strict";
10
+ var __webpack_modules__ = {
11
+ react (module1) {
12
+ module1.exports = __rspack_external_react;
13
+ }
14
+ };
15
+ var __webpack_module_cache__ = {};
16
+ function __webpack_require__(moduleId) {
17
+ var cachedModule = __webpack_module_cache__[moduleId];
18
+ if (void 0 !== cachedModule) return cachedModule.exports;
19
+ var module1 = __webpack_module_cache__[moduleId] = {
20
+ exports: {}
21
+ };
22
+ __webpack_modules__[moduleId](module1, module1.exports, __webpack_require__);
23
+ return module1.exports;
24
+ }
25
+ (()=>{
26
+ __webpack_require__.n = (module1)=>{
27
+ var getter = module1 && module1.__esModule ? ()=>module1['default'] : ()=>module1;
28
+ __webpack_require__.d(getter, {
29
+ a: getter
30
+ });
31
+ return getter;
32
+ };
33
+ })();
34
+ (()=>{
35
+ __webpack_require__.d = (exports1, definition)=>{
36
+ for(var key in definition)if (__webpack_require__.o(definition, key) && !__webpack_require__.o(exports1, key)) Object.defineProperty(exports1, key, {
37
+ enumerable: true,
38
+ get: definition[key]
39
+ });
40
+ };
41
+ })();
42
+ (()=>{
43
+ __webpack_require__.o = (obj, prop)=>Object.prototype.hasOwnProperty.call(obj, prop);
44
+ })();
45
+ (()=>{
46
+ __webpack_require__.r = (exports1)=>{
47
+ if ("u" > typeof Symbol && Symbol.toStringTag) Object.defineProperty(exports1, Symbol.toStringTag, {
48
+ value: 'Module'
49
+ });
50
+ Object.defineProperty(exports1, '__esModule', {
51
+ value: true
52
+ });
53
+ };
54
+ })();
55
+ var __webpack_exports__ = {};
56
+ (()=>{
57
+ __webpack_require__.r(__webpack_exports__);
58
+ __webpack_require__.d(__webpack_exports__, {
59
+ resolveReactEntry: ()=>resolveReactEntry,
60
+ loadBridgeContract: ()=>loadBridgeContract,
61
+ DEFAULT_CONTRACT_ENDPOINT: ()=>DEFAULT_CONTRACT_ENDPOINT,
62
+ ensureBridgeInit: ()=>ensureBridgeInit,
63
+ ReactLoader: ()=>ReactLoader,
64
+ DEFAULT_INIT_ENDPOINT: ()=>DEFAULT_INIT_ENDPOINT,
65
+ resolveReactEntryForLoader: ()=>resolveReactEntryForLoader
66
+ });
67
+ var external_React_ = __webpack_require__("react");
68
+ var external_React_default = /*#__PURE__*/ __webpack_require__.n(external_React_);
69
+ const DEV_TO_REACT_NAMESPACE = 'dev_to_react';
70
+ const DEV_TO_REACT_BASE_PATH = `/__${DEV_TO_REACT_NAMESPACE}__`;
71
+ const DEV_TO_REACT_CONTRACT_PATH = `${DEV_TO_REACT_BASE_PATH}/contract.js`;
72
+ const DEV_TO_REACT_INIT_PATH = `${DEV_TO_REACT_BASE_PATH}/init.js`;
73
+ const DEV_TO_REACT_DEBUG_HTML_PATH = `${DEV_TO_REACT_BASE_PATH}/debug.html`;
74
+ function isRecord(value) {
75
+ return 'object' == typeof value && null !== value;
76
+ }
77
+ function unwrapDefault(value) {
78
+ if (!isRecord(value)) return value;
79
+ const defaultValue = value['default'];
80
+ return null != defaultValue ? defaultValue : value;
81
+ }
82
+ function toError(value) {
83
+ return value instanceof Error ? value : new Error(String(value));
84
+ }
85
+ function resolveRemoteRuntime(runtimeModule) {
86
+ const runtimeRecord = isRecord(runtimeModule) ? runtimeModule : {};
87
+ const reactCandidate = runtimeRecord['default'] ?? runtimeRecord['React'] ?? runtimeModule;
88
+ const domCandidate = runtimeRecord['ReactDOMClient'];
89
+ if (!isRecord(reactCandidate) || 'function' != typeof reactCandidate['createElement'] || !isRecord(domCandidate) || 'function' != typeof domCandidate['createRoot']) throw new Error('Invalid React runtime module from dev server.');
90
+ return {
91
+ React: reactCandidate,
92
+ ReactDOMClient: domCandidate
93
+ };
94
+ }
95
+ const DEFAULT_CONTRACT_ENDPOINT = DEV_TO_REACT_CONTRACT_PATH;
96
+ const DEFAULT_INIT_ENDPOINT = DEV_TO_REACT_INIT_PATH;
97
+ function resolveEndpointUrl(origin, endpoint) {
98
+ if (endpoint.startsWith('http://') || endpoint.startsWith('https://')) return endpoint;
99
+ if (endpoint.startsWith('/')) return `${origin}${endpoint}`;
100
+ return `${origin}/${endpoint}`;
101
+ }
102
+ function isBridgeContract(value) {
103
+ if (!isRecord(value)) return false;
104
+ const paths = value['paths'];
105
+ const events = value['events'];
106
+ if (!isRecord(paths) || 'string' != typeof paths['reactRuntime']) return false;
107
+ return !(!isRecord(events) || 'string' != typeof events['fullReload']);
108
+ }
109
+ function resolveContract(initModule) {
110
+ const moduleRecord = isRecord(initModule) ? initModule : {};
111
+ const contractCandidate = moduleRecord['DEV_TO_REACT_CONTRACT'] ?? moduleRecord['default'] ?? null;
112
+ if (!contractCandidate) throw new Error('Dev server contract not found. Please ensure `@dev-to/react-plugin` (devToReactPlugin) is enabled in the Vite dev server.');
113
+ if (!isBridgeContract(contractCandidate)) throw new Error('Invalid dev server contract.');
114
+ return contractCandidate;
115
+ }
116
+ const nativeImport = new Function('url', 'return import(url)');
117
+ const contractCache = new Map();
118
+ const initCache = new Map();
119
+ async function loadBridgeContract(origin, contractEndpoint) {
120
+ const endpoint = contractEndpoint || DEFAULT_CONTRACT_ENDPOINT;
121
+ const initUrl = resolveEndpointUrl(origin, endpoint);
122
+ if (contractCache.has(initUrl)) return contractCache.get(initUrl);
123
+ const p = nativeImport(initUrl).then((m)=>resolveContract(m)).catch(async (e)=>{
124
+ contractCache.delete(initUrl);
125
+ const err = e instanceof Error ? e : new Error(String(e));
126
+ if (err.message.includes('Failed to fetch')) try {
127
+ const resp = await fetch(initUrl, {
128
+ method: 'HEAD'
129
+ }).catch(()=>null);
130
+ if (resp) err.statusCode = resp.status;
131
+ } catch {}
132
+ throw err;
133
+ });
134
+ contractCache.set(initUrl, p);
135
+ return p;
136
+ }
137
+ async function ensureBridgeInit(origin, contract) {
138
+ const initPath = contract?.paths?.initClient || DEFAULT_INIT_ENDPOINT;
139
+ const initUrl = resolveEndpointUrl(origin, initPath);
140
+ if (initCache.has(initUrl)) return initCache.get(initUrl);
141
+ const p = nativeImport(initUrl).then(()=>void 0).catch((e)=>{
142
+ initCache.delete(initUrl);
143
+ throw e instanceof Error ? e : new Error(String(e));
144
+ });
145
+ initCache.set(initUrl, p);
146
+ return p;
147
+ }
148
+ async function resolveReactEntry(origin, componentName, contractEndpoint) {
149
+ try {
150
+ const contract = await loadBridgeContract(origin, contractEndpoint);
151
+ const dev = contract?.dev || {};
152
+ const componentMap = dev.componentMap || {};
153
+ const entry = componentMap[componentName] || componentMap['*'];
154
+ if (!entry) {
155
+ const errorMessage = `Component "${componentName}" not found in devComponentMap`;
156
+ const isWildcardMode = !!componentMap['*'];
157
+ const errorReason = isWildcardMode ? `The component "${componentName}" is not configured, and the wildcard fallback is also missing or invalid.` : `The component "${componentName}" is not configured in devComponentMap. Please add it to your Vite configuration.`;
158
+ return {
159
+ success: false,
160
+ error: {
161
+ message: errorMessage,
162
+ type: 'COMPONENT_NOT_FOUND',
163
+ componentName,
164
+ errorReason,
165
+ setupGuide: {
166
+ title: 'Setup Guide',
167
+ steps: [
168
+ "import { devToReactPlugin } from '@dev-to/react-plugin'",
169
+ '',
170
+ "// Option 1: Shorthand (Default)",
171
+ `devToReactPlugin('${componentName}')`,
172
+ '',
173
+ "// Option 2: Explicit Mapping",
174
+ "devToReactPlugin({",
175
+ ` '${componentName}': '/', // Default entry`,
176
+ " 'Other': 'src/Card.tsx' // Specific file",
177
+ "})"
178
+ ]
179
+ }
180
+ }
181
+ };
182
+ }
183
+ const entryUrl = entry.startsWith('http://') || entry.startsWith('https://') ? entry : `${origin}${entry.startsWith('/') ? '' : '/'}${entry}`;
184
+ return {
185
+ success: true,
186
+ entryUrl
187
+ };
188
+ } catch (e) {
189
+ const errorMessage = e instanceof Error ? e.message : String(e);
190
+ return {
191
+ success: false,
192
+ error: {
193
+ message: errorMessage,
194
+ type: 'CONTRACT_LOAD_FAILED'
195
+ }
196
+ };
197
+ }
198
+ }
199
+ async function resolveReactEntryForLoader(origin, componentName, contractEndpoint) {
200
+ const r = await resolveReactEntry(origin, componentName, contractEndpoint);
201
+ if (r.success) return r;
202
+ const e = r.error;
203
+ return {
204
+ success: false,
205
+ loaderError: {
206
+ message: e.message,
207
+ origin,
208
+ componentName: e.componentName || componentName,
209
+ type: e.type,
210
+ errorReason: e.errorReason,
211
+ setupGuide: e.setupGuide
212
+ }
213
+ };
214
+ }
215
+ function safeLocationHref() {
216
+ if ("u" < typeof window) return '';
217
+ try {
218
+ return window.location.href;
219
+ } catch {
220
+ return '';
221
+ }
222
+ }
223
+ function safeOrigin() {
224
+ if ("u" < typeof window) return '';
225
+ try {
226
+ return window.location.origin;
227
+ } catch {
228
+ return '';
229
+ }
230
+ }
231
+ function getOriginFromFinalJsUrl(finalJsUrl) {
232
+ let origin = '';
233
+ try {
234
+ const urlParam = finalJsUrl.match(/url=([^&]+)/)?.[1] || '';
235
+ const decoded = urlParam ? decodeURIComponent(urlParam) : finalJsUrl;
236
+ const parsed = decoded.startsWith('http') ? new URL(decoded) : new URL(decoded, safeLocationHref() || 'http://localhost');
237
+ origin = parsed.origin;
238
+ } catch {
239
+ origin = safeOrigin();
240
+ }
241
+ return origin;
242
+ }
243
+ function useReactLoader(options) {
244
+ const { url: directUrl, origin, name, componentProps, contractEndpoint } = options;
245
+ const containerRef = (0, external_React_.useRef)(null);
246
+ const rootRef = (0, external_React_.useRef)(null);
247
+ const runtimeRef = (0, external_React_.useRef)(null);
248
+ const cardRef = (0, external_React_.useRef)(null);
249
+ const fullReloadListenerRef = (0, external_React_.useRef)(null);
250
+ const propsRef = (0, external_React_.useRef)(componentProps);
251
+ propsRef.current = componentProps;
252
+ const [isReady, setIsReady] = (0, external_React_.useState)(false);
253
+ const [error, setError] = (0, external_React_.useState)(null);
254
+ const [version, setVersion] = (0, external_React_.useState)(0);
255
+ const [resolvedUrl, setResolvedUrl] = (0, external_React_.useState)(directUrl);
256
+ (0, external_React_.useEffect)(()=>{
257
+ if (directUrl) {
258
+ setResolvedUrl(directUrl);
259
+ setError(null);
260
+ return;
261
+ }
262
+ if (!origin || !name) {
263
+ if (!directUrl && (origin || name)) setError(new Error('Missing dev server origin or component name for resolution.'));
264
+ return;
265
+ }
266
+ let cancelled = false;
267
+ setIsReady(false);
268
+ setError(null);
269
+ resolveReactEntryForLoader(origin, name, contractEndpoint).then((res)=>{
270
+ if (cancelled) return;
271
+ if (true === res.success) setResolvedUrl(res.entryUrl);
272
+ else setError(res.loaderError);
273
+ });
274
+ return ()=>{
275
+ cancelled = true;
276
+ };
277
+ }, [
278
+ directUrl,
279
+ origin,
280
+ name,
281
+ contractEndpoint
282
+ ]);
283
+ const ensureFullReloadListener = (0, external_React_.useCallback)((eventName)=>{
284
+ if (!eventName) return;
285
+ if ("u" < typeof window) return;
286
+ const { current } = fullReloadListenerRef;
287
+ if (current?.eventName === eventName) return;
288
+ if (current) window.removeEventListener(current.eventName, current.handler);
289
+ const handler = ()=>{
290
+ setVersion((v)=>v + 1);
291
+ };
292
+ window.addEventListener(eventName, handler);
293
+ fullReloadListenerRef.current = {
294
+ eventName,
295
+ handler
296
+ };
297
+ }, []);
298
+ (0, external_React_.useEffect)(()=>()=>{
299
+ if ("u" < typeof window) return;
300
+ const { current } = fullReloadListenerRef;
301
+ if (current) window.removeEventListener(current.eventName, current.handler);
302
+ }, []);
303
+ const renderViteRoot = (0, external_React_.useCallback)(()=>{
304
+ const runtime = runtimeRef.current;
305
+ const Card = cardRef.current;
306
+ if (!runtime || !Card) return;
307
+ if (!containerRef.current) return;
308
+ if (!rootRef.current) rootRef.current = runtime.ReactDOMClient.createRoot(containerRef.current);
309
+ rootRef.current.render(runtime.React.createElement(Card, propsRef.current));
310
+ }, []);
311
+ const loadViteComponent = (0, external_React_.useCallback)(async (entryUrl, exportName, currentVersion)=>{
312
+ if (!entryUrl) throw new Error('Not found entry url.');
313
+ const originFromUrl = getOriginFromFinalJsUrl(entryUrl);
314
+ const connector = entryUrl.includes('?') ? '&' : '?';
315
+ const jsUrlWithParam = currentVersion > 0 ? `${entryUrl}${connector}v=${currentVersion}` : entryUrl;
316
+ try {
317
+ const contract = await loadBridgeContract(originFromUrl, contractEndpoint);
318
+ await ensureBridgeInit(originFromUrl, contract);
319
+ ensureFullReloadListener(contract.events.fullReload);
320
+ const runtimeModule = await nativeImport(`${originFromUrl}${contract.paths.reactRuntime}`);
321
+ const runtime = resolveRemoteRuntime(runtimeModule);
322
+ const moduleNs = await nativeImport(jsUrlWithParam);
323
+ const moduleRecord = isRecord(moduleNs) ? moduleNs : {};
324
+ const exportCandidate = exportName ? moduleRecord[exportName] : void 0;
325
+ const candidate = exportName ? exportCandidate ?? moduleRecord['default'] ?? moduleNs : moduleRecord['default'] ?? moduleNs;
326
+ const Card = unwrapDefault(candidate);
327
+ if (Card) return {
328
+ Card: Card,
329
+ runtime
330
+ };
331
+ throw new Error('Vite Dev Component Load Fail: Component not found in module.');
332
+ } catch (e) {
333
+ const err = toError(e);
334
+ if (err.message.includes('Failed to fetch')) try {
335
+ const resp = await fetch(jsUrlWithParam, {
336
+ method: 'HEAD'
337
+ }).catch(()=>null);
338
+ if (resp) err.statusCode = resp.status;
339
+ } catch {}
340
+ throw err;
341
+ }
342
+ }, [
343
+ contractEndpoint,
344
+ ensureFullReloadListener
345
+ ]);
346
+ (0, external_React_.useEffect)(()=>{
347
+ if (!resolvedUrl) return;
348
+ let cancelled = false;
349
+ setIsReady(false);
350
+ if (error instanceof Error) setError(null);
351
+ loadViteComponent(resolvedUrl, name, version).then(({ Card, runtime })=>{
352
+ if (cancelled) return;
353
+ runtimeRef.current = runtime;
354
+ cardRef.current = Card;
355
+ setIsReady(true);
356
+ renderViteRoot();
357
+ }).catch((err)=>{
358
+ if (cancelled) return;
359
+ setError(err instanceof Error ? err : new Error(String(err)));
360
+ setIsReady(false);
361
+ });
362
+ return ()=>{
363
+ cancelled = true;
364
+ };
365
+ }, [
366
+ loadViteComponent,
367
+ renderViteRoot,
368
+ resolvedUrl,
369
+ name,
370
+ version,
371
+ error
372
+ ]);
373
+ (0, external_React_.useEffect)(()=>{
374
+ if (isReady) renderViteRoot();
375
+ });
376
+ (0, external_React_.useEffect)(()=>()=>{
377
+ try {
378
+ rootRef.current?.unmount?.();
379
+ } catch {}
380
+ rootRef.current = null;
381
+ }, []);
382
+ (0, external_React_.useEffect)(()=>{
383
+ if (error) {
384
+ try {
385
+ rootRef.current?.unmount?.();
386
+ } catch {}
387
+ rootRef.current = null;
388
+ }
389
+ }, [
390
+ error
391
+ ]);
392
+ return {
393
+ containerRef,
394
+ isReady,
395
+ error,
396
+ resolvedUrl
397
+ };
398
+ }
399
+ function InlineViteErrorView(props) {
400
+ const { errorMessage, currentOrigin, componentName, setupGuide, statusCode } = props;
401
+ const isComponentNotFound = errorMessage.includes('not found in devComponentMap');
402
+ const isFetchError = errorMessage.includes('Failed to fetch dynamically imported module');
403
+ const isInternalBridgeFile = errorMessage.includes(DEV_TO_REACT_BASE_PATH) || errorMessage.includes(DEV_TO_REACT_NAMESPACE);
404
+ const isContractError = errorMessage.includes('Vite dev contract not found') || errorMessage.includes('Failed to load Vite bridge contract') || errorMessage.includes('Failed to load contract from') || isFetchError && isInternalBridgeFile;
405
+ const isModuleFetchError = isFetchError && !isInternalBridgeFile;
406
+ let title = 'Vite Server Error';
407
+ let typeLabel = statusCode?.toString() || '500';
408
+ if (isComponentNotFound) {
409
+ title = 'Component Not Configured';
410
+ typeLabel = '412';
411
+ } else if (isModuleFetchError) {
412
+ title = 'Vite Module Not Found';
413
+ typeLabel = statusCode?.toString() || '404';
414
+ } else if (isContractError) {
415
+ title = 'Vite Server Connection Failed';
416
+ typeLabel = statusCode?.toString() || '503';
417
+ }
418
+ const theme = isContractError ? 'urgent' : 'warning';
419
+ const palette = 'urgent' === theme ? {
420
+ bg: 'linear-gradient(135deg, #fef2f2 0%, #fff5f5 100%)',
421
+ border: '#fecaca',
422
+ title: '#dc2626',
423
+ accent: '#dc2626',
424
+ pillBg: 'rgba(220, 38, 38, 0.05)',
425
+ pillBorder: 'rgba(220, 38, 38, 0.2)',
426
+ tipsBg: '#fffbeb',
427
+ tipsBorder: '#fde68a',
428
+ tipsText: '#92400e'
429
+ } : {
430
+ bg: 'linear-gradient(135deg, #fffbeb 0%, #fffdf2 100%)',
431
+ border: '#fde68a',
432
+ title: '#d97706',
433
+ accent: '#d97706',
434
+ pillBg: 'rgba(217, 119, 6, 0.05)',
435
+ pillBorder: 'rgba(217, 119, 6, 0.2)',
436
+ tipsBg: '#fffbeb',
437
+ tipsBorder: '#fde68a',
438
+ tipsText: '#92400e'
439
+ };
440
+ const styles = {
441
+ container: {
442
+ padding: 12,
443
+ borderRadius: 8,
444
+ background: palette.bg,
445
+ border: `1px solid ${palette.border}`,
446
+ boxShadow: '0 1px 4px rgba(0,0,0,0.06)'
447
+ },
448
+ header: {
449
+ display: 'flex',
450
+ alignItems: 'center',
451
+ gap: 8,
452
+ marginBottom: 10,
453
+ paddingBottom: 8,
454
+ borderBottom: `1px solid ${palette.border}66`
455
+ },
456
+ icon: {
457
+ fontSize: 18,
458
+ fontFamily: '"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji", sans-serif'
459
+ },
460
+ title: {
461
+ fontSize: 12,
462
+ fontWeight: 700,
463
+ color: palette.title,
464
+ display: 'flex',
465
+ alignItems: 'center',
466
+ gap: 6
467
+ },
468
+ typeTag: {
469
+ fontSize: 11,
470
+ fontWeight: 700,
471
+ padding: '1px 6px',
472
+ borderRadius: 999,
473
+ border: `1px solid ${palette.pillBorder}`,
474
+ background: palette.pillBg,
475
+ color: palette.accent,
476
+ lineHeight: 1
477
+ },
478
+ content: {
479
+ display: 'flex',
480
+ flexDirection: 'column',
481
+ gap: 8
482
+ },
483
+ message: {
484
+ fontSize: 9,
485
+ color: '#991b1b',
486
+ background: '#fee2e2',
487
+ padding: 5,
488
+ borderRadius: 6,
489
+ borderLeft: `1px solid ${palette.accent}`,
490
+ whiteSpace: 'pre-wrap',
491
+ fontFamily: 'monospace',
492
+ wordBreak: 'break-word'
493
+ },
494
+ info: {
495
+ background: '#fff',
496
+ padding: '8px 10px',
497
+ borderRadius: 6,
498
+ border: `1px solid ${palette.border}`,
499
+ display: 'flex',
500
+ flexDirection: 'column',
501
+ gap: 6
502
+ },
503
+ infoRow: {
504
+ display: 'flex',
505
+ gap: 8,
506
+ alignItems: 'center'
507
+ },
508
+ label: {
509
+ fontSize: 11,
510
+ color: '#64748b',
511
+ fontWeight: 600,
512
+ width: 110,
513
+ textAlign: 'right'
514
+ },
515
+ value: {
516
+ fontSize: 11,
517
+ color: '#1e293b',
518
+ background: '#f8fafc',
519
+ padding: '3px 6px',
520
+ borderRadius: 4,
521
+ fontFamily: 'monospace',
522
+ border: '1px solid #e2e8f0',
523
+ wordBreak: 'break-word',
524
+ flex: 1
525
+ },
526
+ tips: {
527
+ background: palette.tipsBg,
528
+ padding: '8px 10px',
529
+ borderRadius: 6,
530
+ border: `1px solid ${palette.tipsBorder}`
531
+ },
532
+ tipsTitle: {
533
+ fontSize: 12,
534
+ fontWeight: 800,
535
+ color: palette.tipsText,
536
+ marginBottom: 6,
537
+ textAlign: 'center'
538
+ },
539
+ list: {
540
+ padding: 0,
541
+ listStyle: 'none',
542
+ display: 'flex',
543
+ flexDirection: 'column',
544
+ gap: 6
545
+ },
546
+ li: {
547
+ fontSize: 11,
548
+ color: '#78350f'
549
+ },
550
+ code: {
551
+ fontFamily: 'monospace',
552
+ fontSize: 10
553
+ },
554
+ link: {
555
+ color: '#2563eb'
556
+ },
557
+ codeBlock: {
558
+ padding: '10px 12px',
559
+ background: '#1e293b',
560
+ borderRadius: 6,
561
+ border: '1px solid #334155',
562
+ overflowX: 'auto',
563
+ fontSize: 11,
564
+ color: '#e2e8f0',
565
+ fontFamily: 'monospace'
566
+ },
567
+ codeComment: {
568
+ color: '#94a3b8',
569
+ fontStyle: 'italic'
570
+ }
571
+ };
572
+ const debugPanelUrl = `${currentOrigin}${DEV_TO_REACT_DEBUG_HTML_PATH}`;
573
+ const componentNameLabel = componentName || '';
574
+ return /*#__PURE__*/ external_React_default().createElement("div", {
575
+ className: "vdev-container",
576
+ style: styles.container
577
+ }, /*#__PURE__*/ external_React_default().createElement("div", {
578
+ className: "vdev-header",
579
+ style: styles.header
580
+ }, /*#__PURE__*/ external_React_default().createElement("div", {
581
+ className: "vdev-icon",
582
+ style: styles.icon
583
+ }, '\u26A0\uFE0F'), /*#__PURE__*/ external_React_default().createElement("div", {
584
+ className: "vdev-title",
585
+ style: styles.title
586
+ }, /*#__PURE__*/ external_React_default().createElement("span", {
587
+ className: "vdev-type-tag",
588
+ style: styles.typeTag
589
+ }, typeLabel), title)), /*#__PURE__*/ external_React_default().createElement("div", {
590
+ className: "vdev-content",
591
+ style: styles.content
592
+ }, /*#__PURE__*/ external_React_default().createElement("div", {
593
+ className: "vdev-message",
594
+ style: styles.message
595
+ }, errorMessage), /*#__PURE__*/ external_React_default().createElement("div", {
596
+ className: "vdev-info",
597
+ style: styles.info
598
+ }, /*#__PURE__*/ external_React_default().createElement("div", {
599
+ className: "vdev-info-row",
600
+ style: styles.infoRow
601
+ }, /*#__PURE__*/ external_React_default().createElement("span", {
602
+ className: "vdev-label",
603
+ style: styles.label
604
+ }, "Server Address:"), /*#__PURE__*/ external_React_default().createElement("code", {
605
+ className: "vdev-value",
606
+ style: styles.value
607
+ }, currentOrigin)), componentNameLabel ? /*#__PURE__*/ external_React_default().createElement("div", {
608
+ className: "vdev-info-row",
609
+ style: styles.infoRow
610
+ }, /*#__PURE__*/ external_React_default().createElement("span", {
611
+ className: "vdev-label",
612
+ style: styles.label
613
+ }, "Component Name:"), /*#__PURE__*/ external_React_default().createElement("code", {
614
+ className: "vdev-value",
615
+ style: styles.value
616
+ }, componentNameLabel)) : null), /*#__PURE__*/ external_React_default().createElement("div", {
617
+ className: "vdev-tips",
618
+ style: styles.tips
619
+ }, /*#__PURE__*/ external_React_default().createElement("div", {
620
+ className: "vdev-tips-title",
621
+ style: styles.tipsTitle
622
+ }, "Next Steps:"), setupGuide ? /*#__PURE__*/ external_React_default().createElement("pre", {
623
+ className: "vdev-code-block",
624
+ style: styles.codeBlock
625
+ }, setupGuide.steps.map((step, idx)=>{
626
+ const stepKey = `step-${idx}`;
627
+ const commentIdx = step.indexOf('//');
628
+ if (-1 === commentIdx) return /*#__PURE__*/ external_React_default().createElement("div", {
629
+ key: stepKey
630
+ }, step || ' ');
631
+ const codePart = step.substring(0, commentIdx);
632
+ const commentPart = step.substring(commentIdx);
633
+ return /*#__PURE__*/ external_React_default().createElement("div", {
634
+ key: stepKey
635
+ }, /*#__PURE__*/ external_React_default().createElement("span", null, codePart), /*#__PURE__*/ external_React_default().createElement("span", {
636
+ className: "vdev-code-comment",
637
+ style: styles.codeComment
638
+ }, commentPart));
639
+ })) : /*#__PURE__*/ external_React_default().createElement("ul", {
640
+ className: "vdev-list",
641
+ style: styles.list
642
+ }, isModuleFetchError ? /*#__PURE__*/ external_React_default().createElement(external_React_default().Fragment, null, /*#__PURE__*/ external_React_default().createElement("li", {
643
+ className: "vdev-li",
644
+ style: styles.li
645
+ }, /*#__PURE__*/ external_React_default().createElement("b", null, "Verify Path"), ": check the entry mapping for", ' ', /*#__PURE__*/ external_React_default().createElement("code", {
646
+ className: "vdev-code",
647
+ style: styles.code
648
+ }, componentNameLabel || 'this component'), ' ', "in", ' ', /*#__PURE__*/ external_React_default().createElement("code", {
649
+ className: "vdev-code",
650
+ style: styles.code
651
+ }, "vite.config.ts"), "."), /*#__PURE__*/ external_React_default().createElement("li", {
652
+ className: "vdev-li",
653
+ style: styles.li
654
+ }, /*#__PURE__*/ external_React_default().createElement("b", null, "Check Terminal"), ": look at the terminal where", ' ', /*#__PURE__*/ external_React_default().createElement("code", {
655
+ className: "vdev-code",
656
+ style: styles.code
657
+ }, currentOrigin), ' ', "is running for build errors."), /*#__PURE__*/ external_React_default().createElement("li", {
658
+ className: "vdev-li",
659
+ style: styles.li
660
+ }, /*#__PURE__*/ external_React_default().createElement("b", null, "Check Export"), ": ensure the entry module exports a React component (default export recommended).")) : null, isComponentNotFound ? /*#__PURE__*/ external_React_default().createElement(external_React_default().Fragment, null, /*#__PURE__*/ external_React_default().createElement("li", {
661
+ className: "vdev-li",
662
+ style: styles.li
663
+ }, /*#__PURE__*/ external_React_default().createElement("b", null, "Update Config"), ": map", ' ', /*#__PURE__*/ external_React_default().createElement("code", {
664
+ className: "vdev-code",
665
+ style: styles.code
666
+ }, componentNameLabel), ' ', "in", ' ', /*#__PURE__*/ external_React_default().createElement("code", {
667
+ className: "vdev-code",
668
+ style: styles.code
669
+ }, "devComponentMap"), "."), /*#__PURE__*/ external_React_default().createElement("li", {
670
+ className: "vdev-li",
671
+ style: styles.li
672
+ }, /*#__PURE__*/ external_React_default().createElement("b", null, "Wildcard Fallback"), ": add", ' ', /*#__PURE__*/ external_React_default().createElement("code", {
673
+ className: "vdev-code",
674
+ style: styles.code
675
+ }, "'*': '/'"), ' ', "to map all components to the default entry.")) : null, isContractError ? /*#__PURE__*/ external_React_default().createElement(external_React_default().Fragment, null, /*#__PURE__*/ external_React_default().createElement("li", {
676
+ className: "vdev-li",
677
+ style: styles.li
678
+ }, /*#__PURE__*/ external_React_default().createElement("b", null, "Check Server"), ": ensure your Vite server is running at", ' ', /*#__PURE__*/ external_React_default().createElement("code", {
679
+ className: "vdev-code",
680
+ style: styles.code
681
+ }, currentOrigin), "."), /*#__PURE__*/ external_React_default().createElement("li", {
682
+ className: "vdev-li",
683
+ style: styles.li
684
+ }, /*#__PURE__*/ external_React_default().createElement("b", null, "Verify Origin"), ": confirm localStorage key", ' ', /*#__PURE__*/ external_React_default().createElement("code", {
685
+ className: "vdev-code",
686
+ style: styles.code
687
+ }, "VITE_DEV_SERVER_ORIGIN"), ' ', "is set to", ' ', /*#__PURE__*/ external_React_default().createElement("code", {
688
+ className: "vdev-code",
689
+ style: styles.code
690
+ }, currentOrigin), "."), /*#__PURE__*/ external_React_default().createElement("li", {
691
+ className: "vdev-li",
692
+ style: styles.li
693
+ }, /*#__PURE__*/ external_React_default().createElement("b", null, "Open Debug Panel"), ":", ' ', /*#__PURE__*/ external_React_default().createElement("a", {
694
+ className: "vdev-link",
695
+ style: styles.link,
696
+ href: debugPanelUrl,
697
+ target: "_blank",
698
+ rel: "noreferrer"
699
+ }, debugPanelUrl))) : null, isModuleFetchError || isComponentNotFound || isContractError ? null : /*#__PURE__*/ external_React_default().createElement("li", {
700
+ className: "vdev-li",
701
+ style: styles.li
702
+ }, "Open Debug Panel:", ' ', /*#__PURE__*/ external_React_default().createElement("a", {
703
+ className: "vdev-link",
704
+ style: styles.link,
705
+ href: debugPanelUrl,
706
+ target: "_blank",
707
+ rel: "noreferrer"
708
+ }, debugPanelUrl))))));
709
+ }
710
+ function ReactLoader(props) {
711
+ const { url, origin, name, componentProps, contractEndpoint, loading, renderError, externalError } = props;
712
+ const state = useReactLoader({
713
+ url,
714
+ origin,
715
+ name,
716
+ componentProps,
717
+ contractEndpoint
718
+ });
719
+ const defaultLoading = /*#__PURE__*/ external_React_default().createElement("div", null, "Loading...");
720
+ const renderErrorNode = (0, external_React_.useCallback)((err)=>{
721
+ if (renderError) return renderError(err);
722
+ const isLoaderErrorObject = !(err instanceof Error);
723
+ const errorMessage = err.message || String(err);
724
+ const currentOrigin = (isLoaderErrorObject ? err.origin : void 0) || origin || (url ? getOriginFromFinalJsUrl(url) : '');
725
+ const componentName = (isLoaderErrorObject ? err.componentName : void 0) || name;
726
+ const setupGuide = isLoaderErrorObject ? err.setupGuide : void 0;
727
+ const statusCode = isLoaderErrorObject ? err.statusCode : err.statusCode;
728
+ return /*#__PURE__*/ external_React_default().createElement(InlineViteErrorView, {
729
+ errorMessage: errorMessage,
730
+ currentOrigin: currentOrigin,
731
+ componentName: componentName,
732
+ setupGuide: setupGuide,
733
+ statusCode: statusCode
734
+ });
735
+ }, [
736
+ renderError,
737
+ name,
738
+ origin,
739
+ url
740
+ ]);
741
+ if (externalError) return /*#__PURE__*/ external_React_default().createElement(external_React_default().Fragment, null, renderErrorNode(externalError));
742
+ if (state.error) return /*#__PURE__*/ external_React_default().createElement(external_React_default().Fragment, null, renderErrorNode(state.error));
743
+ return /*#__PURE__*/ external_React_default().createElement(external_React_default().Fragment, null, /*#__PURE__*/ external_React_default().createElement("div", {
744
+ ref: state.containerRef,
745
+ className: "vdev-loader-container",
746
+ "data-is": "ReactLoader"
747
+ }), state.isReady ? null : loading ?? defaultLoading);
748
+ }
749
+ })();
750
+ return __webpack_exports__;
751
+ })());
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dev-to/react-loader",
3
- "version": "0.1.0",
3
+ "version": "0.3.0",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -9,7 +9,8 @@
9
9
  ".": {
10
10
  "types": "./dist/index.d.ts",
11
11
  "import": "./dist/index.js"
12
- }
12
+ },
13
+ "./umd": "./dist/index.umd.js"
13
14
  },
14
15
  "files": [
15
16
  "dist"
@@ -28,7 +29,7 @@
28
29
  "access": "public"
29
30
  },
30
31
  "dependencies": {
31
- "@dev-to/react-shared": "0.1.0"
32
+ "@dev-to/react-shared": "0.1.2"
32
33
  },
33
34
  "scripts": {
34
35
  "build": "rslib build",