Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Babel configuration not being applied to files outside app directory after upgrade 9.3.1 -> 9.4.4 #13980

Closed
dminkovsky opened this issue Jun 9, 2020 · 16 comments
Labels
Upstream Related to using Next.js with a third-party dependency. (e.g., React, UI/icon libraries, etc.).

Comments

@dminkovsky
Copy link

dminkovsky commented Jun 9, 2020

Bug report

Describe the bug

I have a yarn workspace project layout like:

|- common/ (shared by mobile and web)
|- web/ (Next.js project)
|- mobile/ (custom Webpack built SPA, not relevant)
|- babel.config.js

My babel configuration requires:

  • The styled-components plugin,
  • Imports from common to be transpiled in my Next.js build.

So I have the following next.config.js:

/* global __dirname */

const path = require('path');
const withPlugins = require('next-compose-plugins');
const withTM = require('next-transpile-modules')([
    '@glidejs/glide',
    'common',
]);

module.exports = withPlugins([withTM], {
    webpack: (config, options) => {
        // Seems to no longer be necessary with 9.4?
        config.module.rules.forEach(rule => {
            if (
                rule.use &&
                rule.use.loader === 'next-babel-loader'
            ) {
               // Set Babel root to workspace root, so config applies to workspace modules.   
               rule.use.options.root = resolve('..');
               // But use the local config
               rule.use.options.configFile = resolve('.babelrc'); 
            }
        });
        return config;
    },
});

function resolve() {
    return path.resolve.apply(path, [__dirname, ...arguments]);
}

  • Using the transpile modules plugin allows transpiling workspacem modules.
  • Setting rule.use.options.root = resolve('..'); sets the babel root to the workspace root, which allows using babel.config.js as global config and which has the following content:
module.exports = {
    presets: ["next/babel"],
    plugins: [
        ["babel-plugin-styled-components"],
        "@babel/plugin-proposal-optional-chaining"
    ],
}

After upgrading 9.3.1 to 9.4.4, this config breaks for some reason. In my browser console I see errors which indicate the styled components plugin is not being used:

Warning: Prop className did not match. Server: "CompleteAccount__Head-sc-1dzpt9v-0 egJJdE" Client: "sc-jWBwVP yNfFn"

Expected

I would expect that as with 9.3.1, the 9.4.4 webpack configuration would allow using the workspace-wide, common babel config in babel.config.js.

@dminkovsky dminkovsky changed the title Files outside app directory not being transpiled after upgrade 9.3.1 -> 9.4.4 Babel configuration not being applied to files outside app directory after upgrade 9.3.1 -> 9.4.4 Jun 9, 2020
@nnennajohn
Copy link

@dminkovsky , I think something changed with this version, that does not make it work with next-transpile-modules. I encountered the same problem, and was only able to get it to work by switching to next-plugin-transpile-modules

See image below:

Screen Shot 2020-06-09 at 6 18 23 PM

@Timer
Copy link
Member

Timer commented Jun 10, 2020

This would be a bug with next-transpile-modules. Please file it upstream!

@Timer Timer closed this as completed Jun 10, 2020
@Timer Timer added the Upstream Related to using Next.js with a third-party dependency. (e.g., React, UI/icon libraries, etc.). label Jun 10, 2020
@dminkovsky
Copy link
Author

dminkovsky commented Jun 10, 2020

This is not related to next-transpile-modules. That still works. The issue here is that although workspace modules are transpiled, the were not being transpiled with the same babel config that Next.js was being transpiled with.

This is, indeed, related to the way fast refresh was added in 9.4 (amazing thing, thing you).

Specifically, the client and server webpack configs now have different structures. Under config.module.rules, in server the first rule's use is:

{
    "loader": "next-babel-loader",
    "options": {
        "isServer": true,
        "distDir": "/Users/dmitry/dev/pony/src/front/pony-web/.next",
        "pagesDir": "/Users/dmitry/dev/pony/src/front/pony-web/pages",
        "cwd": "/Users/dmitry/dev/pony/src/front/pony-web",
        "cache": true,
        "babelPresetPlugins": [],
        "hasModern": false,
        "development": true,
        "hasReactRefresh": false
    }
}

whereas in client the first rule's use is:

