plugin-babel.js 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. var babel = require('systemjs-babel-build').babel;
  2. // the SystemJS babel build includes standard presets
  3. var es2015 = require('systemjs-babel-build').presetES2015;
  4. var es2015Register = require('systemjs-babel-build').presetES2015Register;
  5. var modulesRegister = require('systemjs-babel-build').modulesRegister;
  6. var stage3 = require('systemjs-babel-build').pluginsStage3;
  7. var stage2 = require('systemjs-babel-build').pluginsStage2;
  8. var stage1 = require('systemjs-babel-build').pluginsStage1;
  9. var react = require('systemjs-babel-build').pluginsReact;
  10. var externalHelpers = require('systemjs-babel-build').externalHelpers;
  11. var runtimeTransform = require('systemjs-babel-build').runtimeTransform;
  12. var babelRuntimePath;
  13. var modularHelpersPath = System.decanonicalize('./babel-helpers/', module.id);
  14. var externalHelpersPath = System.decanonicalize('./babel-helpers.js', module.id);
  15. var regeneratorRuntimePath = System.decanonicalize('./regenerator-runtime.js', module.id);
  16. if (modularHelpersPath.substr(modularHelpersPath.length - 3, 3) == '.js')
  17. modularHelpersPath = modularHelpersPath.substr(0, modularHelpersPath.length - 3);
  18. // in builds we want to embed canonical names to helpers
  19. if (System.getCanonicalName) {
  20. modularHelpersPath = System.getCanonicalName(modularHelpersPath);
  21. externalHelpersPath = System.getCanonicalName(externalHelpersPath);
  22. regeneratorRuntimePath = System.getCanonicalName(regeneratorRuntimePath);
  23. }
  24. // disable SystemJS runtime detection
  25. SystemJS._loader.loadedTranspilerRuntime = true;
  26. function prepend(a, b) {
  27. for (var p in b)
  28. if (!(p in a))
  29. a[p] = b[p];
  30. return a;
  31. }
  32. /*
  33. * babelOptions:
  34. * modularRuntime: true / false (whether to use babel-runtime or babel/external-helpers respectively)
  35. * sourceMaps: true / false (defaults to true)
  36. * es2015: true / false (defaults to true)
  37. * stage3: true / false (defaults to true)
  38. * stage2: true / false (defaults to true)
  39. * stage1: true / false (defaults to false)
  40. * react: true / false (defaults to false)
  41. * plugins: array of custom plugins (objects or module name strings)
  42. * presets: array of custom presets (objects or module name strings)
  43. * compact: as in Babel
  44. * comments: as in Babel
  45. *
  46. * babelOptions can be set at SystemJS.babelOptions OR on the metadata object for a given module
  47. */
  48. var defaultBabelOptions = {
  49. modularRuntime: true,
  50. sourceMaps: true,
  51. es2015: true,
  52. stage3: true,
  53. stage2: true,
  54. stage1: false,
  55. react: false,
  56. compact: false,
  57. comments: true
  58. };
  59. exports.translate = function(load, traceOpts) {
  60. // we don't transpile anything other than CommonJS or ESM
  61. if (load.metadata.format == 'global' || load.metadata.format == 'amd' || load.metadata.format == 'json')
  62. throw new TypeError('plugin-babel cannot transpile ' + load.metadata.format + ' modules. Ensure "' + load.name + '" is configured not to use this loader.');
  63. var loader = this;
  64. var pluginLoader = loader.pluginLoader || loader;
  65. // we only output ES modules when running in the builder
  66. var outputESM = traceOpts ? traceOpts.outputESM : loader.builder;
  67. var babelOptions = {};
  68. if (load.metadata.babelOptions)
  69. prepend(babelOptions, load.metadata.babelOptions);
  70. if (loader.babelOptions)
  71. prepend(babelOptions, loader.babelOptions);
  72. prepend(babelOptions, defaultBabelOptions);
  73. // determine any plugins or preset strings which need to be imported as modules
  74. var pluginAndPresetModuleLoads = [];
  75. if (babelOptions.presets)
  76. babelOptions.presets.forEach(function(preset) {
  77. if (typeof preset == 'string')
  78. pluginAndPresetModuleLoads.push(pluginLoader['import'](preset, module.id));
  79. });
  80. if (babelOptions.plugins)
  81. babelOptions.plugins.forEach(function(plugin) {
  82. plugin = typeof plugin == 'string' ? plugin : Array.isArray(plugin) && typeof plugin[0] == 'string' && plugin[0];
  83. if (!plugin)
  84. return;
  85. pluginAndPresetModuleLoads.push(pluginLoader.import(plugin, module.id).then(function (m) {
  86. return m.default || m;
  87. }));
  88. });
  89. return Promise.all(pluginAndPresetModuleLoads)
  90. .then(function(pluginAndPresetModules) {
  91. var curPluginOrPresetModule = 0;
  92. var presets = [];
  93. var plugins = [];
  94. if (babelOptions.modularRuntime) {
  95. if (load.metadata.format == 'cjs')
  96. throw new TypeError('plugin-babel does not support modular runtime for CJS module transpilations. Set babelOptions.modularRuntime: false if needed.');
  97. presets.push(runtimeTransform);
  98. }
  99. else {
  100. if (load.metadata.format == 'cjs')
  101. load.source = 'var babelHelpers = require("' + externalHelpersPath + '");' + load.source;
  102. else
  103. load.source = 'import babelHelpers from "' + externalHelpersPath + '";' + load.source;
  104. presets.push(externalHelpers);
  105. }
  106. if (babelOptions.es2015)
  107. presets.push((outputESM || load.metadata.format == 'cjs') ? es2015 : es2015Register);
  108. else if (!(outputESM || load.metadata.format == 'cjs'))
  109. presets.push(modulesRegister);
  110. if (babelOptions.stage3)
  111. presets.push({
  112. plugins: stage3
  113. });
  114. if (babelOptions.stage2)
  115. presets.push({
  116. plugins: stage2
  117. });
  118. if (babelOptions.stage1)
  119. presets.push({
  120. plugins: stage1
  121. });
  122. if (babelOptions.react)
  123. presets.push({
  124. plugins: react
  125. });
  126. if (babelOptions.presets)
  127. babelOptions.presets.forEach(function(preset) {
  128. if (typeof preset == 'string')
  129. presets.push(pluginAndPresetModules[curPluginOrPresetModule++]);
  130. else
  131. presets.push(preset);
  132. });
  133. if (babelOptions.plugins)
  134. babelOptions.plugins.forEach(function(plugin) {
  135. if (typeof plugin == 'string')
  136. plugins.push(pluginAndPresetModules[curPluginOrPresetModule++]);
  137. else if (Array.isArray(plugin) && typeof plugin[0] == 'string')
  138. plugins.push([pluginAndPresetModules[curPluginOrPresetModule++], plugin[1]]);
  139. else
  140. plugins.push(plugin);
  141. });
  142. var output = babel.transform(load.source, {
  143. babelrc: false,
  144. plugins: plugins,
  145. presets: presets,
  146. filename: load.address,
  147. sourceFileName: load.address,
  148. moduleIds: false,
  149. sourceMaps: traceOpts && traceOpts.sourceMaps || babelOptions.sourceMaps,
  150. inputSourceMap: load.metadata.sourceMap,
  151. compact: babelOptions.compact,
  152. comments: babelOptions.comments,
  153. code: true,
  154. ast: true,
  155. resolveModuleSource: function(m) {
  156. if (m.substr(0, 22) == 'babel-runtime/helpers/') {
  157. m = modularHelpersPath + m.substr(22) + '.js';
  158. }
  159. else if (m == 'babel-runtime/regenerator') {
  160. m = regeneratorRuntimePath;
  161. }
  162. else if (m.substr(0, 14) == 'babel-runtime/') {
  163. if (!babelRuntimePath) {
  164. babelRuntimePath = System.decanonicalize('babel-runtime/', module.id);
  165. if (babelRuntimePath[babelRuntimePath.length - 1] !== '/')
  166. babelRuntimePath += '/';
  167. if (babelRuntimePath.substr(babelRuntimePath.length - 3, 3) == '.js')
  168. babelRuntimePath = babelRuntimePath.substr(0, babelRuntimePath.length - 3);
  169. if (loader.getCanonicalName)
  170. babelRuntimePath = loader.getCanonicalName(babelRuntimePath);
  171. if (babelRuntimePath == 'babel-runtime/')
  172. throw new Error('The babel-runtime module must be mapped to support modular helpers and builtins. If using jspm run jspm install npm:babel-runtime.');
  173. }
  174. m = babelRuntimePath + m.substr(14) + '.js';
  175. }
  176. return m;
  177. }
  178. });
  179. // add babelHelpers as a dependency for non-modular runtime
  180. if (!babelOptions.modularRuntime)
  181. load.metadata.deps.push(externalHelpersPath);
  182. // set output module format
  183. // (in builder we output modules as esm)
  184. if (!load.metadata.format || load.metadata.format == 'detect' || load.metadata.format == 'esm')
  185. load.metadata.format = outputESM ? 'esm' : 'register';
  186. load.metadata.sourceMap = output.map;
  187. return output.code;
  188. });
  189. };