1 | # ember-cli-babel
|
2 |
|
3 | [![CI Status](https://github.com/babel/ember-cli-babel/workflows/CI/badge.svg)](https://github.com/babel/ember-cli-babel/actions?query=workflow%3ACI+branch%3Amaster)
|
4 |
|
5 | This Ember-CLI plugin uses [Babel](https://babeljs.io/) and
|
6 | [@babel/preset-env](https://babeljs.io/docs/en/next/babel-preset-env.html) to
|
7 | allow you to use latest Javascript in your Ember CLI project.
|
8 |
|
9 | ## Table of Contents
|
10 |
|
11 | - [Installation](#installation)
|
12 | - [Compatibility](#compatibility)
|
13 | - [Usage](#usage)
|
14 | * [Options](#options)
|
15 | + [External Helpers](#external-helpers)
|
16 | + [Enabling Source Maps](#enabling-source-maps)
|
17 | + [Modules](#modules)
|
18 | + [Disabling Debug Tooling Support](#disabling-debug-tooling-support)
|
19 | + [Enabling TypeScript Transpilation](#enabling-typescript-transpilation)
|
20 | * [Babel config file usage](#babel-config-usage)
|
21 | * [Addon usage](#addon-usage)
|
22 | + [Adding Custom Plugins](#adding-custom-plugins)
|
23 | + [Additional Trees](#additional-trees)
|
24 | + [`buildBabelOptions` usage](#buildbabeloptions-usage)
|
25 | + [`getSupportedExtensions` usage](#getsupportedextensions-usage)
|
26 | + [`transpileTree` usage](#transpiletree-usage)
|
27 | * [Debug Tooling](#debug-tooling)
|
28 | + [Debug Macros](#debug-macros)
|
29 | + [General Purpose Env Flags](#general-purpose-env-flags)
|
30 | + [Parallel Builds](#parallel-builds)
|
31 |
|
32 | ## Installation
|
33 |
|
34 | ```
|
35 | ember install ember-cli-babel
|
36 | ```
|
37 |
|
38 | ## Compatibility
|
39 |
|
40 | - ember-cli-babel 7.x requires ember-cli 2.13 or above
|
41 |
|
42 | ## Usage
|
43 |
|
44 | This plugin should work without any configuration after installing. By default
|
45 | it will take every `.js` file in your project and run it through the Babel
|
46 | transpiler to convert your ES6 code to code supported by your target browsers
|
47 | (as specified in `config/targets.js` in ember-cli >= 2.13). Running non-ES6
|
48 | code through the transpiler shouldn't change the code at all (likely just a
|
49 | format change if it does).
|
50 |
|
51 | If you need to customize the way that `babel-preset-env` configures the plugins
|
52 | that transform your code, you can do it by passing in any of the
|
53 | [babel/babel-preset-env options](https://babeljs.io/docs/en/next/babel-preset-env.html#options).
|
54 | *Note: `.babelrc` files are ignored by default.*
|
55 |
|
56 | Example (configuring babel directly):
|
57 |
|
58 | ```js
|
59 | // ember-cli-build.js
|
60 |
|
61 | let app = new EmberApp({
|
62 | babel: {
|
63 | // enable "loose" mode
|
64 | loose: true,
|
65 | // don't transpile generator functions
|
66 | exclude: [
|
67 | 'transform-regenerator',
|
68 | ],
|
69 | plugins: [
|
70 | require.resolve('transform-object-rest-spread')
|
71 | ]
|
72 | }
|
73 | });
|
74 | ```
|
75 |
|
76 | Example (configuring ember-cli-babel itself):
|
77 |
|
78 | ```js
|
79 | // ember-cli-build.js
|
80 |
|
81 | let app = new EmberApp({
|
82 | 'ember-cli-babel': {
|
83 | compileModules: false
|
84 | }
|
85 | });
|
86 | ```
|
87 |
|
88 | ### Options
|
89 |
|
90 | There are a few different options that may be provided to ember-cli-babel.
|
91 | These options are typically set in an apps `ember-cli-build.js` file, or in an
|
92 | addon or engine's `index.js`.
|
93 |
|
94 | ```ts
|
95 | type BabelPlugin = string | [string, any] | [any, any];
|
96 |
|
97 | interface EmberCLIBabelConfig {
|
98 | /**
|
99 | Configuration options for babel-preset-env.
|
100 | See https://github.com/babel/babel-preset-env/tree/v1.6.1#options for details on these options.
|
101 | */
|
102 | babel?: {
|
103 | spec?: boolean;
|
104 | loose?: boolean;
|
105 | debug?: boolean;
|
106 | include?: string[];
|
107 | exclude?: string[];
|
108 | useBuiltIns?: boolean;
|
109 | sourceMaps?: boolean | "inline" | "both";
|
110 | plugins?: BabelPlugin[];
|
111 | };
|
112 |
|
113 | /**
|
114 | Configuration options for ember-cli-babel itself.
|
115 | */
|
116 | 'ember-cli-babel'?: {
|
117 | includeExternalHelpers?: boolean;
|
118 | compileModules?: boolean;
|
119 | disableDebugTooling?: boolean;
|
120 | disablePresetEnv?: boolean;
|
121 | disableEmberModulesAPIPolyfill?: boolean;
|
122 | disableEmberDataPackagesPolyfill?: boolean;
|
123 | disableDecoratorTransforms?: boolean;
|
124 | enableTypeScriptTransform?: boolean;
|
125 | extensions?: string[];
|
126 | };
|
127 | }
|
128 | ```
|
129 |
|
130 | The exact location you specify these options varies depending on the type of
|
131 | project you're working on. As a concrete example, to add
|
132 | `babel-plugin-transform-object-rest-spread` so that your project can use object
|
133 | rest/spread syntax, you would do something like this in an app:
|
134 |
|
135 | ```js
|
136 | // ember-cli-build.js
|
137 | let app = new EmberApp(defaults, {
|
138 | babel: {
|
139 | plugins: [require.resolve('transform-object-rest-spread')]
|
140 | }
|
141 | });
|
142 | ```
|
143 |
|
144 | In an engine:
|
145 | ```js
|
146 | // index.js
|
147 | module.exports = EngineAddon.extend({
|
148 | babel: {
|
149 | plugins: [require.resolve('transform-object-rest-spread')]
|
150 | }
|
151 | });
|
152 | ```
|
153 |
|
154 | In an addon:
|
155 | ```js
|
156 | // index.js
|
157 | module.exports = {
|
158 | options: {
|
159 | babel: {
|
160 | plugins: [require.resolve('transform-object-rest-spread')]
|
161 | }
|
162 | }
|
163 | };
|
164 | ```
|
165 |
|
166 | #### External Helpers
|
167 |
|
168 | Babel often includes helper functions to handle some of the more complex logic
|
169 | in codemods. These functions are inlined by default, so they are duplicated in
|
170 | every file that they are used in, which adds some extra weight to final builds.
|
171 |
|
172 | Enabling `includeExternalHelpers` will cause Babel to import these helpers from
|
173 | a shared module, reducing app size overall. This option is available _only_ to
|
174 | the root application, because it is a global configuration value due to the fact
|
175 | that there can only be one version of helpers included.
|
176 |
|
177 | Note that there is currently no way to allow or ignore helpers, so all
|
178 | helpers will be included, even ones which are not used. If your app is small,
|
179 | this could add to overall build size, so be sure to check.
|
180 |
|
181 | `ember-cli-babel` will attempt to include helpers if it believes that it will
|
182 | lower your build size, using a number of heuristics. You can override this to
|
183 | force inclusion or exclusion of helpers in your app by passing `true` or `false`
|
184 | to `includeExternalHelpers` in your `ember-cli-babel` options.
|
185 |
|
186 | ```js
|
187 | // ember-cli-build.js
|
188 |
|
189 | let app = new EmberApp(defaults, {
|
190 | 'ember-cli-babel': {
|
191 | includeExternalHelpers: true
|
192 | }
|
193 | });
|
194 | ```
|
195 |
|
196 | #### Enabling Source Maps
|
197 |
|
198 | Babel generated source maps will enable you to debug your original ES6 source
|
199 | code. This is disabled by default because it will slow down compilation times.
|
200 |
|
201 | To enable it, pass `sourceMaps: 'inline'` in your `babel` options.
|
202 |
|
203 | ```js
|
204 | // ember-cli-build.js
|
205 |
|
206 | let app = new EmberApp(defaults, {
|
207 | babel: {
|
208 | sourceMaps: 'inline'
|
209 | }
|
210 | });
|
211 | ```
|
212 |
|
213 | #### Modules
|
214 |
|
215 | Older versions of Ember CLI (`< 2.12`) use its own ES6 module transpiler.
|
216 | Because of that, this plugin disables Babel module compilation by ignoring
|
217 | that transform when running under affected ember-cli versions. If you find that
|
218 | you want to use the Babel module transform instead of the Ember CLI one, you'll
|
219 | have to explicitly set `compileModules` to `true` in your configuration. If
|
220 | `compileModules` is anything other than `true`, this plugin will leave the
|
221 | module syntax compilation up to Ember CLI.
|
222 |
|
223 | #### Disabling Debug Tooling Support
|
224 |
|
225 | If for some reason you need to disable this debug tooling, you can opt-out via
|
226 | configuration.
|
227 |
|
228 | In an app that would look like:
|
229 |
|
230 | ```js
|
231 | // ember-cli-build.js
|
232 | module.exports = function(defaults) {
|
233 | let app = new EmberApp(defaults, {
|
234 | 'ember-cli-babel': {
|
235 | disableDebugTooling: true
|
236 | }
|
237 | });
|
238 |
|
239 | return app.toTree();
|
240 | }
|
241 | ```
|
242 |
|
243 | #### Enabling TypeScript Transpilation
|
244 |
|
245 | Babel needs a transform plugin in order to transpile TypeScript. When you
|
246 | install `ember-cli-typescript >= 4.0`, this plugin is automatically enabled.
|
247 |
|
248 | If you don't want to install `ember-cli-typescript`, you can still enable
|
249 | the TypeScript-Babel transform. You will need to set `enableTypeScriptTransform`
|
250 | to `true` in select file(s).
|
251 |
|
252 |
|
253 | <details>
|
254 | <summary>Apps</summary>
|
255 |
|
256 | ```js
|
257 | /* ember-cli-build.js */
|
258 |
|
259 | const EmberApp = require('ember-cli/lib/broccoli/ember-app');
|
260 |
|
261 | module.exports = function (defaults) {
|
262 | const app = new EmberApp(defaults, {
|
263 | // Add options here
|
264 | 'ember-cli-babel': {
|
265 | enableTypeScriptTransform: true,
|
266 | },
|
267 | });
|
268 |
|
269 | return app.toTree();
|
270 | };
|
271 | ```
|
272 |
|
273 | </details>
|
274 |
|
275 |
|
276 | <details>
|
277 | <summary>Addons</summary>
|
278 |
|
279 | ```js
|
280 | /* ember-cli-build.js */
|
281 |
|
282 | const EmberAddon = require('ember-cli/lib/broccoli/ember-addon');
|
283 |
|
284 | module.exports = function (defaults) {
|
285 | const app = new EmberAddon(defaults, {
|
286 | // Add options here
|
287 | 'ember-cli-babel': {
|
288 | enableTypeScriptTransform: true,
|
289 | },
|
290 | });
|
291 |
|
292 | return app.toTree();
|
293 | };
|
294 | ```
|
295 |
|
296 | ```js
|
297 | /* index.js */
|
298 |
|
299 | module.exports = {
|
300 | name: require('./package').name,
|
301 |
|
302 | options: {
|
303 | 'ember-cli-babel': {
|
304 | enableTypeScriptTransform: true,
|
305 | },
|
306 | },
|
307 | };
|
308 | ```
|
309 |
|
310 | </details>
|
311 |
|
312 |
|
313 | <details>
|
314 | <summary>Engines</summary>
|
315 |
|
316 | ```js
|
317 | /* ember-cli-build.js */
|
318 |
|
319 | const EmberAddon = require('ember-cli/lib/broccoli/ember-addon');
|
320 |
|
321 | module.exports = function (defaults) {
|
322 | const app = new EmberAddon(defaults, {
|
323 | // Add options here
|
324 | 'ember-cli-babel': {
|
325 | enableTypeScriptTransform: true,
|
326 | },
|
327 | });
|
328 |
|
329 | return app.toTree();
|
330 | };
|
331 | ```
|
332 |
|
333 | ```js
|
334 | /* index.js */
|
335 |
|
336 | const { buildEngine } = require('ember-engines/lib/engine-addon');
|
337 |
|
338 | module.exports = buildEngine({
|
339 | name: require('./package').name,
|
340 |
|
341 | 'ember-cli-babel': {
|
342 | enableTypeScriptTransform: true,
|
343 | },
|
344 | });
|
345 | ```
|
346 |
|
347 | </details>
|
348 |
|
349 |
|
350 | NOTE: Setting `enableTypeScriptTransform` to `true` does *not* enable
|
351 | type-checking. For integrated type-checking, you will need
|
352 | [`ember-cli-typescript`](https://ember-cli-typescript.com).
|
353 |
|
354 | ### Babel config usage
|
355 |
|
356 | If you want to use the existing babel config from your project instead of the auto-generated one from this addon, then you would need to *opt-in* by passing the config `useBabelConfig: true` as a child property of `ember-cli-babel` in your `ember-cli-build.js` file.
|
357 |
|
358 | *Note: If you are using this option, then you have to make sure that you are adding all of the required plugins required for Ember to transpile correctly.*
|
359 |
|
360 | Example usage:
|
361 |
|
362 | ```js
|
363 | //ember-cli-build.js
|
364 |
|
365 | let app = new EmberAddon(defaults, {
|
366 | "ember-cli-babel": {
|
367 | useBabelConfig: true,
|
368 | // ember-cli-babel related options
|
369 | },
|
370 | });
|
371 | ```
|
372 |
|
373 | ```js
|
374 | //babel.config.js
|
375 |
|
376 | const { buildEmberPlugins } = require("ember-cli-babel");
|
377 |
|
378 | module.exports = function (api) {
|
379 | api.cache(true);
|
380 |
|
381 | return {
|
382 | presets: [
|
383 | [
|
384 | require.resolve("@babel/preset-env"),
|
385 | {
|
386 | targets: require("./config/targets"),
|
387 | },
|
388 | ],
|
389 | ],
|
390 | plugins: [
|
391 | // if you want external helpers
|
392 | [
|
393 | require.resolve("@babel/plugin-transform-runtime"),
|
394 | {
|
395 | version: require("@babel/plugin-transform-runtime/package").version,
|
396 | regenerator: false,
|
397 | useESModules: true,
|
398 | },
|
399 | ],
|
400 | // this is where all the ember required plugins would reside
|
401 | ...buildEmberPlugins(__dirname, { /*customOptions if you want to pass in */ }),
|
402 | ],
|
403 | };
|
404 | };
|
405 | ```
|
406 |
|
407 | #### Ember Plugins
|
408 |
|
409 | Ember Plugins is a helper function that returns a list of plugins that are required for transpiling Ember correctly. You can import this helper function and add it to your existing `babel.config` file.
|
410 | The first argument is **required** which is the path to the root of your project (generally `__dirname`).
|
411 | **Config options:**
|
412 |
|
413 | ```js
|
414 | {
|
415 | disableModuleResolution: boolean, // determines if you want the module resolution enabled
|
416 | emberDataVersionRequiresPackagesPolyfill: boolean, // enable ember data's polyfill
|
417 | shouldIgnoreJQuery: boolean, // ignore jQuery
|
418 | shouldIgnoreEmberString: boolean, // ignore ember string
|
419 | shouldIgnoreDecoratorAndClassPlugins: boolean, // disable decorator plugins
|
420 | disableEmberModulesAPIPolyfill: boolean, // disable ember modules API polyfill
|
421 | }
|
422 | ```
|
423 | ### Addon usage
|
424 |
|
425 | #### Adding Custom Plugins
|
426 |
|
427 | You can add custom plugins to be used during transpilation of the `addon/` or
|
428 | `addon-test-support/` trees by ensuring that your addon's `options.babel` is
|
429 | properly populated (as mentioned above in the `Options` section).
|
430 |
|
431 | #### Additional Trees
|
432 |
|
433 | For addons which want additional customizations, they are able to interact with
|
434 | this addon directly.
|
435 |
|
436 | ```ts
|
437 | interface EmberCLIBabel {
|
438 | /**
|
439 | Used to generate the options that will ultimately be passed to babel itself.
|
440 | */
|
441 | buildBabelOptions(type: 'babel' | 'broccoli', config?: EmberCLIBabelConfig): Opaque;
|
442 |
|
443 | /**
|
444 | Supports easier transpilation of non-standard input paths (e.g. to transpile
|
445 | a non-addon NPM dependency) while still leveraging the logic within
|
446 | ember-cli-babel for transpiling (e.g. targets, preset-env config, etc).
|
447 | */
|
448 | transpileTree(inputTree: BroccoliTree, config?: EmberCLIBabelConfig): BroccoliTree;
|
449 |
|
450 | /**
|
451 | Used to determine if a given plugin is required by the current target configuration.
|
452 | Does not take `includes` / `excludes` into account.
|
453 |
|
454 | See https://github.com/babel/babel-preset-env/blob/master/data/plugins.json for the list
|
455 | of known plugins.
|
456 | */
|
457 | isPluginRequired(pluginName: string): boolean;
|
458 | }
|
459 | ```
|
460 |
|
461 | #### `buildBabelOptions` usage
|
462 |
|
463 | ```js
|
464 | // find your babel addon (can use `this.findAddonByName('ember-cli-babel')` in ember-cli@2.14 and newer)
|
465 | let babelAddon = this.addons.find(addon => addon.name === 'ember-cli-babel');
|
466 |
|
467 | // create the babel options to use elsewhere based on the config above
|
468 | let options = babelAddon.buildBabelOptions('babel', config)
|
469 |
|
470 | // now you can pass these options off to babel or broccoli-babel-transpiler
|
471 | require('babel-core').transform('something', options);
|
472 | ```
|
473 |
|
474 | #### `getSupportedExtensions` usage
|
475 |
|
476 | ```js
|
477 | // find your babel addon (can use `this.findAddonByName('ember-cli-babel')` in ember-cli@2.14 and newer)
|
478 | let babelAddon = this.addons.find(addon => addon.name === 'ember-cli-babel');
|
479 |
|
480 | // create the babel options to use elsewhere based on the config above
|
481 | let extensions = babelAddon.getSupportedExtensions(config)
|
482 | ```
|
483 |
|
484 | #### `transpileTree` usage
|
485 |
|
486 | ```js
|
487 | // find your babel addon (can use `this.findAddonByName('ember-cli-babel')` in ember-cli@2.14 and newer)
|
488 | let babelAddon = this.addons.find(addon => addon.name === 'ember-cli-babel');
|
489 |
|
490 | // invoke .transpileTree passing in the custom input tree
|
491 | let transpiledCustomTree = babelAddon.transpileTree(someCustomTree);
|
492 | ```
|
493 |
|
494 | ### Debug Tooling
|
495 |
|
496 | In order to allow apps and addons to easily provide good development mode
|
497 | ergonomics (assertions, deprecations, etc) but still perform well in production
|
498 | mode ember-cli-babel automatically manages stripping / removing certain debug
|
499 | statements. This concept was originally proposed in [ember-cli/rfcs#50](https://github.com/ember-cli/rfcs/pull/50),
|
500 | but has been slightly modified during implementation (after researching what works well and what does not).
|
501 |
|
502 | #### Debug Macros
|
503 |
|
504 | To add convienient deprecations and assertions, consumers (in either an app or an addon) can do the following:
|
505 |
|
506 | ```js
|
507 | import { deprecate, assert } from '@ember/debug';
|
508 |
|
509 | export default Ember.Component.extend({
|
510 | init() {
|
511 | this._super(...arguments);
|
512 | deprecate(
|
513 | 'Passing a string value or the `sauce` parameter is deprecated, please pass an instance of Sauce instead',
|
514 | false,
|
515 | { until: '1.0.0', id: 'some-addon-sauce' }
|
516 | );
|
517 | assert('You must provide sauce for x-awesome.', this.sauce);
|
518 | }
|
519 | })
|
520 | ```
|
521 |
|
522 | In testing and development environments those statements will be executed (and
|
523 | assert or deprecate as appropriate), but in production builds they will be
|
524 | inert (and stripped during minification).
|
525 |
|
526 | The following are named exports that are available from `@ember/debug`:
|
527 |
|
528 | * `function deprecate(message: string, predicate: boolean, options: any): void` - Results in calling `Ember.deprecate`.
|
529 | * `function assert(message: string, predicate: boolean): void` - Results in calling `Ember.assert`.
|
530 | * `function warn(message: string, predicate: boolean): void` - Results in calling `Ember.warn`.
|
531 |
|
532 | #### General Purpose Env Flags
|
533 |
|
534 | In some cases you may have the need to do things in debug builds that isn't
|
535 | related to asserts/deprecations/etc. For example, you may expose certain API's
|
536 | for debugging only. You can do that via the `DEBUG` environment flag:
|
537 |
|
538 | ```js
|
539 | import { DEBUG } from '@glimmer/env';
|
540 |
|
541 | const Component = Ember.Component.extend();
|
542 |
|
543 | if (DEBUG) {
|
544 | Component.reopen({
|
545 | specialMethodForDebugging() {
|
546 | // do things ;)
|
547 | }
|
548 | });
|
549 | }
|
550 | ```
|
551 |
|
552 | In testing and development environments `DEBUG` will be replaced by the boolean
|
553 | literal `true`, and in production builds it will be replaced by `false`. When
|
554 | ran through a minifier (with dead code elimination) the entire section will be
|
555 | stripped.
|
556 |
|
557 | Please note, that these general purpose environment related flags (e.g. `DEBUG`
|
558 | as a boolean flag) are imported from `@glimmer/env` not from an `@ember`
|
559 | namespace.
|
560 |
|
561 | #### Parallel Builds
|
562 |
|
563 | By default, [broccoli-babel-transpiler] will attempt to spin up several
|
564 | sub-processes (~1 per available core), to achieve parallelization. (Once Node.js
|
565 | has built-in worker support, we plan to utilize it.) This yields significant Babel
|
566 | build time improvements.
|
567 |
|
568 | Unfortunately, some Babel plugins may break this functionality.
|
569 | When this occurs, we gracefully fallback to the old serial strategy.
|
570 |
|
571 | To have the build fail when failing to do parallel builds, opt-in is via:
|
572 |
|
573 | ```js
|
574 | let app = new EmberAddon(defaults, {
|
575 | 'ember-cli-babel': {
|
576 | throwUnlessParallelizable: true
|
577 | }
|
578 | });
|
579 | ```
|
580 | or via environment variable via
|
581 | ```sh
|
582 | THROW_UNLESS_PARALLELIZABLE=1 ember serve
|
583 | ```
|
584 |
|
585 | The `ember-cli-build` option is only specifying that *your* `ember-cli-babel` is parallelizable, not that all of them are.
|
586 |
|
587 | The environment variable works by instructing **all** `ember-cli-babel` instances to put themselves in parallelize mode (or throw).
|
588 |
|
589 | *Note: Future versions will enable this flag by default.*
|
590 |
|
591 | Read more about [broccoli parallel transpilation].
|
592 |
|
593 | [broccoli-babel-transpiler]: https://github.com/babel/broccoli-babel-transpiler
|
594 | [broccoli parallel transpilation]: https://github.com/babel/broccoli-babel-transpiler#parallel-transpilation
|