现代框架开发官网

一、项目背景

维护过 灵犀官网、企业邮官网、免费邮官网 均使用 jquery + webpack多页面打包的方式
开发起来较为繁琐
新的官网项目,想使用现代前端框架,但SPA应用不利于SEO
使用SSR方案又依赖运维,增加维护和沟通成本

二、SSG vs 预渲染

SSG(静态站点生成):
特点:SSG 是一种构建时生成静态 HTML 页面的技术。在构建过程中,服务器会根据应用的路由和数据,生成一系列静态 HTML 文件,这些文件可以直接提供给用户,不需要实时的服务器请求。每次页面访问时,都会返回预先生成的静态页面。
优点:SSG 可以提供非常快速的页面加载速度,因为它们是预先生成的静态文件,不需要服务器动态生成页面内容。另外,SSG 也有利于搜索引擎优化(SEO),因为搜索引擎可以直接访问静态 HTML 页面。
适用场景:适用于内容相对固定、不经常更新的网站,如博客、公司官网等。Jekyll、hexo、Gatsby、vite-ssg
预渲染:
特点:预渲染是在构建时生成静态 HTML 页面的过程,但它只会为特定的页面进行预渲染,而不是整个网站。在构建过程中,预渲染工具会解析应用的特定页面,并生成相应的静态 HTML 文件,这些文件会在用户访问时直接返回。
优点:预渲染可以针对特定页面进行优化,可以选择性地预渲染那些对性能和用户体验影响较大的页面。它可以在构建时处理异步数据获取,确保页面在用户访问时已经包含了相关数据,提供更快的初始加载速度。
适用场景:适用于有部分页面需要实时数据的网站,如商品详情页、新闻文章等。

三、SEO标签

<title>:指定网页的标题,是搜索引擎结果页面(SERP)中显示的主要标题。
<meta name="description">:提供网页的描述,用于  SERP 中显示网页的简短描述。
<meta name="description" content="网页描述">
<meta name="keywords">:指定网页的关键词,用逗号分隔多个关键词
<meta name="keywords" content="关键词1, 关键词2, 关键词3">
<meta name="robots">:指定搜索引擎爬虫的行为。
<meta name="robots" content="index,follow">  <!-- 爬取并索引该页面的链接和内容 -->
<meta name="robots" content="noindex,nofollow">  <!-- 不爬取和索引该页面的链接和内容 -->
<meta name="viewport">:用于优化移动设备上的显示效果
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="author">:指定网页的作者
<meta name="author" content="作者名">
<meta name="og:title">:在社交媒体上分享时显示的标题。
<meta name="og:title" content="分享标题">
<meta name="og:description">:在社交媒体上分享时显示的描述
<meta name="og:description" content="分享描述">
<meta name="og:image">:在社交媒体上分享时显示的缩略图。
<meta name="og:image" content="缩略图链接">
<meta name="applicable-device"content="pc,mobile">:告诉浏览器页面属于什么类型设备
<meta name="applicable-device"content="pc">

企业邮官网是两套代码,不设置这个标签有可能会导致在pc搜索时,移动端网站排名靠前
react 使用插件react-helmet
vue 使用插件 vue-meta vue-head

四、最终方案

react + craco + prerender-spa-plugin + tailwindcss

五、脚手架

使用create-react-app 创建的项目默认是无法修改其内部的webpack配置的,不像vue-cli那样可以通过一个配置文件修改。虽然有一个eject 命令可以是将配置完全暴露出来,但这是一个不可逆的操作,同时也会失去CRA带来的便利和后续升级。
如果想要无 eject 重写 CRA 配置,目前成熟的是下面这几种方式
通过 CRA 官方支持的 --scripts-version 参数,创建项目时使用自己重写过的 react-scripts 包
使用 react-app-rewired + customize-cra 组合覆盖配置
使用 craco 覆盖配置

六、预渲染

