使用 Next 和 Redux 获得 100% 完美的 Google Lighthouse 审核分数
next.js
我很无聊,只需将代码发送给我即可。
1. 使用 Redux 的 next.js
2. 获得 100% 的 Lighthouse 评分
结果
(移至此处)
这篇文章介绍了如何使用 Redux 构建一个 React/NextJS 应用程序,该应用程序通过服务器渲染、本地化支持获得 100% 的审核分数,并且可以作为 PWA 安装并在离线时导航。
next.js
Next.js是我最近最喜欢的东西。NextJS 专为 React 构建,它允许你在服务器端渲染 React 应用,而不会对常规的应用构建方式造成太大影响。
开发 React 应用程序将非常熟悉,您必须使用其内置路由器切换 react-router,并且注意您的组件必须在 NodeJS 中可执行(就像您对它们进行单元测试一样)。
主要的区别是我们可以添加到页面中的一点魔法:
// Calls before the page is mounted, the call will happen on the server if it's the first page we visit
static async getInitialProps({ ctx: { store } }) {
await store.dispatch(AppActions.getWidgets());
return {};
}
任何异步任务或获取都可以在我们的页面上发生。
与其反复讲解 Next 的强大功能,我建议你直接看他们的入门指南。这篇文章详细介绍了我如何在 Lighthouse 上添加 Redux 和 Sagas 并获得 100% 的评分。
我很无聊,只需将代码发送给我即可。
好的。该项目也托管在https://nextjs-redux.kyle-ssg.now.sh/。如果您感兴趣,请继续阅读。
1. 使用 Redux 的 next.js
Next 中的路由并非在 JavaScript 中定义,而是基于 /pages 目录中的内容。Next.js
使用 App 组件定义了页面的渲染方式,我们可以通过创建自己的 _app.js 文件来自定义该组件。太棒了,这意味着我们可以像创建其他应用一样,创建 store 并为其指定根应用组件。
import App, { Container } from 'next/app';
import Head from 'next/head';
import React from 'react';
import { Provider } from 'react-redux';
import createStore from '../common/store';
import withRedux from 'next-redux-wrapper';
class MyApp extends App {
static async getInitialProps({ Component, ctx }) {
let pageProps;
// Ensure getInitialProps gets called on our child pages
if (Component.getInitialProps) {
pageProps = await Component.getInitialProps({ ctx });
}
return { pageProps };
}
render() {
const { Component, pageProps, store } = this.props;
return (
<Container>
<Provider store={store}>
<>
<Head>
{/*...script and meta tags*/}
<title>TheProject</title>
</Head>
<Header/>
<Component {...pageProps} />
</>
</Provider>
</Container>
);
}
}
export default withRedux(createStore)(MyApp);
其中一些可能看起来很熟悉,主要区别在于:
- 在我们的路线应用中,我们需要确保在渲染之前调用页面的 getInitialProps 函数
- Next.js 提供了一个 Head 组件,让我们可以渲染 Head 中的所有标准标签,甚至可以按页面进行渲染。这对于按页面添加 opengraph/meta 标签/标题非常有用。
- next-redux-wrapper 是一个开箱即用的库,它允许我们使用 createStore。
结果
添加一个简单的获取小部件操作,我们可以看到以下差异,具体取决于我们是从直接登陆页面加载页面还是从另一个页面导航到该页面。
发生这种情况是因为在初始页面加载期间在服务器上调用 getInitialProps,它根据路由知道在哪个页面上调用它。
2. 获得 100% 的 Lighthouse 评分
即使在本地,我也注意到一切都感觉很快。这让我不禁好奇,我的页面性能究竟能有多好。Chrome 开发者工具里有一款很棒的工具叫 L,它能根据一些公认的最佳实践对你的网站进行评级,并且符合渐进式 Web 应用的标准。
基线评分
基线分数还不错,对于访问 API 的 redux 页面来说,性能不是问题。
无障碍设施
大多数这些问题都很容易解决,并且涉及采用最佳实践,例如图像 alt 标签、输入角色和 aria 属性。
适当的色彩对比
Lighthouse 非常智能,能够识别哪些元素未达到 WCAG 2 AA 对比度阈值,并指出前景和背景的对比度(小文本)至少应为 4.5:1,大文本至少应为 3:1。您可以运行Web AIM 的对比度检查器等工具。快速更改 CSS 即可解决此问题,但显然,对于内容丰富的网站来说,这意味着需要进行大量重构。
本土化
这个有点棘手。为了做好这件事,我希望服务器端渲染能够检测用户的首选语言环境,设置 lang 属性,并提供本地化内容。搜索了一下,我找到了next-i18next,然而,我发现它不支持无服务器,而且很难与react-native-localization共享语言环境字符串。
我想要一些可以与react-localization配合使用的东西,所以我的方法如下:
- 1:当文档尝试在服务器上渲染时,我们需要获取首选语言环境,并将 lang 属性设置为 HTML 标签。此信息来自服务器,可以通过 Cookie(我们可以设置)或解析Accept-Language 标头获取。我实现此操作的代码片段可以在这里找到。
// _document.js
static async getInitialProps(ctx) {
const initialProps = await Document.getInitialProps(ctx);
const locale = API.getStoredLocale(ctx.req);
return { ...initialProps, locale };
}
...
render() {
return (
<html lang={this.props.locale}>
...
</html>
)
}
- 2:我定义了一些本地化的字符串
// localization.js
import LocalizedStrings from 'react-localization';
const Strings = new LocalizedStrings({
en: {
title: 'Hello EN',
},
'en-US': {
title: 'Hello US',
},
});
export default Strings;
- 3:我希望我的应用程序知道商店中的语言环境,以便我以后可以使用该信息。
// _app.js
static async getInitialProps({ Component, ctx }) {
let pageProps;
const locale = API.getStoredLocale(ctx.req); // Retrieve the locale from cookie or headers
await ctx.store.dispatch(AppActions.startup({ locale })); // Post startup action with token and locale
...
}
- 4:我在初始客户端和服务器渲染时在我的应用程序中设置了一次语言。
// _app.js
render(){
if (!initialRender) {
initialRender = true;
const locale = store.getState().locale;
if (locale) {
Strings.setLanguage(locale);
}
}
...
}
- 5:在我的页面中,我现在可以自由使用本地化的字符串。
// pages/index.js
render() {
return (
<div className="container">
<h1>Home</h1>
{Strings.title}
</div>
);
}
最佳实践
由于该项目使用了相当新的库,并且没有做任何不规范的事情,所以它已经获得了不错的分数。我们唯一需要做的就是使用 http2 和 SSL,这更多地取决于你如何托管应用程序。使用Zeit满足了这两项要求。
搜索引擎优化
借助 nextJS,您可以轻松地在每个页面上添加元标记,甚至可以使用来自 getInitialProps 的动态数据。
渐进式 Web 应用
PWAs 使我们的 Web 应用程序可安装,结合服务工作者,我们可以在用户离线时提供内容。
第一步是添加一个简单的清单,这让我们可以配置它在安装时的行为方式。
/static/manifest.json
{
"short_name": "Project Name",
"name": "Project Name",
"icons": [
{
"src": "/static/images/icons-192.png",
"type": "image/png",
"sizes": "192x192"
},
{
"src": "/static/images/icons-512.png",
"type": "image/png",
"sizes": "512x512"
}
],
"start_url": "/?source=pwa",
"background_color": "#3367D6",
"display": "standalone",
"scope": "/",
"theme_color": "#3367D6"
}
//_app.js
<link rel="manifest" href="/static/manifest.json"/>
服务人员提供离线支持
得益于next-offline 的支持,添加 Service Worker 支持非常简单。然而,让 Service Worker 与无服务器环境协同工作并托管在 Zeit 上却有点麻烦,我们必须为服务器添加路由才能提供正确的内容标头。
// now.json
{
"version": 2,
"routes": [
{
"src": "^/service-worker.js$",
"dest": "/_next/static/service-worker.js",
"headers": {
"Service-Worker-Allowed": "/"
}
}
...
]
}
然后配置 next-offline 来静态地为服务工作者提供服务。
next.config.js
{
target: 'serverless',
// next-offline options
workboxOpts: {
swDest: 'static/service-worker.js',
结果
最终,我们拥有了一个坚实的基础项目,其审核分数高达 100%,服务器渲染,本地化,并且可以离线安装和导航。欢迎随时克隆并进行修改!
鏂囩珷鏉ユ簮锛�https://dev.to/kylessg/achieving-a-perfect-100-google-lighthouse-audit-score-with-next-js-and-redux-5p0