id | title |
---|---|
recipes |
Recipes |
If you're using @haul-bundler/babel-preset-react-native
Babel preset, you don't need to do anything and start using Typescript immediately!
The easiest way to use Typescript in React Native apps is by using Babel to transpile TS files. There are some limitations, which you can read more about here.
If you're using Haul's @haul-bundler/babel-preset-react-native
you can start using Typescript without any manual work, since it support TS out of the box.
If you have custom Babel config, you need to add @babel/preset-typescript
preset and configure it.
If you want to use Typescript's official compiler and toolchain, you will need to install ts-loader
and add it to Webpack config:
yarn add --dev ts-loader
To use the Typescript compiler exclusively on Typescript files without Babel's intervention, you have to remove the Babel loader and then re-add it to the module rules. This is needed if you want to use Typescript features that are currently not supported by Babel, like const enum
or namespace
.
The haul.config.js
should then look something like this:
import { makeConfig, withPolyfills } from '@haul-bundler/preset-0.60';
const removeRuleByTest = (moduleConfig, test) => {
const index = moduleConfig.findIndex(rule => {
if (rule.test) {
return rule.test.toString() === test.toString();
}
return false;
});
moduleConfig.splice(index, 1);
};
export default makeConfig({
bundles: {
index: {
entry: withPolyfills('./index.ts'),
transform({ config }) {
// Remove babel-loader, as it handles both .ts(x) and .js(x) files
removeRuleByTest(config.module.rules, /\.[jt]sx?$/);
config.module.rules = [
{
test: /\.tsx?$/,
loader: 'ts-loader',
},
...config.module.rules,
// Re-add the babel-loader, now only for .js(x)
{
test: /\.jsx?$/,
loader: require.resolve('babel-loader'),
options: {
plugins: [
require.resolve(
'@haul-bundler/core/build/utils/fixRequireIssues',
),
],
},
},
];
},
},
},
});
And a corresponding (example) tsconfig.json
{
"compilerOptions": {
"jsx": "react",
"target": "es2015",
"moduleResolution": "node",
"sourceMap": true
},
"exclude": [
"node_modules"
]
}
Please note, that if you want to use synthetic default imports, a.k.a. things like import React from 'react'
instead of import * as React from 'react'
you will need to:
- Add
"allowSyntheticDefaultImports": true
totsconfig.json
. - Pass the compiled TS files through Babel (you will need
babel-loader
for this -yarn add --dev babel-loader
).
Revised haul.config.js
:
import { makeConfig, withPolyfills } from "@haul-bundler/preset-0.59";
export default makeConfig({
bundles: {
index: {
entry: withPolyfills('./index.ts'),
transform({ config }) {
config.module.rules = [
{
test: /\.tsx?$/,
exclude: '/node_modules/',
use: [
{
loader: 'babel-loader',
},
{
loader: 'ts-loader',
}
]
},
...config.module.rules,
];
},
},
},
});
Unless you're using different JavaScript VM than ChakraCore (default) to run your JavaScript, add chakra: true
flag to your babel.config.js
:
module.exports = {
presets: [['module:@haul-bundler/babel-preset-react-native', { chakra: true }]],
};
If you want to use react-native-windows
, you have to register it as a provider of JS modules.
Update your haul.config.js
like so:
import { makeConfig, withPolyfills } from "@haul-bundler/preset-0.59";
export default makeConfig({
platforms: ['windows', 'ios', 'android'], // or ['windows'] if you only use windows platform
bundles: {
index: {
entry: withPolyfills('./index.js'),
providesModuleNodeModules: ['react-native', 'react-native-windows'],
hasteOptions: { platforms: ['native', 'windows'] },
},
},
});
With React Native 0.60 and newer, you need to register react-native-windows
as a module provider and modify InitializeCore
location and alias react-native
.
Update your haul.config.js
like so:
import { makeConfig, withPolyfills } from "@haul-bundler/preset-0.60";
export default makeConfig({
platforms: ['windows', 'ios', 'android'], // or ['windows'] if you only use windows platform
bundles: {
index: {
entry: withPolyfills('./index.js', {
initializeCoreLocation: 'react-native-windows/Libraries/Core/InitializeCore.js'
}),
providesModuleNodeModules: ['react-native', 'react-native-windows'],
hasteOptions: { platforms: ['native', 'windows'] },
transform({ config }) {
config.resolve.alias = {
...config.resolve.alias,
'react-native': 'react-native-windows'
};
},
},
},
});
Detox is a "grey box" e2e framework developed by wix. It provides the ability to mock files during tests using react-native-repackager
react-native-repackager
is built for the standard react-native
packager, so your mocks won't work with Haul out-of-the-box. Luckily, it's easy to configure Haul (webpack, actually) to resolve the mocked files instead of the original ones during tests:
// haul.config.js
import { makeConfig, withPolyfills } from "@haul-bundler/preset-0.59";
export default makeConfig({
bundles: {
index: {
entry: withPolyfills('./index.ts'),
transform({ config }) {
config.resolve = {
...config.resolve,
extensions: process.env.APP_ENV === 'detox_tests'
? ['.mock.behaviour.js', ...config.resolve.extensions]
: config.resolve.extensions
};
},
},
},
});
Set the environment variable APP_ENV
to detox_tests
when running Haul:
APP_ENV=detox_tests yarn haul
Some React Native libraries might not work with Haul out of the box. If the library if throw error, it is possible that it's not compatible with strict mode checks.
By default all modules with Haul have 'use strict';
annotation, which makes the code evaluated in strict mode, whereas the default React Native bundler - Metro - generates the code without this annotation. For that reason, some libraries eg Lottie
need special steps to work.
To enable loose mode, you need to add looseMode
property to your config set to:
true
- removes all'use strict';
from the whole bundle- array for absolute filenames of modules - matched modules will have
'use strict';
removed - array of regexes - matched modules will have
'use strict';
removed - function that accepts absolute module filename and must return
true
to remove'use strict';
orfalse
You can mix string and regexes in array.
For example:
// haul.config.js
import { makeConfig, withPolyfills } from "@haul-bundler/preset-0.59";
export default makeConfig({
bundles: {
index: {
entry: withPolyfills('./index.ts'),
looseMode: [
require.resolve('./MyModule.js'),
/node_modules\/react-native-lottie/,
],
},
},
});
In order to use React Native Tools extension you must first install the extension:
code --install-extension msjsdiag.vscode-react-native
Next, you need to tweak your haul.config.js
and add source-map-loader
:
import { withPolyfills, makeConfig } from "@haul-bundler/preset-0.60";
export default makeConfig({
bundles: {
index: {
entry: withPolyfills('./index.js'),
transform({ config }) {
config.module.rules = [
...config.module.rules,
{
test: /\.js$/,
use: ["source-map-loader"],
enforce: "pre"
}
];
},
},
},
});
Now use can start Haul packager server (yarn haul start
) and use Attach to packager configuration in Debug panel in VS Code.
From within the app tap on Enable remote debugging. This will open a page in Chrome, which you can safely close.
Finally press Start debugging icon (green triangle) in Debug panel in VS Code.
You can easily attach Node debugger to Haul process by passing --node-inspector
option or NODE_INSPECTOR
environment variable when running Haul:
yarn haul bundle --platform ios --dev false --node-inspector
# or
NODE_INSPECTOR=1 yarn haul bundle --platform ios --dev false
It will run Haul and open debugger connection to which you can attach Node debugger using Chrome debugger for Node or Visual Studio Code debugger.
--node-inspector
, --node-inspector true
and NODE_INSPECTOR=1
work in similar way as passing --inspect
to a node
- it doesn't add breakpoint on the first line. If you want to attach debugger before Haul proceed further, use wait
value:
yarn haul bundle --platform ios --dev false --node-inspector=wait
# or
NODE_INSPECTOR=wait yarn haul bundle --platform ios --dev false
This will make sure the Node debugger is attached before Haul starts executing a command. It works in a similar way as --inspect-brk
option for node
.
You can use NODE_INSPECTOR=1
/NODE_INSPECTOR=wait
in XCode build phase Bundle React Native code and images:
export CLI_PATH=node_modules/@haul-bundler/cli/bin/haul.js
export NODE_BINARY=node
export NODE_INSPECTOR=wait
../node_modules/react-native/scripts/react-native-xcode.sh
and --node-inspector
/--node-inspector=wait
in Gradle build file:
// android/app/build.gradle
project.ext.react = [
entryFile: "index.js",
cliPath: "node_modules/@haul-bundler/cli/bin/haul.js"
extraPackagerArgs: ['--node-inspector=wait']
]