Skip to content

Commit e7cce93

Browse files
author
徐远翔
committed
feat: bundler-haul done
1 parent ce40891 commit e7cce93

File tree

13 files changed

+110
-112
lines changed

13 files changed

+110
-112
lines changed

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
> 👷 正在施工...
66
77
- [x] umi-preset-react-native:react-native 插件集,**必需**
8+
- [x] umi-plugin-react-native-bundler-haul:第三方 [haul](https://github.com/callstack/haul) 打包器,与 metro 只能**二选一**
89
- [ ] umi-plugin-react-native-bundler-metro:RN 官方 [metro](https://facebook.github.io/metro/) 打包器,与 haul 只能**二选一**
9-
- [ ] umi-plugin-react-native-bundler-haul:第三方 [haul](https://github.com/callstack/haul) 打包器,与 metro 只能**二选一**
1010

1111
## 目录
1212

packages/bundler-haul/package.json

+4-2
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,11 @@
4646
"@haul-bundler/babel-preset-react-native": "0.16.0",
4747
"@haul-bundler/cli": "0.19.0",
4848
"@haul-bundler/preset-0.59": "0.18.0",
49-
"@haul-bundler/preset-0.60": "0.18.0"
49+
"@haul-bundler/preset-0.60": "0.18.0",
50+
"metro": "^0.59.0"
5051
},
5152
"devDependencies": {
52-
"@umijs/types": "^3.0.0"
53+
"@umijs/types": "^3.0.0",
54+
"@umijs/utils": "^3.0.0"
5355
}
5456
}

packages/bundler-haul/src/haulConfigTpl.ts

-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ export default makeConfig({
1111
bundles: {
1212
index: {
1313
entry: withPolyfills('./index.js'),
14-
type: 'basic-bundle',
1514
transform,
1615
},
1716
},

packages/bundler-haul/src/index.ts

+11-5
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
import { dirname, join } from 'path';
2+
import { fork } from 'child_process';
23
import { IApi } from '@umijs/types';
34
import { yargs } from '@umijs/utils';
45
import { name } from '../package.json';
56
import generateFiles from './generateFiles';
67
import babelConfigTpl from './babelConfigTpl';
78
import haulConfigTpl from './haulConfigTpl';
89
import clean from './asyncClean';
9-
import { fork } from 'child_process';
1010

1111
export interface IHaulStartOptions {
1212
port?: number;
@@ -33,7 +33,7 @@ interface ICommand {
3333
export default (api: IApi) => {
3434
const {
3535
utils: { portfinder, semver, Mustache, lodash, resolve, winPath },
36-
paths: { absTmpPath, cwd },
36+
paths: { absTmpPath },
3737
} = api;
3838
async function handler({ args }: { args: yargs.Arguments<IHaulStartOptions> }): Promise<void> {
3939
const defaultPort = process.env.PORT || args?.port;
@@ -69,9 +69,9 @@ export default (api: IApi) => {
6969

7070
watch(await generateFiles({ api, watch: isWatch }));
7171

72-
const child = fork(require.resolve('@haul-bundler/cli/bin/haul.js'), argv, {
72+
const child = fork(resolve.sync('@haul-bundler/cli/bin/haul.js', { basedir: absTmpPath }), argv, {
7373
stdio: 'inherit',
74-
cwd,
74+
cwd: absTmpPath,
7575
});
7676
child.on('close', (code) => {
7777
unwatch();
@@ -133,11 +133,17 @@ export default (api: IApi) => {
133133
const config = bundleConfigs.filter((bundleConfig: any) => {
134134
return bundleConfig.entry?.umi;
135135
})[0];
136+
137+
const alias = lodash.omit(config.resolve?.alias, ['react-dom']);
138+
Object.assign(alias, {
139+
// haul似乎没有开启treeShaking, 会加载umi common js格式的代码, 导致webpack构建时:out of memory
140+
umi: resolve.sync('umi/dist/index.esm.js', { basedir: absTmpPath }),
141+
});
136142
api.writeTmpFile({
137143
path: 'haul.config.js',
138144
content: Mustache.render(haulConfigTpl, {
139145
haulPresetPath: winPath(detectHaulPresetPath()),
140-
alias: JSON.stringify(lodash.omit(config.resolve?.alias, ['react-dom']), null, 2),
146+
alias: JSON.stringify(alias, null, 2),
141147
}),
142148
});
143149
});

packages/bundler-metro/package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,8 @@
4545
"umi-preset-react-native": "^0.0.0"
4646
},
4747
"devDependencies": {
48-
"@umijs/types": "^3.0.0"
48+
"@umijs/types": "^3.0.0",
49+
"@umijs/utils": "^3.0.0"
4950
},
5051
"dependencies": {
5152
"babel-plugin-module-resolver": "^4.0.0"
+1-21
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,6 @@
11
export default `
22
module.exports = {
3-
presets: ['{{{ metroPresetsPath }}}'],
4-
plugins: [
5-
[
6-
'{{{ moduleResolverPath }}}',
7-
{
8-
root: ['{{{ root }}}'],
9-
extensions: [
10-
'.ios.ts',
11-
'.android.ts',
12-
'.ts',
13-
'.ios.tsx',
14-
'.android.tsx',
15-
'.tsx',
16-
'.jsx',
17-
'.js',
18-
'.json',
19-
],
20-
alias: {{{ alias }}},
21-
},
22-
],
23-
],
3+
presets: ['module:metro-react-native-babel-preset'],
244
};
255
266
`;

packages/bundler-metro/src/index.ts

+13-17
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { dirname, join } from 'path';
2-
import { existsSync, symlinkSync } from 'fs';
3-
import { platform } from 'os';
2+
import { existsSync } from 'fs';
43
import { fork } from 'child_process';
54
import { IApi } from '@umijs/types';
65
import { yargs } from '@umijs/utils';
@@ -10,8 +9,6 @@ import babelConfigTpl from './babelConfigTpl';
109
import clean from './asyncClean';
1110
import metroConfigTpl from './metroConfigTpl';
1211

13-
const PLATFORM = platform();
14-
1512
interface ICommand {
1613
name: string;
1714
alias?: string;
@@ -48,7 +45,13 @@ export default (api: IApi) => {
4845
paths: { absTmpPath, absNodeModulesPath, absSrcPath, cwd },
4946
} = api;
5047
async function handler({ args }: { args: yargs.Arguments<IMetroStartOptions> }): Promise<void> {
51-
const argv: string[] = ['start', '--projectRoot', absTmpPath || ''];
48+
const argv: string[] = [
49+
'start',
50+
'--projectRoot',
51+
absTmpPath || '',
52+
'--config',
53+
join(absTmpPath || '', 'metro.config.js'),
54+
];
5255

5356
const unwatchs: Function[] = [];
5457
const isWatch = process.env.WATCH !== 'none';
@@ -114,7 +117,6 @@ export default (api: IApi) => {
114117
} as ICommand);
115118

116119
api.onGenerateFiles(async () => {
117-
const runtimeBuiltInUmiDir = dirname(resolve.sync('@umijs/runtime/package.json', { basedir: process.env.UMI_DIR }));
118120
const buildDevUtilsPath = resolve.sync('@umijs/preset-built-in/lib/plugins/commands/buildDevUtils', {
119121
basedir: process.env.UMI_DIR,
120122
});
@@ -123,34 +125,28 @@ export default (api: IApi) => {
123125
const config = bundleConfigs.filter((bundleConfig: any) => {
124126
return bundleConfig.entry?.umi;
125127
})[0];
126-
const aliasObj = lodash.omit(config.resolve?.alias, ['react-dom']);
127-
Object.assign(aliasObj, { [runtimeBuiltInUmiDir]: aliasObj['@umijs/runtime'] });
128-
const alias = JSON.stringify({}, null, 2);
128+
// const aliasObj = lodash.omit(config.resolve?.alias, ['react-dom']);
129+
// Object.assign(aliasObj, { [runtimeBuiltInUmiDir]: '@umijs/runtime' }); // hack for umi generateFiles: .umi/core/**/*.ts
130+
// const alias = JSON.stringify(aliasObj, null, 2);
129131
api.writeTmpFile({
130132
path: 'babel.config.js',
131133
content: Mustache.render(babelConfigTpl, {
132134
moduleResolverPath: winPath(dirname(require.resolve('babel-plugin-module-resolver/package.json'))),
133135
metroPresetsPath: winPath(resolve.sync('metro-react-native-babel-preset', { basedir: absSrcPath })),
134136
root: cwd,
135-
alias,
137+
// alias,
136138
}),
137139
});
138140
const userMetroConfig = join(absSrcPath || '', 'metro.config.js');
139141
const userConfigs = existsSync(userMetroConfig) ? `require('${winPath(userMetroConfig)}')` : '{}';
140-
// const watchFolders = lodash.uniq(Object.keys(aliasObj).map((it) => aliasObj[it]));
141142
const watchFolders = [absTmpPath];
142143
api.writeTmpFile({
143144
path: 'metro.config.js',
144145
content: Mustache.render(metroConfigTpl, {
145146
userConfigs,
146147
watchFolders: JSON.stringify(watchFolders, null, 2),
147-
alias,
148-
nodeModulePath: absNodeModulesPath,
148+
// alias,
149149
}),
150150
});
151-
const link = join(absTmpPath || '', 'node_modules');
152-
if (!existsSync(link)) {
153-
symlinkSync(absNodeModulesPath || '', link, PLATFORM === 'win32' ? 'junction' : 'dir');
154-
}
155151
});
156152
};

packages/bundler-metro/src/metroConfigTpl.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@ const watchFolders = {{{ watchFolders }}};
88
99
module.exports = mergeConfig(userConfig, {
1010
resolver: {
11-
resolverMainFields: ['module', 'browser', 'main'],
11+
resolverMainFields: ['react-native', 'module', 'browser', 'main'],
1212
extraNodeModules: new Proxy(extraNodeModules, {
1313
get: (target, name) =>
1414
name in target
1515
? target[name]
16-
: path.join('{{{ nodeModulePath }}}', name),
16+
: path.join(__dirname, 'node_modules', name),
1717
}),
1818
},
1919
watchFolders,

packages/preset/package.json

-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@
4646
"react-router-native": "5.1.2"
4747
},
4848
"devDependencies": {
49-
"@types/react-router": "^5.1.5",
5049
"@types/react-router-native": "^5.1.0",
5150
"@umijs/types": "^3.0.0"
5251
}

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

+50-47
Original file line numberDiff line numberDiff line change
@@ -6,59 +6,34 @@ import { assertExists } from '../../utils';
66

77
export default (api: IApi) => {
88
const {
9-
pkg,
10-
utils: { resolve, winPath },
11-
paths: { absNodeModulesPath = '', absSrcPath = '', cwd },
9+
utils: { winPath, resolve },
10+
paths: { absNodeModulesPath = '', absSrcPath = '', absTmpPath },
1211
} = api;
1312

14-
function getUserLibDir({ library }: { library: string }) {
15-
if ((pkg.dependencies && pkg.dependencies[library]) || (pkg.devDependencies && pkg.devDependencies[library])) {
16-
// 通过 resolve 往上找,可支持 lerna 仓库
17-
// lerna 仓库如果用 yarn workspace 的依赖不一定在 node_modules,可能被提到根目录,并且没有 link
18-
return winPath(
19-
resolve.sync(library, {
20-
basedir: cwd,
21-
}),
22-
);
23-
}
13+
function getUserLibDir(library: string, dir?: boolean) {
14+
try {
15+
if (dir) {
16+
return dirname(
17+
resolve.sync(join(library, 'package.json'), {
18+
basedir: absTmpPath,
19+
}),
20+
);
21+
} else {
22+
return resolve.sync(library, {
23+
basedir: absTmpPath,
24+
});
25+
}
26+
} catch (ignored) {}
2427
return null;
2528
}
2629

27-
const REACT_NATIVE_PATH = join(absNodeModulesPath, 'react-native');
28-
const METRO_PATH = join(absNodeModulesPath, 'react-native');
30+
const REACT_NATIVE_PATH = getUserLibDir('react-native', true) || join(absNodeModulesPath, 'react-native');
2931
assertExists(REACT_NATIVE_PATH);
30-
assertExists(METRO_PATH);
3132
const { version } = require(join(REACT_NATIVE_PATH, 'package.json'));
32-
const Libraries = [
33-
{
34-
name: 'react-router',
35-
path: 'react-router',
36-
},
37-
{
38-
name: 'react-router-config',
39-
path: 'react-router-config',
40-
},
41-
{
42-
name: 'react-router-dom', // hack for plugin-dva
43-
path: 'react-router-native',
44-
},
45-
{
46-
name: 'react-router-native',
47-
path: 'react-router-native',
48-
},
49-
// {
50-
// name: '@umijs/runtime',
51-
// path: '@umijs/runtime',
52-
// },
53-
// {
54-
// name: 'history',
55-
// path: 'history-with-query',
56-
// },
57-
];
5833

5934
let appKey;
6035
try {
61-
const appJson = JSON.parse(readFileSync(join(absSrcPath, 'app.json'), 'utf8'));
36+
const appJson = JSON.parse(readFileSync(getUserLibDir('app.json') || join(absSrcPath, 'app.json'), 'utf8'));
6237
appKey = appJson.name;
6338
} catch (ignored) {}
6439

@@ -78,10 +53,38 @@ export default (api: IApi) => {
7853
});
7954

8055
api.chainWebpack((memo) => {
81-
Libraries.forEach(({ name, path }) => {
82-
memo.resolve.alias.set(name, getUserLibDir({ library: path }) || winPath(require.resolve(join(path))));
83-
});
84-
memo.resolve.alias.set('react-native', REACT_NATIVE_PATH).set('metro', METRO_PATH);
56+
const reactRouterNativePath = winPath(
57+
getUserLibDir('react-router-native', true) || dirname(require.resolve('react-router-native/package.json')),
58+
);
59+
memo.resolve.alias
60+
.set(
61+
'history',
62+
winPath(
63+
getUserLibDir('history-with-query/esm/history.js') || require.resolve('history-with-query/esm/history.js'),
64+
),
65+
)
66+
.set(
67+
'react-router',
68+
winPath(
69+
getUserLibDir('react-router/esm/react-router.js') || require.resolve('react-router/esm/react-router.js'),
70+
),
71+
)
72+
.set('react-router-dom', reactRouterNativePath) // hack for dva
73+
.set('react-router-native', reactRouterNativePath)
74+
.set(
75+
'react-router-config',
76+
winPath(
77+
getUserLibDir('react-router-config/esm/react-router-config.js') ||
78+
require.resolve('react-router-config/esm/react-router-config.js'),
79+
),
80+
)
81+
.set(
82+
'@umijs/runtime',
83+
winPath(
84+
getUserLibDir('@umijs/runtime/dist/index.esm.js') ||
85+
resolve.sync('@umijs/runtime/dist/index.esm.js', { basedir: process.env.UMI_DIR }),
86+
),
87+
);
8588
return memo;
8689
});
8790

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

+10
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,15 @@
1+
import { existsSync, symlinkSync } from 'fs';
2+
import { join } from 'path';
3+
import { platform } from 'os';
14
import { IApi } from '@umijs/types';
25
import indexTpl from './indexTpl';
36

7+
const PLATFORM = platform();
8+
49
export default (api: IApi) => {
510
const {
611
utils: { Mustache, winPath },
12+
paths: { absTmpPath, absNodeModulesPath },
713
} = api;
814

915
function importsToStr(imports: { source: string; specifier?: string }[]): string[] {
@@ -52,5 +58,9 @@ export default (api: IApi) => {
5258
).join('\r\n'),
5359
}),
5460
});
61+
const link = join(absTmpPath || '', 'node_modules');
62+
if (!existsSync(link)) {
63+
symlinkSync(absNodeModulesPath || '', link, PLATFORM === 'win32' ? 'junction' : 'dir');
64+
}
5565
});
5666
};

0 commit comments

Comments
 (0)