src/react.ts
import fs from 'fs'
import path from 'path'
import { BaseTransformOptions, Env } from './types'
import { testEnv } from './test-env'
/**
* 📝 Babel configurations
*
* - Project wide configuration file type `babel.config.js` used to set the
* "root" configurations. This is required for any project that needs to
* transform a linked npm package.
* - Configs are specified by environment to make it easier to understand how
* each env is transformed.
* - Only polyfills required for application code are added with the `usage`
* option of the preset-env `useBuiltIns`, but this does assume that libraries
* have properly handled compiling their polyfills.
* - Under the hood calling `api.env` will enable caching based on NODE_ENV
*
* 📝 Core JS
*
* CoreJS includes the polyfills for new language features compiled by Babel.
* The recommendation for polyfilling is to include the complete set of
* polyfills needed for the target environment (vs only including polyfills used
* in app code with `useBuiltIns: 'usage'`). Many libraries will transpile their
* code but do not polyfill, and it's hard to tell whether polyfills are needed
* in evergreen browsers because they don't need any.
*
* To completely polyfill for target envs, best practice is to use polyfill.io
* for projects that can experience downtime, and to bundle polyfills with
* preset-env for projects with critical uptimes.
*
* To polyfill with preset-env, set `useBuiltIns` to `entry` and import the
* core-js and regenerator-runtime packages first in the application entry.
* Preset env will transform them to just the polyfills needed to match the
* targets environment. Explicitly set the `core-js` version used by
* `preset-env` per Babel best practices.
* - Polyfills are big, around 46.6kb for the `defaults` env target!
* - For applications that need a guarantee for polyfilling, set the
* - Optionally experimental features can be polyfilled by setting corejs to:
* { version: 3, proposals: true } (don't)
* - Optionally the transform-runtime plugin accepts a `corejs` configuration
* option that will use imports from core-js to polyfill language features
* instead of adding polyfills to global scope (this is preferred for package
* compilation) Note that enabling this requires adding `@babel/runtime-corejs3`
* as a dependency.
*/
export default function reactConfigs(env: Env): BaseTransformOptions {
return {
// --------------------------------------------------------
// Presets
presets: [
// Automatically use the minimum set of syntax and polyfill transforms to
// meet target environment using browserslist config.
[
'@babel/preset-env',
{
// Transpile to browserslist default versions, which is any browser
// that isn't dead and has >0.5% market share
targets: 'defaults',
// Transform modules to common js in test for Jest
// Disable module transformation in dev and prod builds to allow
// webpack to smart-manage modules.
modules: testEnv(env, ['test']) ? 'commonjs' : false,
// Transforms the core-js and regenerator-runtime imports in index.js
// to only the polyfills needed for the target environments
useBuiltIns: 'entry',
// Configure core-js version used for polyfills
corejs: 3,
},
],
// Includes plugins required to transform JSX and opts in to the automatic
// runtime which auto imports the functions that JSX transpiles to.
// Development option toggles plugins that add references to source and
// self on each component
[
'@babel/preset-react',
{ development: testEnv(env, ['development']), runtime: 'automatic' },
],
// Enable TypeScript usage 🔐
'@babel/preset-typescript',
],
// --------------------------------------------------------
// Plugins
plugins: [
// Transform Runtime will transform inline Babel helper fns to imports from
// @babel/runtime
// Passing useESModules disables running helper imports through the common
// js module transform and allows webpack to manage the esm
// Passing corejs configs will use imports from @babel/runtime-corejs3
// instead of global polyfills (this should be set for libraries but is
// optional for applications)
// Do not set corejs, that will use module scoped polyfilled helpers, but
// env is polyfilled so we would double polyfill
[
'@babel/plugin-transform-runtime',
{
useESModules: testEnv(env, ['development', 'production']),
// https://github.com/babel/babel/issues/10261
// eslint-disable-next-line
version: require('@babel/helpers/package.json').version,
},
],
// Transforms aliased imports to resolveable paths
[
'babel-plugin-transform-import-aliases',
{ aliases: { '@': path.resolve(fs.realpathSync(process.cwd()), 'src') } },
],
],
// --------------------------------------------------------
// Environments
env: {
development: {
plugins: [
// Babel transform for "Fast Refresh"
'react-refresh/babel',
],
},
production: {
plugins: [
// Strip component prop types in production builds
'transform-react-remove-prop-types',
],
},
test: {
presets: [
// The linaria webpack-loader includes this preset under the hood, provide it for
// test envs to prevent crashes
'@linaria',
],
},
},
}
}