vercel / next-plugins

Official Next.js plugins
MIT License
2.68k stars 319 forks source link

Cant change page with 'next/link' & 'next-css' #282

Closed standy closed 3 years ago

standy commented 5 years ago

This is bug report

Link does not work with css-module imported. That happens when page with Link has no css, and linked page has. No errors in console, so im not sure about reasons, but there is minimal repo to reproduce: https://github.com/standy/next-css-error

Bug appears in next@7.0.0 + next-css@1.0.1, Older next@6.1.2 + next-css@0.2.0 works fine

Dynogic commented 5 years ago

I have the exact same issue, on the exact same versions as well.

Confirmed work around: make every page import some css.

virzak commented 5 years ago

Was trying hard to determine what was causing that. Thanks for reporting @Dynogic and @standy

Enalmada commented 5 years ago

Same problem except with next-css. Clicking links importing less just don't respond. My workaround was to stop using less/css. Note this ticket https://github.com/zeit/next.js/issues/5264#issuecomment-424000127 suggests you can import blank in _app.js.

kylemh commented 5 years ago

https://spectrum.chat/thread/2183fc55-236d-42cb-92b9-3ab10acc6303?m=MTUzODU2NDg2ODA2Mg==

Next team is aware and working on it! It's complex and will take time.

Importing an empty stylesheet into _app.js nor importing a stylesheet on every page resolved the issue for me locally.

nisargrthakkar commented 5 years ago

@kylemh I tried Importing an empty stylesheet into _app.js nor importing a stylesheet on every page resolved the issue for me locally. but still not working

kylemh commented 5 years ago

It's a strategy some have professed, but it doesn't resolve anything for me - just like you.

popuguytheparrot commented 5 years ago

Same problem

timneutkens commented 5 years ago

@kylemh / others could you try @zeit/next-css@canary? It holds #315

kylemh commented 5 years ago

I would fuckin' love to ❀️

aserranom commented 5 years ago

@timneutkens The error is gone, great job! However when changing routes I'm not getting that new route's style... is anyone else having that issue?

Unfortunately I have to go and won't be able to troubleshoot it further or provide additional details today.

kylemh commented 5 years ago

^ this precisely.

It doesn't look like I'm getting more CSS files per route - just on initial load.

SSR gets all styles properly.

nisargrthakkar commented 5 years ago

Same issue with @zeit/next-css@canary not get css load on route change

kylemh commented 5 years ago

That being said, I'd say this issue can be closed and another can be made on route-based code splitting withCSS with CSS Modules + PostCSS (at least for me) not working as desired?

plag commented 5 years ago

Yes, on route change issue still present. Long time i used next6 with old next-css and regulary gets not loaded styles on route change. After refresh page it works as expected even on route change. On 7 version it reproduced on every page change (not sometimes as next6). But if you 1) load first page 2) transition to next page (gets not loaded styles) 3) refresh page - then you take working styles on both pages.

Looks like styles compilation is long process and delayed and page do not have time for take it and apply. After refresh page styles already precompiled and applied immediatelly.

plag commented 5 years ago

my workaround this bug (on latest canary)

somewhere in _app.js

import Router from 'next/router';

Router.events.on('routeChangeComplete', () => {
  if (process.env.NODE_ENV !== 'production') {
    const els = document.querySelectorAll('link[href*="/_next/static/css/styles.chunk.css"]');
    const timestamp = new Date().valueOf();
    els[0].href = '/_next/static/css/styles.chunk.css?v=' + timestamp;
  }
})

on every page reloads css after router change

popuguytheparrot commented 5 years ago

my workaround this bug (on latest canary)

somewhere in _app.js

...
import Router from 'next/router';
...
Router.onRouteChangeComplete = () => {
  if (process.env.NODE_ENV !== 'production') {
    const els = document.querySelectorAll('link[href*="/_next/static/css/styles.chunk.css"]');
    const timestamp = new Date().valueOf();
    els[0].href = '/_next/static/css/styles.chunk.css?v=' + timestamp;
  }
}

on every page reloads css after router change

