Nextjs之a(chǎn)pp router應(yīng)用

項目初始化

  1. 創(chuàng)建項目
npx create-next-app@latest

初始選擇以下配置

What is your project named? my-app
Would you like to use TypeScript? No / Yes
Would you like to use ESLint? No / Yes
Would you like to use Tailwind CSS? No / Yes
Would you like to use `src/` directory? No / Yes
Would you like to use App Router? (recommended) No / Yes
Would you like to customize the default import alias (@/*)? No / Yes
  1. 創(chuàng)建.editorconfig

統(tǒng)一代碼風(fēng)格

# top-most EditorConfig file
root = true

# 針對所有文件
[*]
indent_style = space
indent_size = 2
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
  1. 創(chuàng)建.vscode/settings.json

針對vscode配置,提升vscode開發(fā)效率

{
    "editor.tabSize": 2,
    "typescript.inlayHints.parameterNames.enabled": "all",
    "typescript.inlayHints.parameterTypes.enabled": true,
    "typescript.inlayHints.variableTypes.enabled": true,
    "typescript.inlayHints.propertyDeclarationTypes.enabled": true,
    "typescript.inlayHints.enumMemberValues.enabled": true,
    "typescript.inlayHints.functionLikeReturnTypes.enabled": true
  }

多端適配

多端適配采用的是tailwindcss方案

  1. 安裝tailwindcss
npm i -D tailwindcss postcss autoprefixer
npx tailwindcss init

該操作會自動以下操作:

  • 更新package.json

  • 創(chuàng)建tailwind.config.js

  1. 更新tailwind.config.js配置
import type { Config } from 'tailwindcss';

const config: Config = {
  content: [ // 配置tailwindcss的作用范圍:使用tailwindcss的地方
    './app/**/*.{js,ts,jsx,tsx,mdx}',
    './components/**/*.{js,ts,jsx,tsx,mdx}'
  ],
  theme: {
    extend: { }
  },
  plugins: []
};
export default config;
  1. 引入tailwindcss內(nèi)置樣式組件
/* app/global.css */
@tailwind base;
@tailwind components;
@tailwind utilities;
  1. 創(chuàng)建postcss.config.js文件
module.exports = {
  plugins: {
    tailwindcss: {},
    autoprefixer: {},
  }
}

  1. 測試可用性
// 更新app/page.tsx
export default function Home() {
  return (
    <main>
      <div className="text-3xl text-white bg-black">22222</div>
    </main>
  );
}
  1. 特定斷點配置
// tailwind.config.ts
const config: Config = {
  content: [
    './src/pages/**/*.{js,ts,jsx,tsx,mdx}',
    './src/components/**/*.{js,ts,jsx,tsx,mdx}',
    './src/app/**/*.{js,ts,jsx,tsx,mdx}'
  ],
  screens: {
    xl: { min: '1281px' }, // pc
    lg: { max: '1280px' }, // pad
    md: { max: '760px' }, // 折疊屏
    sm: { max: '450px' } // 手機(jī)
  },
  plugins: []
};
export default config;

Caveat:

screens的配置是有優(yōu)先級的鸯两,上述配置是大屏優(yōu)先,后續(xù)的media樣式會覆蓋先序的media匹配:sm > md > lg > xl。

移動端適配

rem + tailwindcss

移動端適配采用flexiblejs的rem方案

  • tailwindcss單位為rem算撮,html#fontsize以瀏覽器默認(rèn)字號為基準(zhǔn)(通用為16px)

  • 移動端rem基礎(chǔ)由設(shè)計圖&設(shè)備寬度確定生宛,是動態(tài)的

  1. 定制化tailwindcss

根據(jù)設(shè)計稿規(guī)范定制化tailwindcss,單位為px肮柜,后續(xù)由插件自動轉(zhuǎn)換陷舅。

import type { Config } from 'tailwindcss';