[
    "/Users/dmitry/dev/pony/src/front/pony-web/node_modules/@next/react-refresh-utils/loader.js",
    {
        "loader": "next-babel-loader",
        "options": {
            "isServer": false,
            "distDir": "/Users/dmitry/dev/pony/src/front/pony-web/.next",
            "pagesDir": "/Users/dmitry/dev/pony/src/front/pony-web/pages",
            "cwd": "/Users/dmitry/dev/pony/src/front/pony-web",
            "cache": true,
            "babelPresetPlugins": [],
            "hasModern": false,
            "development": true,
            "hasReactRefresh": true
        }
    }
]

So my code:

config.module.rules.forEach(rule => {
    if (
        rule.use &&
        rule.use.loader === 'next-babel-loader'
    ) { 
        // Set Babel root to workspace root, so config applies to workspace modules.   
        rule.use.options.root = resolve('..');
        // But use the local config
        rule.use.options.configFile = resolve('.babelrc'); 
    }   
});

which looks for next-babel-loader in each of server and client fails on the client, because that rule's use is no longer an object but is now an array. Hence the styled components plugin was applied on server but not client:

Warning: Prop className did not match. Server: "CompleteAccount__Head-sc-1dzpt9v-0 egJJdE" Client: "sc-jWBwVP yNfFn"

@dminkovsky
Copy link
Author

dminkovsky commented Jun 10, 2020

Thanks @nnennajohn! In my case, this was not related to next-transpile-modules.

The issue for me was that although workspace modules were being transpiled thanks to that plugin, they were not being transpiled with the same Babel config that Next.js was being transpiled with, because the Babel root was set to my Next.js project and not my Yarn workspaces. I see you are using a plugin for that, but I had code that fixed that and it broke 9.3 -> 9.4.

I updated my question and answer above to hopefully make the issue clear.

In next.config.js, my webpack config now looks like this:

webpack: (config, options) => {                                                                                                                                                                                                                                                                                                                                                                          
    const nextBabelLoader = findNextBabelLoader(config);                                                                                                                                                    
    // Set Babel root to workspace root, so config                                                                                                                                                          
    // applies to workspace modules.                                                                                                                                                                        
    nextBabelLoader.options.root = resolve('..');                                                                                                                                                           
    // But use the local config                                                                                                                                                                             
    nextBabelLoader.options.configFile = resolve('.babelrc');                                                                                                                                               
    return config;                                                                                                                                                                                          
}

where findNextBabelLoader is

function findNextBabelLoader(config) {                                                                                                                                                                      
    for (const rule of config.module.rules) {                                                                                                                                                               
        // server
        if (                                                                                                                                                                                                
            rule.use &&                                                                                                                                                                                     
            rule.use.loader === 'next-babel-loader'                                                                                                                                                         
        ) {                                                                                                                                                                                                 
            return rule.use;                                                                                                                                                                                
        }
        // client 
        else if (                                                                                                                                                                                         
            rule.use &&                                                                                                                                                                                     
            Array.isArray(rule.use) &&                                                                                                                                                                      
            rule.use[1].loader === 'next-babel-loader'                                                                                                                                                      
        ) {                                                                                                                                                                                                 
            return rule.use[1];                                                                                                                                                                             
        }                                                                                                                                                                                                   
    }                                                                                                                                                                                                       
    throw new Error('`next-babel-loader` not found');                                                                                                                                                       
} 

This is really brittle and will break if Next's webpack config structure changes again in the future, but it can be adjusted.

@a-r-db
Copy link

a-r-db commented Jan 19, 2021

Hello
@dminkovsky
Does this issue here look like the same problem that you were having?
When I try to build the project as shown it does not seem to load the babel.config.js or it's just failing to import react native modules.

@dminkovsky
Copy link
Author

dminkovsky commented Jan 19, 2021

Hi @a93h. I'm not sure, but I don't think so... why do you think it might be the same problem?

@a-r-db
Copy link

a-r-db commented Jan 19, 2021

Thanks for the quick response @dminkovsky .
I am just trying to source the main problem by looking at similar issues.
The owner of that repository can't or doesn't have the time to repair that bug,
so I am using my basic knowledge of NodeJS packaging to try and squash this bug.

