NextJS基础配置详解

3,028 阅读3分钟

NextJS基础配置详解

看到了很多Next的基础教程,但是没找到有关于next.config.js详细讲解,这里准备把自己平常用的写下来供大家参考。

配置环境变量

一般在项目开发中会分好几个环境,最常见的比如开发环境(dev)、测试环境(test)、生产环境(prod),既然分这么多环境,一般我们就需要用到环境变量来进行区分配置,我在next项目中区分环境变量用下面这种方式。

首先在package.json中添加cross-env,通过cross-env传递不同的环境变量,配置如下:

  // package.json
  {
    "scripts": {
      "dev": "cross-env NODE_ENV_API=dev next dev -p 3000", // 配置dev环境
      "test": "cross-env NODE_ENV_API=test next dev -p 3000", // 配置test环境
      "prep": "cross-env NODE_ENV_API=prep next dev -p 3000", // 配置prep环境
      "prod": "cross-env NODE_ENV_API=prod next dev -p 3000", // 配置prod环境
    }
  }

上面我们总共配置了四个环境,我们可以在next.config.js中通过process.env.NODE_ENV_API获取到我们设置的环境变量,然后通过next提供的publicRuntimeConfig对象传递到我们的项目中,代码如下:

  // next.config.js
  {
    "publicRuntimeConfig": { //这里的配置既可以服务端获取到,也可以在浏览器端获取到
      "NODE_ENV_API": process.env.NODE_ENV_API || "prod",
    },
  }

在项目中使用,如下:

  // config.ts 
  import getConfig from 'next/config'

  export const { NODE_ENV_API = "prod" }: { NODE_ENV_API: "dev" | "test" | "prep" | "prod" } = getConfig().publicRuntimeConfig

  // 接口前缀
  export const BASE_URL: string = (() => {
    let BASE_URL = "http://www.api.com/api/dev"
    switch (NODE_ENV_API) {
      case "dev":
        BASE_URL = "http://www.api.com/api/dev"
        break
      case "test":
        BASE_URL = "http://www.api.com/api/test"
        break
      case "prep":
        BASE_URL = "http://www.api.com/api/prep"
        break
      case "prod":
        BASE_URL = "http://www.api.com/api/prod"
        break
    }

    return BASE_URL
  })()

sass中引入环境变量&添加全局sass文件

next中,next默认支持sass,允许我们导入(import)具有 .scss.sass 扩展名的 Sass 文件。

next.config.js中提供了sassOptions方法来配置sass编译器。我们可以通过它提供的方法来导入全局变量与配置,比如:

  // next.config.js
  {
    "sassOptions": {
      "includePaths": [path.join(__dirname, 'styles')], // 存放 variables.module.scss 文件夹路径
    },
  }
  /* variables.module.scss */
  $primary-color: #64FF00

  :export {
    primaryColor: $primary-color
  }
  // pages/_app.js
  import variables from '../styles/variables.module.scss'

  export default function MyApp({ Component, pageProps }) {
    return (
      <Layout color={variables.primaryColor}>
        <Component {...pageProps} />
      </Layout>
    )
  }

除了上面的方法我们也可以通过additionalData添加全局变量与scss文件,如下:

  // next.config.js
  {
    "sassOptions": {
      additionalData(content, loaderContext) {
        let $env = ""

        switch (process.env.NODE_ENV_API) { // 通过环境变量来配置不同的全局变量
          case "dev":
            $env = "dev"
            break;
          case "test":
            $env = "test"
            break;
          case "prep":
            $env = "prep"
            break;
          case "prod":
            $env = "prod"
            break;
        }

        let config = "@import './styles/mixin.scss';"; // 添加全局sass文件,也可以通过环境变量改变引入文件,来加载不同的主题色。

        if(!$env) {
          config = config + `$env: "";@import './styles/var.scss';` + content;
        }else {
          config = config +  `$env: "${$env}";@import './styles/var.scss';` + content;
        }

        return config
      },
    },
  }

处理svg文件

