adobe / aem-spa-project-archetype

Maven Archetype for creating new AEM SPA projects
Apache License 2.0
61 stars 32 forks source link

React Code splitting #83

Closed GR1ML0CK closed 4 years ago

GR1ML0CK commented 5 years ago

Based on going through the Getting started project here, it seems like the approach of using aem-clientlib-generator does not allow for utilizing code splitting for react in AEM. I posted an issue about this on that project and it was suggested that i post the question here.

https://github.com/Adobe-Marketing-Cloud/aem-guides-wknd-events/issues/52

ramakrij commented 5 years ago

Any update on this? Ideally I would like to see code splitting working with acs versioned clientlibs. Is there any work around at the moment others have tried successfully?

GR1ML0CK commented 5 years ago

I did end up coming up with a solution that works pretty with create-react-app and versioned clientlibs. When I get a chance I'll throw an example up on github and share a link.

pfauchere commented 5 years ago

Hi, we didn't have the time to explore this topic. Your contribution is welcomed!

GR1ML0CK commented 5 years ago

I'll try to get something up. The main thing for code splitting with cra is that you need to only bundle the main..js and the vendor..js with the clientlibs plug in. These are the main entry points for all your chunks which will have dynamically generated name so you will need to write a script to move these file to a location relative to the clientlib you create, so the pathing that webpack generates. I think 2 extra things we had to do was use sling mappings so that the path to the clientlibs worked for the cra generated paths (e.g /static/*/) and there's a config that needs to be added so the vendor js is output with a predictable name, because by default it will be a random number (I forget what it is off the top of my head). After this the acs versioning only needs applied to the main js clientlib as the chunks will have hashes already generated from webpack

ramakrij commented 5 years ago

Got it. So use the acs versioned clientlibs hash for main and vendor.js. Pack these 2 in the clientlibs. Other chunks are stored under a relative path with webpack generated hashes. Use them as is. 👍

samuelmeuli commented 5 years ago

When building an app with CRA, there are three scripts included in build/index.html. Example:

<script>/* Content of runtime~main.a8a9905a.js */</script>
<script src="/static/js/2.b41502e9.chunk.js"></script>
<script src="/static/js/main.28647029.chunk.js"></script>

According to https://facebook.github.io/create-react-app/docs/production-build,

Unless I'm mistaken, there currently doesn't seem to be a way to identify which one of the [number].[hash].chunk.js needs to be included in the HTML file (see https://github.com/facebook/create-react-app/issues/5306#issuecomment-427940671). Have you been able to find a way to work around that, @GR1ML0CK?

GR1ML0CK commented 5 years ago

You can match the main js files via globbing (e.g. "/main.*.js". The vendor file gets generated with a random name though. There is a way to tell cra to generate it with a non random name. I'll need to look at my project to remember how we did that

GR1ML0CK commented 5 years ago

We had to use customize-cra to get the bundle name for the vendor code renamed. here is the code that should make this all work

// clientlib.config.js
  {
      name: "js/main",
      categories: ["foobar-main"],
      jsProcessor: ["min:gcc"],
      serializationFormat: "xml",
      allowProxy: true,
      assets: {
        js: [
          "build/static/js/vendors~main.*.js",
          "build/static/js/main.*.js"
        ]
      }
    },
// config-overrides.js (using customize-cra)
const rewireWebpack = config => {

  // this forces CRA's webpack config to output named chuck, so you get "vendor.[hash].js"
  config.optimization.splitChunks = { chunks: "all", name: true };

  // This disables chunking runtime~main.js. The code for this file will be included in main.js
  config.optimization.runtimeChunk = false;
  return config;
};

module.exports = override(rewireWebpack);