09
9

随着前端技术的快速发展,React作为一款领先的JavaScript库,不断推动着前端开发的变革。近期,React官网的一个显著变化引起了广大开发者的关注:它不再推荐使用Create-React-App作为构建React应用的默认工具,而是转向了Next.js。

那么,Next.js究竟有何魔力,让React官网做出如此决策?本文将为你详细解析。

一、Next.js:React应用的“升级版”

Next.js并不是一个全新的框架,而是基于React的服务器端渲染框架。它提供了许多开箱即用的功能,使得开发者能够更高效地构建复杂、高性能的React应用。与Create-React-App相比,Next.js更像是一个“升级版”,它为React应用带来了以下显著的优势:

性能优化:Next.js支持自动静态优化(Automatic Static Optimization)和服务器端渲染(Server-Side Rendering),使得页面加载速度更快,用户体验更流畅。此外,Next.js还支持预渲染(Pre-rendering)和动态导入(Dynamic Imports),进一步提升了应用的性能。
数据获取简化:Next.js内置了数据获取功能,使得开发者能够更方便地从API或其他数据源获取数据,并将其注入到组件中。这种无缝的数据获取流程大大简化了开发过程,提高了开发效率。
强大的路由功能:Next.js提供了基于文件系统的路由功能,使得页面之间的导航变得简单直观。开发者只需创建相应的页面文件,Next.js就能自动为其生成路由。这种方式不仅易于理解,还能减少错误和提高可维护性。
更好的SEO支持:由于Next.js支持服务器端渲染和预渲染,因此它能够更好地处理页面渲染和加载问题,从而提高网站的搜索引擎优化(SEO)效果。

二、Create-React-App的局限性

虽然Create-React-App为React开发者提供了一个快速搭建项目的脚手架,但随着项目规模的扩大和复杂度的增加,其局限性也逐渐显现:

配置不灵活:Create-React-App为开发者提供了一套固定的配置,虽然这降低了入门门槛,但对于有特定需求的开发者来说,这种固定配置可能会成为束缚。
性能优化有限:Create-React-App主要关注于项目的快速搭建和开发体验,对于性能优化方面的支持相对有限。对于需要高性能的应用来说,开发者可能需要花费更多的时间和精力进行手动优化。
扩展性不足:随着项目的发展,开发者可能需要集成更多的功能和工具。然而,Create-React-App的扩展性相对有限,可能无法满足一些高级需求。

三、React官网推荐的背后

React官网之所以推荐Next.js而非Create-React-App,背后有多重原因。

首先,Next.js作为React的“升级版”,在性能、数据获取、路由等方面提供了更强大的支持,能够更好地满足现代Web应用的需求。
其次,随着前端技术的不断发展,开发者对于高性能、易扩展的应用框架的需求也在不断增加。Next.js正好符合这一趋势,能够为开发者提供更高效、更灵活的开发体验。
最后,React官网的推荐也反映了社区对于Next.js的广泛认可和支持。越来越多的企业和项目采用Next.js构建应用,证明了其在实际应用中的价值和优势。

四、结语

React官网推荐使用Next.js而非Create-React-App,是基于对现代Web应用需求的深入理解和对前端技术发展趋势的敏锐洞察。对于广大React开发者来说,了解和掌握Next.js将是一个值得投入时间和精力的选择。它将帮助你更高效地构建高性能、易扩展的React应用,提升你的开发能力和竞争力。

https://segmentfault.com/a/1190000044806695

25
7

Create React App 的演变

在 2016 年发布 Create React App 时,工具的环境是分散的。如果想要将 React 添加到现有应用,需要添加一个 script 标签或从 npm 中导入,然后调整现有的构建工具配置。但是,如果要从头开始创建一个仅使用 React 构建的新应用,则没有明确的方法可以做到这一点。
在 Create React App 之前,必须安装一堆工具并将它们连接在一起,提供正确的预设以使用 JSX,为开发和生产环境进行不同的配置,为资源缓存提供正确的设置,配置 linter 等,想要正确完成这一系列工作非常困难。人们通过创建和共享可以克隆的“样板”存储库来解决了这个问题。然而,这产生了另外一个问题:一旦在项目中调整了克隆的样板文件,就很难再拉取样板的更新。这样,项目的设置会变得旧,要么放弃更新,要么花费大量精力让所有工具再次协同工作。在快速发展的生态系统中,这非常困难。
Create React App 通过将多个工具组合在一个包中解决了这个问题。现在,如果想用 React 开始一个新项目,有一个明确的推荐方法(Create React App)可以做到这一点! 然后,每隔一段时间,可以更新这个包,以获得所有底层工具的更新。这种模型变得很流行,以至于今天有很多工具都以这种方式工作。Vite 确实是拥有相似愿景的最佳工具之一,并且在在某些方面更进一步。
Create React App 的目标是为大多数 React 用户提供启动新 React Web 应用的最佳方式,它支持一组协同工作的精选功能。随着时间的推移,它提供的开箱即用的“baseline”会随着我们找到正确的权衡而扩大。 例如,为运行时错误添加了一个遮罩层,添加了对不同样式选项的支持,默认添加了快速刷新,它允许保存组件的代码并查看更改而不会丢失状态。对于默认的 React 开发体验来说,这是一个巨大的里程碑。总的来说,由于 Create React App 完全控制了编译管道,因此添加编译相关的功能是很容易的。
有这样一个精心策划的设置对生态系统仍然很有价值。当 React Hooks 出现时,React 团队将 React Hooks lint 规则添加到默认设置中。除此之外,Create React App 还允许 React 团队向尽可能广泛的受众部署重要的工具更改(快速刷新支持、React Hooks lint 规则)。 如果没有 React 团队策划的流行模板,将很难如此广泛地推出这些工具更改。

