Skip to content

Instantly share code, notes, and snippets.

@marklawlor
Last active May 3, 2021 00:19
Show Gist options
  • Save marklawlor/82cf911cea27a4e118822395ae93ca7b to your computer and use it in GitHub Desktop.
Save marklawlor/82cf911cea27a4e118822395ae93ca7b to your computer and use it in GitHub Desktop.
diff --git a/node_modules/@expo/next-adapter/build/withExpo.js b/node_modules/@expo/next-adapter/build/withExpo.js
index 2e63eb4..b1cf9a9 100644
--- a/node_modules/@expo/next-adapter/build/withExpo.js
+++ b/node_modules/@expo/next-adapter/build/withExpo.js
@@ -7,8 +7,8 @@ function withExpo(nextConfig = {}) {
// Prevent define plugin from overwriting Next.js environment.
process.env.EXPO_WEBPACK_DEFINE_ENVIRONMENT_AS_KEYS = 'true';
const expoConfig = addons_1.withUnimodules(config, {
- projectRoot: nextConfig.projectRoot || process.cwd(),
- }, { supportsFontLoading: false });
+ projectRoot: nextConfig.projectRoot || process.cwd()
+ }, { supportsFontLoading: false, webpack5: (options.config.future || {}).webpack5 });
// Use original public path
(expoConfig.output || {}).publicPath = (config.output || {}).publicPath;
// TODO: Bacon: use commonjs for RNW babel maybe...
diff --git a/node_modules/@expo/webpack-config/webpack/addons/withUnimodules.js b/node_modules/@expo/webpack-config/webpack/addons/withUnimodules.js
index 67671c7..b023007 100644
--- a/node_modules/@expo/webpack-config/webpack/addons/withUnimodules.js
+++ b/node_modules/@expo/webpack-config/webpack/addons/withUnimodules.js
@@ -38,6 +38,7 @@ function withUnimodules(webpackConfig = {}, env = {}, argv = {}) {
webpackConfig.output = {};
// Attempt to use the input webpack config mode
env.mode = env.mode || webpackConfig.mode;
+ const isWebpack5 = argv.webpack5
const environment = env_1.validateEnvironment(env);
let { supportsFontLoading } = argv;
// If the args don't specify this then we'll check if the input already supports font loading.
@@ -105,7 +106,7 @@ function withUnimodules(webpackConfig = {}, env = {}, argv = {}) {
extensions: env_1.getModuleFileExtensions('web') });
// Transpile and remove expo modules from Next.js externals.
const includeFunc = babelLoader.include;
- webpackConfig = ignoreExternalModules(webpackConfig, includeFunc);
+ webpackConfig = ignoreExternalModules(webpackConfig, includeFunc, isWebpack5);
// Add a loose requirement on the ResizeObserver polyfill if it's installed...
webpackConfig = withEntry_1.default(webpackConfig, env, {
entryPath: 'resize-observer-polyfill/dist/ResizeObserver.global',
@@ -125,7 +126,7 @@ exports.default = withUnimodules;
* @param webpackConfig Config to be modified
* @param shouldIncludeModule A method that returns a boolean when the input module should be transpiled and externed.
*/
-function ignoreExternalModules(webpackConfig, shouldIncludeModule) {
+function ignoreExternalModules(webpackConfig, shouldIncludeModule, isWebpack5) {
if (!webpackConfig.externals) {
return webpackConfig;
}
@@ -136,6 +137,14 @@ function ignoreExternalModules(webpackConfig, shouldIncludeModule) {
if (typeof external !== 'function') {
return external;
}
+
+ if (isWebpack5) {
+ return ((ctx) => {
+ const relPath = path_1.default.join('node_modules', ctx.request);
+ return shouldIncludeModule(relPath) ? undefined : external(ctx);
+ })
+ }
+
return ((ctx, req, cb) => {
const relPath = path_1.default.join('node_modules', req);
return shouldIncludeModule(relPath) ? cb() : external(ctx, req, cb);
module.exports = {
presets: ['@expo/next-adapter/babel'],
plugins: ["@babel/plugin-proposal-class-properties"],
};
const { withExpo } = require("@expo/next-adapter");
const withTM = require("next-transpile-modules")(["@shared/components"]);
const withPlugins = require("next-compose-plugins");
module.exports = withPlugins([withTM, [withExpo, { projectRoot: __dirname }]], {
future: { webpack5: true },
});
"resolutions": {
"webpack": "^5",
"react": "17.0.1",
"react-dom": "17.0.1",
"html-webpack-plugin": "5.3.1"
},
@marklawlor
Copy link
Author

marklawlor commented May 2, 2021

Explanation of changes

@expo+next-adapter

Simply passes and extra flag to the @expo+webpack-config

@expo+webpack-config

Webpack5 changed the call signature of the externals function. There are two function signatures (https://webpack.js.org/configuration/externals/#function), however the callback version does not seem to work with NextJS (most likely because NextJS uses an internal stripped down version of webpack)

This function's purpose is to remove the packages that Expo needs to transpile from the Webpacks' externals array (which is normally everything inside node_modules). As they are no longer externals, they can be processed via the babel-loader (which typically skips node_modules but the custom babel-loader has a special match function to target them).

To remove these packages as an external, you simply return undefined. In Webpack4 this was done via cb(undefined, undefined) but in Webpack5 we can simply return undefined.

While Webpack5 documents you need to return a promise, this code is executed in a promise chain so it doesn't matter is you return undefined or Promise.resolve().

Enabling the React 17 JSX transform (TODO)

This can be done via Expo's platform options, however the @expo/next-adapter does not seem to pass the options correctly

How to enable the transform: https://github.com/expo/expo/blob/540185b2680357dbe87b21e7a820d74748f4c943/packages/babel-preset-expo/index.js#L43
But the next adapter calls this plugin with no options: https://github.com/expo/expo-cli/blob/e80a7dddc8d59a909f40eeeef36a677109540d5a/packages/next-adapter/src/babel.ts#L27

babel.config.js

NextJS 10.0.2 removed all class functions, so they no longer include @babel/plugin-proposal-class-properties. As Expo still uses a class for the _document.jsx this needs to be included.

A better solution would be to rewrite _document.jsx as a functional component

@nandorojo
Copy link

Do your react resolutions work normally on native too?

@nandorojo
Copy link

nandorojo commented May 2, 2021

Could you elaborate on your changes in babel-preset-expo?

  1. Why are you always setting dev on web?
  2. Why did you add useTransformReactJsxExperimental? Is this for react 17, or for transpiling?

I'm not that well versed in babel so bear with these questions.

@nandorojo
Copy link

@nandorojo
Copy link

nandorojo commented May 2, 2021

@marklawlor I notice that you aren't including expo packages or react-native-web in the modules to transpile. Is that what the JSX transform solves?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment