index.template.js 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. // Copyright (c) Jupyter Development Team.
  2. // Distributed under the terms of the Modified BSD License.
  3. import { JupyterLab } from '@jupyterlab/application';
  4. import { PageConfig } from '@jupyterlab/coreutils';
  5. // Promise.allSettled polyfill, until our supported browsers implement it
  6. // See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/allSettled
  7. if (Promise.allSettled === undefined) {
  8. Promise.allSettled = promises =>
  9. Promise.all(
  10. promises.map(promise =>
  11. promise
  12. .then(value => ({
  13. status: "fulfilled",
  14. value,
  15. }), reason => ({
  16. status: "rejected",
  17. reason,
  18. }))
  19. )
  20. );
  21. }
  22. import('./style.js');
  23. async function createModule(scope, module) {
  24. try {
  25. const factory = await window._JUPYTERLAB[scope].get(module);
  26. return factory();
  27. } catch(e) {
  28. console.warn(`Failed to create module: package: ${scope}; module: ${module}`);
  29. throw e;
  30. }
  31. }
  32. /**
  33. * The main entry point for the application.
  34. */
  35. export async function main() {
  36. const disabled = [];
  37. const deferred = [];
  38. const ignorePlugins = [];
  39. const pluginsToRegister = [];
  40. const federatedExtensionPromises = [];
  41. const federatedMimeExtensionPromises = [];
  42. const federatedStylePromises = [];
  43. // This is all the data needed to load and activate plugins. This should be
  44. // gathered by the server and put onto the initial page template.
  45. const extensions = JSON.parse(
  46. PageConfig.getOption('federated_extensions')
  47. );
  48. // The set of federated extension names.
  49. const federatedExtensionNames = new Set();
  50. extensions.forEach(data => {
  51. if (data.extension) {
  52. federatedExtensionNames.add(data.name);
  53. federatedExtensionPromises.push(createModule(data.name, data.extension));
  54. }
  55. if (data.mimeExtension) {
  56. federatedExtensionNames.add(data.name);
  57. federatedMimeExtensionPromises.push(createModule(data.name, data.mimeExtension));
  58. }
  59. if (data.style) {
  60. federatedStylePromises.push(createModule(data.name, data.style));
  61. }
  62. });
  63. /**
  64. * Iterate over active plugins in an extension.
  65. *
  66. * #### Notes
  67. * This also populates the disabled, deferred, and ignored arrays.
  68. */
  69. function* activePlugins(extension) {
  70. // Handle commonjs or es2015 modules
  71. let exports;
  72. if (extension.hasOwnProperty('__esModule')) {
  73. exports = extension.default;
  74. } else {
  75. // CommonJS exports.
  76. exports = extension;
  77. }
  78. let plugins = Array.isArray(exports) ? exports : [exports];
  79. for (let plugin of plugins) {
  80. if (PageConfig.Extension.isDisabled(plugin.id)) {
  81. disabled.push(plugin.id);
  82. continue;
  83. }
  84. if (PageConfig.Extension.isDeferred(plugin.id)) {
  85. deferred.push(plugin.id);
  86. ignorePlugins.push(plugin.id);
  87. }
  88. yield plugin;
  89. }
  90. }
  91. // Handle the mime extensions.
  92. const mimeExtensions = [];
  93. {{#each mimeExtensions}}
  94. if (!federatedExtensionNames.has('{{@key}}')) {
  95. try {
  96. let ext = require('{{@key}}{{#if this}}/{{this}}{{/if}}');
  97. for (let plugin of activePlugins(ext)) {
  98. mimeExtensions.push(plugin);
  99. }
  100. } catch (e) {
  101. console.error(e);
  102. }
  103. }
  104. {{/each}}
  105. // Add the federated mime extensions.
  106. const federatedMimeExtensions = await Promise.allSettled(federatedMimeExtensionPromises);
  107. federatedMimeExtensions.forEach(p => {
  108. if (p.status === "fulfilled") {
  109. for (let plugin of activePlugins(p.value)) {
  110. mimeExtensions.push(plugin);
  111. }
  112. } else {
  113. console.error(p.reason);
  114. }
  115. });
  116. // Handled the standard extensions.
  117. {{#each extensions}}
  118. if (!federatedExtensionNames.has('{{@key}}')) {
  119. try {
  120. let ext = require('{{@key}}{{#if this}}/{{this}}{{/if}}');
  121. for (let plugin of activePlugins(ext)) {
  122. pluginsToRegister.push(plugin);
  123. }
  124. } catch (e) {
  125. console.error(e);
  126. }
  127. }
  128. {{/each}}
  129. // Add the federated extensions.
  130. const federatedExtensions = await Promise.allSettled(federatedExtensionPromises);
  131. federatedExtensions.forEach(p => {
  132. if (p.status === "fulfilled") {
  133. for (let plugin of activePlugins(p.value)) {
  134. pluginsToRegister.push(plugin);
  135. }
  136. } else {
  137. console.error(p.reason);
  138. }
  139. });
  140. // Load all federated component styles and log errors for any that do not
  141. (await Promise.allSettled(federatedStylePromises)).filter(({status}) => status === "rejected").forEach(({reason}) => {
  142. console.error(reason);
  143. });
  144. // Create a new JupyterLab object and start it
  145. const lab = new JupyterLab({
  146. mimeExtensions,
  147. disabled: {
  148. matches: disabled,
  149. patterns: PageConfig.Extension.disabled
  150. .map(function (val) { return val.raw; })
  151. },
  152. deferred: {
  153. matches: deferred,
  154. patterns: PageConfig.Extension.deferred
  155. .map(function (val) { return val.raw; })
  156. },
  157. });
  158. lab.registerPluginModules(pluginsToRegister);
  159. lab.start({ ignorePlugins });
  160. lab.restored.then(() => {
  161. console.debug('Example started!');
  162. });
  163. }