36、Gatsby构建与优化全解析

Gatsby构建与优化全解析

1. Webpack构建生成的捆绑包

Webpack在完成JavaScript构建阶段后,会生成多个不同的捆绑包,具体如下表所示:
| 文件名 | 描述 |
| — | — |
| app-[contenthash].js | 由production - app.js生成,并在webpack.config.js中配置。 |
| webpack - runtime - [contenthash].js | 包含webpack运行时的单独捆绑包(在优化部分配置),通常与应用捆绑包一起使用。 |
| framework - [contenthash].js | 包含React,作为单独的捆绑包可提高缓存命中率,因为React库很少频繁更新。 |
| commons - [contenthash].js | 每个Gatsby页面使用的库被捆绑到这个文件中,这样它们只需下载一次。 |
| component—[name]-[contenthash].js | 为每个页面提供单独的捆绑包,以实现代码分割。 |

2. production - app.js文件的作用

production - app.js文件是Webpack的入口点,它生成app - [contenthash].js文件,负责在浏览器加载初始HTML后进行所有导航和页面加载。首次加载时,HTML会立即加载,其中包含一个CDATA部分,将页面信息注入window对象,以便在JavaScript中立即使用。例如,在Gatsby网站的/blog/3页面刷新浏览器后,会有如下输出:

<![
  CDATA[ */
    window.page={
      "path": "/blog/3.js",
      "componentChunkName": "component---src-blog-3-js",
      "jsonName": "blog-3-995"
    };
    window.dataPath="621/path---blog-3-995-a74-dwfQIanOJGe2gi27a9CLKHjamc";
  */ ]
]>

之后,应用程序、webpack运行时、组件、共享库和数据JSON捆绑包通过 <link> <script> 元素加载,随后production - app.js代码初始化。

3. 应用在浏览器中的执行步骤
  • 执行onClientEntry浏览器API :应用在浏览器中首先执行onClientEntry浏览器API,这使插件能够在任何其他页面加载逻辑之前执行重要操作,例如gatsby - plugin - glamor执行的重新水化操作。api - runner - browser.js会遍历已注册的浏览器插件,并逐个执行它们(在从./cache/api - runner - browser - plugins.js检索插件列表之后,该文件在Gatsby引导早期生成)。
  • 执行hydrate函数 :捆绑包执行hydrate函数,这是一个ReactDOM函数,其行为与render类似,但它不会生成全新的DOM树并插入文档中,而是期望页面上已经存在具有相同结构的ReactDOM树。识别匹配的树后,它会遍历树以附加所需的事件监听器,使React DOM“活跃”起来。此水化过程在cache - dir/default - html.js中的 <div id="___gatsby">...</div> 元素上操作。
  • 使用@reach/router替换DOM :production - app.js文件使用@reach/router将现有DOM替换为RouteHandler组件,该组件使用PageRenderer创建用户刚刚导航到的页面,并加载该路径的页面资源。首次加载时,由于 <link rel="preload" ... /> 元素,给定路径的页面资源已经在页面的初始HTML中可用。这些资源包括导入的组件,Gatsby通过执行React.createElement()生成页面组件,然后将该元素呈现给RouteHandler供@reach/router执行渲染。
4. 预加载背景资源

在重新水化之前,Gatsby会提前开始加载背景资源,即用户开始通过页面上的链接和其他元素进行导航时所需的页面资源。页面资源的加载在cache - dir/loader.js中进行,其主要函数是getResourcesForPathname。该函数接受一个路径,发现关联的页面,并导入组件模块的JSON查询结果。对该信息的访问由async - requires.js提供,它包含Gatsby网站上每个页面的列表以及每个关联的dataPath。fetchPageResourcesMap函数负责检索该文件,这在首次调用getResourcesForPathname时发生。

5. 全局状态变量

为了提供全局状态,Gatsby将状态变量附加到window对象上,以便插件可以使用,例如 window.___loader window.___emitter window.___chunkMapping window.___push window.___replace window.___navigate

6. 代码分割和预取

在Gatsby中,代码分割在两种情况下利用Webpack的动态分割功能:
- 如果Webpack遇到import函数调用,则将导入的文件分割成单独的捆绑包。
- 如果通过require加载相关模块,则将其包含在原始捆绑包中。