const config: Config = {
  content: [
    './components/**/*.{js,ts,jsx,tsx,mdx}',
    './app/**/*.{js,ts,jsx,tsx,mdx}',
  ],
  theme: {
    fontSize: {
      xs: '12px',
      sm: '14px',
      base: '16px',
      lg: '18px',
      xl: '20px',
      '2xl': '24px',
      '3xl': '30px',
      '4xl': '36px',
      '5xl': '48px',
      '6xl': '60px',
      '7xl': '72px',
    },
    spacing: {
      px: '1px',
      0: '0',
      0.5: '2px',
      1: '4px',
      1.5: '6px',
      2: '8px',
      2.5: '10px',
      3: '12px',
      3.5: '14px',
      4: '16px',
      5: '20px',
      6: '24px',
      7: '28px',
      8: '32px',
      9: '36px',
      10: '40px',
      11: '44px',
      12: '48px',
      14: '56px',
      16: '64px',
      20: '80px',
      24: '96px',
      28: '112px',
      32: '128px',
      36: '144px',
      40: '160px',
      44: '176px',
      48: '192px',
      52: '208px',
      56: '224px',
      60: '240px',
      64: '256px',
      72: '288px',
      80: '320px',
      96: '384px',
    },
    extend: {
      colors: { // colors在className中使用,才會被打包审洞;否則莱睁,自定義顏色不起作用;
        "whiteFix": "white"
      }
      lineHeight: {
        3: '12px',
        4: '16px',
        5: '20px',
        6: '24px',
        7: '28px',
        8: '32px',
        9: '36px',
        10: '40px',
      },
      backgroundImage: {
        'gradient-radial': 'radial-gradient(var(--tw-gradient-stops))',
        'gradient-conic':
          'conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))',
      },
    },
  },
  plugins: [],
};
export default config;

  • colors在className中使用芒澜,才會被打包仰剿;否則,自定義顏色不起作用痴晦;
  1. 安裝postcss-pxtorem插件

自動將樣式中的px單位轉(zhuǎn)換為rem單位南吮,可通過設(shè)置PX(單位大寫)禁止轉(zhuǎn)換。

npm i -D postcss-pxtorem
  1. 配置postcss.config.js
