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

Bug: basePath config is required otherwise it breaks Router.replace #10355

Closed
SBoudrias opened this issue Jan 31, 2020 · 8 comments
Closed

Bug: basePath config is required otherwise it breaks Router.replace #10355

SBoudrias opened this issue Jan 31, 2020 · 8 comments
Labels
please add a complete reproduction The issue lacks information for further investigation

Comments

@SBoudrias
Copy link
Contributor

Bug report

Describe the bug

process.env.__NEXT_ROUTER_BASEPATH (experimental.basePath) is undefined by default which breaks Router.replace().

To Reproduce

Steps to reproduce the behavior, please provide code snippets or a repository:

  1. Go to a next.js page /bar
  2. Call Router.replace('/foo', '/foo', { shallow: true })
  3. See the url becoming /bar/undefined/foo

Expected behavior

We should not try to append experimental.basePath to our URLs if it is not defined.

System information

  • Version of Next.js: tested on 9.2.1 and 9.1.6

Additional context

The problem is everytime we change the url state, this.changeState(method, url, addBasePath(as), options); gets called, and addBasePath() doesn't act appropriately.

Short term fix is to add the experimental.basePath: '' in the next config.

This issue seems to have been introduced in #9872

@timneutkens
Copy link
Member

Can you post you next.config.js, sounds like you're overriding something as we have tests that cover replace etc.

@SBoudrias
Copy link
Contributor Author

// @noflow
/* eslint-disable global-require, no-param-reassign */
const { PHASE_DEVELOPMENT_SERVER, PHASE_PRODUCTION_BUILD } = require('next/constants');

module.exports = (phase, { defaultConfig }) => {
    const baseConfig = {
        ...defaultConfig,
        assetPrefix: process.env.CDN_URL || '',
        publicRuntimeConfig: {
            version: process.env.VERSION,
            nodeEnv: String(process.env.NODE_ENV),
            clientSentry: process.env.CLIENT_SENTRY,
            cdnUrl: process.env.CDN_URL || '',
            isFeature: Boolean(process.env.IS_FEATURE) || false,
        },
        env: {
            CLIENT_SENTRY: process.env.CLIENT_SENTRY,
            VERSION: process.env.VERSION,
        },
    };

    if (phase === PHASE_DEVELOPMENT_SERVER || phase === PHASE_PRODUCTION_BUILD) {
        const SpeedMeasurePlugin = require('speed-measure-webpack-plugin');
        const withBundleAnalyzer = require('@zeit/next-bundle-analyzer');
        const withPlugins = require('next-compose-plugins');
        const withSourceMaps = require('@zeit/next-source-maps')();
        const withImages = require('next-images');

        const analyzeServer = ['server', 'both'].includes(process.env.BUNDLE_ANALYZE);
        const analyzeBrowser = ['browser', 'both'].includes(process.env.BUNDLE_ANALYZE);
        const path = require('path');

        const bundleAnalyzerConfig = {
            server: {
                analyzerMode: 'static',
                reportFilename: path.join(__dirname, 'logs/bundles/server.html'),
            },
            browser: {
                analyzerMode: 'static',
                reportFilename: path.join(__dirname, 'logs/bundles/client.html'),
            },
        };

        return withPlugins(
            [
                withSourceMaps,
                [withImages, { inlineImageLimit: 1 }],
                [
                    withBundleAnalyzer,
                    { analyzeServer, analyzeBrowser, bundleAnalyzerConfig },
                ],
            ],
            {
                ...baseConfig,
                webpack: (config, { isServer }) => {
                    const originalEntry = config.entry;
                    config.entry = async () => {
                        const entries = await originalEntry();

                        if (
                            entries['main.js'] &&
                            !entries['main.js'].includes('./modules/polyfills.js')
                        ) {
                            entries['main.js'].unshift('./modules/polyfills.js');
                        }

                        return entries;
                    };

                    config.module.rules.push(
                        {
                            test: /\.css$/,
                            use: ['babel-loader', 'raw-loader', 'postcss-loader'],
                        },
                        {
                            test: /\.jsx?$/,
                            resourceQuery: /\.css$/,
                            use: 'raw-loader',
                        }
                    );

                    if (phase === PHASE_PRODUCTION_BUILD) {
                        // Compile all node_modules dependencies with babel for production.
                        // We need to do this because some modules use JS syntax not
                        // supported by IE 11.
                        config.module.rules.push({
                            test: /\.js$/,
                            include: /node_modules/,
                            use: ['babel-loader'],
                        });
                    }

                    config.resolve.alias = {
                        ...config.resolve.alias,
                        'lodash-es': 'lodash',
                        'lodash.get': 'lodash/get',
                        'lodash.isfunction': 'lodash/isFunction',
                        'lodash.isobject': 'lodash/isObject',
                        'lodash.merge': 'lodash/merge',
                        'lodash.reduce': 'lodash/reduce',
                        'lodash.set': 'lodash/set',
                        'lodash.unset': 'lodash/unset',
                        'lodash.find': 'lodash/find',
                        'lodash.max': 'lodash/max',
                        'lodash.padstart': 'lodash/padstart',
                        'lodash.repeat': 'lodash/repeat',
                        'lodash.assign': 'lodash/assign',
                        'lodash.debounce': 'lodash/debounce',
                        'lodash.keys': 'lodash/keys',
                        'lodash.isarguments': 'lodash/isarguments',
                        'lodash.isarray': 'lodash/isarray',
                        'lodash.curry': 'lodash/curry',
                        'lodash.flow': 'lodash/flow',
                        sentry: isServer ? '@sentry/node' : '@sentry/browser',
                    };

                    if (!isServer) {
                        config.resolve.alias['@sentry/node'] = '@sentry/browser';
                    }

                    // Some pretty big modules we can skip parsing to save some time.
                    config.module.noParse = [
                        require.resolve('jed'),
                        require.resolve('brace'),
                    ];

                    if (process.env.BUNDLE_ANALYZE) {
                        const smp = new SpeedMeasurePlugin();
                        return smp.wrap(config);
                    }

                    if (
                        phase === PHASE_PRODUCTION_BUILD &&
                        process.env.MOCK_PRODUCTION !== 'true'
                    ) {
                        // Setup assets size for build
                        config.performance = {
                            hints: 'error',
                            maxEntrypointSize: 1200000,
                            maxAssetSize: 1200000,
                        };
                    }

                    return config;
                },
            }
        )(phase, { defaultConfig });
    }

    return baseConfig;
};

