Skip to content

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Manual code-splitting #18689

Closed
manuelJung opened this issue Oct 15, 2019 · 33 comments
Closed

Manual code-splitting #18689

manuelJung opened this issue Oct 15, 2019 · 33 comments
Assignees
Labels
type: feature or enhancement Issue that is not a bug and requests the addition of a new feature or enhancement.

Comments

@manuelJung
Copy link

manuelJung commented Oct 15, 2019

Summary

Currently Gatsby only supports dynamic code-splitting (by pages). But there are situations, where this process cannot cleverly decide what is the optimal way to split code. That happens when you have to decide at gatsby's bootstrap phase what components you need. One example is, when you use a CMS that defines a Component as a "renderer":

// exampe of a cms-entry
const content = [
  {
    component: 'MyCoolWidget',
    props: {
      title: "Hello World"
    }
  }
]

// later
import * as React from 'react'
import * as components from './components'

export default function CMS ({content}) {
  return (
    <>
      {content.map(row => {
        const Component = components[row.component]
        return <Component {...row.props} />
      })}
    </>
  )
}

The problem here is, that all possible components gets included into the bundle even if they are not used. The Gatsby code-splitting process cannot decide which components are used and which not (Yes, thats a very specific example but there are many more that basically have to deal with the same problem; I used this example because it's easy to understand). That's not a problem, when you have a static file-structure. But as soon as you have to decide at runtime (or at bootstrap-phase in a gatsby context) which components you want to use you have a problem. Code-Splitting does not work any longer

There are solutions to this: react-loadable and loadable-components are designed exactly for this problem. But: they do not work properly with gatsby. So I think it's time for a more gatsby-ish solution for this problem. We could use the exact same mechanism that we use for page-based code-splitting:

Basic example

// gatsby-node.js

exports.createPages = async ({actions}) => {
  actions.createPage({
    path: '/my-cms-component',
    component: path.resolve(__dirname, 'src/theme/templates/cms.js'),
    context: {cmsIdentifier: 'abc'},
    widgets: {
      MyCoolWidget: path.resolve(__dirname, 'src/theme/widgets/MyCoolWidget.js'),
    }
  })
}

// src/theme/templates/cms.js

import * as React from 'react'
import { graphql } from "gatsby"

export default function CMS ({data, widgets}) {
  return (
    <>
      {data.cms.content.map(row => {
        const Component = widgets[row.component]
        return <Component {...row.props} />
      })}
    </>
  )
}

export const query = graphql`
  query($cmsIdentifier: String!) {
    cms (cmsIdentifier: {eq: $cmsIdentifier}){
      content
    }
  }
`

In the above example I add a property "widgets" to the createPage action. Then gatsby resolves these widgets the same way as the components gets resolved and injects these Widgets as props to the page. That way no unnecessary code can be loaded and you get all the cool stuff that gatsby gives you be default, like prefetching and code-splitting (at a widget-level). Some coole side-effect of this approach is, that page-queries could technically also be used inside widgets.

I already created this feature in a fork of mine and it works really smoothly. It took only 2 hours to implement since the whole data-pipeline already exists. I just had to process the widgets the same way the page.component gets processed.

So my question is: Is this something gatsby wants to support? I do not think this feature is something a little blog needs, but for big projects this can be a really badass feature (we pushed our performance from 75 lighthouse points to 93). If so, what do you think about the above implementation? Should I change something before I make a pull-request?

Motivation

My company has really big webshop with over 1000 cms pages and over 400 000 products. I created a similar setup like gatsby (static rendering...) but now we want to move to gatsby because of the better community. We are really happy with gatsby but the above problem is really annoying. By implementing this feature we were able to precisely split our components for our needs and pushed our lighthouse performance by nearly 20 points.

This problem was originally discussed in #5995 and event @KyleAMathews said that this is something gatsby plans to support. By then nothing happens so here I come with a suggestion for an implementation

@pieh
Copy link
Contributor

pieh commented Oct 15, 2019

This is awesome!

In the above example I add a property "widgets" to the createPage action. Then gatsby resolves these widgets the same way as the components gets resolved and injects these Widgets as props to the page. That way no unnecessary code can be loaded and you get all the cool stuff that gatsby gives you be default, like prefetching and code-splitting (at a widget-level). Some coole side-effect of this approach is, that page-queries could technically also be used inside widgets.

Ok, so this to me is problematic part, because you would need to know what "widgets" are needed to render the page in createPages gatsby node hook. With your setup (content.component stating what component is needed) this is probably not a deal breaker, but in general in createPages we should query only minimal amount of information to create a page (so pick page template, and pass minimal amount of context required to query detailed data later in page query).

I think that the data pipeline part is on point, and we need a way for our loader to load additional resources for a page that will work in SSR properly. Just the part that determines what those resources are is something that needs more thought.

My idea here is to implement this inside data layer. When you query:

query($cmsIdentifier: String!) {
    cms (cmsIdentifier: {eq: $cmsIdentifier}){
      content
    }
  }

the content resolver could look into component field, map them to component file, and add this component file as "dependency" for given page. Ideally this would mean that you would get component in query result. There's a lot of question about details of this and how would user specify mappings etc. Also not sure how feasible implementing something like this is? But this is discussion worth having before jumping in on implementing public API that we would have to stick with for a long time.

We also should think about other cases that something like this might be useful other than just this use case. I was thinking about few examples:

  • MDX faces similar challenge with putting too much components in main bundle, and in case of MDX it would be pretty difficult to know those components (with your widget API idea) in createPages.
  • We could use same additional loading to fetch critical (above the fold) images before doing page transition

So my question is: Is this something gatsby wants to support? I do not think this feature is something a little blog needs, but for big projects this can be a really badass feature (we pushed our performance from 75 lighthouse points to 93). If so, what do you think about the above implementation? Should I change something before I make a pull-request?

Yes, we do want to support use cases like this, but we also need to be smart about how we implement this. So there will be a lot of discussion here. It would also be beneficial to create RFC after initial discussion here, to make it a more formal proposal.

@universse
Copy link
Contributor

universse commented Oct 16, 2019

This reminds me of the F8 2019: Building the New Facebook.com with React, GraphQL and Relay @22:00 talk. Not sure how much of it is relevant to Gatsby.

image

@manuelJung
Copy link
Author

manuelJung commented Oct 16, 2019

@pieh You are right. The createPages hook should be as clean and small as possible. But somewhere you have to calculate your needed widgets. So I ended up to create a custom field extension to calculate my widgets:

// gatsby-node.js

exports.createSchemaCustomization = ({actions}) => {
  ...
  // generates dict for used widgets -> { WidgetA: 'path/to/WidggetA' } 
  createFieldExtension({
    name: 'StoryComponentPaths',
    extend: () => ({
      resolve: async (source, args, context, info) => {
        if(!source.story) return null
        return source.story.components
          .reduce((p,{name}) => {
            p[name] = path.resolve(__dirname, `src/storybook/components/${name}.js`)
            return p
          }, {})
      }
    })
  })
  ...
  createTypes(`
    type Page implements Node {
      ...
      storyComponentPaths: JSON @StoryComponentPaths
    }
  `)
} 

exports.createPages = async ({actions, grapqhl}) => {
  const gq = await graphql(`{
    pages:allPage {
      nodes {
        urlKey
        storyComponentPaths
      }
    }
  }`)

  gq.data.pages.nodes.forEach(page => {
    actions.createPage({
      path: `/page/${page.urlKey}/`,
      component: path.resolve(__dirname, 'src/theme/templates/Page.js'),
      context: {urlKey: page.urlKey},
      widgets: page.storyComponentPaths
    })
  })
}

I think something similar should work with MDX too. You could create a custom field extension that does some static analysis in the mdx content. there you could read all your dependencies and format them in a way you need. That ways your createPages will be clean and small

I think that the data pipeline part is on point, and we need a way for our loader to load additional resources for a page that will work in SSR properly. Just the part that determines what those resources are is something that needs more thought.

I already created this feature in my fork of gatsby. The features are:

  • new widgets key in actions.createPage
  • creating custom webpack-chunk-names for each prefix: widget-src-widgets-widgeta-js-[hash].js
  • adding these chunk names to public/chunk-map.json and to the page-data.json of each route
  • preloading widgets on hover (when the page-data.json is prefetched)
  • create preload links and regular links in initial static html (for ssr)

Basically the exact same process that a page-component has. If I'm missing something feel free to point it out. The only thing i'm not really familiar with is the aggressive code-splitting process. Maybe here someone would help, that deeply knows this process

@pieh
Copy link
Contributor

pieh commented Oct 17, 2019

@universse Yup, not gonna lie - I was inspired by that and wanted to do something like this ever since I saw that talk :)