module.exports = {
  plugins: {
    tailwindcss: {},
    autoprefixer: {},
    'postcss-pxtorem': {      
        rootValue: 392 / 10,  //根據(jù)設(shè)計圖    
        unitPrecision: 5,      
        propList: ['*'],      
        selectorBlackList: [/^\.html/],      
        exclude: /(node_module)/,      
        replace: true,      
        mediaQuery: false,      
        minPixelValue: 0,    
    }
  }
}
  1. 引入[flexible.js](https://github.com/amfe/lib-flexible/tree/master)
    <html lang="en">
      <head>
        <script src="http://g.tbcdn.cn/mtb/lib-flexible/0.3.2/??flexible_css.js,flexible.js"></script>
      </head>
      <body>{children}</body>
    </html>

FAQs:

  • 引入flexible.js為什么不使用next/script內(nèi)置<Script>標(biāo)簽阅酪,而使用<script>

next/script內(nèi)置<Script>標(biāo)簽針對腳本加載進(jìn)行了優(yōu)化旨袒,采用的是異步加載;

  • 異步加載flexible.js的話术辐,ssr頁面初始化加載時html標(biāo)簽采用瀏覽器默認(rèn)的樣式,沒有指定fontsize樣式施无;

  • 加載flexible.js執(zhí)行階段辉词,依據(jù)客戶端deviceWidth動態(tài)計算html#fontsize,引發(fā)頁面整體樣式的變化猾骡,瀏覽器會重新繪制頁面瑞躺,導(dǎo)致頁面閃屏;

<script>是同步加載兴想,會阻塞DOM樹的渲染幢哨;

  • 同步加載flexible.js的話,ssr頁面渲染之前flexible已經(jīng)加載執(zhí)行完畢嫂便,不會出現(xiàn)頁面重新渲染而導(dǎo)致的閃屏捞镰。
  • 大字體情況下,flexible.js會受到影響毙替,布局變大

禁止大字體岸售,用戶修改手機(jī)字號時頁面不受影響

function rectifyNonstandardFontSize() {
  var $dom = document.createElement('div');
  $dom.style = 'font-size:20px;';
  document.body.appendChild($dom);
  var scaledFontSize = parseInt(
    window.getComputedStyle($dom, null).getPropertyValue('font-size')
  );
  document.body.removeChild($dom);
  var scaleFactor = 20 / scaledFontSize;
  var originRootFontSize = parseInt(
    window
      .getComputedStyle(document.documentElement, null)
      .getPropertyValue('font-size')
  );
  document.documentElement.style.fontSize =
    originRootFontSize * scaleFactor * scaleFactor + 'px';
}
rectifyNonstandardFontSize();
  • windows環(huán)境下,部分場景下flexible導(dǎo)致布局出現(xiàn)問題厂画,代碼報錯:

使用flexible必須判斷client環(huán)境凸丸,使用typeof window !== 'undefined'

  • tailwindcss在IE上無法使用

一般來說,Tailwind CSS v3.0專為Chrome袱院、Firefox屎慢、Edge和Safari的最新穩(wěn)定版本而設(shè)計瞭稼,并在這些瀏覽器上進(jìn)行了測試。它不支持任何版本的 IE腻惠,包括 IE 11环肘,支持Edge。

若需要支持IE妖枚,可以使用Tailwind CSS v1.9廷臼,具體支持哪些瀏覽器完全取決于樣式的使用,而不是框架绝页。

  • 若使用 Tailwind 的 Flexbox 工具構(gòu)建的網(wǎng)格荠商,它只能在 IE10 以上版本中運(yùn)行,因為IE9 不支持 Flexbox续誉;
    <div class="flex">
      <div class="w-1/3"><!-- ... --></div>
      <div class="w-1/3"><!-- ... --></div>
      <div class="w-1/3"><!-- ... --></div>
    </div>
  • 如果需要支持 IE9莱没,可以使用浮點來構(gòu)建網(wǎng)格,因為幾乎所有瀏覽器都支持浮點酷鸦;
<div class="clearfix">
  <div class="float-left w-1/3"><!-- ... --></div>
  <div class="float-left w-1/3"><!-- ... --></div>
  <div class="float-left w-1/3"><!-- ... --></div>
</div>
  • tailwindcss不會自動為其任何樣式添加供應(yīng)商前綴饰躲,需要手動添加自動前綴器。
# Using npm
npm install autoprefixer

# Using Yarn
yarn add autoprefixer
// postcss.config.js
module.exports = {
  plugins: [
    require('tailwindcss'),
    require('autoprefixer'),
  ]
}

多主題

根據(jù)條件定義主題

const adaptMultipleThemes = () => {
  const isDark = getCookie('darkMode') === 'true'
  isDark && document && document.documentElement.classList.add('isDark')
}

scss聲明主題樣式

// scss主題設(shè)置
$linkColor: #3482FF!default;
$linkDarkColor: red;
@mixin mixDarkTheme () {
  & {
    @content;
  }
  @at-root :global(.isDark) { // :global脫離css module
    $linkColor: $linkDarkColor!global;
  }
  @at-root :global(.isDark) & {
    @content;
  };
}

主題樣式應(yīng)用

  1. 在入口文件中調(diào)用adaptMultipleThemes

  2. 在樣式中使用@include mixDarkTheme

.title {
  @include mixDarkTheme(){
    color: $linkColor;
  }
}

站點配置

每個Page獨立配置title

  1. 給每個頁面增加layout.js

  2. layout.js中配置metadata

拆分next.config.mjs

next.config.js默認(rèn)僅支持commonjs規(guī)范臼隔,若使用ES Module規(guī)范嘹裂,更改后綴名為.mjs

.mjs配置為例進(jìn)行拆分:

  1. 拆分需要使用.mjs后綴文件

  2. .mjs文件使用ES Module格式書寫

  3. 引入需要攜帶.mjs后綴

全局依賴

在Next.js中通過<Script>引入像Swiper這種全局變量,在使用時會報Swiper is not defined這種錯誤摔握。

  1. 定義類型聲明文件
// next-env.d.ts
declare global {
  var Swiper: any;
  interface Window {
    Swiper: any
  }
}
declare interface Window {
  Swiper: any
}

  1. 在使用全局變量的地方引入類型聲明文件
import { Swiper } from '@/types/globals';
// 底屏swiper
useEffect(() => {
  const myswiper = new Swiper('.swiper-container', {
    slidesPerView: 1.05,
    spaceBetween: 16
  });
  return () => {
    myswiper.destroy(true);
  };
}, []);

環(huán)境變量

CLI

  1. 通過命令行配置運(yùn)行環(huán)境
// package.json
  "scripts": {
    "dev": "next dev",
    "build": "cross-env RUN_ENV=production next build && cross-env RUN_ENV=production npm run gennginx",
    "build:dev": "cross-env RUN_ENV=staging next build && cross-env RUN_ENV=staging npm run gennginx",
  },
  1. next.config.js#env讀取環(huán)境變量寫入代碼

    • process.env.*只能node環(huán)境使用寄狼;

    • next.config.js#env會直接打入包內(nèi),server氨淌、client都可以使用泊愧;


import Analyzer from '@next/bundle-analyzer';
import withImages from 'next-images';

import { domains } from './constants/domains.mjs';

const withBundleAnalyzer = Analyzer({
  enabled: process.env.ANALYZE === 'true'
});

const nextConfig = withImages(
  withBundleAnalyzer({
    // output: 'export', // 開啟CSR,需要去除rewrite配置
    assetPrefix:
      process.env.RUN_ENV == void 0
        ? domains.STATIC_URL_PREFIX
        : `${domains.STATIC_URL_PREFIX}${domains.ASSET_PATH_PRFIX}`, // 靜態(tài)資源前綴
    images: {
      loader: 'custom',
      loaderFile: './src/image-loader/index.mjs'
    },
    env: {
      RUN_ENV: process.env.RUN_ENV
    },
    webpack: (config) => {
      // 可自定義webpack配置
      return config;
    },
  })
);

export default nextConfig;

Caveat:

  • next.config.mjs引入自定義模塊只能是.mjs文件盛正,無法訪問*.ts文件删咱,會報錯。

  • next.config.mjs#env配置變量的訪問限制:

    • 不能解構(gòu):const { RUN_ENV } = process.env;

    • 不能使用變量:const env = process.env[$var];

  1. 通過process.env.*聲明環(huán)境配置
// ./constants/domains.mjs
const dev = {
  HOST: '',
  STATIC_URL_PREFIX: '',
  ASSET_PATH_PRFIX: '/assets',
};
const staging = {
  HOST: 'https://<staging.host>.com',
  STATIC_URL_PREFIX: 'https://<staging.static.host.com>',
  ASSET_PATH_PRFIX: '/assets',
};
const prod = {
  HOST: 'https://<prod.host>.com',
  STATIC_URL_PREFIX: 'https://<prod.static.host.com>',
  ASSET_PATH_PRFIX: '/assets',
};
const env = process.env.RUN_ENV;
function getDomains() {
  switch (env) {
    case 'production':
      return prod;
    case 'staging':
      return staging;
    default:
      return dev;
  }
}
const domains = getDomains();
export { domains };

Good to know:

  • 借助import ... from ...的緩存特性豪筝,多次引用痰滋,只有第一次引用會執(zhí)行代碼,后續(xù)使用的是對象引用壤蚜,而非拷貝即寡。
  1. 消費(fèi)者調(diào)用
// app/page.tsx
import { domains } from '@/constants/domains.mjs'; //必須攜帶mjs后綴
console.log(domains.Host)

Good to knows

.env文件

  • 帶Next_Public_開頭的變量,服務(wù)端袜刷、客戶端都可以訪問聪富;

  • 不帶Next_Public_開頭的變量,服務(wù)端可以訪問著蟹,客戶端無法訪問墩蔓;

  • 通過.env文件配置的環(huán)境變量無法自定義環(huán)境關(guān)鍵字梢莽;

  • 通過.env文件配置的環(huán)境變量不會寫入代碼中,可考慮存儲敏感信息(待驗證)

讀取環(huán)境變量寫入代碼有三種方案:

  1. env配置奸披,具體如上

    const nextConfig = withImages(
        ...
        env: {
          RUN_ENV: process.env.RUN_ENV
        },
      })
    );
    
    
  2. webpack配置

    const nextConfig = withImages(
      ...
      webpack: (config, options) => {
        config.plugins.push(new options.webpack.DefinePlugin({
           'process.browser': JSON.stringify(typeof window !== 'undefined')
           'process.env': JSON.stringify(process.env)
        }));
    
        return config;
      }
    );
    
  3. babelrc配置

    • 安裝插件:

      npm install babel-plugin-transform-define --save-dev
      
    • .babelrc 或 Babel 配置中添加插件配置:

      {
        "presets": ["next/babel"],
        "plugins": [
          ["transform-define", { "process.browser": "typeof window !== 'undefined'" }]
        ]
      }
      

