index.js 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. /*-----------------------------------------------------------------------------
  2. | Copyright (c) Jupyter Development Team.
  3. | Distributed under the terms of the Modified BSD License.
  4. |----------------------------------------------------------------------------*/
  5. import { PageConfig } from '@jupyterlab/coreutils';
  6. // Promise.allSettled polyfill, until our supported browsers implement it
  7. // See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/allSettled
  8. if (Promise.allSettled === undefined) {
  9. Promise.allSettled = promises =>
  10. Promise.all(
  11. promises.map(promise =>
  12. promise
  13. .then(value => ({
  14. status: "fulfilled",
  15. value,
  16. }), reason => ({
  17. status: "rejected",
  18. reason,
  19. }))
  20. )
  21. );
  22. }
  23. import './style.js';
  24. async function createModule(scope, module) {
  25. try {
  26. const factory = await window._JUPYTERLAB[scope].get(module);
  27. return factory();
  28. } catch(e) {
  29. console.warn(`Failed to create module: package: ${scope}; module: ${module}`);
  30. throw e;
  31. }
  32. }
  33. /**
  34. * The main entry point for the application.
  35. */
  36. export async function main() {
  37. // Handle a browser test.
  38. // Set up error handling prior to loading extensions.
  39. var browserTest = PageConfig.getOption('browserTest');
  40. if (browserTest.toLowerCase() === 'true') {
  41. var el = document.createElement('div');
  42. el.id = 'browserTest';
  43. document.body.appendChild(el);
  44. el.textContent = '[]';
  45. el.style.display = 'none';
  46. var errors = [];
  47. var reported = false;
  48. var timeout = 25000;
  49. var report = function() {
  50. if (reported) {
  51. return;
  52. }
  53. reported = true;
  54. el.className = 'completed';
  55. }
  56. window.onerror = function(msg, url, line, col, error) {
  57. errors.push(String(error));
  58. el.textContent = JSON.stringify(errors)
  59. };
  60. console.error = function(message) {
  61. errors.push(String(message));
  62. el.textContent = JSON.stringify(errors)
  63. };
  64. }
  65. var JupyterLab = require('@jupyterlab/application').JupyterLab;
  66. var disabled = [];
  67. var deferred = [];
  68. var ignorePlugins = [];
  69. var register = [];
  70. const federatedExtensionPromises = [];
  71. const federatedMimeExtensionPromises = [];
  72. const federatedStylePromises = [];
  73. // Start initializing the federated extensions
  74. const extensions = JSON.parse(
  75. PageConfig.getOption('federated_extensions')
  76. );
  77. const queuedFederated = [];
  78. extensions.forEach(data => {
  79. if (data.extension) {
  80. queuedFederated.push(data.name);
  81. federatedExtensionPromises.push(createModule(data.name, data.extension));
  82. }
  83. if (data.mimeExtension) {
  84. queuedFederated.push(data.name);
  85. federatedMimeExtensionPromises.push(createModule(data.name, data.mimeExtension));
  86. }
  87. if (data.style) {
  88. federatedStylePromises.push(createModule(data.name, data.style));
  89. }
  90. });
  91. /**
  92. * Iterate over active plugins in an extension.
  93. *
  94. * #### Notes
  95. * This also populates the disabled, deferred, and ignored arrays.
  96. */
  97. function* activePlugins(extension) {
  98. // Handle commonjs or es2015 modules
  99. let exports;
  100. if (extension.hasOwnProperty('__esModule')) {
  101. exports = extension.default;
  102. } else {
  103. // CommonJS exports.
  104. exports = extension;
  105. }
  106. let plugins = Array.isArray(exports) ? exports : [exports];
  107. for (let plugin of plugins) {
  108. if (PageConfig.Extension.isDisabled(plugin.id)) {
  109. disabled.push(plugin.id);
  110. continue;
  111. }
  112. if (PageConfig.Extension.isDeferred(plugin.id)) {
  113. deferred.push(plugin.id);
  114. ignorePlugins.push(plugin.id);
  115. }
  116. yield plugin;
  117. }
  118. }
  119. // Handle the registered mime extensions.
  120. const mimeExtensions = [];
  121. {{#each jupyterlab_mime_extensions}}
  122. if (!queuedFederated.includes('{{@key}}')) {
  123. try {
  124. let ext = require('{{@key}}{{#if this}}/{{this}}{{/if}}');
  125. for (let plugin of activePlugins(ext)) {
  126. mimeExtensions.push(plugin);
  127. }
  128. } catch (e) {
  129. console.error(e);
  130. }
  131. }
  132. {{/each}}
  133. // Add the federated mime extensions.
  134. const federatedMimeExtensions = await Promise.allSettled(federatedMimeExtensionPromises);
  135. federatedMimeExtensions.forEach(p => {
  136. if (p.status === "fulfilled") {
  137. for (let plugin of activePlugins(p.value)) {
  138. mimeExtensions.push(plugin);
  139. }
  140. } else {
  141. console.error(p.reason);
  142. }
  143. });
  144. // Handled the registered standard extensions.
  145. {{#each jupyterlab_extensions}}
  146. if (!queuedFederated.includes('{{@key}}')) {
  147. try {
  148. let ext = require('{{@key}}{{#if this}}/{{this}}{{/if}}');
  149. for (let plugin of activePlugins(ext)) {
  150. register.push(plugin);
  151. }
  152. } catch (e) {
  153. console.error(e);
  154. }
  155. }
  156. {{/each}}
  157. // Add the federated extensions.
  158. const federatedExtensions = await Promise.allSettled(federatedExtensionPromises);
  159. federatedExtensions.forEach(p => {
  160. if (p.status === "fulfilled") {
  161. for (let plugin of activePlugins(p.value)) {
  162. register.push(plugin);
  163. }
  164. } else {
  165. console.error(p.reason);
  166. }
  167. });
  168. // Load all federated component styles and log errors for any that do not
  169. (await Promise.allSettled(federatedStylePromises)).filter(({status}) => status === "rejected").forEach(({reason}) => {
  170. console.error(reason);
  171. });
  172. const lab = new JupyterLab({
  173. mimeExtensions,
  174. disabled: {
  175. matches: disabled,
  176. patterns: PageConfig.Extension.disabled
  177. .map(function (val) { return val.raw; })
  178. },
  179. deferred: {
  180. matches: deferred,
  181. patterns: PageConfig.Extension.deferred
  182. .map(function (val) { return val.raw; })
  183. },
  184. });
  185. register.forEach(function(item) { lab.registerPluginModule(item); });
  186. lab.start({ ignorePlugins });
  187. // Expose global app instance when in dev mode or when toggled explicitly.
  188. var exposeAppInBrowser = (PageConfig.getOption('exposeAppInBrowser') || '').toLowerCase() === 'true';
  189. var devMode = (PageConfig.getOption('devMode') || '').toLowerCase() === 'true';
  190. if (exposeAppInBrowser || devMode) {
  191. window.jupyterlab = lab;
  192. window.jupyterapp = lab;
  193. }
  194. // Handle a browser test.
  195. if (browserTest.toLowerCase() === 'true') {
  196. lab.restored
  197. .then(function() { report(errors); })
  198. .catch(function(reason) { report([`RestoreError: ${reason.message}`]); });
  199. // Handle failures to restore after the timeout has elapsed.
  200. window.setTimeout(function() { report(errors); }, timeout);
  201. }
  202. }