Create React App 的问题

随着时间的推移,Create React App 停滞不前。许多人指出它比替代品慢,并且不支持人们如今想要使用的一些流行工具。原则上,React 团队可以解决这些问题。例如,可以更新Create React App 内部,以使用更快的 bundler,甚至在内部使用 Vite。或者可以建议人们从 Create React App 迁移到 Vite 这样的应用。然而,React 团队还想解决一个更深层次的问题。
按照设计,Create React App 会生成一个纯客户端应用。这意味着用它创建的每个应用都包含一个空的 HTML 文件、一个带有 React 的 script 标签和应用包。当加载空的 HTML 文件时,浏览器会等待 React 代码和全部应用包下载。这在低带宽连接上可能需要一段时间,并且此时用户在屏幕上看不到任何内容。然后,加载应用代码。此时用户会在屏幕上看到一些内容——但通常还需要加载数据。所以代码发送了加载数据的请求,用户需要等待它返回。 最后,数据加载,组件重新渲染数据,用户看到最终结果。
这是非常低效的,尽管如果只在客户端运行 React 很难做得更好。将其与 Rails 这样的服务端框架进行对比:服务端将立即启动数据获取,然后生成包含所有数据的页面。在这种情况下,用户会看到包含所有信息的 HTML 文件,而不是等待加载脚本的空白文件。HTML 是Web 的基石——那么为什么创建React 应用会产生一个空的 HTML 文件?为什么不利用 Web 最基本的功能——在所有交互代码加载之前快速查看内容的能力? 为什么要等到所有客户端代码加载完成后才开始加载数据?
Create React App 只解决了问题的一方面,它提供了良好的开发体验,但它没有强加足够的结构来帮助我们利用 Web 的强大功能获得良好的用户体验。开发者可以尝试自己解决这些问题,但这违背了 Create React App 的宗旨。每个真正高效的 React 设置都是自定义的、不同的,并且是 Create React App 无法实现的。
这些用户体验问题并不是 Create React App 特有的。它们甚至不特定于 React。例如,从 Preact、Vue、Lit 和 Svelte 的 Vite 主页模板创建的应用都会遇到相同的问题。这些问题是没有静态站点生成 (SSG) 或服务端渲染 (SSR) 的纯客户端应用所固有的。

React 框架的兴起