@manuelJung
My idea was that you wouldn't have to define widgets in createPage at all.

I will be doing some pseudocode examples do illustrate what I had in mind:

In your gatsby-node -> createPages you would continue to only care about minimal data required to be able to query things for a page so:

exports.createPages = async ({actions, grapqhl}) => {
  const gq = await graphql(`{
    pages:allPage {
      nodes {
        urlKey
-       storyComponentPaths
      }
    }
  }`)

  gq.data.pages.nodes.forEach(page => {
    actions.createPage({
      path: `/page/${page.urlKey}/`,
      component: path.resolve(__dirname, 'src/theme/templates/Page.js'),
      context: {urlKey: page.urlKey},
-     widgets: page.storyComponentPaths
    })
  })
}

The "magic" would happen when executing page queries.

Consider this content data:

[
  {
    "component": "MyCoolWidget",
    "props": {
      "title": "Hello World"
    }
  }
]

Let's assume graphql type name would be CMSBlock for entries in the content array.

exports.createSchemaCustomization = ({actions, schema}) => {
  // create mapping of string component identifier to some concrete component implementation in the project:
  someNewAPIThatRegistersGraphQLComponent('MyCoolWidget', require.resolve(`./src/storybook/components/MyCoolWidget`))

  createTypes(`
    type CMSBlock {
      props: JSON
      component: String @GraphQLComponent
      # this is interesting part, using this yet to be implemented directive, gatsby during query execution would add dependency on components for exact pages where they are used on and on the browser side of things we would automatically convert string to actual react component
    }
  `)
}

