关于 Next.js 开发实践过程中的一些总结(bug问题整理)

5,567 阅读6分钟

最近迷恋Next.js,用自己搭的脚手架做了几个项目,其中既包括普通前端SSR的项目,又包括全栈项目,从开发到上线过程中遇到的问题,在这里总结一下,对Next.js感兴趣的同学可以参考:

脚手架地址:Next-Antd-Scaffold,其中,master是基础的SSR框架,backend分支是基于脚手架扩展的全栈脚手架,大家按需使用~

为什么要用Next.js

这里我应该在最开始的系列文章阐述过了,在这里,就简明扼要的再说一说:

  • React技术展
  • 中后台大型项目
  • SSR + SEO
  • 懒得从头自己搭建一套完善的SSR脚手架

如果你满足上面的几条,那么选择Nextjs是不错的选择。仁者见仁智者见智,Nextjs并不全是优点,也有不足之处,比如约束性较强,路由必须按照规则书写等等。但是,瑕不掩瑜,确实Nextjs在React SSR这一块算是最成熟的解决方案了。

另外,如果你还满足如下条件,那么我的脚手架也很适合你:

  • ant-design UI框架
  • redux
  • redux-saga
  • pm2部署服务

问题汇总

关于Nextjs如何使用以及脚手架的一些东西,我前面写了两个系列文章,这里就不一一赘述了,可以去我的专栏看看,或者你关注我也不会吃亏,哈哈。这篇文章也算是作为Nextjs的毕业报告吧,可能是最后一篇关于Next的文章了,暂时能遇到的问题就贴在这里,以后再遇到会在这里不断补充填坑~

马虎大意的问题

因为Nextjs的路由是读取的/pages文件夹下面的文件,所以你的项目最后部署出来也是按照该目录下的文件而进行路由分割。有时候可能因为我们的马虎出现一些问题,有的小伙伴据遇到过:

 - pages
  | -- user.js
  | -- Login.js
  | ...

比如上面是一个目录结构,那么我们会渲染出来两个路由 /user/Login注意,是大写的Login,有的小伙伴因为失误了,大小写没注意,最后代码里路径跳转都是 /login,这时候就出现404了,因为它的路径是/Login

如何使用CSS Modules

用过Next.js都知道,它用的是css-in-js的解决方案 —— styled-jsx。然后一般用antd的都知道使用的是less,但是一些场景或者第三方库用的是css,那么你的项目里就需要既要使用css,又要使用less。

# install next-css

yarn add @zeit/next-css

# use nextCss warpped the config
// next.config.js
const withLess = require('@zeit/next-less');
const withCSS = require('@zeit/next-css');
...
module.exports = withCSS(
  withLess({
    cssModules: true,
    ... // other config
  })
);

# use css modules

import css from "../style.css";

const Component = props => {
  return (
    <div className={css.example}>
      ...
    </div>
  );
}

export default Component;

ant-design的问题

一般使用next+antd都会去官方clone哪个with-ant-design-less这个demo,巧的是,我也贡献过一次pr代码,这个demo是存在一些问题的。

我来说一下: 这个demo在开发环境,在路由进入第二个页面的时候,会出现样式错乱的场景,需要刷新页面样式才会恢复,生产环境是没问题的。 不过对于开发人员来说应该体验也是很不好的,我这边尝试过一些办法,效果都不好,最后采用的是这种办法:开发环境,额外在_app.js内部引入一次antd的css样式文件,生产环境不引入。代码:

// next.config.js
const isDev = process.env.NODE_ENV !== 'production';

// fix antd bug in dev development
const devAntd = '@import "~antd/dist/antd.less";\n';
const stylesData = fs.readFileSync(
  path.resolve(__dirname, './assets/_styles.less'),
  'utf-8'
);
fs.writeFileSync(
  path.resolve(__dirname, './assets/self-styles.less'),
  isDev ? `${devAntd}${stylesData}` : stylesData,
  'utf-8'
);

详细的可以去脚手架里面去看~

强迫症患者福音

