index.js 5.9 KB

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