prerender-spa-plugin webpack 插件
prerender-spa-plugin 是一个通用的预渲染插件,适用于各种前端框架,包括 React。
它使用 Puppeteer(一个无头浏览器)在构建过程中模拟浏览器环境,并将预渲染的 HTML 文件保存到指定目录。
prerender-spa-plugin 需要在 webpack 的配置文件中进行配置,并与其他 webpack 插件和加载器一起使用。
它支持路由配置,可以指定哪些路由需要预渲染。
prerender-spa-plugin 提供了更多的灵活性和定制选项,可以通过配置文件来设置渲染的行为和页面参数
React Snap命令行工具
React Snap 是专门为 React 应用设计的预渲染工具。
它通过在构建过程中运行 React 应用,并在客户端和服务器端渲染之间进行切换,将 React 组件转换为静态 HTML 文件。
React Snap 的配置相对简单,只需添加一个配置文件并运行构建命令即可。
它支持路由配置,你可以指定哪些路由需要预渲染。
React Snap 还提供了一些其他的配置选项,如添加 HTTP 头、设置超时时间等。
React Snap 更适合与 React 应用紧密集成,并且配置简单,适用于快速实现预渲染。prerender-spa-plugin 则更通用,适用于各种前端框架,并且具有更多的配置选项和定制能力。
打包遇到的问题
webpack5插件兼容问题 报错:
报错:Unable to prerender all routes
可以使用修改后的库

yarn add @dreysolano/prerender-spa-plugin
const PrerenderSPAPlugin = require('@dreysolano/prerender-spa-plugin')

服务器环境
报错:Can’t Use Puppeteer – Error: Failed to launch chrome
linux打包需要安装
https://stackoverflow.com/questions/59112956/cant-use-puppeteer-error-failed-to-launch-chrome

七、原子化css

大部分情况写css应该都是写一个类,然后整一堆样式进去。这种方式写多了以后,会感受到一些痛点,比如说:
取名困难
样式污染
复用难
原子化 CSS 是一种 CSS 的架构方式,它倾向于小巧且用途单一的 class,并且会以视觉效果进行命名
Tailwind CSS:
特点:Tailwind CSS是一个功能强大的工具包,提供了一系列的可复用的原子类,用于构建用户界面。它具有广泛的样式和布局类,可快速搭建页面,并支持自定义配置。
优点:Tailwind CSS具有非常灵活的设计,允许开发者根据需要选择和组合类来创建自定义样式。它的配置文件可以轻松地进行自定义和扩展,而且有大量的文档和社区支持。
缺点:Tailwind CSS生成的样式表文件相对较大,因为它提供了大量的类选择器。对于一些项目而言,文件大小可能会成为一个问题。
WindiCSS:
特点:WindiCSS是一个面向现代框架的类似Tailwind CSS的工具,它具有更好的性能和开发体验。它通过使用 Just-In-Time (JIT) 编译方式,仅生成所需的样式,从而减小了生成的样式表文件的大小。
优点:WindiCSS相比于Tailwind CSS在性能方面有所提升,同时保持了类似的开发体验和灵活性。它的配置文件也支持自定义和扩展。
缺点:相对于Tailwind CSS,WindiCSS的社区和文档资源相对较少,可能会对一些开发者造成一定的学习和使用难度。
UnoCSS:
特点:UnoCSS是另一个类似于Tailwind CSS的CSS框架,提供了一组可复用的原子类。它专注于可访问性和可定制性,并支持通过自定义配置文件进行样式的调整。
优点:UnoCSS具有良好的可访问性和可定制性,可以根据项目需求进行灵活的样式定制。它还提供了一些附加的功能,如主题切换和自动修复样式规则。
缺点:UnoCSS的用户群体相对较小,相比于Tailwind CSS和WindiCSS的知名度和社区支持较少。

className=“h-11 bg-white flex justify-between items-center px-6 shadow”
并且写响应式比较方便
className=“md:text-xl md:mt-4”
维护老项目可以使用
https://github.com/changgeee/bit-css

八:项目优化

图片压缩
在线网站:https://kt.fkw.com/yasuo.html?_ta=8780
开源工具:
ffmpeg号称多媒体的瑞士军刀,可以很完美的处理视频、音频、图片
ffmpeg -i input.jpg -vf scale=640:-1 output.jpg
python库: Pillow
使用图片懒加载
react-lazyloadreact-lazy-load-image-component是两个常用的 React 图片懒加载插件
react-lazyload:
react-lazyload 是一个轻量级的图片懒加载库,可以延迟加载图片,当图片进入可视区域时再进行加载。
它提供了 组件,你可以将需要懒加载的图片包裹在其中。
react-lazyload 提供了一些配置选项,如占位符、阈值等,可以根据需要进行自定义。
这个库相对较小,易于使用,适用于简单的图片懒加载需求。
react-lazy-load-image-component:
react-lazy-load-image-component 是一个功能丰富的图片懒加载库,提供了更多的功能和定制选项。
它提供了 组件,可以代替 元素进行图片懒加载。
react-lazy-load-image-component 支持设置占位符、加载效果、错误处理、渐进式加载等。
这个库的体积相对较大,但提供了更多的灵活性和可定制性,适用于复杂的图片懒加载需求。
css打包优化
mini-css-extract-plugin:将 CSS 代码从 JavaScript 中分离出来,生成单独的 CSS 文件
purgecss-webpack-plugin:清除多余css,必须结合上面的插件使用
前后对比

