Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions docs/Configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,11 @@ The bundle configuration consist of the following properties:
- `dependsOn?: string[]` (_optional_, **multi-bundle mode only**) - Specify on which DLLs the bundle depends on, which will be automatically linked when building the bundle.
- `providesModuleNodeModules?: Array<string | { name: string; directory: string }>` - Provide custom modules for Haste.
- `hasteOptions?: any` - Provide Haste options.
- `looseMode?: true | Array<string | RegExp> | ((filename: string) => boolean)` - Removes `'use strict';` from:
- the whole bundle if `true`
- modules matched by absolute filename if array of string is passed (can be mixed with regexes)
- modules matched by the the regexes if array of regexes is passed (can be mixed with strings)
- modules for which function `(filename: string) => boolean` returns `true`
- `transform?: WebpackConfigTransform` - Customize the Webpack config after it's been created.

The `transform` function will receive an object with `bundleName`, `env`, `runtime` and Webpack's `config`:
Expand Down
34 changes: 34 additions & 0 deletions docs/Recipes.md
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,40 @@ Set the environment variable `APP_ENV` to `detox_tests` when running Haul:
APP_ENV=detox_tests yarn haul
```

## Using with Lottie or loose-mode-only-compatible libraries

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';` or `false`

You can mix string and regexes in array.

For example:

```js
// 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/,
],
},
},
});
```

## Debugging with React Native Tools (`vscode-react-native`)

