Цели
Я пытаюсь интегрировать react-navigation
в проект react-native-web
, запущенный из шаблона Create React App TypeScript. Я хочу добиться наименьшего возможного размера пакета для моего веб-приложения React Native, но хочу также сохранить типизацию TypeScript.
Проблема
Я обнаружил, что когда я импортирую любой модуль из react-navigation
(чья точка входа реэкспортирует многие другие модули), Webpack связывает каждый этих реэкспортированных модулей, даже если я не используя их. Это удваивает весь размер моего пакета!
Я не уверен, связано ли это с плохой архитектурой react-navigation
(например, она не указывает "sideEffects": false
в своем package.json
), или из-за того, что Babel переносит импорт ES6 вниз в формат, который может не трясется Это все вне моей компетенции.
Моя настройка
Я дополнил стандартную конфигурацию Create React App с помощью rescripts
(аналогично customise-cra
). react-navigation
было интегрировано следующим образом:
- Завершить навигацию React Начало работы Guide;
- Добавьте
react-navigation
и его различные зависимости в список CRA Babel, включая rescripts
, как показано ниже.
// .rescriptsrc.js
const {getPaths, edit, getWebpackPlugin, paths} = require('@rescripts/utilities')
module.exports = config => {
const isEnvDevelopment = config.mode === "development";
/* Find the Babel loder. */
const babelLoaderPaths = getPaths(
x => {
if(x && x.loader && x.loader.includes('babel-loader')){
/* This distinguishes CRA's two babel-loaders.
* Here we select the application src loader. */
return inQuestion.include === paths.src;
}
return false;
},
config
);
/* In customise-cra, this would be babelinclude() */
config = edit(
(babelLoader) => {
babelLoader.include = [
path.resolve("src"), // CRA holds just this line by default.
/* These need transpiling (e.g. they contain JSX) */
path.resolve("node_modules/@react-navigation"),
path.resolve("node_modules/react-navigation"),
path.resolve("node_modules/react-native-gesture-handler"),
path.resolve("node_modules/react-native-screens"),
path.resolve("node_modules/react-navigation-drawer"),
path.resolve("node_modules/react-navigation-tabs"),
path.resolve("node_modules/react-native-tab-view"),
];
return babelLoader;
},
babelLoaderPaths,
config
);
/* Emulate the Metro bundler's behaviour of injecting __DEV__ globally */
const definePlugin = getWebpackPlugin("DefinePlugin", config);
Object.assign(definePlugin.definitions, { __DEV__: `${isEnvDevelopment}` });
}
Размер пакета в зависимости от стратегии импорта
Для справки, мой базовый размер пакета (без react-navigation
):
- 91 765 строк кода, 721 КБ в комплекте разработчика
- Минимизированный (производственный) комплект 361 КБ
Я не буду ссылаться на размеры gzip.
Импорт из react-navigation
???
react-navigation
реэкспорт все из @react-navigation/core
, @react-navigation/native
и ряд других модулей, таких как react-navigation-drawer
.
Все эти модули расточительно входят в мой комплект!
import { createAppContainer, createSwitchNavigator } from "react-navigation";
const appNavigator = createSwitchNavigator(/* Whatever */);
createAppContainer(appNavigator);
/*
- Adds 19,391 lines and 115 KB to dev bundle
- Adds 352 KB to minified (production) bundle
*/
Импорт из субмодулей @react-navigation
10
Все эти модули бесполезно входят в мой комплект, но, по крайней мере, он не связывает модули, подобные react-navigation-drawer
!
? Проблема: мы теряем набор текста!
const RNCore: any = require("@react-navigation/core");
const RNNative: any = require("@react-navigation/native");
const appNavigator = RNNative.createSwitchNavigator(/* Whatever */);
RNCore.createAppContainer(appNavigator);
/*
- Adds 9,004 lines and 55 KB to dev bundle
- Adds 226 KB to minified (production) bundle
*/
Импорт напрямую из целевого модуля ?
Эти модули ничего не реэкспортируют, и импорт таким образом приводит к наименьшему размеру пакета.
К сожалению, createAppContainer
сам импортирует некоторые модули из @react-navigation/core
, и я вижу, что пакет, таким образом, тратит впустую все, что также реэкспортируется из @react-navigation/core
, поэтому он все еще не идеален.
? Проблема: мы теряем набор текста!
const createSwitchNavigator: any = require("@react-navigation/core/lib/commonjs/navigators/createSwitchNavigator").default;
const createAppContainer: any = require("@react-navigation/native/dist/createAppContainer").default;
const appNavigator = createSwitchNavigator(/* Whatever */);
createAppContainer(appNavigator);
/*
- Adds 7,000 lines and 40 KB to dev bundle
- Adds 75 KB to minified bundle
*/
Дальнейшее чтение
Эта проблема является сценарием использования для babel-transform-imports
, babel-plugin-import
и babel-plugin-direct-import
. Однако это были очень хитрые обходные пути, представленные два года назад. Я надеюсь, что сейчас есть лучшее современное состояние.