有些人可能不喜欢完全使用 React 进行构建。例如,可以在服务端或在构建过程中使用不同的工具(如 Jekyll 或 Astro)生成 HTML 页面。这解决了空 HTML 文件的问题,但是必须混合使用两种渲染现技术。随着时间的推移,想要添加的交互性越多,这种技术割裂就越明显。
这种割裂不仅会损害开发人员的体验——用户体验也会受到影响。使用真正以 HTML 为中心且未充分利用 React 的工具,每个页面导航都会变成完整的页面重新加载,从而清除了所有客户端状态。如今,许多用户希望在应用内导航顺畅,而不是 90 年代风格的整页重新加载。同样,许多开发人员更喜欢使用单一的渲染模型而不是混合两种不同的模型来构建他们的应用。开发者想用 React 构建整个应用。
如果使用 React 构建整个应用,那么能够使用 SSG/SSR 很重要。 在 Create React App 中缺乏对它们的支持。除此之外,经过多年的生态系统创新,React 的许多其他问题现在都有了成熟的解决方案。 例如,network waterfalls 和 bundle 大小。
即使应用没有像面向内容的网站那样从 SSG 或 SSR 中获益,它也可能会受到网络瀑布的影响。如果在挂载时获取数据,则在加载所有代码并渲染组件之前,第一次数据获取甚至不会开始。这是一个 waterfall:如果应用知道如何在代码仍在加载时开始获取数据,那么就可以并行完成。在导航中,如果父组件和子组件都需要获取某些内容,则会产生更糟糕的 waterfall。当我们谈论 React 性能时,无法回避一个事实:对于如此多的应用来说,waterfall 是性能的瓶颈。要解决这些 waterfall,需要将数据获取与路由集成起来,而Create React App 无法做到这一点。
我们的应用代码会随着添加的每个新功能和额外依赖项而不断增长。如果经常部署,应用在每次使用时加载速度可能会变得非常慢,因为它总是需要加载所有代码。有几种方法可以解决这个问题;可以移动一些代码以在服务端或在构建期间运行(如果工具允许)。理想情况下,还可以按路由拆分代码。然而,如果尝试手动进行代码拆分,通常会使性能更差。要解决这一问题,需要将数据获取与路由和打包相结合,而 Create React App 无法做到这一点。
React 本身只是一个库。它不规定如何使用路由或数据获取。 Create React App 也没有。不幸的是,这意味着单靠 React 和最初设计的 Create React App 都无法解决这些问题。服务端渲染和静态生成、数据获取、打包和路由都是相关联的。当 Create React App 发布时,React 还很新,如何让这些功能独立工作都还有很多东西需要弄清楚,更不用说如何完美地将它们组合在一起了。
时代在发展,现在,越来越难以推荐无法获得这些功能的解决方案。即使不立即使用它们,它们也应该在需要时可用,并且不必迁移到不同的模板并重新构建所有代码即可利用它们。 同样,并非所有数据获取或代码拆分都需要基于路由。但这是一个很好的默认设置,应该适用于大多数 React 应用。
虽然可以自己整合所有这些功能,但很难好。 就像 Create React App 本身集成了与编译相关的几个功能一样,Next.js、Gatsby 和 Remix 等工具跟进一步——将编译与渲染、路由和数据获取集成在一起。这类集编译、渲染、路由和数据获取于一体的工具被称为“框架”(或者,如果喜欢称 React 为框架的话,可以称它们为“元框架”)。这些框架提供了更好的用户体验。
React 作为一个架构
我们喜欢 React 的灵活性,可以使用 React 构建单个按钮,也可以使用它构建整个应用。 可以使用它在已有 20 年历史的 Perl 网站中构建仪表板,或者可以使用 React 制作混合 SSG/SSR 的电子商务网站。这种灵活性是必不可少的,用户也很喜欢它。
React 团队也希望为完全使用 React 构建的新应用提供更好的默认设置。如果默认建议的创建 React 应用的方法支持 SSG 和 SSR、自动代码拆分、路由预加载、保留客户端 UI 状态的导航以及其他可实现出色用户体验的功能,就太好了。至少,创建 React 应用的默认建议方式不应该完全被排除在这些功能之外,因为现有的仅客户端架构没有实现这些功能。
React 面临着挑战,帮助 React 框架提供出色用户体验的最佳方式就是专注于 React 的底层。 React 本身可以在渲染层做一些独特的事情,这些事情大大提高了框架在其他层的能力。例如,与一样,一个 React API 可以在幕后为框架解锁一系列框架优化。
React 是一个库,它提供了一些 API,可让定义和组合组件。 React 也是一种架构,它提供了让框架作者充分利用其渲染模型的构建块。我们可以在没有框架的情况下使用 React。 但需要确保,如果将它与框架一起使用,框架能够充分利用 React。 在过去几年中构建的许多功能(、useTransition、流式 API(如 renderToPipeableStream 和实验性的服务端组件)都是面向框架的。 它们让框架通过集成打包、路由和数据获取来充分利用 React。
可以看到,Next 13、Gatsby 5 和 Remix 1.11 中采用了其中一些功能。还有很多工作要做,其中一些工作正在从实验阶段结束。 尽管如此,React 团队还是很高兴看到多年的努力得到了回报,并使 React 框架(及其用户)能够发布更快的应用。

一个库,多个框架

React 生态系统更适合拥有众多竞争,有多种竞争的数据获取解决方案和路由解决方案。这些选择每年都会变得更好。也有多种集成路由、数据获取、渲染和编译的解决方案——即多个 React 框架。
我们希望保持这种状态,也希望在可能的情况下鼓励融合并使 React 生态系统从中受益。例如,不同的框架可能使用不同的机制来加载数据。但是,如果它们都采用 Suspense 作为加载指示器,那么在 Suspense 中的更高级别的功能将适用于所有框架。
如果大多数 React 应用的最佳方式是从一个框架开始,那我们应该建议使用哪个框架? 我们应该选择一个吗? 我们如何决定选择哪一个? 如果它随着时间的推移停滞不前怎么办? 这就引出了上面提到的问题。
我们应该用 Create React App 做什么?
Create React App 最初的目标是:
• 提供一种无需配置即可启动新 React 项目的简单方法;
• 集成编译相关依赖,方便升级;
• 让 React 团队尽可能广泛地部署工具更新(例如快速刷新支持、Hooks lint 规则)。
然而,它不再满足最初的目标,即成为创建 React 应用的最佳方式。通过提高标准并将编译与渲染、路由和数据获取相集成,框架可以让用户创建 React 应用时:
• 充分利用 Web API 来默认提供快速的应用和网站,无论大小;
• 充分利用 React 及其框架级功能;
• 提供路由和数据获取。
React 生态系统值得推荐一种默认的方法,它可以充分利用 Web 和 React 本身。这甚至并不意味着一定要依赖于 Node.js 服务器。 许多流行的框架不需要服务器并且可以在 SSG 模式下工作,因此它们也可以解决“完全静态”的用例。 框架的好处就是,如果以后需要 SSR,不需要进行迁移,它和其他功能一样开箱即用(例如,Remix 提供了开箱即用的 mutation API)。
那该如何实现这一愿景?有以下选择:
选项 1:从头开始创建一个新框架
可以尝试将 Create React App 重新设计架构成为一个集成数据获取、路由、打包和 SSG/SSR 的框架。构建一个高质量的新框架是一项艰巨的任务,需要大量的生态系统专业知识,即使停止其他项目来实现这一目标,也会存在着随着时间的推移出现停滞不前的重大风险,就像 Create React App 一样。它还会进一步分裂生态系统,尽管没有真正的用户。 所以认为这个选项目前不实用。
选项 2:弃用 Create React App,维护一个Vite模板
可以弃用 Create React App,维护自己的 Vite 模板。 为了实现这个目标,该模板必须非常复杂。 事实上,它必须像 React 框架一样复杂——并且需要集成路由、数据获取等功能。这导致了同样的问题:实际上是在创建另一个框架。
选项 3:弃用 Create React App,建议使用 React 框架
可以不再强调或反对将 Create React App 作为工具,而是更积极地强调 React 框架。这并不意味着必须使用其中一个React框架,但建议在大多数应用中使用其中一个框架。不利的一面就是,这将影响 React 的品牌(“为什么不推荐创建 React 应用?”)。
选项 4:让 Create React App 使用单一框架
可以选择一个指定框架,并更改 Create React App 以默认使用该框架创建应用。这种方法的主要问题是它使其他解决方案很难竞争——尤其是当它们的权衡略有不同,但在流行度、功能集和质量方面大致相同时。 这种行为上的改变也是具有破坏性的,因为所有的旧教程都会以一种不明显的方式中断。
选项 5:将 Create React App 变成启动器
可以将 Create React App 保留为命令,但将其变成启动器。它将建议一个推荐框架列表,然后是“经典”无框架方法。“经典”方法将产生一个像 CRA 现在这样的客户端专用应用(以避免破坏已有教程),但内部最终可能会使用 Vite。
要想进入精选框架列表,React 框架必须满足特定条件。需要考虑社区的流行度和采用率(以保持列表简短)、功能集、性能特征、充分利用 Web 平台和 React 本身的能力、它是否得到积极维护以及是否清楚如何在各种托管服务和环境中托管它。每个框架的入门模板将由 React 团队维护,以确保它们具有一致的设计和品牌,不链接到商业服务,并且结构相似。需要向社区清楚地传达是如何做出这些选择的,并且会定期重新评估它们。

React 团队的建议

React 团队目前倾向于选项 5(“将 Create React App 变成启动器”)。 Create React App 的最初目标是为大多数 React 用户提供启动新的 React web 应用的最佳方式。重新调整它的用途,启动器明确传达了我们认为最适合大多数新 Web 应用的转变。与选项 3 不同,它避免了“创建一个 React 应用”在某种程度上被弃用的看法。
React 团队将制定更详细的 RFC 提案,以充实这些要点。同时,希望听到对这些问题的更多反馈。
对于使用 Vite 替换 Create React App, 你有什么看法?欢迎在评论区分享~
参考:github.com/reactjs/rea…

09
7

Create React App(以下简称 CRA)是一个官方支持的创建 React 单页应用的脚手架,它提供了一个零配置的现代构建设置,将一些复杂工具(比如 webpack, Babel)的配置封装了起来,让使用者不用关心这些工具的具体配置,从而降低了工具的使用难度。

创建方法

npx: npx 来自 npm 5.2+ 或更高版本

npx create-react-app my-app
npm: npm init 在 npm 6+ 中可用

npm init react-app my-app
Yarn: yarn create 在 Yarn 0.25+ 中可用

yarn create react-app my-app
Scripts
在新创建的项目中,你可以运行一些内置命令:

npm start 或 yarn start
在开发模式下运行应用程序, 默认在浏览器打开http://localhost:3000。如果更改代码,页面将自动重新加载。

npm test 或 yarn test
以交互模式运行测试程序。 默认情况下,运行与上次提交后更改的文件相关的测试。

npm run build 或 yarn build
将生产环境的应用程序构建到 build 目录。 它能将 React 正确地打包为生产模式中并优化构建以获得最佳性能。构建将被压缩,文件名中将包含哈希。

npm run eject
注意:这是单向操作。一旦 eject ,就回不去了!
执行完这个命令后会将封装在 CRA 中的配置全部反编译到当前项目,这样开发者完全取得 webpack 文件的控制权,可以自定义修改webpack打包配置。

默认文件结构

创建后,项目文件结构如下所示:

my-app
node_modules
public
favicon.ico
index.html // 页面模板
manifest.json
src
App.css
App.js
App.test.js
index.css
index.js // 项目入口
logo.svg
reportWebVitals.js
setupTests.js
.gitignore
package.json
README.md
yarn.lock
为了加快重新构建的速度,Webpack 只处理 src 中的文件。 你需要将 JS 和 CSS 文件放在 src 中,否则 Webpack 将发现不了。
只能在 public/index.html 中使用 public 中的文件。
manifest.js: 将Web应用程序安装到设备的主屏幕,为用户提供更快的访问和更丰富的体验。

项目升级

Create React App 分为两个包:

create-react-app 是一个全局命令行实用程序,可用于创建新项目。
react-scripts 包含Create React App的脚本与配置
当你运行 create-react-app 时,它始终使用最新版本的 react-scripts 创建项目,新创建的应用会获得所有新功能和改进。

CRA 将所有新特性委托给 react-scripts , 只需要更新 react-scripts, 不需要更新 create-react-app 就可以升级CRA 的特性。比如用老版本 CRA 创建了一个项目,这个项目不具备 PWA 功能,但只要项目升级了 react-scripts 包的版本就可以具备 PWA 的功能,项目本身的代码不需要做任何修改。

如何在启动项目时不清空 terminal?
在运行 yarn start 或 npm start 来启动 create-react-app 创建的项目时,默认会清空 terminal。实际在进行开发调试时,需要在 webpack 中输出一些信息。

解决方法:
1、修改node_modules/react-dev-utils/clearConsole.js 文件:

'use strict';

function clearConsole() {
if (process.env.REACT_APP_NO_CLEAR_CONSOLE) {
return;
}
process.stdout.write(
process.platform === 'win32' ? '\x1B[2J\x1B[0f' : '\x1B[2J\x1B[3J\x1B[H'
);
}

module.exports = clearConsole;
2、修改 package.json文件,将变量 REACT_APP_NO_CLEAR_CONSOLE 添加到script命令中:

// package.json
{
"scripts": {
"start": "REACT_APP_NO_CLEAR_CONSOLE=true react-app-rewired start",
}
}
如何扩展 Create React App 的 Webpack 配置
Create React App已经封装了webpack 配置,如果想对 webpack 配置做一些修改,这个时候应该怎么办呢?CRA提供了以下几种方式来修改 webpack 的配置:

eject 命令

替换 react-scripts 包
使用 react-app-rewired
scripts 包 + override 组合
customize-cra 【推荐】
eject 命令
使用 CRA 创建完项目以后,在package.json里面提供了这样一个命令:

{
...
"scripts": {
"eject": "react-scripts eject"
},
...
}
执行yarn eject后会将封装在 CRA 中的配置全部复制到当前项目。eject 后项目根目录下会新增 config与scripts 文件夹,修改package.json与yarn.lock文件。

config
jest
env.js
getHttpsConfig.js
modules.js
paths.js
pnpTs.js
webpack.config.js
webpackDevServer.config.js
scripts
build.js
start.js
test.js
如果使用了eject命令,虽然扩展了 webpack 配置,但是再也享受不到 CRA 升级带来的好处了。因为react-scripts已经是以文件的形式存在于你的项目,而不是以包的形式,所以无法对其升级。

替换 react-scripts 包

react-scripts 是 CRA 的一个核心包,一些脚本和工具的默认配置都集成在里面,使用 CRA 创建项目默认就是使用这个包。但是 CRA 还提供了另外一种方式来创建 CRA 项目,用自定义 scripts 包的方式。

// 默认方式
$ create-react-app my-app

// 自定义 scripts 包方式
$ create-react-app my-app --scripts-version 自定义包
自定义包可以是下面几种形式:

react-scripts包的版本号,比如0.8.2,这种形式可以用来安装低版本的react-scripts包。
一个已经发布到 npm 仓库上的包的名字,比如your-scripts,里面包含了修改过的 webpack 配置。
一个 tgz 格式的压缩文件,比如/your/local/scripts.tgz,通常是未发布到 npm 仓库的自定义 scripts 包,可以用 npm pack 命令生成。
这种方式相对于之前的eject是一种更灵活地修改 webpack 配置的方式,而且可以做到和 CRA 一样,通过升级 scrips 包来升级项目特性。
自定义 scripts 包的结构可以参照react-scripts包的结构,只要修改对应的 webpack 配置文件,并安装上所需的 webpack loader 或 plugin 包就可以。

使用 react-app-rewired
react-app-rewired 是 react 社区开源的一个修改 CRA 配置的工具,这种方式让开发者既不用eject项目也不用自己创建 scripts 包就可以拓展webpack。

如何使用

1.在 CRA 创建的项目中安装react-app-rewired

npm install react-app-rewired --save-dev
2.在项目根目录下创建config-overrides.js 文件(支持自定义文件路径)

/ config-overrides.js /

module.exports = function override(config, env) {
// 参数中的 config 就是默认的 webpack config

// 对 config 进行任意修改
config.mode = 'development';

// 一定要把新的 config 返回
return config;
}
config-overriders.js 导出的是一个函数,这个函数的签名是 const override = (oldWebpackConfig, env) => newWebpackConfig。

3.修改 scripts 命令:

/ package.json /

"scripts": {

  • "start": "react-scripts start",
  • "start": "react-app-rewired start",
  • "build": "react-scripts build",
  • "build": "react-app-rewired build",
  • "test": "react-scripts test",
  • "test": "react-app-rewired test",
    "eject": "react-scripts eject"
    }
    自定义 config-overrides.js 文件路径
    通过package.json 的config-overrides-path设置自定义路径:

/ package.json /
{
...
"config-overrides-path": "src/app", // src/app/config-overrides.js
...
}
config-overrides.js 文件
默认情况下,config-overrides.js文件导出一个函数,这个函数的签名是 const override = (oldWebpackConfig, env) => newWebpackConfig(oldWepbackConfig 和 newWebpackConfig 实际指向同一个对象,因为直接在原来的 webpack config 对象上进行修改)。

也可以改为此文件导出一个对象,该对象最多包含三个字段,每个字段都是一个函数。

module.exports = {
// The Webpack config
webpack: function(config, env) {
// ...add your webpack config
return config;
},
// The Jest config
jest: function(config) {
// ...add your jest config customisation...
return config;
},
// create a webpack dev server
devServer: function(configFunction) {
return function(proxy, allowedHost) {
const config = configFunction(proxy, allowedHost);
const fs = require('fs');
config.https = {
key: fs.readFileSync(process.env.REACT_HTTPS_KEY, 'utf8'),
cert: fs.readFileSync(process.env.REACT_HTTPS_CERT, 'utf8'),
ca: fs.readFileSync(process.env.REACT_HTTPS_CA, 'utf8'),
passphrase: process.env.REACT_HTTPS_PASS
};
return config;
};
},
paths: function(paths, env) {
// ...add your paths config
return paths;
},
}

实现原理实现原理

编译时,react-app-rewired 会先取到 create-react-app 生成的默认的 webpack config,然后调用 override(config) 方法,对 config 进行修改,得到新的 webpack config。webpack 最终会使用这个新的 config 进行打包。

流程大致如下:

const overrides = require('../config-overrides');
const webpackConfigPath = paths.scriptVersion + "/config/webpack.config.prod";

// load original config
const webpackConfig = require(webpackConfigPath);

// override config in memory
require.cache[require.resolve(webpackConfigPath)].exports =
overrides.webpack(webpackConfig, process.env.NODE_ENV);

// run original script
require(paths.scriptVersion + '/scripts/build');
scripts 包 + override 组合
虽然 react-app-rewired 的方式已经可以很方便地修改 webpack 的配置了,但也可以在自定义的 script 包中实现类似的功能。

以 build.js 为例,在获取基本 webpack 配置对象和使用 webpack 对象之间加入以下代码:

// override config
const override = require(paths.configOverrides);
const overrideFn = override || ((config, env) => config);
const overrideConfig = overrideFn(config, process.env.NODE_ENV);
overrideConfig 就是修改后的 webpack 对象,最后修改调用了 webpack 对象的代码,将原来的 webpack 对象替换成修改后的 webpack 对象。

customize-cra
react-app-rewired 原生写法,对 webpack config 的修改全部写在 override() 一个方法中,不够模块化。customized-cra 提供了一些 helper 方法,可以将每一个独立的修改放到单独的函数中,再串行执行这些函数。
customize-cra 依赖于 react-app-rewired 库,通过 config-overrides.js 来修改底层的 webpack,babel等配置。

安装
yarn add customize-cra react-app-rewired --dev

使用
customize-cra 导出 customizers 和 utilities 两种类型的api,查看 api docs了解更多。

customizers: 是对配置对象进行修改的方法, 让用户轻松启用或禁用 webpack,webpack-dev-server,babel等功能。
utilities: 定制一些方法用于浏览其配置。
所有代码都应写在 config-overrides.js 文件中。
参阅 api.md 文档获取有关 customize-cra 提供的功能。
const {
override,
addWebpackAlias,
} = require("customize-cra");
const path = require("path");

module.exports = override(
// add an alias for "page" imports
addWebpackAlias({
page: path.resolve(__dirname, "src/page")
}),
);
override()
新的 override() 方法,是一个高阶函数,接受可变数量的参数,每个参数都是签名为 const fn = (oldConfig) => newConfig 的函数;同时会返回一个新的函数,这个函数的签名也是 const fn = (oldConfig) => newConfig。

override() 会在内部依次调用传入的参数函数,把前一个函数返回的 newConfig 作为后一个函数的 oldConfig 参数,得到最终的 webpack config。

大致实现如下:

function override(fns) {
return function (oriConfig) {
let finalConfig = oriConfig
for (const fn of fns) {
finalConfig = fn(finalConfig)
}
return finalConfig
}
}
如何添加文件别名?
通过 addWebpackAlias,添加文件别名。

// config-overrides.js
const { override, addWebpackAlias } = require('customize-cra')
const path = require("path")

module.exports = override(
addWebpackAlias({
"components": path.resolve(__dirname, "src/components")
}),
)
fixBabelImports()
babel 模块化导入插件。具体查看 babel-plugin-import

const { override, fixBabelImports } = require("customize-cra");

module.exports = override(
fixBabelImports('antd', {
"libraryName": "antd",
libraryDirectory: 'es',
"style": true,
})
);
style
style: true 导入CSS源文件,在编译期间进行优化。可以明显减小分发包的大小,具体取决于对库的使用情况。
style: css 将预捆绑的CSS文件直接导入。

如何自定义 babel?
通过 useBabelRc,实现自定义 babel。

// config-overrides.js
const { override, useBabelRc } = require('customize-cra')

module.exports = override(
useBabelRc(),
)
项目根目录新建 babelrc文件:

// .babelrc
{
"presets": ["@babel/env"],
"plugins": ["@babel/plugin-transform-runtime"]
}
如何添加插件?
通过 addWebpackPlugin,添加插件。

// config-overrides.js
const { override, addWebpackPlugin } = require('customize-cra')
const DefinePlugin = require('webpack').DefinePlugin
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin

module.exports = override(
addWebpackPlugin(
new DefinePlugin({
'test': 12244,
}),
),
addWebpackPlugin(new BundleAnalyzerPlugin()),
)
如何 SplitChunks?
通过 setWebpackOptimizationSplitChunks,自定义拆包。

// config-overrides.js
const { override, setWebpackOptimizationSplitChunks } = require('customize-cra')

module.exports = override(
setWebpackOptimizationSplitChunks({
maxSize: 1024 1024 3,
minChunks: 2,
})
)

03
6

解决ng : 无法将“ng”项识别为 cmdlet、函数、脚本文件或可运行程序的名称 及 ng : 无法加载文件 C:\Users\15762\AppData\Roaming\npm\ng.ps1问题
ng : 无法将“ng”项识别为 cmdlet、函数、脚本文件或可运行程序的名称
解决 在命令行执行npm install -g @angular/cli
ng : 无法加载文件 C:\Users\15762\AppData\Roaming\npm\ng.ps1
解决 以管理员身份运行Windows PowerShell,输入set-ExecutionPolicy RemoteSigned 选择是选择 A

ng : 无法将“ng”项识别为 cmdlet、函数、脚本文件或可运行程序的名称

解决 在命令行执行npm install -g @angular/cli

ng : 无法加载文件 C:\Users\15762\AppData\Roaming\npm\ng.ps1

解决 以管理员身份运行Windows PowerShell,输入set-ExecutionPolicy RemoteSigned 选择是选择 A

03
12

https请求报错block:mixed-content

0
归档:2021年12月分类:前端技术

我的wordpress域名都换成了https,今天发现用的一个插件加载css和js的时候报错了,原来是因为https页面去发送http请求报错,因为浏览器阻止https发送http请求。我一开始打算改插件的源码,折腾好一两个小时都不成功,最后用了最简单、最粗暴的办法,一行代码解决了。

浏览器不允许在https页面里嵌入http的请求,现在高版本的浏览器为了用户体验,都不会弹窗报错,只会在控制台上打印一条错误信息。

解决办法: 在主页面的head中加入下面代码(将调用的http请求升级成https请求并调用):

<meta http-equiv="Content-Security-Policy" content="upgrade-insecure-requests">

wordpress的话,就改admin-head.php

file

28
11

如何用codesmith连接mysql

0
归档:2021年11月分类:前端技术

之前用的codesmith一直都是链接sql server,最近写新的模板需要用到mysql,居然发现无法使用,于是找了下原因,发现是没有添加mysql.data.dll的支持。

网上提供这个办法(我没有成功,我甚至专门在nuget上下载了对应版本的MySql.Data.dll,依然不成功):

1、下载MySql.Data.dll:https://dev.mysql.com/downloads/windows/visualstudio/ 下载zip格式的即可,解压后将MySql.Data.dll复制到codesmith的bin文件夹下。

2、修改DbProviderFactories:找到C:\Windows\Microsoft.NET\Framework64\v4.0.30319\Config\machine.config 注意64位的,因为权限问题可能无法修改,将其复制到桌面做如下修改后替换回来。

在DbProviderFactories节点下添加

<add name="MySQL Data Provider" invariant="MySql.Data.MySqlClient" description=".Net Framework Data Provider for MySQL" type="MySql.Data.MySqlClient.MySqlClientFactory, MySql.Data, Version=6.10.7.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d" />

此处的版本号要与下载的dll版本一致, 可以右键查看dll的详细信息获取。

3、重新打开codesmith配置数据源即可。

我最终是新装了更高版本的codesmith,然后装了mysqlconnect之后,顺利链接上了,这里有各种版本的下载:https://downloads.mysql.com/archives/c-net/

01
7

Angular项目部署和跨域问题

0
归档:2019年7月分类:前端技术

采用Angular开发,部署的时候有两种方式:第一种是把打包后的文件直接发布到站点根目录下面,这种情况Angular的项目将作为一个独立的网站,那么必然会面对跨域的问题;第二种是把Angular打包后的文件放到站点根目录下的某个文件夹,这种情况不需要跨域,但是需要对路径做相关的配置。这里先讨论第一种情况。

一、开发环境

可以通过代理跨域,在angular项目中

1)在项目根目录新建proxy.config.json;

2)跟上面的proxyTable 一样配置好;

3)执行命令ng serve --proxy-config proxy.config.json即可

4)可以在package.json里配置下

"scripts": {
"start": "ng serve --proxy-config proxy.config.json"
},
然后执行npm run start

二、生产环境

上面的方式可以解决我们在Angualr项目中开发环境的跨域问题,但是无法解决生产环境上的跨域问题,有的时候生产环境上也需要处理跨域问题,这个时候proxyTable是不行的,需要通过Nginx或者IIS反向代理(你没有看错,IIS反向代理,而且效率也很高,下一篇我会讨论)。

反向代理作用

1) http服务器,可以独立提供http服务;

2) 虚拟主机:多个域名指向同一个服务器,服务器根据不同的域名把请求转发到不同的应用服务器;

3) 反向代理:负载均衡,将请求转发至不同的服务器

nginx的相关配置

location / {
root D:\cross-demo\dist #直接指向打包后的文件
index index.html index.htm;
}

location /api/ {
proxy_pass http://localhost:8888/; # 将地址代理到api上
}

02
11

Facebook决定不再使用这两三年所规划的HTML5,回到原生应用的道路上。本文讲述了FB转变背后的技术细节,以及Xamarin和Mozilla对这一转变的反应。

Facebook的CEO 马克·扎克伯格最近在TechCrunch的一次采访中宣称:“作为一个公司,我们最大的错误是在HTML5上下注太多了,我们没有选原生应用,因为HTML5没有达到我们的预期”,而且,“自从发布了iOS应用后,我们发现人们订阅feed的数量增加了一倍。”