So in the page template user could do:

export default ({ data }) => {
  return <div>
    {data.page.content.map(({ Component, props }) => {
        // using Component that came as "query result" directly as component
        return <Component {...props} />
      }
    }
  </div>
}

export const q = graphql`
  query pageQuery($urlKey: String!) {
     page(urlKey: { eq: $urlKey }) {
       content {
         Component: component
         props
       }
     }
  }
`

What @GraphQLComponent extension would do is:

  • add component identifier as dependencies for page that executed the query
  • instruct loader to convert component identifier into component implementation

With this everything would be lazy, you don't need to know what components will be used for page during createPages. This is definitely trickier to implement, but I feel like is much nicer API to use.

This also align nicer with MDX use case better, because we wouldn't need to do extra static analisys to figure out components/widgets during createPages.

What are your thoughts?

@manuelJung
Copy link
Author

manuelJung commented Oct 17, 2019

ok, i understand. That's a really cool api! but how would you solve ssr, like creating preload links and injecting the used scripts into the DOM. All of this is done within the createPage hook. Also the code-splitting could be a tricky thing: Webpack analyses the code and creates shared chunks (1.[hash].js...) different pages can use. This can be done, because you have a single entry (createPage) for your code-splitting. But as soon as you add another totally different entry (createSchemaCustomization) it can be a really hard task (maybe impossible) to create shared chunks.
But basically I'm with you. Enabling to dynamically load components from within graphql would be a game changer and could lead to really cool new patterns. But to implement this idea can take months or even longer to have a stable api. The "widgets api" could be done within hours since everything is already here.

Can we support both? Also you could basically do the same thing in both apis, both have their strength and weaknesses. Your idea would be perfect for plugins but can be quite complex for beginners, whereas my idea is easy to use, but not so plugin-friendly as yours. Let the programmer decide, what fits best for his needs

@pieh
Copy link
Contributor

pieh commented Oct 17, 2019

ok, i understand. That's a really cool api! but how would you solve ssr, like creating preload links and injecting the used scripts into the DOM.

Under the hood it would be pretty similar to what you already implemented - so page-data for pages would contain list of additional modules (components in this case) that both loader.js (in browser) and static-entry.js (for ssr) would need to handle.

Also the code-splitting could be a tricky thing: Webpack analyses the code and creates shared chunks (1.[hash].js...) different pages can use. This can be done, because you have a single entry (createPage) for your code-splitting. But as soon as you add another totally different entry (createSchemaCustomization) it can be a really hard task (maybe impossible) to create shared chunks.

I don't think there would be any difference in terms of webpack setup for both of our ideas - in the end we would end up with list of additional components that each page depend on and need to figure out what's best strategy for webpack setup for this - should we let webpack do some automatic splitting with splitChunks, should we force separate chunks for each component? Those questions are common for both approaches.

But to implement this idea can take months or even longer to have a stable api. The "widgets api" could be done within hours since everything is already here.

I would argue that implementation part wouldn't take that long (similar to implementation of widgets that you did). But I'm with you about figuring out stable API (and this includes both approaches). Your implementation does add new public APIs and adding those is not something that should be rushed to quickly solve particular use case. This is why I mentioned RFC process, because API design should be scrutinized by a lot of people, especially ones like these that could impact a lot of DX flows (which could impact future API decisions).

Can we support both? Also you could basically do the same thing in both apis, both have their strength and weaknesses. Your idea would be perfect for plugins but can be quite complex for beginners, whereas my idea is easy to use, but not so plugin-friendly as yours. Let the programmer decide, what fits best for his needs

In my idea we would essentially need internal APIs that would accomplish similar things as widgets field in page objects. I could see implementation roadmap for this feature that would first implement those APIs, that you could probably utilize in user code, before full graphql component idea is implemented:

exports.createPages = ({ actions }) => {
  actions.createPage({
    path: `/x`,
    component: <page-template-path>
  })

  // make use of internal api - beware that this can stop working without notice
  actions.internal.addModuleToPageDependencies({
    path: `/x`,
    module: <path-to-component>,
    identifier: `MyCoolWidget`,
  })
}

@manuelJung
Copy link
Author

ok. so what are the next steps? Who should create the RFC?

@KyleAMathews
Copy link
Contributor

Awesome to see this discussion! There's a lot of fun things we could do with this. One note is that the API would need to be generic so multiple types of resources could be attached to pages for prefetching (didn't see if that came out clearly in the above discussion).

See my RFC on prefetching critical images for another use case this would satisfy https://github.com/gatsbyjs/rfcs/blob/prefetch-images/text/0000-support-prefetching-images.md

@universse
Copy link
Contributor

Another use case could be loading language bundles. Right now if we query language bundle via page queries, routes of the same language will have their own and potentially duplicated language data passed as props. It would be great if all routes of the same language can share the same bundle.

@manuelJung
Copy link
Author

so should I create an RFC or should someone from the gatsby team do this? (due to the complexity)

@pieh
Copy link
Contributor

pieh commented Nov 2, 2019

Just commenting that I didn't forgot about this. We are looking into other cases where this feature/API could be used:

We need this to figure our requirements and constraints. We need to figure out how those extra resources would be accessed (adding it to page component props won't work ultimately, because at least some of them might end up above page level - so I'm looking into some solution with react context, with Provider wrapping entire application)

so should I create an RFC or should someone from the gatsby team do this? (due to the complexity)

Because of the above, I think I'll be person that will write up RFC for it.

I do think that querying component directly idea will not be part of the rfc (it could be build using that API probably, but this will be out of scope of the initial one)

@gatsbot gatsbot bot added the stale? Issue that may be closed soon due to the original author not responding any more. label Nov 23, 2019
@gatsbot
Copy link

gatsbot bot commented Nov 23, 2019

Hiya!

This issue has gone quiet. Spooky quiet. 👻

We get a lot of issues, so we currently close issues after 30 days of inactivity. It’s been at least 20 days since the last update here.

If we missed this issue or if you want to keep it open, please reply here. You can also add the label "not stale" to keep this issue open!

As a friendly reminder: the best way to see this issue, or any other, fixed is to open a Pull Request. Check out gatsby.dev/contribute for more information about opening PRs, triaging issues, and contributing!

Thanks for being a part of the Gatsby community! 💪💜

@github-actions
Copy link

github-actions bot commented Dec 4, 2019

Hey again!

It’s been 30 days since anything happened on this issue, so our friendly neighborhood robot (that’s me!) is going to close it.
Please keep in mind that I’m only a robot, so if I’ve closed this issue in error, I’m HUMAN_EMOTION_SORRY. Please feel free to reopen this issue or create a new one if you need anything else.
As a friendly reminder: the best way to see this issue, or any other, fixed is to open a Pull Request. Check out gatsby.dev/contribute for more information about opening PRs, triaging issues, and contributing!

Thanks again for being part of the Gatsby community! 💪💜

@github-actions github-actions bot closed this as completed Dec 4, 2019
@vpicone
Copy link
Contributor

vpicone commented Dec 9, 2019

@pieh curious if you have any more insight on "Using this to tie MDX imports to pages instead of main app bundle"

Our theme exports a bunch of components for themed sites to use. When they add additional MDX components, the main bundle balloons up pretty quickly. Would be great for those components to be split up per page.

@TomPridham
Copy link

could this be reopened? integrating with react-loadable and supporting prefetch webpack hints would be great. we have a large search component that is not needed on initial load and would preferably be fetched once everything else was done

@karlsander
Copy link
Contributor

@manuelJung are you still working on this idea / using it? Could you share the work you did in a fork to create a POC? I'm very interested in this for my own work.

Seems like a killer feature for gatsby if it could be supported in a generic way.

@Macil
Copy link

Macil commented Mar 19, 2020

I think a good solution to this could be made by using React.lazy and Suspense, but React doesn't support those yet for server-side rendering. It might make sense to wait on React to make progress in this area before trying to attack this issue. (+1 to re-opening the issue though.)

@manuelJung
Copy link
Author

@karlsander yes ic can share with you. give me a week to setup a clean gatsby repo where i can create a POC. I think it would be best if we can have a zoom-call where i can explain my thoughts behind this

@manuelJung
Copy link
Author

for everyone who is interested: I created a POC of this feature.

@pristas-peter
Copy link

Hi guys, I was inspired by this thread and created a plugin which does the querying of components. The solution is a little bit different than @manuelJung POC without the need to patch anything in gatsby's core.

Would be happy if you test it out and leave feedback.

https://github.com/pristas-peter/gatsby-plugin-graphql-component

@manuelJung
Copy link
Author

@pristas-peter WOW!!! The idea is brilliant. I will check it out and test it in a real-world example with dozend of components.

@pieh pieh reopened this May 11, 2020
@pieh
Copy link
Contributor

pieh commented May 11, 2020

Hey folks, I just want to let you know that work has started on the code-splittable modules added by queries. We are still in API design and exploration phase, but what I'm aiming for right now is something like that:

This register module (so webpack can bundle it) and ties this module to page we execute query for (so it get's loaded in frontend as part of resource loading)
https://github.com/pieh/gatsby/blob/82d6367eeb4fe82aa53e8c0ca9656a5e4e56f199/packages/query-webpack-modules-demo-site/gatsby-node.js#L33-L63

Later on on frontend it get's consumed like this:

https://github.com/pieh/gatsby/blob/82d6367eeb4fe82aa53e8c0ca9656a5e4e56f199/packages/query-webpack-modules-demo-site/src/templates/page.js

( there is getModule function)

Now - this is pretty low-level API. It's not expected for all users to make use of. We are still looking to do GraphQL Components ( awesome plugin btw @pristas-peter! I didn't even know it was doable as a plugin - tho granted you do have a fair share of hacks to make it work :P). Plan is that GraphQL Components will make use of the low-level API internally, so ideally users don't have to use those themselves and this can be nicely abstracted from them.

For the MDX case - we do plan to migrate MDX plugin to make use of those new APIs, but there's quite a bit work ahead of us. My code "works" today but in very limited way (i.e. only page queries are handled, and you better not use if with gatsby develop). It was mostly done as exploration/research effort to check soundness of API and figure out requierments and roadblocks.

@pieh pieh removed the stale? Issue that may be closed soon due to the original author not responding any more. label May 11, 2020
@freiksenet
Copy link
Contributor

@pristas-peter Awesome plugin! One missing part that we planned for this api is being able to pass props to components from the GraphQL resolver (so you can eg create component child for fluid and fixed fields of ImageSharp).

The initialization logic that you do in gatsby-browser will get much easier with so-called "Page Data Processor", which would allow custom initialization logic for page-data fields through GraphQL Directives.

@pristas-peter
Copy link

pristas-peter commented May 11, 2020

Thanks @freiksenet and @pieh. In a bigger scale of things I needed this feature for my gatsby-theme-wordpress-gutenberg plugin, when the components are autogenerated during the build phase (you map a block from content editor to a react component in gatsby and everything is patched together into content component automatically), but were hard to get to from userland.

@freiksenet the props feature is cool, it should not be hard to add support for it, will have a look at it when I am finished with mentioned above, thanks.