參考文檔:

https://nextjs.org/docs/messages/non-standard-node-env

https://www.51cto.com/article/773164.html

路由守護(hù)

中間件允許你在請求完成前運(yùn)行代碼昏名。然后,您可以根據(jù)接收到的請求阵面,通過重寫轻局、重定向、修改請求或響應(yīng)標(biāo)頭或直接響應(yīng)等方式修改響應(yīng)样刷。

中間件在緩存內(nèi)容和路徑匹配之前運(yùn)行仑扑。

import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'

export function middleware(request: NextRequest) {
  return NextResponse.redirect(new URL('/home', request.url))
}

export const config = {
  matcher: '/about/:path*',
}

多級狀態(tài)管理Reducer

useReducer:

  1. useReducer可以管理復(fù)雜的、具有多個相關(guān)狀態(tài)的組件狀態(tài)置鼻;

    • 如不想通過useState定義多排狀態(tài)镇饮,可以考慮useReducer替代;

    • 可以進(jìn)行新舊狀態(tài)數(shù)據(jù)對比箕母,類同useState((prev) => {})储藐;

  2. useReducer & useContext實現(xiàn)多級狀態(tài)同步;

  1. useReducer & useContext多級狀態(tài)管理封裝
import {
  createContext,
  Dispatch,
  useMemo,
  PropsWithChildren,
  useContext,
  useReducer
} from 'react';
import { useSearchParams } from 'react-router-dom';

interface ContextStateDef {
  login: {
    loginToken: string;
    openId: string;
  }
}
enum ActionsEnum {
  setState = 1,
}
interface ContextActionDef {
  type: ActionsEnum.setState;
  payload: ContextStateDef['login'];
}

const initialState = { // 定義初始上下文
  login: {
    loginToken: '',
    openId: ''
  }
};
type ActionDef = ContextActionDef;
const RootContextContainer = createContext<{  // 定義上下文嘶是,對應(yīng)Provider的value必須符合當(dāng)前類型钙勃;
  state: ContextStateDef;
  dispatch: Dispatch<ActionDef>;
}>({
  state: initialState,
  dispatch: (() => {}) as Dispatch<ActionDef>
});

const reducer = (state: ContextStateDef, action: ActionDef) => {
  const { type, payload } = action;
  switch (type) {
    case ActionsEnum.setState:
      return {
        ...state,
        login: payload
      };
    default:
      return {
        ...state
      } as never;
  }
};
const useRootContext = () => {  // 封裝Consumer hooks方法,避免原始上下文暴露聂喇,提供調(diào)試信息
  const rootContext = useContext(RootContextContainer);
  if (!rootContext) {
    throw new Error('useRootContext must be used within a RootProvider');
  }
  const updateContext = useMemo(() => {  // 避免context引發(fā)的無限渲染循環(huán)
    return rootContext.dispatch;
  }, [rootContext]);
  const context = useMemo(() => {  // 避免context引發(fā)的無限渲染循環(huán)
    return rootContext.state;
  }, [rootContext]);
  return {
    context,
    updateContext
  };
};
const RootProvider = ({ children }: PropsWithChildren) => {
  const [state, dispatch] = useReducer(reducer, initialState);
  const [searchParams] = useSearchParams();
  // Provider實現(xiàn)多級傳遞上下文
  return (
    <RootContextContainer.Provider value={{ state, dispatch }}>
      {children}
    </RootContextContainer.Provider>
  );
};
export type { ContextStateDef };
export { ActionsEnum, useRootContext };
export default RootProvider;
  1. Provider調(diào)用