原因是tailwindcss有太多未使用的样式,这里使用 prugecss 去除

yarn add  purgecss-webpack-plugin@next -D
yarn add mini-css-extract-plugin@1.6.0  -D

webpack配置

      new MiniCssExtractPlugin({ filename: "[name].css",}),new PurgecssPlugin({paths: glob.sync(`${PATHS.src}/**/*`,  { nodir: true }),}),

查看&&优化 js包体积
webpack4+无需手动添加 UglifyJsPlugin
craco webpackConfig.optimization.minimize 默认设置为true

使用webpack-bundle-analyzer进行分析

const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer'); new BundleAnalyzerPlugin({analyzerMode: 'server',analyzerHost: '127.0.0.1',analyzerPort: 8888,openAnalyzer: true, // 构建完打开浏览器reportFilename: path.resolve(__dirname, `analyzer/index.html`), }),

代码拆分的情况

使用splitChunks拆分代码

plugins:[],
configure: (webpackConfig, { env: webpackEnv, paths }) => {webpackConfig.optimization.splitChunks = {...webpackConfig.optimization.splitChunks,cacheGroups: {base: {// 基本框架chunks: 'all',test: /(react|react-dom|react-dom-router|axios)/,name: 'base',priority: 100,},moment: {test: /[\\/]node_modules[\\/]moment[\\/]/,name: 'moment',priority: 90,},commons: {chunks: 'all',// 将两个以上的chunk所共享的模块打包至commons组。minChunks: 2,name: 'commons',priority: 80,},},};return webpackConfig;}

使用babel-plugin-import按需引入

 babel: {plugins: [// 配置 babel-plugin-import ant按需加载['import',{libraryName: 'antd',libraryDirectory: 'es',style: 'true',},'antd',],['import',{libraryName: 'moment',libraryDirectory: 'es',style: 'true',},'moment',],],

css异步加载
css文件的加载是会block网站渲染的 因此我们可以把非关键(非首屏)css异步加载

<link rel="preload" href="style.css" as="style" onload="this.onload=null;this.rel='stylesheet'"><link href="73131f5.css" rel="stylesheet" media="xxx" onload="this.media='all'" />

静态资源CDN
考虑访问网站的国外用户较多,需要将打包后的js,css资源放在http://storage.cowork.netease.com/upload.html

/*将静态资源css,js上传至cdn并替换*/
const fs = require('fs');
const rp = require('request-promise');
const glob = require('glob');//上传文件并获取url
async function uploadFile(filePath) {var options = {method: 'POST',// url: 'http://10.242.0.216:8080/api/pub/intranet/upload',// url: 'http://storage.cowork.netease.com/api/pub/intranet/upload',url: 'http://storage.cowork.netease.com/api/pub/file/upload',formData: {bizCode: 'common-40b61c',contentType: 'text/css',needHttps: 'true',file: fs.createReadStream(filePath),},};//   console.log(rp(options))return await rp(options).then(res => JSON.parse(res).data);
}//读取文件,并且替换文件中指定的字符串
function replaceFile(filePath, sourceRegx, targetStr) {fs.readFile(filePath, function(err, data) {if (err) {return err;}let str = data.toString();str = str.replace(sourceRegx, targetStr);fs.writeFile(filePath, str, function(err) {if (err) {console.log(err);return err;}});});
}
//遍历statics文件夹,找到main_*.js
function findFile(dir, filenameReg, cb) {fs.readdir(dir, function(err, files) {if (err) {return err;}if (files.length != 0) {files.forEach(item => {let path = dir + '/' + item;//判断文件的状态,用于区分文件名/文件夹fs.stat(path, function(err, status) {if (err) {return err;}let isFile = status.isFile(); //是文件let isDir = status.isDirectory(); //是文件夹if (isFile) {if (item.match(new RegExp(filenameReg))) {//  console.log('找到了', path);//   arr.push(path);cb(path);}}if (isDir) {findFile(path, filenameReg, cb);}});});}});
}function test() {findFile('./build', '^main.*css$', function(css) {uploadFile(css).then(url => {console.log('----', url);});});
}//  替换静态资源
function replaceCss(htmls, dynamicValue) {findFile('./build', '^' + dynamicValue + '.*css$', function(path) {console.log(path);uploadFile(path).then(url => {console.log(url);htmls.forEach(html => {replaceFile(html, new RegExp('\/static\/css\/' + dynamicValue + '.[a-z0-9]{8}.css'), url);});});});}
function replaceJs(htmls, dynamicValue) {findFile('./build', '^' + dynamicValue + '.*js$', function(path) {console.log(path);uploadFile(path).then(url => {// /\/static\/js\/main.[a-z0-9]{8}.js/htmls.forEach(html => {replaceFile(html, new RegExp('\/static\/js\/' + dynamicValue + '.[a-z0-9]{8}.js'), url);});});});}
let htmls = [];
glob.sync('./build/**/index.html').forEach(html => {htmls.push(html);
});replaceCss(htmls, 'main');
replaceJs(htmls, 'main');
replaceJs(htmls, 'base');
replaceJs(htmls, 'moment');
replaceJs(htmls, 'lodash');// test()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/56936.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

视频网站开发:Spring Boot框架的高效实现

5 系统实现 5.1用户信息管理 管理员管理用户信息&#xff0c;可以添加&#xff0c;修改&#xff0c;删除用户信息信息。下图就是用户信息管理页面。 图5.1 用户信息管理页面 5.2 视频分享管理 管理员管理视频分享&#xff0c;可以添加&#xff0c;修改&#xff0c;删除视频分…

linux线程 | 同步与互斥 | 全解析信号量、环形生产消费者模型

前言: 本节内容讲述linux下的线程的信号量&#xff0c; 我们在之前进程间通信那里学习过一部分信号量&#xff0c; 但是那个是systemV版本的信号量&#xff0c;是以进程间通信的视角谈的。 但是本篇内容会以线程的视角谈一谈信号量。 ps&#xff1a;本篇内容建议学习了生产者消…

Qml-Item的Id生效范围

Qml-Item的Id生效范围 前置声明 本实例在Qt6.5版本中做的验证同一个qml文件中&#xff0c;id是唯一的&#xff0c;即不同有两个相同id 的Item;当前qml文件中声明的id在当前文件中有效&#xff08;即如果其它组件中传入的id&#xff0c;与当前qml文件中id 相同&#xff0c;当前…

国庆旅游高峰期,如何利用可视化报表来展现景区、游客及消费数据

国庆黄金周&#xff0c;作为国内旅游市场的年度盛宴&#xff0c;总是吸引着无数游客的目光。今年&#xff0c;随着旅游市场的强劲复苏&#xff0c;各大景区又再次迎来游客流量的高峰。全国国内出游7.65亿人次&#xff0c;同比增长5.9%&#xff0c;国内游客出游总花费7008.17亿元…

Java | Leetcode Java题解之第485题最大连续1的个数

题目&#xff1a; 题解&#xff1a; class Solution {public int findMaxConsecutiveOnes(int[] nums) {int maxCount 0, count 0;int n nums.length;for (int i 0; i < n; i) {if (nums[i] 1) {count;} else {maxCount Math.max(maxCount, count);count 0;}}maxCou…

一起搭WPF架构之livechart的MVVM使用介绍

一起搭WPF架构之livechart使用介绍 前言ModelViewModelView界面设计界面后端 效果总结 前言 简单的架构搭建已经快接近尾声了&#xff0c;考虑设计使用图表的形式将SQLite数据库中的数据展示出来。前期已经介绍了livechart的安装&#xff0c;今天就详细介绍一下livechart的使用…

前三章例题【现代控制理论】

【现代控制理论-状态空间方程能观性分解】https://www.bilibili.com/video/BV1KU4y1N7jV?p17&vd_source3cc3c07b09206097d0d8b0aefdf07958

2024CSP-J模拟赛9————S12678

一&#xff0c;赛中得分 T1100T2100T350T440总分290 二&#xff0c;赛中概括 T1T2较快过&#xff0c;T3T4骗了90分&#xff08;意料之中&#xff0c;这么好骗分&#xff01;&#xff01;&#xff01;&#xff09;。 三&#xff0c;题目解析 涂格子(paint) 问题描述 现在有…

前端Socket互动小游戏开发体验分享

随着实时网络通信技术的不断发展&#xff0c;基于WebSocket的前端互动小游戏成为了一种非常流行的选择。WebSocket允许客户端和服务器之间进行双向通信&#xff0c;为游戏互动带来了更快的响应时间和更流畅的体验。本文将通过一个简单的互动小游戏来探讨前端如何利用WebSocket技…

LeetCode 19 - 删除链表的倒数第N个节点

题目描述 给你一个链表&#xff0c;删除链表的倒数第 N 个节点&#xff0c;并且返回链表的头结点。 例如&#xff1a; 输入&#xff1a;head [1,2,3,4,5], n 2 输出&#xff1a;[1,2,3,5]解题思路 我们可以使用双指针的方法来解决这个问题。主要思路是使用两个指针fsat和…

如何下载3GPP协议?

一、进入3GPP网页 https://www.3gpp.org/ 二、点击“Specifications &Technologies” 三、点击“FTP Server” 网址&#xff1a; https://www.3gpp.org/specifications-technologies 四、找到“latest”&#xff0c;查看最新版 网址&#xff1a; https://www.3gpp.org/ftp…

Python 多线程学习与使用

Python 多线程学习与使用 目录 引言&#xff1a;为什么需要多线程&#xff1f;Python中的线程基础 2.1 什么是线程&#xff1f; 2.2 Python的threading模块 2.3 创建和启动线程线程同步与互斥 3.1 竞态条件 3.2 锁&#xff08;Lock&#xff09; 3.3 可重入锁&#xff08;RLoc…

【jQuery】jQuery 处理 Ajax 以及解决跨域问题的方式

文章目录 HTTP原生创建 AjaxjQuery 处理 Ajax$.ajax()$().load()$.get()$.post() 跨域CORSJSONPiframeweb sockets HTTP 超文本传输协议&#xff08;HTTP&#xff0c;HyperText Transfer Protocol)是互联网上应用最为广泛的一种网络协议。设计 HTTP 最初的目的是为了提供一种发…

计算机网络易混知识点

1.以太网采用曼彻斯特编码&#xff1b;以太网帧最短为64B&#xff0c;其中14个B首部(目的MAC-6B&#xff0c;源MAC-6B&#xff0c;类型-2B)4B尾部 2.OSI协议中&#xff0c;每一层为上一层提供服务&#xff0c;为下一层提供接口 3.帧序号的比特数表示的是发送窗口的大小&#…

LabVIEW提高开发效率技巧----离线调试

离线调试是LabVIEW开发中一项重要的技巧&#xff0c;通过使用Simulate Signal Express VI生成虚拟数据&#xff0c;开发者能够有效减少对实际硬件的依赖&#xff0c;加速开发过程。这种方法不仅可以提高开发效率&#xff0c;还能降低成本&#xff0c;增强系统的灵活性。 ​ 离…

SQL 自学:事务处理的COMMIT 和 ROLLBACK 语句的运用

在 SQL 中&#xff0c;事务处理是确保数据库操作的完整性和一致性的重要机制。事务可以看作是一组作为一个单元执行的数据库操作&#xff0c;要么全部成功提交&#xff08;COMMIT&#xff09;&#xff0c;要么全部回滚&#xff08;ROLLBACK&#xff09;到事务开始之前的状态。 …

前端性能优化之概述篇

对于前端开发来说,性能优化老生常谈了。不管是日常工作中,还是涉及到晋级答辩,性能都是频繁被我们提及的一个话题。 性能优化不是一劳永逸的解决方案,项目在发展过程,代码不断地迭代和变更。我们在某个阶段优化过的代码,过段时间性能又会慢慢下降,这也是前端开发常把性…

从零开始使用最新版Paddle【PaddleOCR系列】——第二部分:自建数据集 + 模型微调训练

目录 一、自建数据集 1.官方数据集格式参考 2.自建数据集txt文件编写代码 3.数据集检验 二、模型训练 1.模型配置yaml文件 2.命令行指令训练 在上一篇文章中&#xff0c;构建好了paddleOCR 运行必需的环境&#xff0c;并通过在线下载的方式&#xff0c;使用官方训练好的模型进…

架构师备考论文-面向服务的架构设计与应用

题目 在面向服务的架构&#xff08;Service-Oriented Architecture&#xff0c;SOA&#xff09;中&#xff0c;服务的概念有了延伸&#xff0c;泛指系统对外提供的功能集。例如&#xff0c;在一个大型企业内部&#xff0c;可能存在进销存、人事档案和财务等多个系统&#xff0c…

OpenCV图像处理——查找线条的转折点

问题描述 图像中有一条线&#xff0c;如何判断这条线的转折点&#xff1f; 比如下面一张图&#xff1a; 目的是找到图中的三个转折点。 要在图像中检测线的转折点&#xff0c;可以通过分析线的几何形状来完成。这通常需要首先提取线的轮廓&#xff0c;然后根据曲率、角度变化…