項目初始化
- 創(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
- 創(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
- 創(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
方案
- 安裝
tailwindcss
npm i -D tailwindcss postcss autoprefixer
npx tailwindcss init
該操作會自動以下操作:
更新
package.json
;創(chuàng)建
tailwind.config.js
- 更新
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;
- 引入
tailwindcss
內(nèi)置樣式組件
/* app/global.css */
@tailwind base;
@tailwind components;
@tailwind utilities;
- 創(chuàng)建
postcss.config.js
文件
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
}
}
- 測試可用性
// 更新app/page.tsx
export default function Home() {
return (
<main>
<div className="text-3xl text-white bg-black">22222</div>
</main>
);
}
- 特定斷點配置
// 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)的
- 定制化
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中使用芒澜,才會被打包仰剿;否則,自定義顏色不起作用痴晦;
- 安裝
postcss-pxtorem
插件
自動將樣式中的px單位轉(zhuǎn)換為rem單位南吮,可通過設(shè)置PX(單位大寫)禁止轉(zhuǎn)換。
npm i -D postcss-pxtorem
- 配置
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,
}
}
}
- 引入
[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)用
在入口文件中調(diào)用
adaptMultipleThemes
在樣式中使用
@include mixDarkTheme
.title {
@include mixDarkTheme(){
color: $linkColor;
}
}
站點配置
每個Page獨立配置title
給每個頁面增加
layout.js
在
layout.js
中配置metadata
拆分next.config.mjs
next.config.js
默認(rèn)僅支持commonjs
規(guī)范臼隔,若使用ES Module
規(guī)范嘹裂,更改后綴名為.mjs
以.mjs
配置為例進(jìn)行拆分:
拆分需要使用
.mjs
后綴文件.mjs
文件使用ES Module
格式書寫引入需要攜帶
.mjs
后綴
全局依賴
在Next.js中通過
<Script>
引入像Swiper這種全局變量,在使用時會報Swiper is not defined
這種錯誤摔握。
- 定義類型聲明文件
// next-env.d.ts
declare global {
var Swiper: any;
interface Window {
Swiper: any
}
}
declare interface Window {
Swiper: any
}
- 在使用全局變量的地方引入類型聲明文件
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
- 通過命令行配置運(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",
},
-
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];
- 通過
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ù)使用的是對象引用壤蚜,而非拷貝即寡。
- 消費(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)境變量寫入代碼有三種方案:
-
env配置奸披,具體如上
const nextConfig = withImages( ... env: { RUN_ENV: process.env.RUN_ENV }, }) );
-
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; } );
-
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:
useReducer可以管理復(fù)雜的、具有多個相關(guān)狀態(tài)的組件狀態(tài)置鼻;
如不想通過useState定義多排狀態(tài)镇饮,可以考慮useReducer替代;
可以進(jìn)行新舊狀態(tài)數(shù)據(jù)對比箕母,類同
useState((prev) => {})
储藐;useReducer & useContext實現(xiàn)多級狀態(tài)同步;
- 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;
- Provider調(diào)用
<RootProvider>
<HeaderNavigation
above
defaultTheme={ThemeEnum.light}
themeChangable
transparent
/>
{children}
<FooterSiteMap />
</RootProvider>
- 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ù)載均衡()指向客戶端渲染棺滞。
- 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
-
部署
部署SSR
部署CSR
宕機(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
- 靜態(tài)資源加載失敗
查看
next.config#assetPrefix
字段配置饲做,該配置會影響js/css靜態(tài)資源加載路徑线婚。
- 跳轉(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+墊片
-
安裝相關(guān)依賴
npm i -S core-js regenerator-runtime npm i -D @babel/core @babel/preset-env
-
根文件引入墊片
// src/app/layout.tsx import 'core-js' import 'regenerator-runtime/runtime' // 支持async、await
-
配置
.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": [] }
配置next.config.mjs
const nextConfig = withImages(
...
webpack: (config, options) => {
config.plugins.push(new options.webpack.DefinePlugin({
'process.env': JSON.stringify(process.env)
}));
return config;
}
);
-
配置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