<RootProvider>
  <HeaderNavigation
    above
    defaultTheme={ThemeEnum.light}
    themeChangable
    transparent
  />
  {children}
  <FooterSiteMap />
</RootProvider>
  1. Consumer調(diào)用
  // 使用時肺缕,通過useCallback、useMemo承接授帕,創(chuàng)建緩存,避免引發(fā)無限渲染循環(huán)浮梢;
  const updateScroller = useCallback(() => {
    updateContext({
      type: ActionsEnum.setScroller,
      payload: scrollContainerRef
    });
  }, [updateContext, scrollContainerRef]);
  useEffect(() => {
    updateScroller();
  }, [updateScroller]);

無限渲染循環(huán)

有時可能會遇到無限循環(huán)的問題跛十。這通常是因為在使用時,依賴項沒有正確設(shè)置秕硝,導(dǎo)致組件在每次渲染時都會重新創(chuàng)建新的上下文芥映。

使用上下文時,需要通過useCallback远豺、useMemo承接奈偏,組件使用memo()包裹,創(chuàng)建緩存躯护,避免引發(fā)無限渲染循環(huán)

降級CSR

將Next應(yīng)用打包為CSR惊来,在服務(wù)崩潰時,通過Nginx負(fù)載均衡()指向客戶端渲染棺滞。

  1. CSR導(dǎo)出配置
//next.config.js
const nextConfig = {  
  // https://nextjs.org/docs/app/building-your-application/deploying/static-exports
  output: 'export', 
} 
module.exports = nextConfig
  • next14導(dǎo)出靜態(tài)資源時裁蚁,只需要修改next.config.js即可矢渊,無需像v13版本使用next export

  • 執(zhí)行next build枉证,生成包含HTML/CSS/JS的out目錄矮男。

  • 通過browser-sync start --cors -s "./out"即可訪問導(dǎo)出的靜態(tài)頁面。

CSR針對部分next特性不支持室谚,詳見https://nextjs.org/docs/app/building-your-application/deploying/static-exports#unsupported-features

  1. 部署

    • 部署SSR

    • 部署CSR

  2. 宕機(jī)自動降級CSR

http {
    include       mime.types;
    default_type  application/octet-stream;

    sendfile        on;
    keepalive_timeout  65;
    upstream backend {
        server host.ssr.com max_fails=3 fail_timeout=30s; // 在30s內(nèi)重試3次都失敗毡鉴,則標(biāo)記當(dāng)前服務(wù)不可用,會走下邊的bak.com服務(wù)秒赤。
        server bak.csr.com backup;  // 當(dāng)上游服務(wù)器都不可用時猪瞬,該服務(wù)接收Nginx請求。
    }  // 如果所有配置的上游服務(wù)器都無法響應(yīng)倒脓,Nginx將返回錯誤給客戶端撑螺。默認(rèn)情況下,這通常是 502 Bad Gateway 錯誤崎弃。
    server {
        listen  80;                                                         
        server_name domain.com;
        index  index.php index.html index.htm;

        location / {
            proxy_pass http://backend;  //將請求domain.com的請求代理到upstream服務(wù)集群中甘晤,按負(fù)載均衡策略訪問不同的服務(wù)器。 
            proxy_set_header Host $host;
        }
    }
}

FAQs

  1. 靜態(tài)資源加載失敗

查看next.config#assetPrefix字段配置饲做,該配置會影響js/css靜態(tài)資源加載路徑线婚。

  1. 跳轉(zhuǎn)失敗,404

程序內(nèi)的頁面跳轉(zhuǎn)需要使用next內(nèi)置的組件next/link盆均,使用a無法正常跳轉(zhuǎn)塞弊。

參考文檔

https://juejin.cn/post/7338280070304809010

https://blog.csdn.net/javaboyweng/article/details/97612605