Webpack将决定要分割哪些模块的问题留给Gatsby和网站开发者。在浏览器中加载页面时,无需加载网站中其他页面所需的所有脚本和样式表,除非需要预取它们以实现即时导航。Gatsby在捆绑过程中最后要做的工作是确保正确的JavaScript位于正确的位置,以便Webpack进行适当的代码分割。

7. 分割和命名块

在Gatsby的引导阶段结束并生成完整页面时,会输出.cache/async - requires.js文件。该文件导出一个components对象,其中包含ComponentChunkNames到负责导入磁盘上每个组件文件的函数的映射。示例如下:

exports.components = {
  "component--src-blog-js": () =>
    import(
      "/home/site/src/blog.js"
      /* webpackChunkName: "component---src-blog-js" */
    ),
  // more components
}

Webpack的入口点(production - app.js)需要这个async - requires.js文件来实现页面组件文件的动态导入。Webpack随后会进行动态分割,为每个导入的文件生成不同的块。该文件的一个导出还包括一个data函数,用于动态导入data.json文件,该文件也进行了代码分割。Gatsby可以通过Webpack配置的输出部分中的chunkFilename配置自定义磁盘上这些文件的命名,默认在webpack.config.js中设置为[name] - [contenthash].js。其中,[contenthash]表示最初进行代码分割的块内容的哈希值,[name]源自前面示例中的webpackChunkName。

8. 块与块资产的映射

为了生成客户端导航和未来即时加载所需的映射,Gatsby需要创建:
- 与Gatsby运行时块对应的 <link> <script> 元素。
- 给定页面的相关页面块(例如,带有内容哈希的component–src - blog - js - 2e49587d85e03a033f58.js)。

Gatsby通过Webpack的编译钩子(done)获取包含所有块组的stats数据结构。使用自定义的Webpack插件GatsbyWebpackStatsExtractor,Gatsby将块数据写入公共目录中的webpack.stats.json文件。示例如下:

// public/webpack.stats.json
{
  "assetsByChunkName": {
    "app": [
      "webpack-runtime-e402cdceeae5fad2aa61.js",
      "app-2e49587d85e03a033f58.js"
    ],
    "component---src-blog-2-js": [
      "0.f8e7f9e53550f997bc53.css",
      "0-d55d2d6645e11739b63c.js",
      "1.93002d5bafe5ca491b1a.css",
      "1-4c94a37dc2061cb7beb9.js",
      "component---src-blog-2-js-cebc3ae7596cbb5b0951.js"
    ]
  }
}

此外,Gatsby的自定义Webpack配置还会生成一个chunk - map.json文件,将每个块组映射到组件的核心块,为每个单独的块组中的JavaScript和CSS资产生成单个组件块。示例如下:

// public/chunk-map.json
{
  "app":["/app-2e49587d85e03a033f58.js"],
  "component---src-blog-2-js": [
    "/component---src-blog-2-js-cebc3ae7596cbb5b0951.css",
    "/component---src-blog-2-js-860f9fbc5c3881586b5d.js"
  ]
}
9. 在当前页面HTML中引用块

static - entry.js加载webpack.stats.json和chunk - map.json文件,在构建当前页面的 <link> <script> 元素以及预取后续导航的块时,搜索与各个componentChunkName值匹配的块资产。
- 创建 <link> <script> 元素 :生成当前活动页面的HTML后,static - entry.js在当前页面的头部创建必要的 <link> 元素,并在结束的 </body> 标签之前创建 <script> 元素,它们都引用与该页面相关的JavaScript运行时和客户端JavaScript。Gatsby运行时捆绑包(名为app)通过使用componentChunkName搜索assetsByChunkName项来获取页面和组件的所有块资产文件,然后将这两个块资产数组合并,每个块在 <link> 元素中引用如下:

<link
  as="script"
  rel="preload" 
  key="app-2e49587d85e03a033f58.js"
  href="/app-2e49587d85e03a033f58.js"
/>

在HTML主体末尾,对于JavaScript资产,Gatsby插入引用预加载资产的 <script> 元素:

<script
  key="app-2e49587d85e03a033f58.js"
  src="app-2e49587d85e03a033f58.js"
  async
/>

对于CSS资产,CSS直接内联注入HTML头部:

<style
  data-href="/1.93002d5bafe5ca491b1a.css"
  dangerouslySetInnerHTML="...contents of public/1.93002d5bafe5ca491b1a.css"