look like bicyclecode

stian-midlertidig commented 5 years ago

@plag thanks so much for sharing that! πŸ˜„

timneutkens commented 5 years ago

@plag I've updated your comment to use Router.events instead: https://github.com/zeit/next.js#router-events

zhanglin-doudou commented 5 years ago

I had found a way to solve it. Not really perfect.

I have used a component Layout in every page.

import React, { Component } from 'react';
import Head from 'next/head';

export default class Layout extends Component {
  render() {
    const { children, title, style, className } = this.props;

    return (
      <div className={'main-layout col ' + className} style={style}>
        <Head>
          <title>{title}</title>
          {process.env.NODE_ENV !== 'production' && (
            <link rel="stylesheet" type="text/css" href={'/_next/static/css/styles.chunk.css?v=' + Date.now()} />
          )}
        </Head>
        <div className="main-content">{children}</div>
      </div>
    );
  }
}
popuguytheparrot commented 5 years ago

I had found a way to solve it. Not really perfect.

I have used a component Layout in every page.

import React, { Component } from 'react';
import Head from 'next/head';

export default class Layout extends Component {
  render() {
    const { children, title, style, className } = this.props;

    return (
      <div className={'main-layout col ' + className} style={style}>
        <Head>
          <title>{title}</title>
          {process.env.NODE_ENV !== 'production' && (
            <link rel="stylesheet" type="text/css" href={'/_next/static/css/styles.chunk.css?v=' + Date.now()} />
          )}
        </Head>
        <div className="main-content">{children}</div>
      </div>
    );
  }
}

How ur layout will work in _app.js For example

<Container>
  <Layout>
    <Component>
  </Layout>
</Container>
zhanglin-doudou commented 5 years ago

I had found a way to solve it. Not really perfect. I have used a component Layout in every page.

import React, { Component } from 'react';
import Head from 'next/head';

export default class Layout extends Component {
  render() {
    const { children, title, style, className } = this.props;

    return (
      <div className={'main-layout col ' + className} style={style}>
        <Head>
          <title>{title}</title>
          {process.env.NODE_ENV !== 'production' && (
            <link rel="stylesheet" type="text/css" href={'/_next/static/css/styles.chunk.css?v=' + Date.now()} />
          )}
        </Head>
        <div className="main-content">{children}</div>
      </div>
    );
  }
}

How ur layout will work in _app.js For example

<Container>
  <Layout>
    <Component>
  </Layout>
</Container>

I am not using Layout in _app.js. Every single page has a container with Layout. e.g. :

import React, { Component } from 'react';
import { connect } from 'react-redux';
import Layout from '../components/layout/Layout';

class FeedbackSuccess extends Component {
  render() {
    return <Layout title="ζ“δ½œζˆεŠŸ">ζ“δ½œζˆεŠŸ</Layout>;
  }
}

export default connect()(FeedbackSuccess);
dankythuat commented 5 years ago

Same issue, anyone can resolve it?

cherniavskii commented 5 years ago

@tuanhuu While waiting for fix, the simplest workaround is to create empty css file in static catalog and import it in _app.jsx

popuguytheparrot commented 5 years ago

@tuanhuu While waiting for fix, the simplest workaround is to create empty css file in static catalog and import it in _app.jsx

this doesnt work

cherniavskii commented 5 years ago

@popugang well, it works for me ;)

stian-midlertidig commented 5 years ago

@cherniavskii did you try following https://github.com/zeit/next-plugins/issues/282#issuecomment-432127816 ?

cherniavskii commented 5 years ago

@stian-midlertidig no, I've resolved it by importing empty css file and it works

stian-midlertidig commented 5 years ago

Sorry, I meant to cc @popugang πŸ˜„

dankythuat commented 5 years ago

@tuanhuu While waiting for fix, the simplest workaround is to create empty css file in static catalog and import it in _app.jsx

it doesn't work for me but i try to add router event in _app.js as plag mentioned and it works

dankythuat commented 5 years ago

@tuanhuu While waiting for fix, the simplest workaround is to create empty css file in static catalog and import it in _app.jsx