瀏覽器兼容

ES6+墊片

  1. 安裝相關(guān)依賴

    npm i -S core-js regenerator-runtime
    npm i -D @babel/core @babel/preset-env
    
  2. 根文件引入墊片

    // src/app/layout.tsx
    import 'core-js'
    import 'regenerator-runtime/runtime' // 支持async、await
    
  3. 配置.babelrc

    {
      "presets": [
        [
          "next/babel", 
          {
            "preset-env": { // 配置同@babel/preset-env
              "debug": true, // 開啟調(diào)試模式泪姨,在命令行輸出當(dāng)前詳細(xì)配置&執(zhí)行游沿。
              /**
                * 設(shè)置為 "entry" 時,Babel 會根據(jù) core-js 版本和 targets 配置肮砾,自動引入目標(biāo)環(huán)境所需的所有 polyfills诀黍。這需要在入口文件中手動引入 core-js/stable(包含 ECMAScript 標(biāo)準(zhǔn)特性)和 regenerator-runtime/runtime(如果你使用了異步函數(shù))。
                * 使用 useBuiltIns: "usage" 時仗处,不需要在代碼中手動引入 core-js 或 regenerator-runtime眯勾,Babel 會根據(jù)需要自動處理這些引入。
              */
              "useBuiltIns": "entry",
              "corejs": {
                "version": "3.36", // Warning! Recommended to specify used minor core-js version, like corejs: '3.36', instead of corejs: 3, since with corejs: 3 will not be injected modules which were added in minor core-js releases.
                // "proposals": true
              },
              "targets": { 
              /**
               * 如果在 Babel 的配置文件(如 .babelrc婆誓、babel.config.js)中直接指定了 targets吃环,這將具有最高優(yōu)先級。Babel 會忽略 .browserslistrc 文件或 package.json 中的 browserslist 配置洋幻,僅使用 targets 選項的設(shè)置郁轻。
               * 兩種設(shè)置模式:
                 * browserslist兼容模式
                 * browserslist模式
              */
              // "chrome": "49" // browserslist兼容模式
                "browsers": [ // browserslist模式
                  ">0.02%", // 包含chrome 48+
                  "not op_mini all",
                  "not op_mob >= 1"
                ]
              }
            },
            "transform-runtime": {},
            "styled-jsx": {},
            "class-properties": {}
          }
        ]
      ],
      "plugins": []
    }
    
  4. 配置next.config.mjs

const nextConfig = withImages(
  ...
  webpack: (config, options) => {
    config.plugins.push(new options.webpack.DefinePlugin({
       'process.env': JSON.stringify(process.env)
    }));

    return config;
  }
);
  1. 配置browserslist【必須】

    可通過npx browserslist查看當(dāng)前支持的瀏覽器

    // package.json 
    {
      ...
      /**
       * 配置了.babelrc#targets,這個也需要配置鞋屈,否則會報錯范咨。
       * 配置了browserslist故觅,可以不用配置.babelrc#targets
      */
      "browserslist": [
        ">0.02%", // 包含chrome 48+
        "not op_mini all",
        "not op_mob >= 1"
      ]
    }
    

FAQs

  • globalThis is not defined.

報錯代碼回源:

node_modules/next/dist/client/components/async-local-storage.js

30L

const maybeGlobalAsyncLocalStorage = globalThis.AsyncLocalStorage;

解決方案:

https://www.npmjs.com/package/globalthis

修改代碼庫,追加下述代碼:
var globalThis = require('globalthis')()

  • Illegal Constructor error.

報錯代碼回源:

node_modules/next/dist/compiled/next-server/app-page.runtime.dev.js

new ReadableStream

解決方案:

https://github.com/MattiasBuelens/web-streams-polyfill/tree/masterIllegal

在html頂部追加:

<script src="``https://unpkg.com/web-streams-polyfill/dist/polyfill.js``"></script>

參考文檔

https://www.jnielson.com/demystifying-babel-preset-env

https://github.com/vercel/next.js/issues/44250

