Using react-native dependencies which contain Flow code is broken with Next.js 7.0.0
Depending on e.g. react-native-tab-view worked fine with Next.js 6.1.2 / React 16.4.2 / RNW ^0.8.8 / Babel 6
But is giving very strange behaviour with Next.js 7.0.0 / React 16.5.2 / RNW ^0.9.0 / Babel 7
A clear and concise description of what the bug is.
Build error, which when worked around produces very strangely behaving components.
1.
git clone https://github.com/msand/repro-native-web-bug.git
cd repro-native-web-bug
yarn
yarn dev
open localhost:3000
2.
see build error:
Failed to compile
./node_modules/react-native-tab-view/src/index.js
Module build failed (from ./node_modules/next/dist/build/webpack/loaders/next-babel-loader.js):
SyntaxError: /Users/jannegylling/Micke/repro-native-web-bug/node_modules/react-native-tab-view/src/index.js: Support for the experimental syntax 'exportDefaultFrom' isn't currently enabled (12:8):
10 | export { default as SceneMap } from './SceneMap';
11 |
> 12 | export type { Route } from './TypeDefinitions';
| ^
13 | export type { Scene } from './TypeDefinitions';
14 | export type { NavigationState } from './TypeDefinitions';
15 | export type { SceneRendererProps } from './TypeDefinitions';
Add @babel/plugin-proposal-export-default-from (https://git.io/vb4yH) to the 'plugins' section of your Babel config to enable transformation.
This error occurred during the build time and cannot be dismissed.
restart next, open the page, no more build error, instead the content is spinning

add a newline to index.js or mutate it somehow to cause next.js to hot reload the content

The code builds without error, allowing to style react-native components
Expected looks can be seen in the initial commit (second commit only upgrades deps and babel conf to reproduce the bugs)

While investigating this, I've found that if I add this prepare step (available from the "workaround" branch of the repo):
https://github.com/msand/repro-native-web-bug/commit/d1258cd52f285bb4fc3401f3b95282aba46b5bf6#diff-b9cfc7f2cdf78a7f4b91a753d10865a2R7
"prepare": "npx babel node_modules/react-native-tab-view/ --out-dir react-native-tab-view --presets=@babel/preset-react,@babel/preset-flow --plugins=@babel/plugin-proposal-class-properties,@babel/plugin-proposal-object-rest-spread"
And, import the built version of the dependency, it works as expected and without touching the Next.js internals. Thus eliminating the babel, react-native-web and react version changes as potential candidates for causing the symptoms.
Thus, the error most likely resides in the babel/webpack/Next.js configuration of the setup. Could anyone give suggestions for what to try next? Thanks!
@timneutkens
Using react-native dependencies which contain Flow code is broken with Next.js 7.0.0
How would this not be broken in v6 🤔 We never transpiled node_modules
@steida Have you seen/solved any similar issue? Seems Este hasn't upgraded to v7 of Next.js and Babel yet, nor have any dependencies on react-native libraries, but thought you might know quite a lot about Flow + Babel and Next.js and similar setups to this.
@timneutkens I have a custom next.config.js to compile the dependency, I thought this was the standard way to achieve this with Next.js:
https://github.com/msand/repro-native-web-bug/blob/dd191684a2c936bd389c62b21f84eec01a0ed5f7/next.config.js#L1-L32
I guess that would probably work 🤔
Found a different workaround: https://github.com/msand/repro-native-web-bug/commit/70d4198d605f69db72b7ece5304c5a8e7bebeef4
.babelrc
{
"presets": ["next/babel"],
"plugins": [["react-native-web", { "commonjs": true }]]
}
next.config.js
// Update these to match your package scope name.
const internalNodeModulesRegExp = /(?:react-native-tab-view)(?!.*node_modules)/;
const externalNodeModulesRegExp = /node_modules(?!\/(?:react-native-tab-view)(?!.*node_modules))/;
module.exports = {
webpack: (config, { dev, isServer, defaultLoaders }) => {
config.resolve.symlinks = false;
config.externals = config.externals.map(external => {
if (typeof external !== 'function') return external;
return (ctx, req, cb) =>
internalNodeModulesRegExp.test(req) ? cb() : external(ctx, req, cb);
});
config.module.rules.push({
test: /\.+(js|jsx)$/,
use: {
loader: 'next-babel-loader',
options: {
presets: ['module:metro-react-native-babel-preset'],
plugins: [
['react-native-web', { commonjs: true }],
],
},
},
include: [internalNodeModulesRegExp],
});
config.resolve.alias = {
...config.resolve.alias,
'react-native$': 'react-native-web',
};
config.resolve.extensions = ['.web.js', '.js'];
return config;
},
webpackDevMiddleware: config => {
config.watchOptions.ignored = [
...config.watchOptions.ignored,
externalNodeModulesRegExp,
];
return config;
},
};
@timneutkens Is this the correct way to handle this?
I was about to report a similar problem. That is, flow types not being removed; I'm not using react-native(-web) though.
I haven't used next.js before v7 in monorepos, but I'm trying and I cannot import files from other packages in my Yarn Workspaces that use flow types.
No matter what I do, I cannot seem to have the strip-flow-types plugin be applied. I tried manually creating the .babelrc file, I tried applying the transpileModules config key and the next-plugin-transpile-modules plugin.
EDIT: I tried using the configuration example above, adapting it to my own packages, with no luck. I also tried to debug it a bit - it seems like the config.externals array is empty. Also, during my debug, I could see that Next.js is properly loading my custom .babelrc that includes the transform-flow-strip-types plugin. Tried multiple import paths of the plugin btw. Also, I tested just writing garbage in my custom .babelrc to verify that it is indeed being used, and it is (ie, garbage in babel config breaks the build completely).
@msand I just updated http://github.com/este/este, and it seems it works.
Good news.
After investigating this a bit further, I think I found a solution to the issue -- at least as it was happening to me.
What I have is a Yarn Workspace with 2 packages -- one is a "web" package using Next.js, the other is just a library. I added flow type annotations to the library. This would make impossible to import the library in the web package -- it would complain about the type Xxx = {...} definitions.
I tried using the "withTranspileModule" plugin, tried using configuration based on the snippet above shared by @msand , tried customizing my .babelrc to include the @babel/transform-flow-strip-types plugin, tried using a bunch of different presets. Nothing seemed to solve the problem.
Now, the solution I found was to change the defaultLoaders.babel in the Next config file, and include the @babel/transform-flow-strip-types plugin in the .options.plugins field.
Also, I have no idea if this would break any other parts of the build. In a tiny little test scenario it seems to be working OK.
Below is the final version of my next.config.js file that is working just fine -- hope it might help others. Also, might be nice to make sure that there's an example/ that shows (and can be used as a test case) how to setup Yarn Workspaces + Flow across multiple packages. Today, in the examples there's one showing that Yarn Workspaces can be set up, and another one that shows Flow being set up. But no example showed Yarn Workspaces + Flow at the same time.
Here's the next.config.js that works for me. Btw, I have very limited knowledge on Webpack configuration, so I have no clue what the "externals" thing is; I just copied it from the snippet above. It seems like if I remove it, it breaks the config again.
const internalNodeModulesRegExp = /(?:mylib)(?!.*node_modules)/;
const externalNodeModulesRegExp = /node_modules(?!\/(?:mylib)(?!.*node_modules))/;
module.exports = {
webpack: (config, { dev, isServer, defaultLoaders }) => {
// This is the fix that worked for me:
if (!defaultLoaders.babel.options.plugins) {
defaultLoaders.babel.options.plugins = []
}
defaultLoaders.babel.options.plugins.push("@babel/transform-flow-strip-types")
config.resolve.symlinks = false;
// No idea why we use config.externals here, copied from snippet above.
// Without it, the build fails.
config.externals = config.externals.map(external => {
console.log('external', JSON.stringify(external, null, 2))
if (typeof external !== 'function') return external;
return (ctx, req, cb) =>
internalNodeModulesRegExp.test(req) ? cb() : external(ctx, req, cb);
});
// Adding the rule to match my library
config.module.rules.push({
test: /\.+(js|jsx)$/,
use: defaultLoaders.babel,
include: [internalNodeModulesRegExp]
});
return config;
},
// Not sure why we add the "external" regexp to the middleware, but keeping
// it from the snippet above.
webpackDevMiddleware: config => {
config.watchOptions.ignored = [
...config.watchOptions.ignored,
externalNodeModulesRegExp,
];
return config;
},
};
I'm seeing this too — I'm using yarn workspaces and flow for a web project (not react native). I was using flow in this project with Next 5 and Next 6, but am now encountering this issue while upgrading to Next 7.
Syntax Error: SyntaxError: ./src/store.js: Unexpected token, expected "," (18:38)
18 > export const initStore = (initialState: Object = {}) => {
| ^
Interestingly, I'm able to work around the error by renaming my package.json file (not the one in the root dir, but rather the one that corresponds to my monorepo's subpackage) to something else. Perhaps a package.json deeper in the project tree is interfering with Next and the flow strip types babel plugin?
I think this is a more generic bug (feature?). It seems .babelrc is not being found/applied.
cf https://github.com/martpie/next-plugin-transpile-modules/issues/1#issuecomment-425839242
I am not sure who is responsible for this change (Babel, Next.js...)
I'm experiencing this as well after upgrading to 7.0.2 its clearly a regression @timneutkens
Moving to the babel.config.js with the exact same setup works for me. Hence the .babelrc are not being picked up correctly.
Looks like RNW does not support Babel 7 yet? https://github.com/necolas/react-native-web/pull/1191
Webpack is somehow broken, Babel works.
https://github.com/necolas/react-native-web/blob/master/docs/guides/getting-started.md#configuring-babel
Closing as this is the intended behavior of Babel 7 (upgraded from Babel 6). You'll have to use next-transpile-modules if you need this behavior.
Also, be sure to add flow syntax support to your .babelrc.
Most helpful comment
Good news.
After investigating this a bit further, I think I found a solution to the issue -- at least as it was happening to me.
What I have is a Yarn Workspace with 2 packages -- one is a "web" package using Next.js, the other is just a library. I added flow type annotations to the library. This would make impossible to import the library in the web package -- it would complain about the
type Xxx = {...}definitions.I tried using the "withTranspileModule" plugin, tried using configuration based on the snippet above shared by @msand , tried customizing my
.babelrcto include the@babel/transform-flow-strip-typesplugin, tried using a bunch of different presets. Nothing seemed to solve the problem.Now, the solution I found was to change the
defaultLoaders.babelin the Next config file, and include the@babel/transform-flow-strip-typesplugin in the.options.pluginsfield.Also, I have no idea if this would break any other parts of the build. In a tiny little test scenario it seems to be working OK.
Below is the final version of my
next.config.jsfile that is working just fine -- hope it might help others. Also, might be nice to make sure that there's anexample/that shows (and can be used as a test case) how to setup Yarn Workspaces + Flow across multiple packages. Today, in the examples there's one showing that Yarn Workspaces can be set up, and another one that shows Flow being set up. But no example showed Yarn Workspaces + Flow at the same time.Here's the
next.config.jsthat works for me. Btw, I have very limited knowledge on Webpack configuration, so I have no clue what the "externals" thing is; I just copied it from the snippet above. It seems like if I remove it, it breaks the config again.