@pieh
Copy link
Contributor

pieh commented May 11, 2020

In a bigger scale of things I needed this feature for my gatsby-theme-wordpress-gutenberg plugin, when the components are autogenerated during the build phase (you map a block from content editor to a react component in gatsby and everything is patched together into content component automatically), but were hard to get to from userland.

Yesss!! Page builder is the other "demo" scenario I have for this API we work on (other being MDX) - if you check code links I provided in #18689 (comment) - those actually showcase API in page builder scenario (so I assume Gutenberg case would be very similar)

Few more links to my demo site:
Structured content similuating page builder data:

component field maps directly to components defined in https://github.com/pieh/gatsby/tree/82d6367eeb4fe82aa53e8c0ca9656a5e4e56f199/packages/query-webpack-modules-demo-site/src/components/page-builder (and passing options are props to those components)

Of course it's very simplified and doesn't touch on more complex scenarios (i.e. having image component that would want to run image optimizations and use gatsby-image to display it) - this is case that we are also missing in your plugin right now I think?

@pristas-peter
Copy link

Well, what I am doing is that since every block has its own graphql type (sourced by new wordpress plugin by @TylerBarnes - still working on a support for this (I am also the author of wp-graphql-gutenberg)) you create a fragment in the react component which represents the block of the structured content on the block graphql type and the fragment is automatically included in the auto generated component, so image optimalisations kinda work this way and not as feature of this plugin.

@pieh
Copy link
Contributor

pieh commented May 11, 2020

I will take a look at using wp-graphql-gutenberg in my demo sites (that I use to validate API designs). It's much more real-worldy case than using my somewhat mocked page builder.

Do you use gatsby-source-graphql or new version of gatsby-source-wordpress in your project?

Also is your project public? Maybe I could use yours and not have to build one from scratch 🤔 Alternatively - do you have smaller example sites that use Gutenberg? I see you have example https://github.com/pristas-peter/gatsby-plugin-graphql-component/blob/master/examples/gatsby-plugin-graphql-component-default-example/ but this seems pretty static (you statically register Tester component and query for it)

@pristas-peter
Copy link

Yes, it's open-source, but it it still a WIP, although I have written some docs here: https://gatsbywpgutenberg.netlify.app/features/page-templates/. However I want to get rid of that page templates part and replace it with this queryable component.

Yes, it uses gatsby-source-wordpress (v4), but I have to source some parts myself because of the complicated schema. We are chatting with Tyler to work things out so I can also get rid of that gatsby-source-wordpress-gutenberg, which is also a part of this mini framework, and rely on his extension exclusively.

@TylerBarnes
Copy link
Contributor

fwiw @pristas-peter @pieh I believe I have wp-graphql-gutenberg working in the new WP source plugin now (and as a side effect sped up some parts of the build process by 20x). I should have a release out in the next little while.

@nandorojo
Copy link
Contributor

Hey folks, I just want to let you know that work has started on the code-splittable modules added by queries. We are still in API design and exploration phase, but what I'm aiming for right now is something like that:

@pieh That's so exciting – thanks for the great work. Can't wait to use it.

@pieh
Copy link
Contributor

pieh commented Jun 10, 2020

Hey folks - it was quiet here for some time, but it doesn't mean that there was no work done!

I just opened first PR (in the series) that implements needed low-level APIs to make "data-driven code-splitting" a reality in Gatsby - if you are interested in experimenting with it - go ahead to #24903 (especially "Trying it out" section which mentions canary version of gatsby that you can try out)

@pristas-peter
Copy link

@pieh Thanks, will try to rewrite my gatsby-theme-wordpress-gutenberg with this

@juanferreras
Copy link

juanferreras commented Jun 18, 2020

@pieh Thanks for such an amazing work!

We've tried it out internally and it's working correctly – totally helped with TBT/TTI metrics as it reduces the amount of code that ended up otherwise in app-[hash].js. However we've been suffering of some odd variance on FCP/Speed Index so we'll dive deep into it to understand it better.

@LekoArts LekoArts closed this as completed May 7, 2021
@gatsbyjs gatsbyjs locked and limited conversation to collaborators May 7, 2021
@LekoArts LekoArts removed the not stale label May 7, 2021

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

Labels
type: feature or enhancement Issue that is not a bug and requests the addition of a new feature or enhancement.
Projects
None yet
Development

No branches or pull requests