Skip to content

Instantly share code, notes, and snippets.

@shirakaba
Created May 21, 2020 21:38
Show Gist options
  • Save shirakaba/bf1ee22a4e4270a02b5ae3f5708322f0 to your computer and use it in GitHub Desktop.
Save shirakaba/bf1ee22a4e4270a02b5ae3f5708322f0 to your computer and use it in GitHub Desktop.
Old, messy rescript config for making react-scripts work with React Native Web
const path = require('path');
const { getPaths, edit, getWebpackPlugin, replaceWebpackPlugin, removeWebpackPlugin, prependWebpackPlugin, paths, appendWebpackPlugin } = require('@rescripts/utilities');
const getModule = (name) => path.resolve(path.join('node_modules', name));
/* With reference to: https://github.com/expo/expo-cli/blob/master/packages/webpack-config/src/webpack.config.ts */
module.exports = config => {
const isEnvDevelopment = config.mode === "development";
const isEnvProduction = config.mode === "production";
config.resolve.alias = {
...config.resolve.alias,
/* https://github.com/expo/expo-cli/blob/master/packages/webpack-config/src/env/alias.ts */
// Alias direct react-native imports to react-native-web
'react-native$': 'react-native-web',
'@react-native-community/netinfo': 'react-native-web/dist/exports/NetInfo',
// Add polyfills for modules that react-native-web doesn't support
// Depends on expo-asset
'react-native/Libraries/Image/AssetSourceResolver$': 'expo-asset/build/AssetSourceResolver',
'react-native/Libraries/Image/assetPathUtils$': 'expo-asset/build/Image/assetPathUtils',
'react-native/Libraries/Image/resolveAssetSource$': 'expo-asset/build/resolveAssetSource',
// Alias internal react-native modules to react-native-web
'react-native/Libraries/Components/View/ViewStylePropTypes$':
'react-native-web/dist/exports/View/ViewStylePropTypes',
'react-native/Libraries/EventEmitter/RCTDeviceEventEmitter$':
'react-native-web/dist/vendor/react-native/NativeEventEmitter/RCTDeviceEventEmitter',
'react-native/Libraries/vendor/emitter/EventEmitter$':
'react-native-web/dist/vendor/react-native/emitter/EventEmitter',
'react-native/Libraries/vendor/emitter/EventSubscriptionVendor$':
'react-native-web/dist/vendor/react-native/emitter/EventSubscriptionVendor',
'react-native/Libraries/EventEmitter/NativeEventEmitter$':
'react-native-web/dist/vendor/react-native/NativeEventEmitter',
/* https://github.com/necolas/react-native-web/issues/1020#issuecomment-416227930 */
// 'react-native-web/dist/exports/Modal': 'modal-react-native-web',
'react-native-modal': 'modal-enhanced-react-native-web',
};
/****** UNINFORMED ATTEMPT TO SUPPORT REACT-NAVIGATION ******/
/* Based on: https://github.com/arackaf/customize-cra/blob/master/src/utilities.js */
const babelLoaderForSrcPaths = getPaths(
inQuestion => {
if(inQuestion && inQuestion.loader && inQuestion.loader.includes('babel-loader')){
/* This distinguishes the two babel-loaders: here we select the one for src rather than node_modules. */
return inQuestion.include === paths.src; /* Where paths.src is 'our' reference to paths.appSrc. */
}
return false;
},
config
);
/* Based on: https://github.com/arackaf/customize-cra/blob/master/api.md#babelinclude */
config = edit(
(babelLoaderForSrc) => {
/* https://github.com/expo/expo-cli/blob/master/packages/webpack-config/src/loaders/createBabelLoader.ts */
const includeModulesThatContainPaths = [
getModule('react-native'),
getModule('react-navigation'),
getModule('expo'),
getModule('unimodules'),
getModule('@react'),
getModule('@expo'),
getModule('@unimodules'),
getModule('native-base'),
];
babelLoaderForSrc.include = [
// make sure you link your own source
path.resolve("src"),
...includeModulesThatContainPaths,
];
/*
* This currently consists of just "...node_modules/babel-preset-react-app/index.js"
* https://github.com/facebook/create-react-app/tree/master/packages/babel-preset-react-app */
// babelLoaderForSrc.options.presets = [
// require.resolve('babel-preset-react-app'),
// /* Based on: https://stackoverflow.com/a/37667682/5951226 (react-native was renamed to: module:metro-react-native-babel-preset)
// * https://github.com/facebook/metro/tree/master/packages/metro-react-native-babel-preset */
// 'module:metro-react-native-babel-preset',
// // babel-plugin-react-native-web ?
// ];
/* "A Babel plugin that will alias react-native to react-native-web and exclude any modules not required by your app (keeping bundle size down)."
* https://github.com/necolas/react-native-web/tree/master/packages/babel-plugin-react-native-web
* In practice, this actually increased the gzipped, minified bundle from 203.34 KB to 243.83 KB! */
// babelLoaderForSrc.options.plugins.push(
// ["react-native-web", { commonjs: true }]
// );
/* Numeric separators (e.g. 10_000_000) have been supported by TypeScript since version 2.7.
* It's still an ES proposal, however, so it doesn't get transpiled by Babel.
* https://github.com/facebook/create-react-app/issues/7329
* Arguably this should be pushed into the plugins of node_modules/babel-preset-react-app/create.js, but it works just as well here. */
babelLoaderForSrc.options.plugins.push(
["@babel/plugin-proposal-numeric-separator", {}],
["react-native-web", { commonjs: true }],
);
return babelLoaderForSrc;
},
babelLoaderForSrcPaths,
config
);
const definePlugin = getWebpackPlugin("DefinePlugin", config);
/* The CRA define process.env with an extra layer of quotes on values, and so so shall we.
* This substitutes for the global variables normally injected by the Metro bundler:
* https://github.com/facebook/metro/blob/1f9a557e892716dffe9ffa250e0c62c2a65a0bdb/packages/metro/src/lib/getPreludeCode.js#L22
* I had expected metro-react-native-babel-preset to do this for us, but I guess it doesn't.
* DefinePlugin docs: https://webpack.js.org/plugins/define-plugin/ */
Object.assign(
definePlugin.definitions,
{
/* Just because it's defined globally doesn't mean that window links to it, so we define both here (it's not redundant).
* However, technically no React code references window.__DEV__ in practice; we shouldn't really look for it on window ourselves either. */
__DEV__: `${isEnvDevelopment}`,
"window.__DEV__": `${isEnvDevelopment}`,
}
);
/************************************************************/
/* https://github.com/necolas/react-native-web/issues/1260#issuecomment-487283912
* Won't need this until AsyncStorage has been removed from core; and by then, RNW should have official recommendations. */
// if (!config.resolve) {
// config.resolve = {};
// }
// if (!config.resolve.alias) {
// config.resolve.alias = {};
// }
// Object.assign(config.resolve.alias, {
// 'react-native-web/dist/exports/AsyncStorage/index.js': '@react-native-community/async-storage',
// // '@react-native-community/async-storage': 'react-native-web/dist/exports/AsyncStorage/index.js'
// });
return config;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment