Search code examples
viteminifyesbuildterser

vite: use "keep-names" esbuild flag for production build


one of our third party libraries requires us to preserve specific function names. in webpack we did that with terser.keep_fnames. esbuild has https://esbuild.github.io/api/#keep-names so we'd like to use that but we cannot find how to enable this option for a vite production build.

according to the docs esbuild is used for minification. how do we enable this flag (or a comparable option)? note that we'd like to not use terser, as its much slower than esbuild.

there is an undocumented config.esbuild prop. that seems to be used in the current master code: https://github.com/vitejs/vite/blob/f72fdc7c995db502ca89f0057cfc1fcd6660212f/packages/vite/src/node/plugins/esbuild.ts#L352

but when i tried adding config.esbuild.keepNames to the config object (as object fields of course) it didnt do anything.


Solution

  • for our ForgeViewer friends, here's some more context for the solution:

    when using a custom query function to query the property database, you need to define a function that is called userFunction. as this function gets serialized and sent to the web worker, you need to make sure the function name is not mangled, when using a bundler.

    https://aps.autodesk.com/en/docs/viewer/v7/developers_guide/advanced_options/propdb-queries/

    in webpack this is done via a terser plugin. where you need to set keep_fnames: true for terserOptions

    vite uses esbuild, so we need to supply the config in our defineConfig

      esbuild: {
        minifyIdentifiers: false,
        keepNames: true,
      },
    

    additionally, make sure you dont inline the function definition for userFunction in the call like we did before:

    //doesnt work
      await viewer.model
        .getPropertyDb()
        .executeUserFunction(function userFunction() { ... }, {
          dbIds,
          propertyNames,
          includeRevitCategory,
        });
    
    // works
      function userFunction() {
        // ...
      }
      await viewer.model
        .getPropertyDb()
        .executeUserFunction(userFunction, {
          dbIds,
          propertyNames,
          includeRevitCategory,
        });
    

    not mangling any function names in the whole codebase leads to an increase in bundle size. we only needed to preserve the function name userFunction so I instead opted to use terser instead, in vite.config (dont forget npm add -D terser)

      build: {
        minify: 'terser',
        terserOptions: {
          mangle: {
            reserved: ['userFunction'],
          },
        },
    

    for us this was a 22,2% decrease in client bundle size, which is a lot.