If you have any suggestions on where to look, your advice is very welcome.
I've been smashing my head against the wall for a couple days now.
I'm not entirely sure where to start or how to diagnose this bug.

It's weird dev works just fine, but build does not.
So it seems like the build is missing the babel.config.js

Example of next start

web-nextjs> yarn workspace @rnwmr/web-nextjs dev      
yarn workspace v1.22.10
warning package.json: No license field
yarn run v1.22.10
warning package.json: No license field
$ next
ready - started server on http://localhost:3000
info  - Using external babel configuration from C:\Users\me\Documents\GitHub\react-native-web-monorepo\packages\web-nextjs\babel.config.js
event - compiled successfully

Example of yarn clean && next build && next export

web-nextjs> yarn workspace @rnwmr/web-nextjs build-out
yarn workspace v1.22.10
warning package.json: No license field
yarn run v1.22.10
warning package.json: No license field
$ yarn clean && yarn build && yarn export
warning package.json: No license field
$ shx rm -rf ./out && shx rm -rf ./.next
warning package.json: No license field
$ next build
Failed to compile.

../components\src\App.tsx:3:3
Type error: Module '"react-native"' has no exported member 'SafeAreaView'.

  1 | import React from 'react'
  2 | import {
> 3 |   SafeAreaView,
    |   ^
  4 |   ScrollView,
  5 |   StatusBar,
  6 |   StyleSheet,
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
error Command failed.
Exit code: 1
Command: C:\Program Files\nodejs\node.exe
Arguments: C:\Users\me\AppData\Roaming\npm\node_modules\yarn\lib\cli.js build-out
Directory: C:\Users\me\Documents\GitHub\react-native-web-monorepo\packages\web-nextjs
Output:

info Visit https://yarnpkg.com/en/docs/cli/workspace for documentation about this command.

@a-r-db
Copy link

a-r-db commented Jan 19, 2021

Yes it does.

@dminkovsky
Copy link
Author

dminkovsky commented Jan 19, 2021

No idea what this could be. Never seen anything like this before that I remember. I would break it down to something simpler that does work with next build and then build it back up so it works.

@a-r-db
Copy link

a-r-db commented Jan 19, 2021

So I found this somewhat old repo. I might try to upgrade the packages and code until it breaks so I can see what's causing the problem.
Thanks for the idea.

@dminkovsky
Copy link
Author

dminkovsky commented Jan 19, 2021

Yes it does.

Yeah I saw it in your post after I asked.

So I found this somewhat old repo.

I don't think this is a monorepo issue? It's definitely not related to this bug, anyway.

Also, Next.js works with react-native?? I'm sorry but I don't even understand that at all. Next.js is for creating a universal rendered DOM/browser apps. react-native is ... react-native. I wouldn't have thought the two have any overlap.

@a-r-db
Copy link

a-r-db commented Jan 19, 2021

Here's one better, react native with web.

React-Native-Web

They do overlap.

@a-r-db
Copy link

a-r-db commented Jan 19, 2021

The repo I'm working on and the repo that is older are similar except the old one still builds and the new does not build, but both work with next start.

@dminkovsky
Copy link
Author

dminkovsky commented Jan 19, 2021

Here's one better, react native with web.

Far out! Thank you.

Anyway, yeah... whenever I have totally bewildering issues like you describe, I reduce the problem to the smallest possible thing, like, maybe something extreme like a fresh, empty install of Next.js, and proceed by adding back my app until I experience the problem. Then most of the time the issue makes itself clear. Sorry if this something you've already done or something you know, but I can't really think of anything else.

@dminkovsky
Copy link
Author

I'll say the reason I think this isn't monorepo related is because your build isn't finding an npm-installed package. All of the monorepo issues I've had have been related to workspace modules, not node_modules modules.

@balazsorban44
Copy link
Member

This issue has been automatically locked due to no recent activity. If you are running into a similar issue, please create a new issue with the steps to reproduce. Thank you.

@vercel vercel locked as resolved and limited conversation to collaborators Jan 28, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Upstream Related to using Next.js with a third-party dependency. (e.g., React, UI/icon libraries, etc.).
Projects
None yet
Development

No branches or pull requests

5 participants