next中使用svg文件非常简单,我们只需要引入@svgr/webpack依赖,修改一下webpack配置即可如下:

  // next.config.js
  {
    webpack(webpackConfig) {
      webpackConfig.module.rules.push({
        test: /\.svg$/,
        use: [ "@svgr/webpack" ]
      }); // 针对 SVG 的处理规则

      return webpackConfig
    },
  }

通过上面的配置我们就可以在项目中直接使用svg文件了

// home.tsx
import DownIcon from "../../svg/down_icon.svg"

export default function Page() {

  return (
    <>
      <DownIcon />
    </>
  )
}

路由添加后缀(.html、.htm、.php、.shtml)

我们去写next时有的时候项目第一期写完了很有可能会碰到这种需要,xxx来说大哥这个网页地址栏(路由)后面能不加个后缀啊,加个.html的后缀。我们去添加这个后缀的时候,大部分可能会直接选择去修改文件名称,比如把Home目录改为Home.html,其实我们也可以通过next.config.js中提供的rewrites方法去给路由添加多个映射路径,简单来说就是多个匹配地址来解决上面的需求。

比如说我们想让路由支持.html.htm后缀,如下:

  {

    // 映射多个路径
    async rewrites() {
      return [
        { // 登录
          source: '/login(.html|.htm)?(.*)', // 我们要支持请求的路径
          destination: '/login', // next中要路由到的路径
        },
        { // 详情页面
          source: '/desc(.html|.htm|.php)', // 我们要支持请求的路径 /desc.html /desc.htm /desc.php
          destination: '/desc', // next中要路由到的路径
        },
      ]
    }
  }

通过上面的方法我们就不用修改目录或文件名称了,如果要配置动态路由也很简单,如下:

  {

    // 映射多个路径
    async rewrites() {
      return [
        { // 详情
          source: '/desc/:params(\\d{1,})(.html|.htm)?(.*)', // 匹配的对应地址 /desc/123    /desc/123.html    /desc/1333.htm
          destination: '/desc/:params',
        },
        { // 详情
          source: '/desc_:params(\\d{1,})(.html|.htm)?(.*)', // 匹配的对应地址 /desc_123    /desc_123.html    /desc_1333.htm
          destination: '/desc/:params',
        },
      ]
    }
  }

添加移动端viewport配置

我们如果要通过next去写m站,我们可以通过postcss-px-to-viewport,将px单位自动转换成viewport单位,去适配手机浏览器,我们只需要安装postcss-loaderpostcss-px-to-viewport依赖,并且在根目录下创建postcss.config.js即可。

  // postcss.config.js
  module.exports = {
    plugins: {
      'postcss-px-to-viewport': {
        unitToConvert: 'px', //需要转换的单位,默认为"px"
        viewportWidth: 375, // 视窗的宽度,对应的是我们设计稿的宽度
        // viewportHeight: 1334,//视窗的高度,根据375设备的宽度来指定,一般指定667,也可以不配置
        unitPrecision: 13, // 指定`px`转换为视窗单位值的小数位数(很多时候无法整除)
        propList: ['*'], // 能转化为vw的属性列表
        viewportUnit: 'vw', // 指定需要转换成的视窗单位,建议使用vw
        fontViewportUnit: 'vw', //字体使用的视口单位
        // selectorBlackList: ['.ignore-', '.hairlines'], //指定不转换为视窗单位的类,可以自定义,可以无限添加,建议定义一至两个通用的类名
        minPixelValue: 1, // 小于或等于`1px`不转换为视窗单位,你也可以设置为你想要的值
        mediaQuery: false, // 允许在媒体查询中转换`px`
        replace: true, //是否直接更换属性值,而不添加备用属性
        exclude: [
          /RightBar/,
          /gotop.vue/,
        ], //忽略某些文件夹下的文件或特定文件,例如 'node_modules' 下的文件
        // landscape: false, //是否添加根据 landscapeWidth 生成的媒体查询条件 @media (orientation: landscape)
        landscapeUnit: 'vw', //横屏时使用的单位
        // landscapeWidth: 1134 //横屏时使用的视口宽度
      }
    }
  }

修改UI组件的样式

