@putzisan/babel-config v0.0.0
babel
babel7 is used equally for all build+test+develop.
babel.config.js
Babel is configured via the babel.config.js-file. The process.env.NODE_ENV
-variable is used to determine which plugins and presets should be added.
presets and plugins
Presets are a predefined set of plugins, see babel-dependencies for the individual presets/plugins we use.
- Plugins run before Presets
- Plugin ordering is first to last
- Preset ordering is reversed (last to first)
production
-specific options
- add @babel/plugin-transform-runtime, see babel-helper-functions via babel-runtime for smaller bundle-size
- turns off the
development
-option in @babel/preset-react
development
-specific options
- do not include the @babel/preset-env, you will use a new browser for dev, so no need to waste compile-time with this preset during dev
- add react-hot-loader/babel, look at react-hot-loader for more information.
test
-specific options
Customizations for jest, since jest ES6 cannot import
/export
and does not understand dynamic imports, see jest-documentation:
- ES6-exports to commonjs:
@babel/preset-env
will be adapted from"modules": false
to"modules": "commonjs"
- dynamic imports: use babel-plugin-dynamic-import-node by AirBnb instead of @babel/plugin-syntax-dynamic-import
babel-helper-functions via babel-runtime for smaller bundle-size
Babel injects small helper-functions like _extend
, when needed. With @babel/plugin-transform-runtime the code is not copied in every file, but the transform-runtime-plugin will inject referneces to the @babel/runtime-package, which holds the implementations of the helper-functions ("Helper aliasing"). This will result in a smaller bundle. The "useESModules": true
-option will use ES6-modules (import
/export
) instead of the implementations with commonjs (require
/module.exports
).
Please note that the @babel/plugin-transform-runtime can also perform other transformations:
corejs
will polyfill new built-ins (Promise, Map, ...) via the core-js-libraryregenerator
will transform generator-functions (function*
) into ES5-Code with a local regenerator-runtime
In my opinion it is not a good idea to use these options, because the inserted transformations can take up a lot of space and it is very likely that others also use polyfills, so it may be that a feature is polyfilled by several different libraries which bloats your bundle. If you are developing a library, it is best not to use features that require polyfills at all. If really necessary, use ponyfills and document the use.
polyfills
In src/index.tsx
the first line loads a polyfill-script (import './bootstrap/polyfills';
), so that the app also runs under Internet Explorer 11 (IE11). Following polyfills are included:
Promise
via this promise-library (Promises are required for code-splitting via dynamic imports)Object.assign
via this object-assign-library (Object.assign
is needed for the @babel/plugin-proposal-object-rest-spread with theuseBuiltIns
-option and in some libraries (e.g. react-loadable) but not included in IE11)
Both polyfills together increase the bundle-size by ~ 5kb. If you think you do not need this polyfills you can remove them. If you need other polyfills, because you use new features or have to support very old browsers, you should attach them in src/bootstrap/polyfills.js
.
polyfills via babel-polyfill (not recommended)
To stop thinking about polyfills you can automate this process with babel-polyfill. Similar to @babel/plugin-transform-runtime with the corejs
-option, polyfills via core-js are added for older browsers. In contrast to runtime, the polyfills are loaded globally into the application (which is not recommended for libraries).
You can then additionaly use the useBuiltIns
-option of the babel-preset-env:
useBuiltIns: 'usage'
: Adds specific imports for polyfills when they are used in each file. We take advantage of the fact that a bundler will load the same polyfill only once. Be aware that this will not polyfill usages innode_modules
useBuiltIns: 'entry'
: You need to import@babel/polyfill
in your entry-file once, babel will transform this import to only include imports needed by the specified preset-envtarget
-option; At the moment (as of 13.08.2018) this is forbrowsers: ['>0.25%']
still over 80 kb
I would not recommend the use of babel-polyfill since:
- either significantly too many polyfills are imported (library standalone or with
useBuiltIns: 'entry'
) or - using
useBuiltIns: 'usage'
the polyfills are incosistent (they are included locally per file but change the global namespace) and only functions used in your code are analyzed (since usednode_modules
s are not examined), außerdem ist auch mit dieser Methode- Also with this method the resulting package is bigger than if you install the polyfills yourself as described above
- For the example app only the two polyfills mentioned above are needed to run under IE11, the bundle size was still ~ 14 kb bigger and I had to install the required imports manually into
index.ts
, because preset-env did not recognize that for the dynamicimport()
Promise must polyfill and for React-LoadableObject.assign
babel-dependencies
package | description |
---|---|
@babel/core | peer-dependency for everything else |
@babel/plugin-proposal-class-properties | see proposal, so that ES6 class fields can not only be set in the constructor; the "loose": true -option will assign the properties via assignment expressions instead of Object.defineProperty which results in less code |
@babel/plugin-proposal-object-rest-spread | The Object-React-Operator (... ) is not natively supported by preset-env.The rest operator works in TypeScript files without this transformation because the TypeScript compiler has been compiling it to ES5 code since TypeScript 2.1.The useBuiltIns: true -Option transforms it to Object.assign -calls, make sure to include a polyfill for older browsers (IE 11) |
@babel/plugin-syntax-dynamic-import | only Syntax-Plugin! so babel understands dynamic imports, which webpack uses for code-splitting |
@babel/plugin-transform-runtime | Babel-helpers and -polyfills will use @babel/runtime, without this babel copies the needed helper into every single file when needed, for more information visit their documentation; the "useESModules": true -option will use ES6-modules with import /export |
@babel/runtime | Babel will inject this dependency in your code when needed via @babel/plugin-transform-runtime, see upper line |
@babel/preset-env | ES>5 to ES5, should always run as the last transformation, so it should always remain the first presets -entry |
@babel/preset-react | JSX to ES6;useBuiltIns -option will passed through the useBuiltIns -option in @babel/plugin-transform-react-jsx => "When spreading props, use Object.assign directly instead of Babel's extend helper."development -option will add debug-informations, turned off in production |
@babel/preset-typescript | TS/TSX to ES6/JSX |
babel-plugin-dynamic-import-node | the only one not by babel itself but by airbnb, only for jest-tests, see jest-declaration |
further babel-dependencies
package | description |
---|---|
babel-core@7.0.0-bridge.0 | for jest-test, siehe jest-doku |
babel-jest | so that jest also uses the babel-transformations |
babel-loader@8.0.0-beta.4 | to transform files via webpack, new babel-load-v8 must be used with new babel7 |
react-hot-loader/babel | babel extension for hot-loading to work with react, see react-hot-loader |
5 years ago