Created
May 21, 2020 21:38
-
-
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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