Skip to content

Commit fa230d2

Browse files
author
徐远翔
committed
feat: support haul
1 parent 43e073c commit fa230d2

File tree

15 files changed

+154
-70
lines changed

15 files changed

+154
-70
lines changed

packages/umi-preset-react-native/src/plugins/features/reactNative.ts

+17-12
Original file line numberDiff line numberDiff line change
@@ -112,18 +112,23 @@ export default (api: IApi) => {
112112
throw new TypeError('"history.type" 配置错误');
113113
}
114114

115-
if (api.config.haul) {
116-
if (api.config.dynamicImport && !api.config.dynamicImport.loading) {
117-
api.logger.error(
118-
`在 RN 环境中启用"dynamicImport"功能时,必须实现自定义的"loading"!${EOL}因为 umi 默认 loading 使用了 HTML 标签,在 RN 中运行会报错!${EOL}查看如何配置自定义 loading:https://umijs.org/config#dynamicimport`,
119-
);
120-
throw new TypeError('"dynamicImport.loading" 未配置');
121-
}
122-
} else {
123-
if (api.config.dynamicImport) {
124-
api.logger.error('在 RN 环境中暂不支持:"dynamicImport"功能。');
125-
throw new TypeError('在 RN 环境中暂不支持:"dynamicImport"功能。');
126-
}
115+
if (api.config.dynamicImport) {
116+
api.logger.error('在 RN 环境中暂不支持:"dynamicImport"功能。');
117+
throw new TypeError('在 RN 环境中暂不支持:"dynamicImport"功能。');
127118
}
119+
120+
// if (api.config.haul) {
121+
// if (api.config.dynamicImport && !api.config.dynamicImport.loading) {
122+
// api.logger.error(
123+
// `在 RN 环境中启用"dynamicImport"功能时,必须实现自定义的"loading"!${EOL}因为 umi 默认 loading 使用了 HTML 标签,在 RN 中运行会报错!${EOL}查看如何配置自定义 loading:https://umijs.org/config#dynamicimport`,
124+
// );
125+
// throw new TypeError('"dynamicImport.loading" 未配置');
126+
// }
127+
// } else {
128+
// if (api.config.dynamicImport) {
129+
// api.logger.error('在 RN 环境中暂不支持:"dynamicImport"功能。');
130+
// throw new TypeError('在 RN 环境中暂不支持:"dynamicImport"功能。');
131+
// }
132+
// }
128133
});
129134
};

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

+65-3
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,83 @@
11
import { IApi } from 'umi';
2-
import { asyncClean, generateConfigFiles, generateFiles } from '../../utils';
2+
import { join } from 'path';
3+
import { asyncClean, generateConfigFiles } from '../../utils';
34

45
interface IRNGeneratorArguments {
56
dev?: boolean;
67
}
78

