2

I have a nuxt-app, where I have a lot of posts. I recently refactored the project and I won't generate all posts anymore, as it is just taking too much time to do that.

Instead I have a page where I would fetch the matching post content via url query: www.mypage.com/posts/?post=my-post-slug

Because the content is lying in static json files, for example in:

/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

I read the post https://github.com/nuxt/nuxt.js/issues/123 about how to load json in the best way.

I decided to do something like this in the fetch() hook:

// ... 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
}

As already said, I do not generate the actual posts, but I generate all post urls in my sitemap.xml.

When running the generate in analyze mode I have now a huuuuge bundle size (app.js), and I can't understand why... -> Check out the attached image. (Note: app.js has a size of 34MB!)

  1. I don't understand why all my post jsons appear in the static and the dist part of the bundle???
  2. I don't understand at all why they appear in there. I want them to just lie in the static folder, but not be included in the app bundle. (you can see that there are files like events.bundle.de.json included. I need those to fetch a list of all posts for example. I do that also within my fetch hook only.

I would be very happy if somebody could point out why those files are included (twice)!

enter image description here

jonrsharpe
  • 115,751
  • 26
  • 228
  • 437
Merc
  • 4,241
  • 8
  • 52
  • 81
  • I realized that when I delete the dist folder I end up with half of the size. The data in there was some leftover from before I refactored. Also I realized that whatever json I put into the static folder, it will always end up in the app.js – even when it is not required/imported or used in any other way... (which does not make sense to me?!?) – Merc Dec 21 '21 at 01:26

2 Answers2

2

Those files are not included "twice". You need them, so you do have them locally in your static folder.

Meanwhile, you should probably put them inside of your src directory if you don't want/need to have them exposed publicly and benefit from code-splitting thanks to Webpack as explained in the post you've linked (which is still valid even if it's a 2017 one!).

Here, since you're making an axios call and using target: 'static', it will bundle your whole thing to work even without JS and it does that ahead of time. So, in order to have all the possibilities, it includes all in the final bundle I think.

If you want to only load what is needed while not shipping a big static directory, you should import them dynamically. You can use a dynamic import: load only the needed JSON by passing the actual postSlug.

PS: style-wise, prefer using async/await (.then is deprecated) and maybe also $axios.$get.

kissu
  • 40,416
  • 14
  • 65
  • 133
  • Thanks a lot for your input. I can partly understand what you say, but some things don't make sense to me. In the meantime I already did what you propose: I import the data dynamically like proposed here (https://github.com/nuxt/nuxt.js/issues/123#issuecomment-272246782) and in your answer. This works but when I generate the app I would still get an app.js that includes all the events.jsons, although I moved them out of the `static` folder. – Merc Dec 21 '21 at 13:29
  • What I don't understand: if I don't generate the actual event- and post-pages, but would like to only load this data on the client (kind of lazy, and not full static anymore), so why is this even showing up in my app.js. The app.js should just include some global data and a few pages, which should be enough to run the app etc. — only after I want to import the jsons, that absolutely don't have to appear in the bundle... I probably still still misunderstand a few things ... – Merc Dec 21 '21 at 13:31
  • It seems that webpack is just grabbing json files in a greedy way and putting it into my bundle. If I create a random folder in my project root `/random-folder/folder-containing-jsons/...` and I put all my jsons into that folder, this whole data is still appearing in my bundled app.js... I think I need to tell webpack specifically not to bundle that folder. (But how?!?) To actually import it on the client I think I would have to put it back into the static folder... – Merc Dec 21 '21 at 14:01
  • @Merc At the end, webpack analyzer will give you all the possibilities. It will display all of them because they can be imported at some point, webpack analyzer is not dynamic when it is displaying all the chunks (no runtime lazy-loading there). To inspect this, you're better suited loading your app and tracking what is loaded thanks to the Network tab of your devtools. – kissu Dec 21 '21 at 14:53
2

Although I think @kissu's answer is answering my question in the title, it was not the solution for my problem. For the sake of completeness I will post what I found out after long and many hours of debugging. I still don't quite understand why this even happened, but maybe someone could comment on that as well:

In my nuxt-project I am using a utility file getData.js of which I import a function getDataServer into one of my vuex store modules.

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

The code looks like this:

// 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`)
}

Only by importing and not even by executing that function webpack would bundle EVERY .json file it can find in my root folder into my app.js.

That is why I had a dist folder appearing in my bundle, if not deleted. (The point I talk about in my original question, where I have things included twice).

I even created additional folders and .json files to see, and they were all bundled no matter what.

Only after removing the getData.js from my project my bundle became clean.

I understand that with the require command, webpack cannot tree-shake things, so I would have expected that some code-splitting features would not work, but what I did not expect was that this bit of code would automatically get every .json in my folder...

Does anyone know why importing that function would execute it in a way that acts as a wildcard for all .jsons? To me it still does not make any sense.

halfer
  • 19,824
  • 17
  • 99
  • 186
Merc
  • 4,241
  • 8
  • 52
  • 81
  • 1
    `require` is the old of importing things in Node. `import` enables tree-shaking when used in conjonction of ES modules and Webpack above v2. If you require a package, you'll load 100% of it, even if you only use a small piece of code. While if you [import properly](https://stackoverflow.com/a/70394716/8816585) and ES module, you can pick only the code that is being used thanks for Webpack/Rollup/etc doing some analysis on the exported code upfront. Tree-shaking and code-splitting are part of the same "`import` club benefits". In modern app, you should just ditch `require` in favor of `import`. – kissu Dec 22 '21 at 10:20
  • Yes I was aware of that. Thanks for summing it up again. What I don't understand: I did never execute the function that uses `require` and it would also not know which file to `require` as the actual path is dependent on some function params (like path and name). So how would you explain the fact that just by importing the function that uses `require` I would end up with a bundle in which ALL jsons around were required and therefore bundled? That does still not make sense to me... – Merc Dec 22 '21 at 16:52
  • I guess that because it doesn't know what it is using, and that there is no analysis of the actual exported code, it just imports it all. `require` is pretty stupid by nature, sync code, brings the whole code etc... Not an expert but I just know that nowadays, you should probably never use `require` anymore, especially since Node environments now support it too (on the server I mean). – kissu Dec 22 '21 at 16:55