single-spa / single-spa.js.org

https://single-spa.js.org/
108 stars 234 forks source link

Using single-spa with webpack hashing? #564

Open karfau opened 2 years ago

karfau commented 2 years ago

The recommended setup suggests to not use webpack caching features, since it would be easier to add a commit hash at deployment time.

Since the suggested method will produce new URLs for bundles even though their content didn't change, I would love to know what exactly is required to let webpack create bundles with consistent hashes in the bundle file names.

We are using a monorepo with lerna (currently still v4).

I assume we would need to generate something like an import map for each package the "resolves" the filename with the hash and merge those import maps of the required packages for each root config, but I'm not sure how to access the hash value in the webpack build to create/dump such an import map per package.

Another approach might of course be to calculate and add the hashes to the files after webpack is done, including modifying the import map accordingly.

Any other ideas, or showcases of how it can be done?

karfau commented 2 years ago

I solved this by adding https://github.com/webdeveric/webpack-assets-manifest to our webpack config and reading that file in packages that depend on other packages to create the import map.

There are two main caveats to that approach:

  1. If you also need to use the CopyWebpackPlugin, the hashes for the assets is only available when webpack is complete, which means I need to build root config packages twice, once to build the assets manifest, second time to include the correct file names into the ejs template.
  2. It only works when the packages correctly depend on each other and are build in that order. In our case we build everything in parallel in development mode, so we can not use chunk hashes in that case. Which makes the whole webpack configs more complicated. We hope to switch to a setup in which nx takes care of watching, so we can always have hashes.

Not able to share any code.

filoxo commented 1 year ago

The recommended setup suggests to not use webpack caching features, since it would be easier to add a commit hash at deployment time.

That is not the reason why we recommend this. Webpack chunking isn't compatible with non-AMD modules, and our webpack config is configured to output System module format to interop best with SystemJS. The hashes aren't related.

I would love to know what exactly is required to let webpack create bundles with consistent hashes in the bundle file names.

This configuration isn't dependent on webpack optimizations, so it should be as noted in webpack's docs: https://webpack.js.org/configuration/output/#outputfilename

I assume we would need to generate something like an import map for each package the "resolves" the filename with the hash and merge those import maps of the required packages for each root config, but I'm not sure how to access the hash value in the webpack build to create/dump such an import map per package.

I don't think an entire import map is necessary here... unless you want some advanced SystemJS features like subpath imports. You just need the output filename of the entry file, and that is what you'd use to update your import map. Then, its just a matter of hitting your import-map-deployer endpoint with that updated value.

which means I need to build root config packages twice, once to build the assets manifest, second time to include the correct file names into the ejs template.

Ah, I see. By externalizing the import map in some fashion (i'd previously referenced import-map-deployer) you can avoid redeploying the root-config project every time those URLs change. Then "deploying" is just a matter of updating a JSON file.

In our case we build everything in parallel in development mode, so we can not use chunk hashes in that case.

Having a single output entry filename to deal with could possibly make this pain go away.