UNPKG

17.4 kBMarkdownView Raw
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
5This Ember-CLI plugin uses [Babel](https://babeljs.io/) and
6[@babel/preset-env](https://babeljs.io/docs/en/next/babel-preset-env.html) to
7allow 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```
35ember 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
44This plugin should work without any configuration after installing. By default
45it will take every `.js` file in your project and run it through the Babel
46transpiler 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
48code through the transpiler shouldn't change the code at all (likely just a
49format change if it does).
50
51If you need to customize the way that `babel-preset-env` configures the plugins
52that 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
56Example (configuring babel directly):
57
58```js
59// ember-cli-build.js
60
61let 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
76Example (configuring ember-cli-babel itself):
77
78```js
79// ember-cli-build.js
80
81let app = new EmberApp({
82 'ember-cli-babel': {
83 compileModules: false
84 }
85});
86```
87
88### Options
89
90There are a few different options that may be provided to ember-cli-babel.
91These options are typically set in an apps `ember-cli-build.js` file, or in an
92addon or engine's `index.js`.
93
94```ts
95type BabelPlugin = string | [string, any] | [any, any];
96
97interface 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
130The exact location you specify these options varies depending on the type of
131project you're working on. As a concrete example, to add
132`babel-plugin-transform-object-rest-spread` so that your project can use object
133rest/spread syntax, you would do something like this in an app:
134
135```js
136// ember-cli-build.js
137let app = new EmberApp(defaults, {
138 babel: {
139 plugins: [require.resolve('transform-object-rest-spread')]
140 }
141});
142```
143
144In an engine:
145```js
146// index.js
147module.exports = EngineAddon.extend({
148 babel: {
149 plugins: [require.resolve('transform-object-rest-spread')]
150 }
151});
152```
153
154In an addon:
155```js
156// index.js
157module.exports = {
158 options: {
159 babel: {
160 plugins: [require.resolve('transform-object-rest-spread')]
161 }
162 }
163};
164```
165
166#### External Helpers
167
168Babel often includes helper functions to handle some of the more complex logic
169in codemods. These functions are inlined by default, so they are duplicated in
170every file that they are used in, which adds some extra weight to final builds.
171
172Enabling `includeExternalHelpers` will cause Babel to import these helpers from
173a shared module, reducing app size overall. This option is available _only_ to
174the root application, because it is a global configuration value due to the fact
175that there can only be one version of helpers included.
176
177Note that there is currently no way to allow or ignore helpers, so all
178helpers will be included, even ones which are not used. If your app is small,
179this 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
182lower your build size, using a number of heuristics. You can override this to
183force inclusion or exclusion of helpers in your app by passing `true` or `false`
184to `includeExternalHelpers` in your `ember-cli-babel` options.
185
186```js
187// ember-cli-build.js
188
189let app = new EmberApp(defaults, {
190 'ember-cli-babel': {
191 includeExternalHelpers: true
192 }
193});
194```
195
196#### Enabling Source Maps
197
198Babel generated source maps will enable you to debug your original ES6 source
199code. This is disabled by default because it will slow down compilation times.
200
201To enable it, pass `sourceMaps: 'inline'` in your `babel` options.
202
203```js
204// ember-cli-build.js
205
206let app = new EmberApp(defaults, {
207 babel: {
208 sourceMaps: 'inline'
209 }
210});
211```
212
213#### Modules
214
215Older versions of Ember CLI (`< 2.12`) use its own ES6 module transpiler.
216Because of that, this plugin disables Babel module compilation by ignoring
217that transform when running under affected ember-cli versions. If you find that
218you want to use the Babel module transform instead of the Ember CLI one, you'll
219have to explicitly set `compileModules` to `true` in your configuration. If
220`compileModules` is anything other than `true`, this plugin will leave the
221module syntax compilation up to Ember CLI.
222
223#### Disabling Debug Tooling Support
224
225If for some reason you need to disable this debug tooling, you can opt-out via
226configuration.
227
228In an app that would look like:
229
230```js
231// ember-cli-build.js
232module.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
245Babel needs a transform plugin in order to transpile TypeScript. When you
246install `ember-cli-typescript >= 4.0`, this plugin is automatically enabled.
247
248If you don't want to install `ember-cli-typescript`, you can still enable
249the TypeScript-Babel transform. You will need to set `enableTypeScriptTransform`
250to `true` in select file(s).
251
252
253<details>
254<summary>Apps</summary>
255
256```js
257/* ember-cli-build.js */
258
259const EmberApp = require('ember-cli/lib/broccoli/ember-app');
260
261module.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
282const EmberAddon = require('ember-cli/lib/broccoli/ember-addon');
283
284module.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
299module.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
319const EmberAddon = require('ember-cli/lib/broccoli/ember-addon');
320
321module.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
336const { buildEngine } = require('ember-engines/lib/engine-addon');
337
338module.exports = buildEngine({
339 name: require('./package').name,
340
341 'ember-cli-babel': {
342 enableTypeScriptTransform: true,
343 },
344});
345```
346
347</details>
348
349
350NOTE: Setting `enableTypeScriptTransform` to `true` does *not* enable
351type-checking. For integrated type-checking, you will need
352[`ember-cli-typescript`](https://ember-cli-typescript.com).
353
354### Babel config usage
355
356If 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
360Example usage:
361
362```js
363//ember-cli-build.js
364
365let 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
376const { buildEmberPlugins } = require("ember-cli-babel");
377
378module.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
409Ember 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.
410The 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
427You 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
429properly populated (as mentioned above in the `Options` section).
430
431#### Additional Trees
432
433For addons which want additional customizations, they are able to interact with
434this addon directly.
435
436```ts
437interface 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)
465let babelAddon = this.addons.find(addon => addon.name === 'ember-cli-babel');
466
467// create the babel options to use elsewhere based on the config above
468let options = babelAddon.buildBabelOptions('babel', config)
469
470// now you can pass these options off to babel or broccoli-babel-transpiler
471require('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)
478let babelAddon = this.addons.find(addon => addon.name === 'ember-cli-babel');
479
480// create the babel options to use elsewhere based on the config above
481let 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)
488let babelAddon = this.addons.find(addon => addon.name === 'ember-cli-babel');
489
490// invoke .transpileTree passing in the custom input tree
491let transpiledCustomTree = babelAddon.transpileTree(someCustomTree);
492```
493
494### Debug Tooling
495
496In order to allow apps and addons to easily provide good development mode
497ergonomics (assertions, deprecations, etc) but still perform well in production
498mode ember-cli-babel automatically manages stripping / removing certain debug
499statements. This concept was originally proposed in [ember-cli/rfcs#50](https://github.com/ember-cli/rfcs/pull/50),
500but has been slightly modified during implementation (after researching what works well and what does not).
501
502#### Debug Macros
503
504To add convienient deprecations and assertions, consumers (in either an app or an addon) can do the following:
505
506```js
507import { deprecate, assert } from '@ember/debug';
508
509export 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
522In testing and development environments those statements will be executed (and
523assert or deprecate as appropriate), but in production builds they will be
524inert (and stripped during minification).
525
526The 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
534In some cases you may have the need to do things in debug builds that isn't
535related to asserts/deprecations/etc. For example, you may expose certain API's
536for debugging only. You can do that via the `DEBUG` environment flag:
537
538```js
539import { DEBUG } from '@glimmer/env';
540
541const Component = Ember.Component.extend();
542
543if (DEBUG) {
544 Component.reopen({
545 specialMethodForDebugging() {
546 // do things ;)
547 }
548 });
549}
550```
551
552In testing and development environments `DEBUG` will be replaced by the boolean
553literal `true`, and in production builds it will be replaced by `false`. When
554ran through a minifier (with dead code elimination) the entire section will be
555stripped.
556
557Please note, that these general purpose environment related flags (e.g. `DEBUG`
558as a boolean flag) are imported from `@glimmer/env` not from an `@ember`
559namespace.
560
561#### Parallel Builds
562
563By default, [broccoli-babel-transpiler] will attempt to spin up several
564sub-processes (~1 per available core), to achieve parallelization. (Once Node.js
565has built-in worker support, we plan to utilize it.) This yields significant Babel
566build time improvements.
567
568Unfortunately, some Babel plugins may break this functionality.
569When this occurs, we gracefully fallback to the old serial strategy.
570
571To have the build fail when failing to do parallel builds, opt-in is via:
572
573```js
574let app = new EmberAddon(defaults, {
575 'ember-cli-babel': {
576 throwUnlessParallelizable: true
577 }
578});
579```
580or via environment variable via
581```sh
582THROW_UNLESS_PARALLELIZABLE=1 ember serve
583```
584
585The `ember-cli-build` option is only specifying that *your* `ember-cli-babel` is parallelizable, not that all of them are.
586
587The 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
591Read 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