Skip to content

Commit

Permalink
feat: export functions for getting a list of plugins and utilities (#664
Browse files Browse the repository at this point in the history
)
  • Loading branch information
zamotany authored Oct 17, 2019
1 parent 73d7c85 commit 69f2955
Show file tree
Hide file tree
Showing 2 changed files with 134 additions and 85 deletions.
29 changes: 29 additions & 0 deletions packages/haul-babel-preset-react-native/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,35 @@ Babel preset for __React Native >=0.59.x__ with Haul - Webpack-based React Nativ

You can read more about Haul here: https://github.com/callstack/haul.

## API

For easier extendability, `@haul-bundler/babel-preset-react-native` exports a list of functions for getting plugins and default options for them.

Each of the functions below returns an array of `PluginSpec` which is an tuple with plugin name and plugin default options or `undefined`:
```ts
type PluginSpec = [string] | [string, object];
// plugin[0] => plugin name
// plugin[1] => plugin default options
```

To get list of plugins use the following:

- `getDefaultPrePlugins(): PluginSpec[]` - Get list of default plugins to include at the very beginning.
- `getDefaultPostPlugins(): PluginSpec[]` - Get list of default plugins to include at the end, after all other plugins are included.
- `getHermesPlugins(): PluginSpec[]` - Get list of plugins to include when targeting Hermes.
- `getChakraPlugins(): PluginSpec[]` - Get list of plugins to include when targeting ChakraCore.
- `getHaulPlugins(opts: { platform: string }): PluginSpec[]` - Get list of plugins used in Haul.
- `getTsPlugins(opts: { isTSX: boolean }): PluginSpec[]` - Get list of plugins for transpiling TypeScript files (TS/TSX depending on `isTSX` option).
- `getReactNativePlugins(): PluginSpec[]` - Get list of plugins for React Native.
- `getDevelopmentEnvPlugins(): PluginSpec[]` - Get list of plugins for `development` mode - intended to be used in `env.development` in Babel preset.
- `getTestEnvPlugins(): PluginSpec[]`- Get list of plugins for `test` mode - intended to be used in `env.test` in Babel preset.

For convenience, the following util functions are exported as well:

- `isTypeScriptSource(fileName: string): boolean` - returns `true` if the filename is regular TS file (without TSX).
- `isTSXSource(fileName: string): boolean` - returns `true` if the filename is a TSX file.
- `isReactNative(fileName: string): boolean` - returns `true` if the filename is pointing to `react-native` in `node_modules`.

<!-- badges (common) -->

[license-badge]: https://img.shields.io/npm/l/@haul-bundler/babel-preset-react-native.svg?style=flat-square
Expand Down
190 changes: 105 additions & 85 deletions packages/haul-babel-preset-react-native/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,47 +1,106 @@
import path from 'path';

const defaultPlugins = [
[require('@babel/plugin-proposal-class-properties'), { loose: true }],
[require('@babel/plugin-proposal-optional-catch-binding')],
[require('@babel/plugin-syntax-dynamic-import')],
[require('@babel/plugin-syntax-export-default-from')],
[require('@babel/plugin-transform-react-jsx')],
[require('@babel/plugin-transform-sticky-regex')],
[require('@babel/plugin-transform-unicode-regex')],
// For some reason native async/await don't behave correctly
// on RN 0.59 on both platforms, so we need to transpile it
// to native Promises.
[require('./transforms/superMemberArrowFunction').default],
[require('@babel/plugin-transform-async-to-generator')],
];
export function isTypeScriptSource(fileName: string) {
return !!fileName && fileName.endsWith('.ts');
}

// Additional plugins for Hermes because it doesn't support ES6 yet
const hermesPlugins = [
[require('@babel/plugin-transform-classes')],
[require('@babel/plugin-transform-shorthand-properties')],
[require('@babel/plugin-transform-template-literals'), { loose: true }],
];
export function isTSXSource(fileName: string) {
return !!fileName && fileName.endsWith('.tsx');
}

const chakraPlugins = [
[require('@babel/plugin-transform-spread')],
[require('@babel/plugin-proposal-object-rest-spread')],
];
export function isReactNative(fileName: string) {
return !!fileName && fileName.includes(`node_modules${path.sep}react-native`);
}

type PluginSpec = [string] | [string, object];