扎克伯格没有谈及他们在使用HTML5时遇到的问题,但他认为这些产品的质量不够好:“外界已经有非常好的移动体验了……我们追求最高品质,唯一的办法就是使用原生应用。”

Tobie Langel是Facebook软件工程师和W3C咨询委员会代表,他在一篇帖子中详细描述了Facebook基于HTML5做移动网页时遇到的性能问题。Langel提到的第一个问题是缺少调试工具:

移动浏览器缺少工具,从而很难深入进去,发现真正的问题是什么……我们遇到的最大的问题是内存相关的。对于给定内容大小,我们的应用很容易耗尽设备硬件能力,引起系统崩溃。不幸的是,我们很难理解到底是什么引起了这些问题。GPU缓存耗尽?达到资源限制?或是其他原因?很难说。

Langel希望知道堆栈、对象、GPU缓存的内存使用情况,以及GC(垃圾回收)周期、FPS和其他资源限制信息。

Langel谈到的HTML5的另一问题是其页面滚动性能,大部分页面滚动通过JavaScript实现,因为“其他选择不够快”。他提道:

不连贯的帧率,UI线程滞后(断断续续)。由于内容大小和图片数量导致的GPU缓存耗尽。

在不同操作系统中,原生的滚动有着不同的体验。针对一种操作系统优化过的JS实现,在其他系统上的体验却很差(机器人学中的“神秘波谷”)。

