在 Nuxt 中加载 JSON 时如何从摇树和代码拆分中受益?

Posted

技术标签:

【中文标题】在 Nuxt 中加载 JSON 时如何从摇树和代码拆分中受益?【英文标题】:How to benefit from tree-shaking and code-splitting while loading JSON in Nuxt? 【发布时间】:2022-01-22 12:39:34 【问题描述】:

我有一个 nuxt 应用程序,其中有很多帖子。我最近重构了这个项目,我不会再generate所有帖子了,因为这样做会花费太多时间。

相反,我有一个页面,可以通过 url 查询获取匹配的帖子内容: www.mypage.com/posts/?post=my-post-slug

因为内容位于静态 json 文件中,例如:

/static/data/posts/my-post-slug.json
/static/data/posts/my-post-slug_2.json
/static/data/posts/my-post-slug_3.json
/static/data/posts/my-post-slug_n.json

我看了帖子https://github.com/nuxt/nuxt.js/issues/123 关于如何以最佳方式加载 json。

我决定在 fetch() 钩子中做这样的事情:

// ... simplified code
async fetch() 
  let postSlug = this.$route.query.post
  
  const post = this.$axios
    .get(`/posts/posts.de.$postSlug.json`)
    .then((data) => 
      return data?.data
    )
    .catch((error) => 
      console.error('error: ', error)
      const code = parseInt(error.response && error.response.status)
      if (code === 404) 
        this.$nuxt.error( statusCode: 404, message: 'Post not found' )
      
    )


  this.activePost = post?.items?.[0] || false

如前所述,我不会生成实际的帖子,但会在我的 sitemap.xml 中生成所有帖子网址。

在analyze 模式下运行生成时,我现在有一个 huuuuge 包大小 (app.js),但我不明白为什么... -> 查看附件图片。 (注意:app.js 有 34MB 的荒谬大小!!!!!!????)

    我不明白为什么我所有的 post json 都出现在 bundle 的 static 和 dist 部分??? 我完全不明白他们为什么会出现在那里。我希望它们仅位于静态文件夹中,但不包含在应用程序包中。 (您可以看到其中包含 events.bundle.de.json 之类的文件。例如,我需要这些文件来获取所有帖子的列表。我也仅在我的 fetch 挂钩中执行此操作。

如果有人能指出为什么包含这些文件(两次),我会非常高兴!

【问题讨论】:

我意识到当我删除 dist 文件夹时,我最终得到了一半的大小。那里的数据是我重构之前的一些剩余数据。我还意识到,无论我将什么 json 放入静态文件夹,它总是会出现在 app.js 中——即使它不需要/导入或以任何其他方式使用......(这对我来说没有意义吗? !?) 【参考方案1】:

这些文件没有“两次”包含。你需要它们,所以你在本地的 static 文件夹中拥有它们。

同时,如果您不希望/不需要将它们公开暴露并受益于代码拆分得益于 Webpack,您可能应该将它们放在您的 src 目录中,正如您链接的帖子中所解释的那样(即使是 2017 年的也仍然有效!)。

在这里,由于您正在进行 axios 调用并使用 target: 'static',即使没有 JS,它也会将您的整个工作捆绑在一起,并且它会提前完成。所以,为了拥有所有的可能性,我认为它包含了所有的最终捆绑包。

如果您只想加载需要的内容而不发送大的static 目录,您应该动态导入它们。您可以使用dynamic import:通过传递实际的postSlug 仅加载所需的JSON。

PS:风格方面,更喜欢使用async/await.then 已弃用),也可能使用$axios.$get

【讨论】:

非常感谢您的意见。我可以部分理解你所说的,但有些事情对我来说没有意义。与此同时,我已经按照您的建议进行了操作:我按照此处 (github.com/nuxt/nuxt.js/issues/123#issuecomment-272246782) 和您的回答中的建议动态导入数据。这可行,但是当我生成应用程序时,我仍然会得到一个包含所有 events.jsons 的 app.js,尽管我将它们移出 static 文件夹。 我不明白的是:如果我不生成实际的事件页面和帖子页面,但只想在客户端上加载这些数据(有点懒惰,而不是完全静态不再),那么为什么这甚至出现在我的 app.js 中。 app.js 应该只包含一些全局数据和一些页面,这应该足以运行应用程序等 - 只有在我想要导入 jsons 之后,绝对不必出现在包中......?我可能仍然误解了一些事情...... 看来 webpack 只是贪婪地抓取 json 文件并将其放入我的包中。如果我在我的项目根/random-folder/folder-containing-jsons/... 中创建一个随机文件夹并将我所有的 json 放入该文件夹中,那么整个数据仍然出现在我捆绑的 app.js 中......我想我需要特别告诉 webpack 不要捆绑那个文件夹。 (但是如何?!?)要在客户端上实际导入它,我想我必须将它放回静态文件夹中...... @Merc 最后,webpack 分析器会给你所有的可能性。它将显示所有这些,因为它们可以在某个时候导入,webpack 分析器在显示所有块时不是动态的(那里没有运行时延迟加载)。要检查这一点,您更适合加载您的应用程序并跟踪加载的内容,这要归功于您的 devtools 的 Network 选项卡。【参考方案2】:

虽然我认为@kissu 的回答是在标题中回答了我的问题,但这并不是我的问题的解决方案。为了完整起见,我将发布经过长时间调试后发现的内容。我仍然不太明白为什么会发生这种情况,但也许有人也可以对此发表评论:

在我的 nuxt 项目中,我使用了一个实用程序文件 getData.js,我将其中的一个函数 getDataServer 导入到我的一个 vuex 存储模块中。

// vuex store module: store/data.js
import  getPreviewData  from '~/api/getData'

代码如下所示:

// getData.js

// Get static JSON file (e.g. basic.de.json or posts.de.1.json)
export function getDataServer(fileProps) 
  return require(`~/$fileProps.path$fileProps.name.$fileProps.lang$
    fileProps.page ? `.$fileProps.page` : ''
  .json`)

只有通过导入,甚至不通过执行该功能,webpack 才会将它可以在我的根文件夹中找到的每个 .json 文件捆绑到我的 app.js 中。

这就是为什么我的包中出现了一个 dist 文件夹,如果没有删除的话。 (我在最初的问题中谈到了这一点,其中包含了两次内容)。

我什至创建了额外的文件夹和 .json 文件来查看,无论如何它们都被捆绑了。

只有在从我的项目中删除 getData.js 之后,我的包才变得干净。

我了解使用require 命令,webpack 不能 tree-shake 东西,所以我本以为某些代码拆分功能不起作用,但我没想到的是这段代码会 自动获取我文件夹中的每个.json...

有谁知道为什么导入该函数会以充当所有 .json 通配符的方式执行它? 对我来说仍然没有任何意义。

感谢和欢呼。

【讨论】:

require 是在 Node.js 中导入东西的旧方法。 import 在 ES 模块和 v2 以上的 Webpack 结合使用时启用 tree-shaking。如果你需要一个包,你会加载它的 100%,即使你只使用一小段代码。如果你 import properly 和 ES 模块,你可以只选择正在使用的代码,感谢 Webpack/Rollup/etc 对导出的代码进行了一些分析。摇树和代码拆分是相同的“import 俱乐部福利”的一部分。在现代应用程序中,您应该放弃 require 以支持 import 是的,我知道这一点。谢谢你再次总结。我不明白的是:我从未执行过使用require 的函数,它也不知道require 是哪个文件,因为实际路径取决于某些函数参数(如路径和名称)。那么,您如何解释这样一个事实,即仅通过导入使用 require 的函数,我最终会得到一个捆绑包,其中需要所有 jsons 并因此捆绑在一起?这对我来说仍然没有意义...... 我猜是因为它不知道它在使用什么,并且没有分析实际导出的代码,它只是将它全部导入。 require 本质上是相当愚蠢的,同步代码,带来整个代码等等......不是专家,但我只知道现在,你可能永远不应该再使用 require,特别是因为 Node 环境现在也支持它(在我的意思是服务器)。

以上是关于在 Nuxt 中加载 JSON 时如何从摇树和代码拆分中受益?的主要内容,如果未能解决你的问题,请参考以下文章

Vuetify,Nuxt,在开发模式下使用摇树

如何使用 JSON API 在滚动时在 recyclerview 中加载更多数据

在 Python 中加载 JSON 代码的问题

如何在 appsettings.json 中加载多态对象

如何在 Javascript 中加载本地 JSON 文件

如何在主方法 Flutter 中加载 json?