const commonJsPlugin = [
require('@babel/plugin-transform-modules-commonjs'),
const commonJsPlugin: PluginSpec = [
'@babel/plugin-transform-modules-commonjs',
{ allowTopLevelThis: true },
];

function isTypeScriptSource(fileName: string) {
return !!fileName && fileName.endsWith('.ts');
export function getDefaultPrePlugins(): PluginSpec[] {
return [
// The flow strip types plugin must go BEFORE class properties!
['@babel/plugin-transform-flow-strip-types'],
['@babel/plugin-proposal-class-properties', { loose: true }],
['@babel/plugin-proposal-optional-catch-binding'],
['@babel/plugin-syntax-dynamic-import'],
['@babel/plugin-syntax-export-default-from'],
['@babel/plugin-transform-react-jsx'],
['@babel/plugin-transform-sticky-regex'],
['@babel/plugin-transform-unicode-regex'],
[
// For some reason native async/await don't behave correctly
// on RN 0.59 on both platforms, so we need to transpile it
// to native Promises.
'./transforms/superMemberArrowFunction',
],
['@babel/plugin-transform-async-to-generator'],
];
}

function isTSXSource(fileName: string) {
return !!fileName && fileName.endsWith('.tsx');
export function getDefaultPostPlugins(): PluginSpec[] {
return [
['@babel/plugin-transform-exponentiation-operator'],
['@babel/plugin-proposal-nullish-coalescing-operator', { loose: true }],
['@babel/plugin-proposal-optional-chaining', { loose: true }],
['@babel/plugin-transform-react-display-name'],
['metro-react-native-babel-preset/src/transforms/transform-symbol-member'],
];
}

function isReactNative(fileName: string) {
return !!fileName && fileName.includes(`node_modules${path.sep}react-native`);
export function getHermesPlugins(): PluginSpec[] {
// Additional plugins for Hermes because it doesn't support ES6 yet
return [
['@babel/plugin-transform-classes'],
['@babel/plugin-transform-shorthand-properties'],
['@babel/plugin-transform-template-literals', { loose: true }],
];
}

export function getChakraPlugins(): PluginSpec[] {
return [
['@babel/plugin-transform-spread'],
['@babel/plugin-proposal-object-rest-spread'],
];
}

export function getHaulPlugins({
platform,
}: {
platform: string;
}): PluginSpec[] {
return [
[require.resolve('./transforms/stripDeadPlatformSelect'), { platform }],
];
}

export function getTsPlugins({ isTSX }: { isTSX: boolean }): PluginSpec[] {
return [
[
'@babel/plugin-transform-typescript',
{
isTSX,
},
],
];
}

export function getReactNativePlugins(): PluginSpec[] {
return [commonJsPlugin];
}

export function getDevelopmentEnvPlugins(): PluginSpec[] {
return [['@babel/plugin-transform-react-jsx-source']];
}

export function getTestEnvPlugins(): PluginSpec[] {
return [commonJsPlugin, ...getDevelopmentEnvPlugins()];
}

function requirePlugin(plugin: PluginSpec) {
return [require(plugin[0])].concat(...(plugin[1] ? [plugin[1]] : []));
}

export default function getHaulBabelPreset(
Expand All @@ -53,77 +112,38 @@ export default function getHaulBabelPreset(
env: {
// Add CommonJS transform when running in NODE_ENV === test, for example when testing.
test: {
plugins: [commonJsPlugin],
plugins: getTestEnvPlugins().map(requirePlugin),
},
development: {
plugins: getDevelopmentEnvPlugins().map(requirePlugin),
},
},
overrides: [
// The flow strip types plugin must go BEFORE class properties!
{
plugins: [require('@babel/plugin-transform-flow-strip-types')],
},
{
plugins: [
...defaultPlugins,
...(options.hermes ? hermesPlugins : []),
...(options.chakra ? chakraPlugins : []),
...getDefaultPrePlugins().map(requirePlugin),
...(options.hermes ? getHermesPlugins() : []).map(requirePlugin),
...(options.chakra ? getChakraPlugins() : []).map(requirePlugin),
...(process.env.HAUL_PLATFORM
? [
[
require('./transforms/stripDeadPlatformSelect'),
{ platform: process.env.HAUL_PLATFORM },
],
]
: []),
? getHaulPlugins({ platform: process.env.HAUL_PLATFORM })
: []
).map(requirePlugin),
],
},
{
test: isReactNative,
plugins: [commonJsPlugin],
plugins: getReactNativePlugins().map(requirePlugin),
},
{
test: isTypeScriptSource,
plugins: [
[
require('@babel/plugin-transform-typescript'),
{
isTSX: false,
},
],
],
plugins: getTsPlugins({ isTSX: false }).map(requirePlugin),
},
{
test: isTSXSource,
plugins: [
[
require('@babel/plugin-transform-typescript'),
{
isTSX: true,
},
],
],
plugins: getTsPlugins({ isTSX: true }).map(requirePlugin),
},
{
plugins: [
require('@babel/plugin-transform-exponentiation-operator'),
[
require('@babel/plugin-proposal-nullish-coalescing-operator'),
{
loose: true,
},
],
[
require('@babel/plugin-proposal-optional-chaining'),
{
loose: true,
},
],
require('@babel/plugin-transform-react-display-name'),
require('metro-react-native-babel-preset/src/transforms/transform-symbol-member'),
...(process.env.BABEL_ENV === 'production' ||
process.env.NODE_ENV === 'production'
? []
: [require('@babel/plugin-transform-react-jsx-source')]),
],
plugins: getDefaultPostPlugins().map(requirePlugin),
},
],
};
Expand Down

0 comments on commit 69f2955

Please sign in to comment.