修改UI库组件样式是一件挺麻烦的事情,我一般去修改UI组件样式时喜欢用下面的方法。

  .page {

    :global {
      .antd_btn { // 组件的class
        display: inline-block;
        width: 5px;
        height: 5px;
        margin-left: 4px;
        background: #FF4F74;
        border-radius: 50%;
      }
    }
  }

项目打包部署

  1. 自定义服务器打包部署 我们通过执行打包命令,会在目录下构建一个.next文件,我们只需要把 .nextpublicpackage.jsonnext.config.js与自定义的server.js上传到服务器然后安装依赖启动服务即可。

  2. 使用pm2koa部署服务器 我比较喜欢使用pm2koa部署next,因为可以去自定义一些配置,下面是我的server.js

  // server.js
  const Koa = require('koa')
  const next = require('next')
  const Router = require('@koa/router')
  const logger = require('koa-logger')

  const port = 4050 // 服务端口号

  const app = next({})
  const handle = app.getRequestHandler()

  app.prepare().then(() => {
    const server = new Koa()
    const router = new Router()

    router.all('(.*)', async (ctx) => {
      await handle(ctx.req, ctx.res)
      ctx.respond = false
    })

    server.use(async (ctx, next) => {
      ctx.res.statusCode = 200
      await next()
    })

    server
      .use(logger({
        transporter: (str, args) => {
          const arr = [ "_next/static/", "/favicon.ico", "/assets/" ]

          if(typeof str === "string") {
            const find = arr.find(item => str.includes(item))
    
            if(!find) {
              console.log(str)
            }
          }
          // redirect koa logger to other output pipe
          // default is process.stdout(by console.log function)
        }
      }))
      .use(router.routes())
    
    server.listen(port, () => {
      console.log(`> Ready on http://localhost:${port}`)
    })
  })

pm2配置文件如下

  // ecosystem.config.js
  module.exports = {
    apps: [
      {
        name: 'xxxxxx', // 项目名称
        // script: './node_modules/nuxt/bin/nuxt.js', // 启动脚本
        script: './server.js', // 启动脚本
        args: 'start',
        // cwd: './.nuxt',
        watch: false, // 是否开启监听
        exec_mode: 'cluster', // 分為 cluster 以及 fork 模式
        instances: '4',
        max_memory_restart: '400M', // 當佔用的 memory 達到 400M, 就自動重啟
        // pm2 會根據此選項內的時間來判定程序是否有成功啟動
        // 格式可使用 number 或 string, number 的話, 3000 代表 3000 ms。 string 的話, 可使用 '1h' 代表一個小時, '5m' 代表五分鐘, '10s' 代表十秒
        min_uptime: '15s',
        listen_timeout: 15000, // 單位為 ms, 如果在該時間內 app 沒有聽 port 的話,強制重啟
        ignore_watch: [ // 不用监听的文件
          "node_modules",
          "logs"
        ],
        autorestart: true,
        log_date_format: "YYYY-MM-DD HH:mm:ss",
        error_file: "./logs/app-err.log", // 错误日志文件
        out_file: "./logs/app-out.log",
        // 环境变量配置
        env_dev: {
          NODE_ENV_API: "dev",
          prot: 3000,
        },
        env_test: {
          NODE_ENV_API: "test",
          prot: 3000,
        },
        env_prep: {
          NODE_ENV_API: "prep",
          prot: 3000,
        },
        env_prod: {
          NODE_ENV_API: "prod",
          prot: 3000,
        },
      }
    ],
  }

创建并配置好上面的文件之后,我们把上面的文件与next打包文件上传到服务器,执行pm2启动命令即可

  // PM2常用命令
  pm2 start ecosystem.config.js --env=test // 启动服务 --env=test 对应的部署环境
  pm2 reload name // name 填写 ecosystem.config.js 中的name也就是项目名称,进行重启
  pm2 stop name // 停止服务
  pm2 del name // 删除服务
  pm2 ls // 查看pm2 启动列表与状态
  pm2 restart all // 重启所有应用程序
  pm2 stop all // 停止所有应用程序
  pm2 del all // 关闭并删除所有应用程序
  pm2 ecosystem // 生成一个示例json配置文件
  1. 使用 outputStandalone 来进行部署 因为官方文档写的已经很详细了,这里就不再写了,具体详情可以查看官方文档