https://cloud.tencent.com/developer/ask/sof/106622781

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末渠啊,一起剝皮案震驚了整個濱河市输吏,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌替蛉,老刑警劉巖贯溅,帶你破解...
    沈念sama閱讀 219,589評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異躲查,居然都是意外死亡它浅,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,615評論 3 396
  • 文/潘曉璐 我一進(jìn)店門镣煮,熙熙樓的掌柜王于貴愁眉苦臉地迎上來姐霍,“玉大人,你說我怎么就攤上這事典唇∧髡郏” “怎么了?”我有些...
    開封第一講書人閱讀 165,933評論 0 356
  • 文/不壞的土叔 我叫張陵介衔,是天一觀的道長恨胚。 經(jīng)常有香客問我,道長炎咖,這世上最難降的妖魔是什么赃泡? 我笑而不...
    開封第一講書人閱讀 58,976評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮乘盼,結(jié)果婚禮上升熊,老公的妹妹穿的比我還像新娘。我一直安慰自己绸栅,他們只是感情好僚碎,可當(dāng)我...
    茶點故事閱讀 67,999評論 6 393
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著阴幌,像睡著了一般。 火紅的嫁衣襯著肌膚如雪卷中。 梳的紋絲不亂的頭發(fā)上矛双,一...
    開封第一講書人閱讀 51,775評論 1 307
  • 那天,我揣著相機(jī)與錄音蟆豫,去河邊找鬼议忽。 笑死,一個胖子當(dāng)著我的面吹牛十减,可吹牛的內(nèi)容都是我干的栈幸。 我是一名探鬼主播愤估,決...
    沈念sama閱讀 40,474評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼速址!你這毒婦竟也來了玩焰?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,359評論 0 276
  • 序言:老撾萬榮一對情侶失蹤芍锚,失蹤者是張志新(化名)和其女友劉穎昔园,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體并炮,經(jīng)...
    沈念sama閱讀 45,854評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡默刚,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,007評論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了逃魄。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片荤西。...
    茶點故事閱讀 40,146評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖伍俘,靈堂內(nèi)的尸體忽然破棺而出邪锌,到底是詐尸還是另有隱情,我是刑警寧澤养篓,帶...
    沈念sama閱讀 35,826評論 5 346
  • 正文 年R本政府宣布秃流,位于F島的核電站,受9級特大地震影響柳弄,放射性物質(zhì)發(fā)生泄漏舶胀。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,484評論 3 331
  • 文/蒙蒙 一碧注、第九天 我趴在偏房一處隱蔽的房頂上張望嚣伐。 院中可真熱鬧,春花似錦萍丐、人聲如沸轩端。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,029評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽基茵。三九已至,卻和暖如春壳影,著一層夾襖步出監(jiān)牢的瞬間拱层,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,153評論 1 272
  • 我被黑心中介騙來泰國打工宴咧, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留根灯,地道東北人。 一個月前我還...
    沈念sama閱讀 48,420評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像烙肺,于是被迫代替她去往敵國和親纳猪。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,107評論 2 356

推薦閱讀更多精彩內(nèi)容

  • 1. webpack介紹 本質(zhì)上桃笙,webpack 是一個用于現(xiàn)代 JavaScript 應(yīng)用程序的靜態(tài)模塊打包工具...
    WangLizhi閱讀 1,011評論 0 1
  • 1 為什么需要babel怎栽? 事實上丽猬,在開發(fā)中我們很少直接去接觸babel,但是babel對于前端開發(fā)來說熏瞄,目前是不...
    AShuiCoder閱讀 978評論 0 0
  • Babel 是什么脚祟? Babel 是一個 JavaScript 編譯器 Babel 是一個工具鏈,主要用于將采用 ...
    AAA前端閱讀 3,647評論 0 1
  • title: 前端工程化探索——Babel補(bǔ)遺category: Webtag: [前端工程化,Babel]dat...
    水煮香蕉閱讀 628評論 0 1
  • 安裝 五大核心概念 entry:打包入口强饮,支持多入口打包output:輸出由桌,可以配置輸入路徑,文件名等loader...
    瓢鰭小蝦虎閱讀 180評論 0 0