In order to use React Native Tools extension you must first install the extension:
Expand Down
1 change: 1 addition & 0 deletions packages/haul-core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
"terser": "^4.1.3",
"utility-types": "^3.7.0",
"webpack": "^4.39.1",
"webpack-sources": "^1.4.1",
"wrap-ansi": "^6.0.0",
"ws": "^6.2.1"
},
Expand Down
2 changes: 2 additions & 0 deletions packages/haul-core/src/config/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ export type BundleConfig = Assign<
Exclude<keyof MinifyOptions, 'sourceMap'>
>;
sourceMap?: boolean | 'inline';
looseMode?: true | Array<string | RegExp> | ((filename: string) => boolean);
dll?: boolean;
app?: boolean;
dependsOn?: string[];
Expand Down Expand Up @@ -82,6 +83,7 @@ export type NormalizedBundleConfig = Assign<
DeepNonNullable<ExternalBundleConfig>,
{ manifestPath: ExternalBundleConfig['manifestPath'] }
>;
looseMode: (filename: string) => boolean;
}
>;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ Object {
],
"external": false,
"hasteOptions": Object {},
"looseMode": [Function],
"minify": false,
"minifyOptions": undefined,
"name": "app",
Expand All @@ -38,6 +39,7 @@ Object {
],
"external": false,
"hasteOptions": Object {},
"looseMode": [Function],
"minify": false,
"minifyOptions": undefined,
"name": "base_dll",
Expand All @@ -62,6 +64,7 @@ Object {
],
"external": false,
"hasteOptions": Object {},
"looseMode": [Function],
"minify": false,
"minifyOptions": undefined,
"name": "index",
Expand Down Expand Up @@ -150,6 +153,9 @@ Object {
"singleBundleMode": false,
"sourceMap": true,
},
LooseModeWebpackPlugin {
"checkLooseMode": [Function],
},
DllReferencePlugin {
"options": Object {
"context": "<<REPLACED>>/packages/haul-core/src/preset/__tests__",
Expand Down Expand Up @@ -218,6 +224,9 @@ Object {
"singleBundleMode": false,
"sourceMap": true,
},
LooseModeWebpackPlugin {
"checkLooseMode": [Function],
},
DllPlugin {
"options": Object {
"name": "base_dll",
Expand Down Expand Up @@ -279,6 +288,9 @@ Object {
],
"sourceMap": true,
},
LooseModeWebpackPlugin {
"checkLooseMode": [Function],
},
DllReferencePlugin {
"options": Object {
"context": "<<REPLACED>>/packages/haul-core/src/preset/__tests__",
Expand Down Expand Up @@ -309,6 +321,7 @@ Object {
],
"external": false,
"hasteOptions": Object {},
"looseMode": [Function],
"minify": false,
"minifyOptions": undefined,
"name": "app",
Expand All @@ -331,6 +344,7 @@ Object {
],
"external": false,
"hasteOptions": Object {},
"looseMode": [Function],
"minify": false,
"minifyOptions": undefined,
"name": "base_dll",
Expand All @@ -355,6 +369,7 @@ Object {
],
"external": false,
"hasteOptions": Object {},
"looseMode": [Function],
"minify": false,
"minifyOptions": undefined,
"name": "index",
Expand Down Expand Up @@ -437,6 +452,9 @@ Object {
],
"sourceMap": true,
},
LooseModeWebpackPlugin {
"checkLooseMode": [Function],
},
DllReferencePlugin {
"options": Object {
"context": "<<REPLACED>>/packages/haul-core/src/preset/__tests__",
Expand Down Expand Up @@ -499,6 +517,9 @@ Object {
"preloadBundles": Array [],
"sourceMap": true,
},
LooseModeWebpackPlugin {
"checkLooseMode": [Function],
},
DllPlugin {
"options": Object {
"name": "base_dll",
Expand Down Expand Up @@ -560,6 +581,9 @@ Object {
],
"sourceMap": true,
},
LooseModeWebpackPlugin {
"checkLooseMode": [Function],
},
DllReferencePlugin {
"options": Object {
"context": "<<REPLACED>>/packages/haul-core/src/preset/__tests__",
Expand Down Expand Up @@ -588,6 +612,7 @@ Object {
],
"external": false,
"hasteOptions": Object {},
"looseMode": [Function],
"minify": false,
"minifyOptions": undefined,
"name": "index",
Expand Down Expand Up @@ -666,6 +691,9 @@ Object {
"preloadBundles": Array [],
"sourceMap": true,
},
LooseModeWebpackPlugin {
"checkLooseMode": [Function],
},
],
"target": "webworker",
},
Expand Down
60 changes: 60 additions & 0 deletions packages/haul-core/src/preset/__tests__/makeConfigFactory.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import makeConfigFactory from '../makeConfigFactory';
import { Runtime, ProjectConfig, EnvOptions } from '../../';
// @ts-ignore
import { replacePathsInObject } from 'jest/helpers'; // eslint-disable-line
import LooseModeWebpackPlugin from '../../webpack/plugins/LooseModeWebpackPlugin';

const makeConfig = makeConfigFactory(
(_runtime, env, bundleName, projectConfig) => ({
Expand Down Expand Up @@ -354,4 +355,63 @@ describe('makeConfig', () => {
expect(replacePathsInObject(config)).toMatchSnapshot();
});
});

describe('with looseMode', () => {
const baseEnv: EnvOptions = {
platform: 'ios',
root: __dirname,
dev: false,
bundleMode: 'single-bundle',
bundleTarget: 'file',
};

it('should build all modules in loose mode', () => {
const projectConfig: ProjectConfig = {
bundles: {
index: {
entry: './index.js',
looseMode: true,
},
},
};
const env: EnvOptions = {
...baseEnv,
bundleTarget: 'server',
};
const config = makeConfig(projectConfig)(runtime, env);
const looseModePlugin = config.webpackConfigs.index.plugins.find(
plugin => {
return plugin.constructor.name === 'LooseModeWebpackPlugin';
}
) as LooseModeWebpackPlugin;
expect(looseModePlugin.checkLooseMode('')).toBe(true);
});

it('should build some modules in loose mode', () => {
const moduleFilename = path.join(__dirname, 'someModule.js');

const projectConfig: ProjectConfig = {
bundles: {
index: {
entry: './index.js',
looseMode: [moduleFilename, /haul/],
},
},
};
const env: EnvOptions = {
...baseEnv,
bundleTarget: 'server',
};
const config = makeConfig(projectConfig)(runtime, env);
const looseModePlugin = config.webpackConfigs.index.plugins.find(
plugin => {
return plugin.constructor.name === 'LooseModeWebpackPlugin';
}
) as LooseModeWebpackPlugin;
expect(looseModePlugin.checkLooseMode('')).toBe(false);
expect(looseModePlugin.checkLooseMode(moduleFilename)).toBe(true);
expect(looseModePlugin.checkLooseMode(__filename)).toBe(true);
expect(looseModePlugin.checkLooseMode('path')).toBe(false);
});
});
});
30 changes: 30 additions & 0 deletions packages/haul-core/src/preset/makeConfigFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {
import applySingleBundleTweaks from './utils/applySingleBundleTweaks';
import applyMultiBundleTweaks from './utils/applyMultiBundleTweaks';
import getBundlePlugin from './utils/getBundlePlugin';
import LooseModeWebpackPlugin from '../webpack/plugins/LooseModeWebpackPlugin';

type GetDefaultConfig = (
runtime: Runtime,
Expand Down Expand Up @@ -73,6 +74,30 @@ export default function makeConfigFactory(getDefaultConfig: GetDefaultConfig) {
? bundleConfigBuilder(env, runtime)
: bundleConfigBuilder;

let looseMode: NormalizedBundleConfig['looseMode'] = () => false;
if (bundleConfig.looseMode === true) {
looseMode = () => true;
} else if (Array.isArray(bundleConfig.looseMode)) {
looseMode = (filename: string) => {
return (bundleConfig.looseMode as Array<string | RegExp>).some(
element => {
if (typeof element === 'string') {
if (!path.isAbsolute(element)) {
throw new Error(
`${element} in 'looseMode' property must be an absolute path or regex`
);
}
return element === filename;
}

return element.test(filename);
}
);
};
} else if (typeof bundleConfig.looseMode === 'function') {
looseMode = bundleConfig.looseMode;
}

// TODO: use minifyOptions to configure terser for basic bundle
const dev = bundleConfig.dev || env.dev;
const root = bundleConfig.root || env.root;
Expand All @@ -97,6 +122,7 @@ export default function makeConfigFactory(getDefaultConfig: GetDefaultConfig) {
typeof bundleConfig.sourceMap !== 'undefined'
? bundleConfig.sourceMap
: true,
looseMode,
app: Boolean(bundleConfig.app),
dll: Boolean(bundleConfig.dll),
dependsOn: bundleConfig.dependsOn || [],
Expand Down Expand Up @@ -202,6 +228,10 @@ export default function makeConfigFactory(getDefaultConfig: GetDefaultConfig) {
getBundlePlugin(env, normalizedBundleConfig)
);

webpackConfig.plugins.push(
new LooseModeWebpackPlugin(normalizedBundleConfig.looseMode)
);

if (env.bundleMode === 'single-bundle') {
applySingleBundleTweaks(
env,
Expand Down
35 changes: 35 additions & 0 deletions packages/haul-core/src/webpack/plugins/LooseModeWebpackPlugin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import webpack from 'webpack';
import sources from 'webpack-sources';

export default class LooseModeWebpackPlugin {
constructor(public checkLooseMode: (filename: string) => boolean) {}

apply(compiler: webpack.Compiler) {
compiler.hooks.make.tap(
'LooseModeWebpackPlugin',
(compilation: webpack.compilation.Compilation) => {
compilation.moduleTemplates.javascript.hooks.render.tap(
'LooseModeWebpackPlugin',
(
moduleSource: sources.Source,
{ resource }: { resource: string }
) => {
const useLooseMode = this.checkLooseMode(resource);
if (!useLooseMode) {
return moduleSource;
}

const source = moduleSource.source();
const match = source.match(/['"]use strict['"]/);
if (!match || match.index === undefined) {
return moduleSource;
}
const replacement = new sources.ReplaceSource(moduleSource);
replacement.replace(match.index, match.index + match[0].length, '');
return replacement;
}
);
}
);
}
}
Loading