Skip to content

Commit a1552d0

Browse files
author
徐远翔
committed
feat: support custom haul configuration
1 parent 3016441 commit a1552d0

File tree

18 files changed

+155
-294
lines changed

18 files changed

+155
-294
lines changed

README.md

+37-2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
[![npm version](https://img.shields.io/npm/v/umi-preset-react-native.svg?style=flat-square)](https://www.npmjs.com/package/umi-preset-react-native)
44

5+
[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](http://makeapullrequest.com)
6+
57
针对 [react-native](https://reactnative.dev/) 应用的 [umi](https://umijs.org/) 插件集。
68

79
[发布日志](/CHANGELOG.md)
@@ -57,15 +59,17 @@ _以下是`umi-preset-react-native`对 Node、react、react-native、umi 版本
5759
```javascript
5860
// .umirc.js
5961
export default {
62+
mountElementId: '',
6063
history: {
6164
type: 'memory',
6265
},
6366
};
6467
```
6568

66-
**注意:**
69+
**注意:RN 环境中没有 DOM 和 BOM, 所以这两项配置为必填,需要覆盖[umi](https://umijs.org/)的默认值,避免运行时进入到调用 DOM/BOM API 的代码分支导致运行错误。**
6770

68-
- `history`[umi](https://umijs.org/) 默认值是:`'browser'`,在 RN 中只能使用:`'memory'`类型。
71+
- `mountElementId`[umi](https://umijs.org/) 默认值是:`'root'`,在 RN 中**必须覆盖为空字符串**
72+
- `history`[umi](https://umijs.org/) 默认值是:`'browser'`,在 RN 中**只能使用:`'memory'`类型**
6973

7074
> All dependencies start with @umijs/preset-@umijs/plugin-、umi-preset-、umi-plugin- will be registered as plugin/plugin-preset.
7175
@@ -127,11 +131,38 @@ _上文未列出的[umi 配置](https://umijs.org/config)暂不支持。RN 开
127131
- [ ] theme
128132
- [ ] styles
129133
- 其他:
134+
130135
- [ ] base
131136
- [ ] publicPath
132137
- [ ] runtimePublicPath
133138
- [ ] ssr
134139

140+
#### umi-preset-react-native 扩展配置
141+
142+
```javascript
143+
// .umirc.js
144+
module.default = {
145+
reactNative: {
146+
appKey: require('./app.json').name,
147+
version: require('react-native/package.json').version,
148+
},
149+
haul: {
150+
bundles: {
151+
index: {
152+
entry: './umi.ts',
153+
},
154+
},
155+
},
156+
};
157+
```
158+
159+
- `reactNative`:选填,默认值:上面代码示例中的值
160+
- `haul`:选填,默认值:上面代码示例中的值,即[Project Configuration](https://github.com/callstack/haul/blob/master/docs/Configuration.md#project-configuration-reference)
161+
162+
**注意**:不需要使用 haul 提供的工具:`makeConfig``withPolyfills`。直接填入[Project Configuration](https://github.com/callstack/haul/blob/master/docs/Configuration.md#project-configuration-reference)的字段即可。
163+
164+
在做多 bundle 切分时,要保证主 bundle 中必须包含`./umi.ts`
165+
135166
### 开发
136167

137168
修改`package.json`文件,使用`umi`取代`react-native`
@@ -219,3 +250,7 @@ yarn add @umijs/plugin-dva --dev
219250
```npm
220251
yarn add umi-plugin-antd-react-native --dev
221252
```
253+
254+
## 深入
255+
256+
### 切分多 bundle

packages/preset/package.json

-1
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,6 @@
4949
"@haul-bundler/preset-0.60": "0.18.0",
5050
"@umijs/bundler-utils": "^3.0.0",
5151
"metro": "^0.51.1",
52-
"umi-react-native-renderer": "^0.0.2",
5352
"umi-react-native-runtime": "^0.0.2",
5453
"webpack-chain": "6.4.0"
5554
},

packages/preset/src/index.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,13 @@ export default function () {
33
plugins: [
44
require.resolve('./plugins/commands/buildRn'),
55
require.resolve('./plugins/commands/devRn'),
6-
require.resolve('./plugins/generateFiles/rn/umi'),
6+
require.resolve('./plugins/generateFiles/react-native/polyfill'),
7+
require.resolve('./plugins/generateFiles/react-native/runtime'),
8+
require.resolve('./plugins/generateFiles/react-native/umi'),
79
require.resolve('./plugins/generateFiles/babelConfig'),
810
require.resolve('./plugins/generateFiles/haulConfig'),
9-
require.resolve('./plugins/generateFiles/index'),
1011
require.resolve('./plugins/features/reactNative'),
12+
require.resolve('./plugins/features/haul'),
1113
],
1214
};
1315
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { IApi } from '@umijs/types';
2+
3+
export default (api: IApi) => {
4+
api.describe({
5+
key: 'haul',
6+
config: {
7+
default: { bundles: { index: { entry: './umi.ts' } } },
8+
schema(joi) {
9+
return joi
10+
.object({
11+
bundles: joi.object().required(),
12+
})
13+
.optional();
14+
},
15+
},
16+
});
17+
};

packages/preset/src/plugins/features/reactNative.ts

+6-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ export default (api: IApi) => {
1212
} = api;
1313

1414
/**
15-
* 优先读取用户目录下依赖的绝对路径(下面会解释为什么不用api.addProjectFirstLibraries)
15+
* 优先读取用户目录下依赖的绝对路径
1616
* @param library 比如:'react-native'(目录) 或者 'react-router/esm/index.js'(文件)
1717
* @param defaults library找不到时的缺省值
1818
* @param dir true-返回目录绝对路径,false-返回文件绝对路径
@@ -57,12 +57,15 @@ export default (api: IApi) => {
5757
.object({
5858
appKey: joi.string(), // moduleName app.json#name
5959
version: joi.string(), // RN 版本号
60+
templates: joi.string(),
61+
bundles: joi.object(),
6062
})
6163
.optional();
6264
},
6365
},
6466
});
6567

68+
// haul中没有treeShaking, mainFields 写死了。
6669
api.addProjectFirstLibraries(() => [
6770
{ name: 'react-native', path: REACT_NATIVE_PATH },
6871
{ name: 'react-router', path: require.resolve('react-router/esm/react-router.js') },
@@ -117,4 +120,6 @@ export default (api: IApi) => {
117120
}
118121
throw new TypeError(`"${name}" 只支持 react-native:"0.59.0及以上(>= 0.59.0)" 和 "1.0.0以下(< 1.0.0)" 版本。`);
119122
});
123+
124+
api.addTmpGenerateWatcherPaths(() => ['react-native']);
120125
};

packages/preset/src/plugins/generateFiles/haulConfig.ts

+13-8
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,23 @@ import webpack from 'webpack';
44
import Config from 'webpack-chain';
55

66
const CONTENT = `import _defaultsDeep from 'lodash/defaultsDeep';
7-
import { withPolyfills, makeConfig } from '{{{ haulPresetPath }}}';
7+
import { makeConfig } from '{{{ haulPresetPath }}}';
88
99
const transform = ({ config }) => {
1010
return _defaultsDeep({{{ webpackConfig }}}, config);
1111
};
1212
13+
const haulConfig = {{{ haulConfig }}};
14+
15+
const bundles = haulConfig.bundles;
16+
1317
export default makeConfig({
14-
bundles: {
15-
index: {
16-
entry: withPolyfills('./index.ts'),
17-
transform,
18-
},
19-
},
18+
bundles: Object.keys(bundles)
19+
.map((bundleName) => ({
20+
[bundleName]: _defaultsDeep(bundles[bundleName], {transform}),
21+
}))
22+
.reduce((prev, curr) => ({...prev, ...curr})),
23+
...haulConfig,
2024
});
2125
2226
`;
@@ -69,12 +73,13 @@ export default (api: IApi) => {
6973
await api.config.chainWebpack(webpackConfig, { env, webpack: defaultWebpack, createCSSRule });
7074
}
7175
// 防止加载umi Common JS格式的代码
72-
webpackConfig.resolve.alias.set('umi', winPath(join(absTmpPath || '', 'rn', 'umi')));
76+
webpackConfig.resolve.alias.set('umi', winPath(join(absTmpPath || '', 'react-native', 'umi')));
7377
const config = webpackConfig.toConfig();
7478
api.writeTmpFile({
7579
path: 'haul.config.js',
7680
content: Mustache.render(CONTENT, {
7781
haulPresetPath: winPath(detectHaulPresetPath()),
82+
haulConfig: JSON.stringify(api.config?.haul || {}, null, 2),
7883
webpackConfig: JSON.stringify(config, null, 2),
7984
}),
8085
});

packages/preset/src/plugins/generateFiles/index.ts

-63
This file was deleted.

packages/preset/src/plugins/generateFiles/indexTpl.ts

-46
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import { IApi } from '@umijs/types';
2+
3+
const CONTENT = `{{{ polyfills }}}
4+
import 'react-native/Libraries/Core/InitializeCore.js';
5+
6+
// @ts-ignore
7+
if (global.window === undefined) {
8+
// @ts-ignore
9+
global.window = global;
10+
}
11+
12+
`;
13+
14+
export default (api: IApi) => {
15+
const {
16+
utils: { Mustache, semver },
17+
} = api;
18+
api.addPolyfillImports(() => [
19+
{
20+
source: './react-native/polyfill',
21+
},
22+
]);
23+
24+
api.onGenerateFiles(() => {
25+
const polyfills: string[] = [];
26+
if (semver.lt(api.config?.reactNative?.version, '0.60.0')) {
27+
polyfills.push(
28+
require.resolve('@haul-bundler/preset-0.59/vendor/polyfills/Object.es6.js'),
29+
require.resolve('@haul-bundler/preset-0.59/vendor/polyfills/console.js'),
30+
require.resolve('@haul-bundler/preset-0.59/vendor/polyfills/error-guard.js'),
31+
require.resolve('@haul-bundler/preset-0.59/vendor/polyfills/Number.es6.js'),
32+
require.resolve('@haul-bundler/preset-0.59/vendor/polyfills/String.prototype.es6.js'),
33+
require.resolve('@haul-bundler/preset-0.59/vendor/polyfills/Array.prototype.es6.js'),
34+
require.resolve('@haul-bundler/preset-0.59/vendor/polyfills/Array.es6.js'),
35+
require.resolve('@haul-bundler/preset-0.59/vendor/polyfills/Object.es7.js'),
36+
);
37+
} else {
38+
polyfills.push(
39+
'react-native/Libraries/polyfills/console.js',
40+
'react-native/Libraries/polyfills/error-guard.js',
41+
'react-native/Libraries/polyfills/Object.es7.js',
42+
);
43+
}
44+
api.writeTmpFile({
45+
path: 'react-native/polyfill.ts',
46+
content: Mustache.render(CONTENT, {
47+
polyfills: polyfills.map((it: string) => `import '${it}';`).join('\n'),
48+
}),
49+
});
50+
});
51+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { IApi } from '@umijs/types';
2+
import { join } from 'path';
3+
4+
const runtimeTpl = `import {AppRegistry} from 'react-native';
5+
6+
export function render(clientRender: () => any, args: {hot?: boolean} = {}) {
7+
AppRegistry.registerComponent('{{{ appKey }}}', () => clientRender);
8+
}
9+
10+
11+
`;
12+
13+
export default (api: IApi) => {
14+
api.addRuntimePlugin(() => [join(api.paths.absTmpPath!, 'react-native', 'runtime.ts')]);
15+
api.onGenerateFiles(() => {
16+
delete api.config.mountElementId;
17+
api.writeTmpFile({
18+
path: 'react-native/runtime.ts',
19+
content: api.utils.Mustache.render(runtimeTpl, {
20+
appKey: api.config?.reactNative?.appKey,
21+
}),
22+
});
23+
});
24+
};

packages/preset/src/plugins/generateFiles/rn/umi.ts packages/preset/src/plugins/generateFiles/react-native/umi.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@ export * from '../core/umiExports';
1212
`;
1313

1414
export default (api: IApi) => {
15-
api.onGenerateFiles(async () => {
15+
api.onGenerateFiles(() => {
1616
api.writeTmpFile({
17-
path: 'rn/umi.ts',
17+
path: 'react-native/umi.ts',
1818
content: CONTENT,
1919
});
2020
});

0 commit comments

Comments
 (0)