百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术教程 > 正文

太猛了!GIThub大佬总结《Next.js 实践记录》,掀起业内热潮

csdh11 2025-02-26 11:42 17 浏览

背景

因主技术栈使用Vue,部分服务端渲染的项目就自然的选择了使用 Nuxt.js 框架进行开发。近期在尝试进行技术栈更新,所以选择使用 Next.js进行页面开发。目前采用 Next.js 12.13.1 版本,官方最近版本迭代到了 Next.js 13.4

Next.js 是基于React 的服务端渲染框架。

在传统的SPA项目中,例如使用 Vue-cli 创建的项目,最终build生成的静态文件,是基于浏览器渲染的,即所谓的 CSR (Client-side Rendering)。

CSR往往都是单页面应用,即一个HTML文件和若干个js、css文件。打开build后的HTML文件,发现代码很简单,页面和组件的元素都是放在了js里,由js动态渲染到HTML中。CSR模式是目前前端开发项目中应用最为广泛的。

但有些也场景,特别是需要SEO优化的时候,CSR就不太合适了,所以服务端(Server-side Rendering))渲染应运而生,SSR是由服务器将用户请求的页面DOM组装好后,再返回给浏览器,因此通过“查看网页源代码”,是可以看到完整的页面DOM的。

而SSG (Static Site Generation)顾名思义就是静态网站生成,也就是常说的“网页静态化”,除了适合SEO,还很方便CDN加速,比较适合内容相对比较固定的资讯发布类网站。

以下是关于CSR、SSR、SSG的简单对比


先说明依赖包版本

Node.js 16.17.0

next.js 12.13.1

react 18.2.0

react-dom 18.2.0

axios 0.27.2

sass 1.55.0

redux 4.2.0

创建Next.js项目

首先我们先对 Next.js 的项目进行初始化,Next.js 提供了脚手架来帮助我们初始化项目,我们可以执行下面的命令来初始化项目:


npx create-next-app@latest --typescript

其中 next-env.d.ts 是 Next.js 的类型文件,可以保证 ts 选择 Next.js 相关的类型,通常我们不需要对它进行修改,可以在提交后加到 .gitignore 中。next.config.js 是 Next.js 的构建配置,底层也是基于 Webpack 去打包的,我们可以在默认的配置上加上下面的配置来提供别名的能力。


// next.config.js
const path = require("path");

module.exports = {
  reactStrictMode: true,
  swcMinify: true,
  webpack: (config) => {
    config.resolve.alias = {
      ...config.resolve.alias,
      "@": path.resolve(__dirname),
    };
    return config;
  },
};

tsconfig.json 中我们也需要加一下对应的别名解析识别(baseurl , paths)。

{
  "compilerOptions": {
    "target": "es5",
      "lib": ["dom", "dom.iterable", "esnext"],
      "allowJs": true,
      "skipLibCheck": true,
      "strict": true,
      "forceConsistentCasingInFileNames": true,
      "noEmit": true,
      "esModuleInterop": true,
      "module": "esnext",
      "moduleResolution": "node",
      "resolveJsonModule": true,
      "isolatedModules": true,
      "jsx": "preserve",
      "incremental": true,
      "baseUrl": ".",
      "paths": {
	"@/*": ["./*"]
      }
  },
    "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
    "exclude": ["node_modules"]
}

到这里项目其实就已经初步初始化完成了,我们执行npm run dev打开http://localhost:3000 就可以看到一个 Next.js 的默认服务器端渲染页面

配置项目


设置路径别名

Next的官方脚手架没有src目录,但是考虑src目录是普遍存在大多数脚手架工程中,所以Next也对src目录做了支持,我们可以新建一个 src 目录,将 pages、styles、api 目录移动到src 目录里,在执行 npm run dev,项目依旧正常运行


关于src目录,官方的规则如下:

1.如果根目录下有 pages,则src/pages 将被忽略

2.public 目录以及 next.config.js、tsconfig.json 等配置相关文件,不能放在src目录里

修改 tsconfig.json 别名解析

  "paths": {
    "@/*": ["src/*"]
  }

这样在代码中引用 src 目录下的文件,可以直接使用 @表示src目录,不需要 "../" 了。

修改 tsconfig.json 需要重启项目才能生效。

按照以上目录设置后,项目的入口文件变为 src/pages/_app.js。

配置 SourceMap

development 环境是开启sourceMap的,production 环境默认不开启。如果需要在prod 环境中开启,可以在next.config.js 中进行配置,为了不暴露项目源码,不建议进行配置


module.exports = {
  productionBrowserSourceMaps: !!isDev,
}

设置页面Title

设置页面的title很简单,修改 src/pages/_app.js

import '../styles/globals.css' // 引入全局样式
import Head from 'next/head';
import type { AppProps } from 'next/app'

export default function App({ Component, pageProps }: AppProps) {
  return (
    <>
      
        页面标题
      
      
    
  )
}

运行项目,发现页面的title 已经修改成功

设置HTML框架代码

新建 src/pages/_document.js,代码如下:

import Document, { Html, Head, Main, NextScript } from 'next/document';
import Script from 'next/script';

class MyDocument extends Document {
  render() {
    return (
      
        
        
          
); } } MyDocument.getInitialProps = async (ctx) => { const initialProps = await Document.getInitialProps(ctx); return { ...initialProps }; }; export default MyDocument;

_document.js 也是Next.js 的指定文件名,且必须在pages目录下才生效。

那么 _document.js 和 _app.js 有什么区别呢?

自定义 App,可以对App 组件进行重构

  • 页面切换之间保持布局的持久化
  • 切换页面时保持状态(state)
  • 使用 componentDidCatch 自定义错误处理
  • 向页面(pages)注入额外的数据
  • 添加全局CSS

自定义Document

只有在服务端渲染的时候才会被调用,主要用来修改服务端渲染的文档内容,通常服务端渲染会使用一些 css-in-js 库,它在_document.js 中定义。

在next/document中提供的并不仅是Document组件,还有一些跟HTML标签对应的组件,在重写的时候要记得都要写上。

官方不建议把 title 放到_document.js中,如果在_document.js 中的head 设置了title,在build 的时候会收到 warning。所以我们将 head 的内容放在 _app.js 中设置。

设置错误页面

Next.js 自带了 404、500页面,但是比较简陋,我们可以自定义页面覆盖掉自带错误页面

可以自定义 404.tsx、500.tsx或者 _error.tsx。

环境变量

  • .env.development
  • .env.production
  • .env.test

CSS预处理及使用


集成Sass

Next.js 允许你导入(import)具有 .scss 和 .sass 扩展名的 Sass 文件。 你可以通过 CSS 模块以及 .module.scss 或 .module.sass 扩展名来使用组件及的 Sass。

npm install sass

Postcss 配置

为了适配移动端,采用 px-to-vw 方案,项目中引入

npm install postcss postcss-px-to-viewport-8-plugin autoprefixer css-loader cssnano tailwindcss --save-dev

新增 postcss.config.js

module.exports = {
  plugins: {
    'postcss-px-to-viewport-8-plugin': {
      // 视窗的宽度,对应的是我们设计稿的宽度,我们公司用的是750
      viewportWidth: 750,
      // 指定`px`转换为视窗单位值的小数位数
      unitPrecision: 3,
      // 指定需要转换成的视窗单位,建议使用vw
      viewportUnit: 'vw',
      // 指定不转换为视窗单位的类,可以自定义,可以无限添加,建议定义一至两个通用的类名
      selectorBlackList: ['.ignore'],
      // 小于或等于`1px`不转换为视窗单位,你也可以设置为你想要的值
      minPixelValue: 1,
      // 允许在媒体查询中转换`px`
      mediaQuery: false,
      // exclude: undefined
    },
    // 自动补全
    autoprefixer: {
      overrideBrowserslist: [
        'Android 4.1',
        'iOS 7.1',
        'Chrome > 31',
        'ff > 31',
        'ie >= 8',
      ],
      grid: true,
    },
    tailwindcss: {},
    ...(process.env.NODE_ENV === 'development' ? {} : { cssnano: {} }),
  },
};

配置全局样式

新建 src/styles/globals.scss,内部进行样式初始化。然后在入口文件引入 globals.scss。参考_app.tsx

配置页面样式

需要注意的是,在Next.js 项目中,组件的代码中是无法引入全局样式的,对于组件自身的样式,只能使用 CSS Module 来引用,即文件名为 ***.module.scss。否则会报错。组件中的className,也需要按CSS Module的方式进行设置。

注意一下,这里使用 CSS Module 的方式加载样式,因此生成的HTML中,className 会自动加上随机字符串后缀,对应的css也会自动添加相应的字符串,正因为 CSS Module 这个机制,同名样式互相污染的问题也就不存在了。

页面路由

基于文件系统的路由

Next.js 的优势是 基于文件系统的路由,对应的只需要在 src/pages 下创建的对应页面即可。

在pages/ 下创建 /about.tsx 文件,重新启动项目,

next/link

Next.js 项目内的页面跳转使用, 该组件会预先加载引用的页面。如果是项目外部链接,则使用

next/router

Next.js 自带的router,通过 useRouter 来获取当前页面的pathname等信息

图片引用

使用原生标签引入图片

本地图片资源,存放在 public/img/*** 下,图片会跟随项目进行打包,图片根路径地址与项目跟路径地址一致

引用方式一



publicRuntimeConfig.basePath
是根据当前环境,获取的 basePath 路径

使用 next/image 引用图片

Next.js 自带的 可以认为是 的升级版,提供了非常方便的尺寸适配,加载等属性,会根据客户端的情况,进行图片的动态优化处理,但也会自动增加很多样式,会影响原生的 样式,所以要根据情况使用。

如果要使用,需要在包裹一个父容器,并为父容器定义样式。会自动适配父容器的大小,因为可以不用为特意设置宽高。需要注意的是,如果使用加载图片,因为 Next.js 的安全机制,还需要在 next.config.js文件中设置图片域属性,例如设置图片域名属性 qq.com

module.exports = {
  images: {
    domains: ['qq.com'],
    path: `${basePath}/_next/image`,
  },
}

项目中开始部分网络图片采用加载,Next 的确会做懒加载等处理,但是在安卓低端机下存在兼容问题,无法展示,所以后来统一使用原生 标签进行加载。

接口请求

CSR/SSR/SSG三种API请求方式

在Next.js 项目中,API请求有三种方式。但是根据项目的部署方式,最多可以同时有两种,即:

  1. CSR+SSR
  2. CSR+SSG

CSR 的API请求,就是常规的前端项目中的请求方式,即:由客户端浏览器发起请求,拿到数据后渲染到页面

SSR的API请求,是由服务端(Next.js的Node.js)发起请求,拿到数据后,组装到HTML里,然后将组装好的HTML返回给客户端浏览器

SSG的API请求,于SSR的API请求类似,也是由服务发起请求并把数据组装到HTML里,然后进行静态化输出。 但由于是完全静态化的,所以当API数据发生变化时,必须重新静态化才能更新页面。

getInitialProps (SSR)

getInitialProps是在渲染页面之前就会运行的API。 如果该路径下包含该请求,则执行该请求,并将所需的数据作为props传递给页面。

getServerSideProps (SSR)

getServerSideProps 每次访问时请求数据

getStaticProps(SSG)

所谓的SSG也就是静态站点生成,在build阶段将页面构建成静态的html文件,这样线上直接访问HTML文件,性能极高。

getStaticPaths (SSG)

用于在使用动态路由时生成静态文件。

如何选择SSR还是SSG?

axios

使用 axios,并进行的简单的封装,进行了请求拦截及响应拦截。

开发过程中的优化方案

上面提到的本地图片引用,因为项目采用Docker构建,图片如果跟随项目一起打包,每次更新上线后,图片的缓存会失效,页面会重新加载图片,体验上很不好,后来修改为将本地图片上传至CDN。需修改配置文件中的 assetPrefix 配置为CDN文件路径,需结合next-compose-plugins,next-optimized-images 使用

修改页面图片引用方式


npm install --save next-compose-plugins next-optimized-images
// next.config.js
const withPlugins = require('next-compose-plugins');

const optimizedImages = require('next-optimized-images');

const nextConfig = {
  assetPrefix: isDev ? '' : 'https://图片cdn地址',
  distDir: 'build', // 项目文件打包路径
  basePath: '',
  sassOptions: {
    includePaths: [path.join(__dirname, 'src/styles')],
  },
  ...
}

module.exports = withPlugins([optimizedImages], nextConfig);

module.exports = nextConfig;

修改图片的目录,原目录在public/img/*** 下,修改为src/assets/images/***

页面/组件引用方式修改

// 导入本地图片
import demoImg from '@/assets/image/demoImg.png';

// 使用

项目构建,执行 npm run build 后,会在项目目录下生成 build 文件夹,该文件夹下就是项目的构建结果。其中 build/static/media 文件夹存放的是项目引用的图片,并且文件名已经经过hash 处理,可通过工具上传至CDN目录。


Next.js 实践记录
原文链接:
https://juejin.cn/post/7232596270551711799

相关推荐

探索Java项目中日志系统最佳实践:从入门到精通

探索Java项目中日志系统最佳实践:从入门到精通在现代软件开发中,日志系统如同一位默默无闻却至关重要的管家,它记录了程序运行中的各种事件,为我们排查问题、监控性能和优化系统提供了宝贵的依据。在Java...

用了这么多年的java日志框架,你真的弄懂了吗?

在项目开发过程中,有一个必不可少的环节就是记录日志,相信只要是个程序员都用过,可是咱们自问下,用了这么多年的日志框架,你确定自己真弄懂了日志框架的来龙去脉嘛?下面笔者就详细聊聊java中常用日志框架的...

物理老师教你学Java语言(中篇)(物理专业学编程)

第四章物质的基本结构——类与对象...

一文搞定!Spring Boot3 定时任务操作全攻略

各位互联网大厂的后端开发小伙伴们,在使用SpringBoot3开发项目时,你是否遇到过定时任务实现的难题呢?比如任务调度时间不准确,代码报错却找不到方向,是不是特别头疼?如今,随着互联网业务规模...

你还不懂java的日志系统吗 ?(java的日志类)

一、背景在java的开发中,使用最多也绕不过去的一个话题就是日志,在程序中除了业务代码外,使用最多的就是打印日志。经常听到的这样一句话就是“打个日志调试下”,没错在日常的开发、调试过程中打印日志是常干...

谈谈枚举的新用法--java(java枚举的作用与好处)

问题的由来前段时间改游戏buff功能,干了一件愚蠢的事情,那就是把枚举和运算集合在一起,然后运行一段时间后buff就出现各种问题,我当时懵逼了!事情是这样的,做过游戏的都知道,buff,需要分类型,且...

你还不懂java的日志系统吗(javaw 日志)

一、背景在java的开发中,使用最多也绕不过去的一个话题就是日志,在程序中除了业务代码外,使用最多的就是打印日志。经常听到的这样一句话就是“打个日志调试下”,没错在日常的开发、调试过程中打印日志是常干...

Java 8之后的那些新特性(三):Java System Logger

去年12月份log4j日志框架的一个漏洞,给Java整个行业造成了非常大的影响。这个事情也顺带把log4j这个日志框架推到了争议的最前线。在Java领域,log4j可能相对比较流行。而在log4j之外...

Java开发中的日志管理:让程序“开口说话”

Java开发中的日志管理:让程序“开口说话”日志是程序员的朋友,也是程序的“嘴巴”。它能让程序在运行过程中“开口说话”,告诉我们它的状态、行为以及遇到的问题。在Java开发中,良好的日志管理不仅能帮助...

吊打面试官(十二)--Java语言中ArrayList类一文全掌握

导读...

OS X 效率启动器 Alfred 详解与使用技巧

问:为什么要在Mac上使用效率启动器类应用?答:在非特殊专业用户的环境下,(每天)用户一般可以在系统中进行上百次操作,可以是点击,也可以是拖拽,但这些只是过程,而我们的真正目的是想获得结果,也就是...

Java中 高级的异常处理(java中异常处理的两种方式)

介绍异常处理是软件开发的一个关键方面,尤其是在Java中,这种语言以其稳健性和平台独立性而闻名。正确的异常处理不仅可以防止应用程序崩溃,还有助于调试并向用户提供有意义的反馈。...

【性能调优】全方位教你定位慢SQL,方法介绍下!

1.使用数据库自带工具...

全面了解mysql锁机制(InnoDB)与问题排查

MySQL/InnoDB的加锁,一直是一个常见的话题。例如,数据库如果有高并发请求,如何保证数据完整性?产生死锁问题如何排查并解决?下面是不同锁等级的区别表级锁:开销小,加锁快;不会出现死锁;锁定粒度...

看懂这篇文章,你就懂了数据库死锁产生的场景和解决方法

一、什么是死锁加锁(Locking)是数据库在并发访问时保证数据一致性和完整性的主要机制。任何事务都需要获得相应对象上的锁才能访问数据,读取数据的事务通常只需要获得读锁(共享锁),修改数据的事务需要获...