@KeithYeh
Copy link

KeithYeh commented Feb 4, 2020

Same issue in our project. Add the experimental.basePath: '' in the next config does not fix the problem in for me.

I dump process.env. __NEXT_ROUTER_BASEPATH in the console always got undefined in both dev and prod build.

Here are our next.config.js and babel.config.js

next.config.js

const path = require('path');
const withTranspileModules = require('next-transpile-modules')(['@sparkamplify']);
const withCustomBabelConfigFile = require('next-plugin-custom-babel-config');

module.exports = withCustomBabelConfigFile(
  withTranspileModules({
    poweredByHeader: false,
    babelConfigFile: path.resolve(__dirname, './babel.config.js'),
    typescript: {
      ignoreDevErrors: true,
    },

    webpack: (config) => {
      config.node = { fs: 'empty' };

      config.optimization.removeAvailableModules = false;
      config.optimization.removeEmptyChunks = false;
      config.output.pathinfo = false;

      return config;
    },
  }),
);

babel.config.js

module.exports = (api) => {
  api.cache(true);

  const presets = [
    'next/babel',
  ];
  const plugins = [
    [
      'inline-dotenv',
    ],
    [
      'lodash',
    ],
    [
      '@babel/plugin-proposal-nullish-coalescing-operator',
    ],
    [
      '@babel/plugin-proposal-optional-chaining',
    ],
    [
      'module-resolver',
      {
        'root': [
          './src',
          './server',
        ],
        'extensions': [
          '.js',
          '.jsx',
          '.ts',
          '.tsx',
        ],
      },
    ],
    [
      'styled-components',
      {
        'ssr': true,
        'displayName': true,
        'preprocess': false,
      },
    ],
  ];

  return {
    plugins,
    presets,
  };
};

@ijjk
Copy link
Member

ijjk commented Feb 4, 2020

Hi, the provided reproduction seems to be inaccurate, you mention that addBasePath is causing /bar/undefined/foo on a Router.replace although if this was the case addBasePath would have resulted in it becoming /undefined/foo as bar is not passed to this method

Also, basePath is an empty string by default and we even error if you provide an invalid value here so an invalid webpack or babel config would have to be causing this value to be incorrect.

@KeithYeh the main thing that might be causing conflict with the basePath value looking at your provided configs may be the inline-dotenv plugin added in your babel.config.js. Looking at your config you can remove @babel/plugin-proposal-nullish-coalescing-operator and @babel/plugin-proposal-optional-chaining as they are provided in Next.js by default since v9.1.5. I'd also recommend removing the inline-dotenv and using the built-in env option in next.config.js to make sure you aren't providing env values you don't intend to and to see if this is the cause

@ijjk ijjk added the please add a complete reproduction The issue lacks information for further investigation label Feb 4, 2020
@KeithYeh
Copy link

KeithYeh commented Feb 6, 2020

@ijjk I use built-in env option to replace babel-inline-dotenv did solve undefined basePath, thanks a lot 😄

@oliviertassinari
Copy link
Contributor

oliviertassinari commented Mar 14, 2020

process.env.__NEXT_ROUTER_BASEPATH (experimental.basePath) is undefined by default which breaks Router.replace().

I have observed the same problem (undefined on the server-side, defined on the client-side) with process.env.__NEXT_EXPORT_TRAILING_SLASH.

oliviertassinari added a commit to oliviertassinari/material-ui that referenced this issue Mar 14, 2020
oliviertassinari added a commit to oliviertassinari/material-ui that referenced this issue Mar 15, 2020
oliviertassinari added a commit to oliviertassinari/material-ui that referenced this issue Mar 15, 2020
@Timer
Copy link
Member

Timer commented Apr 15, 2020

This behavior should be fixed in 9.3.5 or newer.

@Timer Timer closed this as completed Apr 15, 2020
@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 30, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
please add a complete reproduction The issue lacks information for further investigation
Projects
None yet
Development

No branches or pull requests

7 participants