安卓设备上触摸事件相关的性能问题(延时,事件不足)使JS实现的页面滚动更加脆弱。

Langel提到的其他问题有:以“黑盒”出现的GPU、安卓系统中更好的触摸跟踪支持的需求、平滑动画以及更好的缓存。其中一些问题已经提交给W3C Web性能工作组

Nat Friedman是Xamarin的CEO,Xamarin是构建跨平台本机应用的工具提供商。在一次InfoQ评论中,他表示欢迎Facebook的改变:“对包括设备提供商,应用发布商以及最重要的消费者在内的整个移动生态系统而言,这一支持原生体验的转变是非常重要的事件”。他还指出,移动标准现在还为时尚早:

移动创新仍在飞速发展,远超“标准”方式能达到的速度。历史上,当新的操作系统出现时,它的能力非常新,使用它们的唯一方式就是在操作系统层次使用。这一阶段,最好的应用和最具突破性的创新都在靠近操作系统层面出现。对于当前移动设备平台,这种状态非常准确。市场份额的竞赛驱动了设备操作系统层面上巨大的变革和创新。在接下来的几年里,这些操作系统将会稳定下来,这一层次的创新将会变缓,使得标准化方式更加可行。但这种转变需要几年时间。

Mozilla(Mozilla是致力于Web技术的组织)的CTO Brendan Eich在ZDNet对Brendan Eich的采访中,他对Facebook在HTML5上的失败表达了不同的看法

