getRefreshGlobal.js 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. const { getRefreshGlobalScope } = require('../globals');
  2. /**
  3. * @typedef {Object} RuntimeTemplate
  4. * @property {function(string, string[]): string} basicFunction
  5. * @property {function(): boolean} supportsConst
  6. * @property {function(string, string=): string} returningFunction
  7. */
  8. /**
  9. * Generates the refresh global runtime template.
  10. * @param {import('webpack').Template} Template The template helpers.
  11. * @param {Record<string, string>} [RuntimeGlobals] The runtime globals.
  12. * @param {RuntimeTemplate} [RuntimeTemplate] The runtime template helpers.
  13. * @returns {string} The refresh global runtime template.
  14. */
  15. function getRefreshGlobal(
  16. Template,
  17. RuntimeGlobals = {},
  18. RuntimeTemplate = {
  19. basicFunction(args, body) {
  20. return `function(${args}) {\n${Template.indent(body)}\n}`;
  21. },
  22. supportsConst() {
  23. return false;
  24. },
  25. returningFunction(returnValue, args = '') {
  26. return `function(${args}) { return ${returnValue}; }`;
  27. },
  28. }
  29. ) {
  30. const declaration = RuntimeTemplate.supportsConst() ? 'const' : 'var';
  31. const refreshGlobal = getRefreshGlobalScope(RuntimeGlobals);
  32. return Template.asString([
  33. `${refreshGlobal} = {`,
  34. Template.indent([
  35. // Lifecycle methods - They should be specific per module and restored after module execution.
  36. // These stubs ensure unwanted calls (e.g. unsupported patterns, broken transform) would not error out.
  37. // If the current module is processed by our loader,
  38. // they will be swapped in place during module initialisation by the `setup` method below.
  39. `register: ${RuntimeTemplate.returningFunction('undefined')},`,
  40. `signature: ${RuntimeTemplate.returningFunction(
  41. RuntimeTemplate.returningFunction('type', 'type')
  42. )},`,
  43. // Runtime - This should be a singleton and persist throughout the lifetime of the app.
  44. // This stub ensures calls to `runtime` would not error out.
  45. // If any module within the bundle is processed by our loader,
  46. // it will be swapped in place via an injected import.
  47. 'runtime: {',
  48. Template.indent([
  49. `createSignatureFunctionForTransform: ${RuntimeTemplate.returningFunction(
  50. RuntimeTemplate.returningFunction('type', 'type')
  51. )},`,
  52. `register: ${RuntimeTemplate.returningFunction('undefined')}`,
  53. ]),
  54. '},',
  55. // Setup - This handles initialisation of the global runtime.
  56. // It should never be touched throughout the lifetime of the app.
  57. `setup: ${RuntimeTemplate.basicFunction('currentModuleId', [
  58. // Store all previous values for fields on `refreshGlobal` -
  59. // this allows proper restoration in the `cleanup` phase.
  60. `${declaration} prevModuleId = ${refreshGlobal}.moduleId;`,
  61. `${declaration} prevRegister = ${refreshGlobal}.register;`,
  62. `${declaration} prevSignature = ${refreshGlobal}.signature;`,
  63. `${declaration} prevCleanup = ${refreshGlobal}.cleanup;`,
  64. '',
  65. `${refreshGlobal}.moduleId = currentModuleId;`,
  66. '',
  67. `${refreshGlobal}.register = ${RuntimeTemplate.basicFunction('type, id', [
  68. `${declaration} typeId = currentModuleId + " " + id;`,
  69. `${refreshGlobal}.runtime.register(type, typeId);`,
  70. ])}`,
  71. '',
  72. `${refreshGlobal}.signature = ${RuntimeTemplate.returningFunction(
  73. `${refreshGlobal}.runtime.createSignatureFunctionForTransform()`
  74. )};`,
  75. '',
  76. `${refreshGlobal}.cleanup = ${RuntimeTemplate.basicFunction('cleanupModuleId', [
  77. // Only cleanup if the module IDs match.
  78. // In rare cases, it might get called in another module's `cleanup` phase.
  79. 'if (currentModuleId === cleanupModuleId) {',
  80. Template.indent([
  81. `${refreshGlobal}.moduleId = prevModuleId;`,
  82. `${refreshGlobal}.register = prevRegister;`,
  83. `${refreshGlobal}.signature = prevSignature;`,
  84. `${refreshGlobal}.cleanup = prevCleanup;`,
  85. ]),
  86. '}',
  87. ])}`,
  88. ])}`,
  89. ]),
  90. '};',
  91. ]);
  92. }
  93. module.exports = getRefreshGlobal;