/>
10. 预取块的引用

当前页面加载完成后,Gatsby会继续在页面中查找可以预取的链接。当Gatsby的浏览器运行时遇到 <link rel="prefetch" href="..." /> 元素时,它会在当前活动页面所需的所有资源加载完成后,以低优先级开始下载资源。 <Link /> 组件的componentDidMount回调被调用时,Gatsby会自动将目标路径排入production - app.js文件的加载器中进行预取。

为了确定组件所需的块组,static - entry.js文件需要chunk - map.json文件,并将其直接注入当前页面HTML的CDATA部分的window.___chunkMapping下,以便任何production - app.js代码都可以引用它:

<![
  CDATA[ */
    window.___chunkMapping={
      "app":[
        "/app-2e49587d85e03a033f58.js"
      ],
      "component---src-blog-2-js": [
        "/component---src-blog-2-js-cebc3ae7596cbb5b0951.css",
        "/component---src-blog-2-js-860f9fbc5c3881586b5d.js"
      ]
    }
  */ ]
]>

借助这些信息,production - app.js加载器可以推导出完整的组件资产路径,并在prefetch.js中动态生成 <link rel="prefetch" ... /> 元素,然后将其注入DOM供浏览器处理,从而实现Gatsby页面之间的即时导航。预取功能可以通过在Gatsby中实现disableCorePrefetching浏览器API并返回true来禁用。

11. Gatsby CLI的使用
11.1 安装Gatsby CLI

首先,安装全局可执行文件:

$ npm install -g gatsby-cli

执行 gatsby --help 可获取所有可用命令和选项的完整列表。

11.2 常用CLI命令
命令 描述
gatsby new my - gatsby - site - name 使用默认starter创建新的本地Gatsby网站。
gatsby develop 启动Gatsby开发服务器,可选择使用 - H和–host设置主机(默认为localhost),- p和–port设置端口(默认为8000),- o和–open在默认浏览器中打开网站,- S和–https使用HTTPS。
gatsby build 编译应用程序并为部署做准备,可选择使用–prefix - paths在设置pathPrefix后构建带有前缀链接路径的网站,–no - uglify构建不压缩JavaScript捆绑包的网站(用于调试),–open - tracing - config - file启用使用OpenTracing兼容的配置文件。
gatsby serve 为测试提供生产构建服务,可选择使用 - H和–host设置主机(默认为localhost),- p和–port设置端口(默认为9000),- o和–open在默认浏览器中打开网站,–prefix - paths提供带有前缀链接路径的网站(如果使用pathPrefix构建)。
gatsby info 获取有用的环境信息,用于在https://github.com/gatsbyjs/gatsby/issues报告问题,可选择使用 - C和–clipboard自动将环境信息复制到剪贴板。
gatsby clean 删除Gatsby的.cache和public目录。
11.3 快速启动命令

使用博客starter创建新的Gatsby网站:

$ gatsby new my-gatsby-blog-name \
  https://github.com/gatsbyjs/gatsby-starter-blog
$ cd my-gatsby-blog-name
$ gatsby develop

此时,网站将在https://localhost:8000运行,你可以在https://localhost:8000/___graphql上试验查询数据。

11.4 有用的文件定义

在Gatsby项目的根目录应该有以下文件:
- gatsby - config.js :配置Gatsby网站的选项,包括项目标题、描述、插件等元数据。
- gatsby - node.js :实现Gatsby的Node.js API,以自定义和扩展影响构建过程的默认设置。
- gatsby - browser.js :使用Gatsby的浏览器API自定义和扩展影响浏览器的默认设置。
- gatsby - ssr.js :使用Gatsby的服务器端渲染(SSR)API自定义影响服务器端渲染的默认设置。

11.5 Gatsby CLI详细命令
  • gatsby new :不带任何参数运行时,会启动一个交互式shell,询问一系列问题并为你创建Gatsby网站:
$ gatsby new
What would you like to name the folder where your site will be created?
my-gatsby-site
Will you be using a CMS? (single choice)
  No (or I'll add it later)
  –
  WordPress
  Contentful
  Sanity
  DatoCMS
  Shopify
Would you like to install a styling system? (single choice)
  No (or I'll add it later)
  –
  CSS Modules/PostCSS
  styled-components
  Emotion
  Sass
  Theme UI
Would you like to install additional features with other plugins? (multiple choice)
  ◯ Add the Google Analytics tracking script
  ◯ Add responsive images
  ◯ Add page meta tags with React Helmet
  ◯ Add an automatic sitemap
  ◯ Enable offline functionality
  ◯ Generate a manifest file
  ◯ Add Markdown support (without MDX)
  ◯ Add Markdown and MDX support

也可以通过提供一到两个参数,基于starter创建Gatsby网站,不会提示你进行自定义设置:

$ gatsby new [site-name [starter-url]]

综上所述,Gatsby通过Webpack实现了高效的代码分割和预取,结合强大的CLI工具,为开发者提供了便捷的网站构建和优化方案。开发者可以深入了解这些内部机制,为Gatsby项目的开发和优化做出贡献。

Gatsby构建与优化全解析

12. 核心文件作用总结
文件 作用
production - app.js Webpack入口点,负责导航和页面加载,依赖async - requires.js实现组件动态导入
async - requires.js 导出components对象,映射ComponentChunkNames到导入组件文件的函数,还包含data函数用于动态导入data.json
webpack.stats.json 映射chunk groups到依赖的chunk asset names
chunk - map.json 映射每个chunk group到组件的核心块,为JavaScript和CSS资产生成单个组件块
static - entry.js 加载webpack.stats.json和chunk - map.json,构建当前页面的 <link> <script> 元素,处理块的引用和预取
13. 构建流程总结

以下是Gatsby构建的主要流程,使用mermaid流程图展示:

graph LR
    classDef startend fill:#F5EBFF,stroke:#BE8FED,stroke-width:2px
    classDef process fill:#E5F6FF,stroke:#73A6FF,stroke-width:2px

    A([开始]):::startend --> B(Webpack编译):::process
    B --> C(生成捆绑包):::process
    C --> D(生成async - requires.js):::process
    D --> E(生成webpack.stats.json和chunk - map.json):::process
    E --> F(生成HTML页面):::process
    F --> G(注入块映射信息):::process
    G --> H(加载页面资源):::process
    H --> I(预取资源):::process
    I --> J([结束]):::startend
14. 代码分割和预取的优势
  • 性能优化 :代码分割将大的代码块拆分成小的、按需加载的模块,减少了初始加载时间。预取功能在后台提前加载未来可能需要的资源,当用户导航到其他页面时,可以实现即时加载,提高了用户体验。
  • 缓存命中率提升 :将不常更新的库(如React)单独打包成framework - [contenthash].js,可提高缓存命中率,减少不必要的重复下载。
  • 资源管理 :通过将每个页面的资源单独打包,避免了在加载一个页面时加载其他页面的不必要资源,提高了资源利用效率。
15. 开发建议
  • 合理使用代码分割 :根据页面的实际情况,合理使用Webpack的动态分割功能,将不同页面或功能模块的代码进行分割,避免一次性加载过多代码。
  • 预取策略优化 :根据用户的行为习惯和页面的访问频率,优化预取策略。例如,对于热门页面或用户经常访问的页面,可以提前预取相关资源。
  • 关注文件命名和映射 :理解Gatsby对文件命名和块映射的机制,确保在开发过程中能够正确引用和管理资源。
  • 利用CLI工具 :熟练掌握Gatsby CLI的各种命令,如创建项目、启动开发服务器、构建和部署等,提高开发效率。
16. 未来发展方向

随着Web技术的不断发展,Gatsby也在不断演进。未来,Gatsby可能会在以下方面进行改进和优化:
- 更智能的代码分割和预取 :结合机器学习和用户行为分析,实现更智能的代码分割和预取策略,进一步提高性能和用户体验。
- 更好的跨平台支持 :支持更多的平台和设备,如移动应用、桌面应用等,扩大Gatsby的应用范围。
- 与更多技术的集成 :与更多的前端技术和后端服务进行集成,如微服务、容器化等,提供更强大的功能和扩展性。

17. 总结

Gatsby是一个强大的静态网站生成器,通过Webpack实现了高效的代码分割和预取,结合功能丰富的CLI工具,为开发者提供了便捷的网站构建和优化方案。通过深入了解Gatsby的内部机制,如捆绑包的生成、代码分割和预取的实现、块与资产的映射等,开发者可以更好地利用这些特性,提高网站的性能和用户体验。同时,开发者也可以根据自己的需求和经验,为Gatsby的发展做出贡献,推动其不断进步和完善。

在实际开发中,开发者可以按照以下步骤进行操作:
1. 使用Gatsby CLI创建项目,根据需求选择合适的starter。
2. 在开发过程中,合理使用代码分割和预取功能,优化资源加载。
3. 利用Gatsby的各种API和插件,如Node.js API、Browser API、SSR API等,自定义和扩展网站的功能。
4. 在构建和部署阶段,使用Gatsby CLI的相关命令,确保网站的顺利发布。

通过以上步骤和方法,开发者可以充分发挥Gatsby的优势,构建出高性能、易维护的网站。

内容概要:本文介绍了一个基于冠豪猪优化算法(CPO)的无人机三维路径规划项目,利用Python实现了在复杂三维环境中为无人机规划安、高效、低能耗飞行路径的完整解决方案。项目涵盖空间环境建模、无人机动力学约束、路径编码、多目标代价函数设计以及CPO算法的核心实现。通过体素网格建模、动态障碍物处理、路径平滑技术和多约束融合机制,系统能够在高维、密集障碍环境下快速搜索出满足飞行可行性、安能效最优的路径,并支持在线重规划以适应动态环境变化。文中还提供了关键模块的代码示例,包括环境建模、路径评估和CPO优化流程。; 适合人群:具备一定Python编程基础和优化算法基础知识,从事无人机、智能机器人、路径规划或智能优化算法研究的相关科研人员工程技术人员,尤其适合研究生及有一定工作经验的研发工程师。; 使用场景及目标:①应用于复杂三维环境下的无人机自主导航避障;②研究智能优化算法(如CPO)在路径规划中的实际部署性能优化;③实现多目标(路径最短、能耗最低、安性最高)耦合条件下的工程化路径求解;④构建可扩展的智能无人系统决策框架。; 阅读建议:建议结合文中模型架构代码示例进行实践运行,重点关注目标函数设计、CPO算法改进策略约束处理机制,宜在仿真环境中测试不同场景以深入理解算法行为系统鲁棒性。
在科技快速演进的时代背景下,移动终端性能持续提升,用户对移动应用的功能需求日益增长。增强现实、虚拟现实、机器人导航、自动驾驶辅助、手势识别、物体检测距离测量等前沿技术正成为研究应用的热点。作为支撑这些技术的核心,双目视觉系统通过模仿人类双眼的成像机制,同步获取两路图像数据,并借助图像处理立体匹配算法提取场景深度信息,进而生成点云并实现三维重建。这一技术体系对提高移动终端的智能化程度及优化人机交互体验具有关键作用。 双目视觉系统需对同步采集的两路视频流进行严格的时间同步空间校正,确保图像在时空维度上精确对齐,这是后续深度计算立体匹配的基础。立体匹配旨在建立两幅图像中对应特征点的关联,通常依赖复杂且高效的计算算法以满足实时处理的要求。点云生成则是将匹配后的特征点转换为三维空间坐标集合,以表征物体的立体结构;其质量直接取决于图像处理效率匹配算法的精度。三维重建基于点云数据,运用计算机图形学方法构建物体或场景的三维模型,该技术在增强现实虚拟现实等领域尤为重要,能够为用户创造高度沉浸的交互环境。 双目视觉技术已广泛应用于多个领域:在增强现实虚拟现实中,它可提升场景的真实感沉浸感;在机器人导航自动驾驶辅助系统中,能实时感知环境并完成距离测量,为路径规划决策提供依据;在手势识别物体检测方面,可精准捕捉用户动作物体位置,推动人机交互设计智能识别系统的发展。此外,结合深度计算点云技术,双目系统在精确距离测量方面展现出显著潜力,能为多样化的应用场景提供可靠数据支持。 综上所述,双目视觉技术在图像处理、深度计算、立体匹配、点云生成及三维重建等环节均扮演着不可或缺的角色。其应用跨越多个科技前沿领域,不仅推动了移动设备智能化的发展,也为丰富交互体验提供了坚实的技术基础。随着相关算法的持续优化硬件性能的不断提升,未来双目视觉技术有望在各类智能系统中实现更广泛、更深层次的应用。 资源来源于网络分享,仅用于学习交流使用,请勿用于商业,如有侵权请联系我删除!
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值