PageSourceSearch

https://www.sitemodify.com/editor/services/modulesManager.js?v=7

js sitemodify.com collected 2026-09-24 18:43:00 UTC 11,694 bytes, 311 lines download raw bytes

1(function (global) {
2    const MODULES_ROOT_MARKER = '/editor/apps/modules';
3    const modules = {};
4    window.loadedExternals = window.loadedExternals || {};
5    let basePromise = null;
6    let manifestFile = null;
7
8    // Environment, resolved once commonProps exists (see resolveEnvironment,
9    // run after waitForCommonProps in init). There is exactly one module
10    // source. Local dev: server.for.resources is the local static server
11    // (localhost:8888), which 302-redirects module and /@vite/client requests
12    // to the group Vite dev server — Vite serves source and injects its own
13    // styles, so there is no manifest. Prod: server.for.resources is blank, so
14    // modules load from common.resources.folder (CDN) and their eager CSS
15    // comes from the build manifest.
16    let isDev = false;
17    let serverName = '';
18    let modulesRoot = '';
19
20    // commonProps is injected by a JSP <script> before this one, but on some
21    // pages/timings it isn't defined yet when this script evaluates. Poll for
22    // it so init never reads an undefined global; resolve (don't hang) after a
23    // cap so a genuinely missing commonProps surfaces as a normal error below.
24    function waitForCommonProps() {
25        return new Promise(function (resolve) {
26            if (typeof commonProps !== 'undefined' && commonProps) {
27                resolve();
28                return;
29            }
30            const startedAt = Date.now();
31            const intervalId = setInterval(function () {
32                if (
33                    (typeof commonProps !== 'undefined' && commonProps) ||
34                    Date.now() - startedAt > 30000
35                ) {
36                    clearInterval(intervalId);
37                    resolve();
38                }
39            }, 20);
40        });
41    }
42
43    function resolveEnvironment() {
44        const serverForResources = commonProps['server.for.resources'];
45        isDev = (serverForResources || '').includes('localhost');
46        serverName =
47            serverForResources || commonProps['common.resources.folder'];
48        modulesRoot = serverName + MODULES_ROOT_MARKER;
49    }
50
51    function loadExternals() {
52        const url = commonProps['externalsUrl'];
53        if (window.loadedExternals[url]) {
54            return Promise.resolve(window.loadedExternals[url]);
55        }
56        return new Promise(function (resolve) {
57            $.ajax({
58                url: url,
59                type: 'GET',
60                dataType: 'script',
61                cache: true,
62                success: function (result) {
63                    window.loadedExternals[url] = result || true;
64                    resolve(result);
65                },
66                error: function (xhr, status, error) {
67                    console.error(
68                        'loading script ' + url + ' failed.',
69                        error
70                    );
71                    resolve();
72                },
73            });
74        });
75    }
76
77    // The consolidated Vite build ships a single manifest at the modules root.
78    // Resolves to the manifest object, or null when there is none (dev, or a
79    // build that still inlines its CSS). Best-effort: never rejects.
80    function fetchManifest() {
81        if(isDev){
82            return Promise.resolve()
83        }
84        return fetch(modulesRoot + '/.vite/manifest-apps.json')
85            .then(function (response) {
86                return response.ok ? response.json() : null;
87            })
88            .then(function (manifest) {
89                manifestFile = manifest;
90            })
91            .catch(function () {
92                return null;
93            });
94    }
95
96    // Vite's HMR client. The static dev server redirects /@vite/client to the
97    // apps Vite dev server (it knows the dynamic port we don't). Loading it
98    // sets up the HMR socket + style hot-swap runtime the dev-transformed
99    // modules expect; deduped with the copy modules import themselves.
100    function loadViteClient() {
101        if(isDev) {
102            return import(serverName + '/@vite/client').catch(function (err) {
103                console.error('Unable to load @vite/client', err);
104            });
105        }
106        return Promise.resolve()
107    }
108
109    function buildModuleUrl(moduleName) {
110        return modulesRoot + '/' + moduleName + '/' + moduleName + '.js';
111    }
112
113    // Modules emit real `.css` files (Vite `cssCodeSplit: true`) instead of
114    // inlining styles into the JS bundle, so `url(...)` assets resolve relative
115    // to the stylesheet. Since we render no HTML, the entry stylesheet has no
116    // <link> — inject the links from the build manifest before the JS import
117    // starts, matching the links-before-script markup of Vite's
118    // backend-integration guide (https://vite.dev/guide/backend-integration).
119    function injectModuleCss(manifest, moduleName) {
120        // Pick this module's entry record by its emitted JS. The group
121        // manifest holds one entry per module, with files relative to the
122        // modules root (`<module>/<module>.js`).
123        const jsFilePath = moduleName + '/' + moduleName + '.js';
124        const entryKey = Object.keys(manifest).find(function (key) {
125            return manifest[key].isEntry && manifest[key].file === jsFilePath;
126        });
127        if (!entryKey) {
128            return;
129        }
130        // CSS owned by dynamic imports is loaded on demand by Vite's preload
131        // helper, so only the entry and its static `imports` are walked here.
132        const cssFiles = [];
133        const pushCss = function (record) {
134            (record.css || []).forEach(function (cssPath) {
135                if (cssFiles.indexOf(cssPath) === -1) {
136                    cssFiles.push(cssPath);
137                }
138            });
139        };
140        pushCss(manifest[entryKey]);
141        // Mirrors `importedChunks()` from the Vite guide: each chunk's
142        // static imports are emitted before the chunk itself.
143        const seen = {};
144        (function collectImported(key) {
145            (manifest[key].imports || []).forEach(function (imported) {
146                if (seen[imported] || !manifest[imported]) {
147                    return;
148                }
149                seen[imported] = true;
150                collectImported(imported);
151                pushCss(manifest[imported]);
152            });
153        })(entryKey);
154        cssFiles.forEach(function (cssPath) {
155            insertStylesheet(modulesRoot + '/' + cssPath, moduleName);
156        });
157    }
158
159    function insertStylesheet(href, moduleName) {
160        if (
161            document.querySelector(
162                'link[rel="stylesheet"][href="' + href + '"]'
163            )
164        ) {
165            return;
166        }
167        const link = document.createElement('link');
168        link.rel = 'stylesheet';
169        link.href = href;
170        link.setAttribute('data-module', moduleName);
171        document.head.appendChild(link);
172    }
173
174    // A failed dynamic import() throws a bare "Failed to fetch dynamically
175    // imported module" TypeError with no HTTP detail — status, content-type
176    // and body are all hidden. Re-request the same URL with fetch() so the
177    // real server response is visible: a 404/500, an HTML error page served
178    // with a JS content-type, a CORS rejection, or a genuine network failure
179    // each surface differently here. Best-effort: never throws.
180    async function probeModuleUrl(url) {
181        if (!url) {
182            return { probeError: 'url not resolved' };
183        }
184        try {
185            const response = await fetch(url, { cache: 'no-store' });
186            let bodySnippet = '';
187            try {
188                bodySnippet = (await response.text()).slice(0, 200);
189            } catch (bodyErr) {
190                bodySnippet = '<unreadable body: ' + bodyErr + '>';
191            }
192            return {
193                status: response.status,
194                statusText: response.statusText,
195                ok: response.ok,
196                type: response.type,
197                redirected: response.redirected,
198                finalUrl: response.url,
199                contentType: response.headers.get('content-type'),
200                bodySnippet: bodySnippet,
201            };
202        } catch (probeErr) {
203            // fetch itself rejected — same failure class as the import
204            // (network down, DNS, CORS). The message distinguishes them.
205            return { probeError: String(probeErr) };
206        }
207    }
208
209    const RETRY_DELAY_MS = 300;
210    const MAX_RETRIES = 3;
211
212    // Chrome, Firefox and Safari each word the same fetch failure differently.
213    const FETCH_IMPORT_ERRORS = [
214        'Failed to fetch dynamically imported module',
215        'error loading dynamically imported module',
216        'Importing a module script failed',
217    ];
218
219    function isFetchImportError(err) {
220        const message = (err && err.message) || '';
221        return FETCH_IMPORT_ERRORS.some(function (wording) {
222            return message.indexOf(wording) !== -1;
223        });
224    }
225
226    function delay(ms) {
227        return new Promise(function (resolve) {
228            setTimeout(resolve, ms);
229        });
230    }
231
232    async function importModule(moduleUrl) {
233        for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {
234            try {
235                return await import(
236                    attempt === 0 ? moduleUrl : moduleUrl + '?retry=' + attempt
237                );
238            } catch (err) {
239                if (!isFetchImportError(err) || attempt === MAX_RETRIES) {
240                    throw err;
241                }
242                await delay(RETRY_DELAY_MS);
243            }
244        }
245    }
246
247    async function getModuleAsync(moduleName) {
248        if (modules[moduleName]) {
249            return modules[moduleName];
250        }
251        let moduleUrl = null;
252        try {
253            await basePromise;
254            if (!isDev && manifestFile) {
255                injectModuleCss(manifestFile, moduleName);
256            }
257            moduleUrl = buildModuleUrl(moduleName);
258            const module = await importModule(moduleUrl);
259            modules[moduleName] = module;
260            return module;
261        } catch (err) {
262            const probe = await probeModuleUrl(moduleUrl);
263            console.error('Error in loading ' + moduleName + " | " + JSON.stringify({
264                moduleName: moduleName,
265                url: moduleUrl,
266                isDev: isDev,
267                serverName: serverName,
268                online:
269                    typeof navigator !== 'undefined' ? navigator.onLine : null,
270                errorName: err && err.name,
271                errorMessage: err && err.message,
272                probe: probe,
273            }), err);
274            throw new Error('Failed to load module ' + moduleName, {
275                cause: err,
276            });
277        }
278    }
279
280    function getModuleSync(moduleName) {
281        return modules[moduleName];
282    }
283
284    function setModule(moduleName, module) {
285        modules[moduleName] = module;
286    }
287
288    (function init() {
289        const loadedModules = window.loadedModules;
290        if (loadedModules) {
291            Object.keys(loadedModules).forEach(function (name) {
292                modules[name] = loadedModules[name];
293            });
294        }
295
296        basePromise = waitForCommonProps().then(function () {
297            resolveEnvironment();
298            return Promise.all([
299                loadExternals(),
300                loadViteClient(),
301                fetchManifest(),
302            ]);
303        });
304    })();
305
306    global.$.modulesManager = {
307        getModuleAsync: getModuleAsync,
308        getModuleSync: getModuleSync,
309        setModule: setModule,
310    };
311})(window);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.