this doesnt work

Try https://github.com/zeit/next-plugins/issues/282#issuecomment-432127816, it works

Jero786 commented 5 years ago

@tuanhuu While waiting for fix, the simplest workaround is to create empty css file in static catalog and import it in _app.jsx

This doesn't work me.

48554964-8950bc00-e8be-11e8-9d0a-a77eaaa4f3da

cemsusal commented 5 years ago

None of them is working for me too.

cheong12001 commented 5 years ago

None of them is working for me too.

Hope solution will come out soon....

elliottsj commented 5 years ago

My current workaround is to import all of the .css files used throughout my app in the _app.js file.

The drawback is that I have stylesheets loaded that are mostly unused on the current page, and I cannot co-locate CSS imports in the module that uses those styles. But it avoids this bug πŸ˜„

kylemh commented 5 years ago

@cheong12001 @cemsusal @Jero786 @popugang

I'm curious how many of you are using @font-face in your stylesheets.

Jero786 commented 5 years ago

@kylemh I'm using it!

cemsusal commented 5 years ago

@kylemh I have @font-face in my style sheets with the following code:

@font-face { font-family: 'GothamBlack_TR'; src: url('/static/fonts/gotham/GothamBlack_TR.eot'); src: url('/static/fonts/gotham/GothamBlack_TR.eot') format('embedded-opentype'), url('/static/fonts/gotham/GothamBlack_TR.woff2') format('woff2'), url('/static/fonts/gotham/GothamBlack_TR.woff') format('woff'), url('/static/fonts/gotham/GothamBlack_TR.ttf') format('truetype'), url('/static/fonts/gotham/GothamBlack_TR.svg#GothamBlack_TR') format('svg'); }

kylemh commented 5 years ago

Need more sample size to confirm that it’s somehow related, but this makes me πŸ€”

dmshvetsov commented 5 years ago

I'm curious how many of you are using @font-face in your stylesheets.

@kylemh Not in my case. Have no @font-face and experiencing the same problems.

You can try to reproduce with this repo. Sorry no sample data, you have to create a project and a subproject and try to navigate to a subproject from a project page to reproduce the issue. No @font-face used in this repo.

cemsusal commented 5 years ago

I also removed @font-face from my css and tested it and the issue persists.

kylemh commented 5 years ago

So much for that idea πŸ˜‚

Jero786 commented 5 years ago

I read out there a workaround that seems like fix this problem, could you try guys if that works for you as well?

just add in their .eslintrc

...
"rules": {
...
        "no-console": 1,
...
}
...
kylemh commented 5 years ago

@Jero786 that isn't a fix, but it's just preventing the react error renderer showing up. You likely still have hash collisions and your website should appear sightly off (missing some - if not all - styles)

samhenri commented 5 years ago

I'm facing the same issues and tried all the workarounds suggested above. It has fixed the error messages however it is not loading the components CSS. Here's my next.config.js:

const withSass = require('@zeit/next-sass');

module.exports = withSass({
  cssModules: true,
  cssLoaderOptions: {
    importLoaders: 1,
    localIdentName: "[local]",
  },
  webpack: (config, { dev }) => {
    config.module.rules.push(
      {
        test: /\.js$/,
        loader: 'eslint-loader',
        exclude: /node-modules/,
        enforce: 'pre',
        options: {
          emitWarning: true
        }
      },
      {
        test: /\.(config)$/,
        loader: 'file-loader',
        options: {
          name: '[path][name].[ext]',
        }
      },
      {
        test: /\.(png|ttf|eot|wtf|jpg|svg|gif)$/,
        use: [
          {
            loader: 'url-loader',
            options: {}
          }
        ]
      },
    );

    const StyleLintPlugin = require('stylelint-webpack-plugin');

    config.plugins.push(
      new StyleLintPlugin({
        emitErrors: false,
        quiet: false,
      }),
    );

    return config;
  }
});

My _app.js:

import App, { Container } from 'next/app';
import Head from 'next/head';
import React, { Fragment } from 'react';
import '../style/global.scss';
import INITIAL_STATE from '../utils/initialState';