如果你品一品言外之意,他(马克·扎克伯格)说的应该是将原生应用和HTML糅合起来。当这样糅合时,两个系统间总会有差距。Joe Hewitt是我的一个朋友,他曾在Facebook工作,做了第一个糅合应用,将两者很好地集成起来。但他离开了Facebook,后续版本中,将两者无缝集成的技能(可能还有苹果公司的一些支持)不见了。

Eich坚信Web将最终胜出:

我从不相信Web会失败。这只是个语用学的问题,而你却被这些给绕进去了。像Facebook这样的公司搞得起开发原生应用,尤其是iOS上的原生应用。但根据长尾理论,开发者将主要集中于开发Web应用,并且以此为乐。

如果Web发展到提供缺失的API,并具有更好的性能,开发者就没必要开发其他应用了。

我有一种感觉,Web将变得非常好(十年之后),那时将不会有现今这样地在原生应用对Web应用之间无休止的论战了。

Matt Asay是The Register的编辑,他在“本机应用vs.HTML5应用的争论”中,引用了一位匿名Facebook工程经理的话说:

现在,Fackbook通过写原生代码是行动最快的。这并不是说HTML5将一直无法达到宣称的效果,而是在当前情况下,摩尔定律和Web引擎仍然有效。因此我们做了一个务实的决定。最终,如果HTML5使得我们发展更快,你将看到我们会回归到HTML5。我们将使用任何让我们高效高质量工作的技术栈。

马克·扎克伯格也看好HTML5的长远前景:

并不是说HTML5不好。长期来看,事实上HTML5真的让我非常兴奋。有趣的是,实际上每天使用移动Web Facebook的人比使用iOS应用或Android应用加起来的更多。因此移动Web对我们来说非常重要。

Facebook八月份发布了iOS本机应用,他们正在开发Android上的类似应用,应该很快会在Google Play应用商店上架。

查看英文原文:Facebook: “Betting on HTML5 Was a Mistake” – Technical Reasons and Reactions

via:http://www.infoq.com/cn/news/2012/10/Facebook-HTML5-Native

公告栏

欢迎大家来到我的博客,我是dodoro,希望我的博客能给你带来帮助。