上面这两个图,应该很多人都遇到过吧,打包过程警告,生产过程控制台警告。当然了,因为是换色的,不是我们所熟悉的红色Error,所以其实可以不必理会,不会影响什么,但是应该有很多跟我一样的强迫症患者(暴露了自己是处女座的事实)。不能忍受这种东西,怎么办呢?解决吧:

// next.config.js

// define the webpack plugn
class FilterPlugin {
  constructor(options) {
    this.options = options;
  }

  apply(compiler) {
    compiler.hooks.afterEmit.tap(
      'FilterPlugin',
      (compilation) => {
        compilation.warnings = (compilation.warnings).filter(
          warning => !this.options.filter.test(warning.message)
        );
      }
    );
  }
}

webpack: (config, {...args}) => {
  config.plugins.push(
    ...[
      // Instantiate the plugin and add it as a Webpack plugin
      new FilterPlugin(
        { filter: /chunk styles \[mini-css-extract-plugin]\nConflicting order between:/ }
      )
    ]
  );
}

经过上面的处理,就不会报错啦~

兼容IE10/9

因为我自己做的项目都没有考虑过兼容IE10甚至是9,所以在写一些东西的时候确实没思考太多,最近有一些小伙伴用架子写项目,但是公司要求兼容IE9,结果就出现各种问题了。那能怎么办?兼容呗:

# 新建polyfill.js文件
// /core/polyfills.js
/* eslint no-extend-native: 0 */
// core-js comes with Next.js. So, you can import it like below
import includes from 'core-js/library/fn/string/virtual/includes';
import repeat from 'core-js/library/fn/string/virtual/repeat';
import assign from 'core-js/library/fn/object/assign';
import 'core-js/es6/map';
import 'core-js/es6/set';

// Add your polyfills
// This files runs at the very beginning (even before React and Next.js core)
console.log('Load your polyfills');

String.prototype.includes = includes;
String.prototype.repeat = repeat;
Object.assign = assign;

# 配置兼容
// next.config.js
...
webpack: function (cfg) {
    const originalEntry = cfg.entry
    cfg.entry = async () => {
      const entries = await originalEntry()

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

      return entries
    }

    return cfg
  }
...

如果上面两个步骤过后还是不能兼容,请把Nextjs版本号降级到v7.0.2,这是一个较为稳定的版本~

文档上有但是你可能没看过的

  • 如何监听路由变化
// _app.js
   
   import Router from 'next/router';
   ...
   // Listen the route path change
   Router.events.on('routeChangeStart', (path) => {
     console.log('route start change, the next route is:', path);
     // do something what you want to do.
     ...
   });

就像我说的,文档上面是有的,不过可能大家没认真阅读就给忽略掉了,在这里也说明一下,就是可能有的时候需要监听路由的变化情况做一些事情,Nextjs给我们提供了几个API,大家自己掌握~

  • assetPrefix

Nextjs支持我们在生产的时候带上前缀部署,比如我有一个域名a.com然后想把项目部署后通过a.com/project/xxx去访问,这时候就可以配置assetPrefix了。

// server.js
const server = new http.Server((req, res) => {
    // Add assetPrefix support based on the hostname
    if (req.headers.host === 'my-app.com') {
      app.setAssetPrefix('http://cdn.com/myapp');
    } else {
      app.setAssetPrefix('');
    }
    
    handleNextRequests(req, res);
});

// next.config.js
const isProd = process.env.NODE_ENV === 'production';
module.exports = {
  // You may only need to add assetPrefix in the production.
  assetPrefix: isProd ? 'https://cdn.mydomain.com' : ''
};

在把Nextjs部署到Github Page的时候,使用的就是assetPrefix。

Next.js + Ant-Design动态换肤

上面我也说过了,Nextjs适合中后台项目,那么一般的中后台项目都需要换肤功能,所以我也自己开发了一个。dynamic-antd-theme,感兴趣的小伙伴可以使用,star和pr。总之,任何形式都欢迎啊~

这个项目也兼容了IE10/9,所以大家是可以放心使用的~

总结

后续可能会不断的在这篇文章里新增遇到的问题和小伙伴们分享的问题和解决方法。感兴趣的同学可以加入下面的微信群一起聊天~单纯的交流沟通,欢迎~

如果微信图片失效,请加QQ群:641113448,我会拉你入群~