[英]React Stripe Elements & SSR - Webpack Error: Window is Not Defined
React Stripe Elements 在開發中運行良好,但通過 Netlify 進行實時部署會在 Provider.js react Stripe Elements 節點模塊文件中拋出“Webpack: Window is undefined”。
根據其他一些建議,我嘗試了 ComponentDidMount 方法並使用以下內容編輯 Provider.js:
if (typeof window !== 'undefined') {
let iInnerHeight = window.innerHeight;
}
兩者仍然會導致部署失敗。
另外,我嘗試在 StripeProvider 組件中設置 stripe 或 apiKey,設置 Stripe 會引發錯誤,需要 Stripe 對象,例如 Stripe(...) --> 當使用此 get Stripe 未定義時,apiKey 會引發窗口未定義錯誤。
這是我的 gatsby-ssr.js 文件:
import React from 'react'
import { ShopkitProvider } from './src/shopkit'
import { StripeProvider, Elements } from 'react-stripe-elements'
import Layout from './src/components/Layout'
export const wrapRootElement = ({ element }) => {
return (
<StripeProvider apiKey={process.env.GATSBY_STRIPE_PUBLISHABLE_KEY}>
<ShopkitProvider clientId{process.env.GATSBY_MOLTIN_CLIENT_ID}>
<Elements>{element}</Elements>
</ShopkitProvider>
</StripeProvider>
)
}
export const wrapPageElement = ({ element, props }) => {
return <Layout {...props}>{element}</Layout>
}
一切都在開發中按預期工作,但 SSR 出現 Webpack 的窗口未定義問題。 我還在 Netlify 以及 .env 文件中設置了 env 變量
問題是在StripeProvider
window
檢查了 Stripe 對象。 這意味着您不能在wrapRootElement
使用它。 簡單的解決方案是不要在gatsby-ssr.js
使用StripeProvider
,您只需要在gatsby-browser.js
。
但是,由於您使用多個服務提供者包裝根,並且如果您像這樣異步加載 Stripe:
// somewhere else vvvvv
<script id="stripe-js" src="https://js.stripe.com/v3/" async />
您不妨制作一個可在gatsby-ssr
和gatsby-browser
使用的通用包裝gatsby-browser
以便更易於維護。
我通過創建一個包裝這樣做StripeProvider
其中Stripe
取決於可用性手動啟動window
和window.Stripe
。 然后將stripe
實例作為 prop 傳遞給StripeProvider
而不是 api 密鑰。
// pseudo
const StripeWrapper = ({ children }) => {
let stripe,
if (no window) stripe = null
if (window.Stripe) stripe = window.Stripe(...)
else {
stripeLoadingScript.onload = () => window.Stripe(...)
}
return (
<StripeProvider stripe={stripe}>
{children}
<StripeProvider>
)
}
這個邏輯應該放在componentDidMount
或useEffect
鈎子中。 這是一個帶有鈎子的示例:
import React, { useState, useEffect } from 'react'
import { StripeProvider } from 'react-stripe-elements'
const StripeWrapper = ({ children }) => {
const [ stripe, setStripe ] = useState(null)
useEffect(() => {
// for SSR
if (typeof window == 'undefined') return
// for browser
if (window.Stripe) {
setStripe(window.Stripe(process.env.STRIPE_PUBLIC_KEY))
} else {
const stripeScript = document.querySelector('#stripe-js')
stripeScript.onload = () => {
setStripe(window.Stripe(process.env.STRIPE_PUBLIC_KEY))
}
}
}, []) // <-- passing in an empty array since I only want to run this hook once
return (
<StripeProvider stripe={stripe}>
{children}
</StripeProvider>
)
}
// export a `wrapWithStripe` function that can used
// in both gatsby-ssr.js and gatsby-browser.js
const wrapWithStripe = ({ element }) => (
<StripeWrapper>
<OtherServiceProvider>
{element}
</OtherServiceProvider>
</StripeWrapper>
)
通過在 gatsby-config.js 中將 async 設置為true
{
resolve: `gatsby-plugin-stripe`,
options: {
async: true
}
}
可以簡化上面的代碼。
const Stripe = props => {
const [stripe, setStripe] = useState(null);
useEffect(() => {
(async () => {
const obj = await window.Stripe(process.env.STRIPE_PUBLIC_KEY);
setStripe(obj);
})();
}, []);
return (
<>
<StripeProvider stripe={stripe}>
{children}
</StripeProvider>
</>
);
};
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.