89
export default (api: IApi) => {
10+
const {
11+
utils: { lodash, winPath, chokidar },
12+
paths,
13+
} = api;
14+
async function generateFiles() {
15+
await api.applyPlugins({
16+
key: 'onGenerateFiles',
17+
type: api.ApplyPluginsType.event,
18+
});
19+
}
20+
921
async function handler(watch?: boolean): Promise<void> {
1022
const start = Date.now();
1123
api.logger.info(`Starting react-native generator in ${process.env.NODE_ENV} mode.`);
1224

1325
await asyncClean(api, '.cache', 'node_modules');
14-
const unwatch = await generateFiles(api, watch);
26+
await generateFiles();
1527
await generateConfigFiles(api);
1628

29+
const unwatches: ((() => void) | { close: () => void })[] = [];
30+
31+
if (watch) {
32+
const watcherPaths = await api.applyPlugins({
33+
key: 'addTmpGenerateWatcherPaths',
34+
type: api.ApplyPluginsType.add,
35+
initialValue: [
36+
paths.absPagesPath!,
37+
join(paths.absSrcPath!, api.config?.singular ? 'layout' : 'layouts'),
38+
join(paths.absSrcPath!, 'app.tsx'),
39+
join(paths.absSrcPath!, 'app.ts'),
40+
join(paths.absSrcPath!, 'app.jsx'),
41+
join(paths.absSrcPath!, 'app.js'),
42+
],
43+
});
44+
lodash.uniq<string>(watcherPaths.map((p: string) => winPath(p))).forEach((p: string) => {
45+
createWatcher(p);
46+
});
47+
}
48+
49+
function unwatchAll() {
50+
while (unwatches.length) {
51+
const unwatch = unwatches.pop();
52+
try {
53+
if (typeof unwatch === 'function') {
54+
unwatch();
55+
} else if (unwatch && typeof unwatch.close === 'function') {
56+
unwatch.close();
57+
}
58+
} catch (ignored) {}
59+
}
60+
}
61+
62+
function createWatcher(path: string) {
63+
const watcher = chokidar.watch(path, {
64+
// ignore .dotfiles and _mock.js
65+
// eslint-disable-next-line no-useless-escape
66+
ignored: /(^|[\/\\])(_mock.js$|\..)/,
67+
ignoreInitial: true,
68+
});
69+
watcher.on(
70+
'all',
71+
lodash.throttle(async () => {
72+
api.logger.info('File change detected. Starting regenerate...');
73+
await generateFiles();
74+
}, 500),
75+
);
76+
unwatches.push(watcher);
77+
}
78+
1779
process.on('exit', () => {
18-
unwatch();
80+
unwatchAll();
1981
if (!watch) {
2082
api.logger.info(`Successfully completed in ${Date.now() - start}ms.`);
2183
}

packages/umi-preset-react-native/src/templates/haulConfigTpl.ts

+17
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ const transform = ({ config }) => {
55
return _.defaultsDeep({{{ webpackConfig }}}, config);
66
};
77
8+
{{#bundles}}
89
export default makeConfig({
910
templates: {
1011
filename: {
@@ -35,5 +36,21 @@ export default makeConfig({
3536
...{{{ bundles }}},
3637
},
3738
});
39+
{{/bundles}}
40+
{{^bundles}}
41+
export default makeConfig({
42+
bundles: {
43+
index: {
44+
entry: withPolyfills(
45+
'@/index',
46+
{
47+
additionalSetupFiles: ['@@/react-native/polyfill', '@@/core/plugin'],
48+
}
49+
),
50+
transform,
51+
},
52+
},
53+
});
54+
{{/bundles}}
3855
3956
`;

packages/umi-preset-react-native/src/utils.ts

+55-55
Original file line numberDiff line numberDiff line change
@@ -322,16 +322,14 @@ export async function generateConfigFiles(api: IApi): Promise<void> {
322322
presets.push('module:metro-react-native-babel-preset');
323323
}
324324

325-
if (!api.config.haul) {
326-
plugins.push([
327-
require.resolve('babel-plugin-module-resolver'),
328-
{
329-
root: [paths.absSrcPath],
330-
extensions: ['.ts', '.tsx', '.native.js', '.native.jsx', '.esm.js', '.js', '.jsx', '.json'],
331-
alias: config.resolve.alias,
332-
},
333-
]);
334-
}
325+
plugins.push([
326+
require.resolve('babel-plugin-module-resolver'),
327+
{
328+
root: [paths.absSrcPath],
329+
extensions: ['.ts', '.tsx', '.native.js', '.native.jsx', '.esm.js', '.js', '.jsx', '.json'],
330+
alias: config.resolve.alias,
331+
},
332+
]);
335333

336334
const presetOpts = await api.applyPlugins({
337335
type: api.ApplyPluginsType.modify,
@@ -401,61 +399,63 @@ export async function generateConfigFiles(api: IApi): Promise<void> {
401399
isExpo,
402400
}),
403401
),
402+
asyncWriteTmpFile(
403+
api,
404+
join(cwd, 'metro.config.js'),
405+
Mustache.render(METRO_CONFIG_TPL, {
406+
watchFolders: [paths.absTmpPath],
407+
userConfigFile: winPath(userConfigFile),
408+
useUserConfig: existsSync(userConfigFile),
409+
}),
410+
),
404411
asyncWriteTmpFile(api, join(cwd, 'index.js'), INDEX_TPL),
405412
];
406413

407414
if (api.config.haul) {
408-
const routes = await api.getRoutes();
409-
tasks.push(
410-
asyncWriteTmpFile(
411-
api,
412-
join(cwd, 'haul.config.js'),
413-
Mustache.render(HAUL_CONFIG_TPL, {
414-
haulPresetPath: winPath(detectHaulPresetPath()),
415-
webpackConfig: JSON.stringify(config, null, 2),
416-
dependencies: JSON.stringify(
417-
lodash.keys(
418-
lodash.omit(config.resolve.alias, [
419-
'@',
420-
'@@',
421-
'react-dom',
422-
'react-router-dom',
423-
'regenerator-runtime',
424-
'./core/polyfill',
425-
'./core/routes',
426-
'@@/core/routes',
427-
]),
415+
if (api.config.dynamicImport && api.config.dynamicImport.loading) {
416+
const routes = await api.getRoutes();
417+
tasks.push(
418+
asyncWriteTmpFile(
419+
api,
420+
join(cwd, 'haul.config.js'),
421+
Mustache.render(HAUL_CONFIG_TPL, {
422+
haulPresetPath: winPath(detectHaulPresetPath()),
423+
webpackConfig: JSON.stringify(config, null, 2),
424+
dependencies: JSON.stringify(
425+
lodash.keys(
426+
lodash.omit(config.resolve.alias, [
427+
'@',
428+
'@@',
429+
'react-dom',
430+
'react-router-dom',
431+
'regenerator-runtime',
432+
'./core/polyfill',
433+
'./core/routes',
434+
'@@/core/routes',
435+
]),
436+
),
428437
),
429-
),
430-
bundles: bundlesToJSON(api, transformRoutesToBundle(routes)),
431-
}),
432-
),
433-
);
434-
} else {
435-
tasks.push(
436-
asyncWriteTmpFile(
437-
api,
438-
join(cwd, 'metro.config.js'),
439-
Mustache.render(METRO_CONFIG_TPL, {
440-
watchFolders: [paths.absTmpPath],
441-
userConfigFile: winPath(userConfigFile),
442-
useUserConfig: existsSync(userConfigFile),
443-
}),
444-
),
445-
);
438+
bundles: bundlesToJSON(api, transformRoutesToBundle(routes)),
439+
}),
440+
),
441+
);
442+
} else {
443+
tasks.push(
444+
asyncWriteTmpFile(
445+
api,
446+
join(cwd, 'haul.config.js'),
447+
Mustache.render(HAUL_CONFIG_TPL, {
448+
haulPresetPath: winPath(detectHaulPresetPath()),
449+
webpackConfig: JSON.stringify(config, null, 2),
450+
}),
451+
),
452+
);
453+
}
446454
}
447455

448456
await Promise.all(tasks);
449457
}
450458

451-
export async function generateFiles(api: IApi, watch?: boolean): Promise<() => void> {
452-
const generateFiles = require(api.utils.resolve.sync('@umijs/preset-built-in/lib/plugins/commands/generateFiles', {
453-
basedir: process.env.UMI_DIR,
454-
})).default;
455-
456-
return generateFiles({ api, watch });
457-
}
458-
459459
interface IGetUserLibDirOptions {
460460
api: IApi;
461461
/**

0 commit comments

Comments
 (0)