export default class MyApp extends App {
  state = { appState: INITIAL_STATE }

  static async getInitialProps({ Component, ctx }) {
    let pageProps = {};

    if (Component.getInitialProps) {
      pageProps = await Component.getInitialProps(ctx);
    }

    return { pageProps };
  }

  handleUpdateAppState = (event, step) => {
    const appState = { ...this.state.appState };
    appState[step][event.target.name] = event.target.value;

    this.setState({ appState });
  }

  handleUpdateCheckboxState = (checkboxObj, step) => {
    const appState = { ...this.state.appState };
    appState[step] = checkboxObj;

    this.setState({ appState });
  }

  render() {
    const { Component, pageProps } = this.props;
    return (
      <Fragment>
        <Head>
          {process.env.NODE_ENV !== 'production' && (
            <link rel="stylesheet" type="text/css" href={`/_next/static/css/styles.chunk.css?v=${Date.now()}`} />
          )}
        </Head>
        <Container>
          <Component
            onUpdateAppState={this.handleUpdateAppState}
            onUpdateCheckboxState={this.handleUpdateCheckboxState}
            appState={this.state.appState}
            {...pageProps}
          />
        </Container>
      </Fragment>
    );
  }
}

I was able to prevent the error message by using these options in the withSass import:

  cssModules: true,
  cssLoaderOptions: {
    importLoaders: 1,
    localIdentName: "[local]",
  },

The reason why the localIdentName is just [local] is because I'm not using hashes in the css class names and if I disable cssModules I get the 'Unhandled rejection' error

afuggini commented 5 years ago

For me a slightly different version of the above worked as temporary fix.

I am using Less so I installed "@zeit/next-less": "^1.0.2-canary.2" and then in _app.js:

import Router from 'next/router'
Router.events.on('routeChangeComplete', () => {
  const els = document.querySelectorAll('link[href*="/_next/static/chunks/styles.chunk.css"]')
  const timestamp = new Date().valueOf()
  els[0].href = '/_next/static/chunks/styles.chunk.css?v=' + timestamp
})

The difference with the above is that I used /_next/static/chunks/styles.chunk.css instead of /_next/static/css/styles.chunk.css

farisT commented 5 years ago

I am using sass in my project and initially had the "Unexpected Rejection", however upgrading to "@zeit/next-sass": "^1.0.2-canary.2" worked in removing the error. However, now I have the problem that my css wont load when switching pages, only after I refresh does it load. I have tried the solutions mentioned by @afuggini and @plag however I keep getting this error.

schermafbeelding 2018-12-13 om 10 32 36

afuggini commented 5 years ago

@farisT Make sure the path on your _app.js and the path on your page source code matches.

janustoth commented 5 years ago

@samhenri this solution worked for me. Thank you very much! Also I did not need to install any canary builds to make it work. I just needed the 3 lines in the withSass config

Edit: It seems I was too quick with my testing. It only works on some pages :(

chaance commented 5 years ago

I just wanted to add that I'm also experiencing this issue beyond simply route changes: any time I render a component in the client that is different than what is rendered on the server, the component's CSS fails to load.

class Comp extends Component {
  state = {
    isMobile: false
  };
  componentDidMount() {
    if (window && window.matchMedia("(max-width: 400px)").matches) {
      this.setState({ isMobile: true });
    }
  }
  render() {
    // MobileComponent.scss is not working
    return this.state.isMobile ? <MobileComponent /> : <DesktopComponent />
  }
}

I assumed this was worth mentioning here as it feels related, but if I'm alone here or this is actually unrelated I am happy to open a new issue with all of the necessary details.

samhenri commented 5 years ago

@chancestrickland Exactly the same here. I have at least one component that is not stateless and any state change unloads the CSS and then loads it again with the config that I've posted above. Since I have some transitions in the CSS it shows the default properties such as colors and borders transitioning to the properties I have set in my styles.

I had to move all SCSS imports to my global.scss and downgraded next and next-sass to the stable versions.