vitejs / vite

Next generation frontend tooling. It's fast!
http://vite.dev
MIT License
68.45k stars 6.17k forks source link

Lib mode format: es.min #6555

Open yyx990803 opened 2 years ago

yyx990803 commented 2 years ago

Clear and concise description of the problem

Currently when building in lib mode we do not minify the ES build because that would remove pure annotations and break treeshaking. However, this is assuming that the ES build is only used with bundlers. In the future, more users could be using ES builds over CDNs with native ES imports, so a minified ES build could be necessary for those cases.

Suggested solution

// vite config
build: {
  lib: {
    formats: ['es', 'es.min']
  }
}

Alternative

lib: { minifyES: true }

Additional context

https://github.com/vuejs/petite-vue/pull/112

Validations

Niputi commented 2 years ago

prior related https://github.com/vitejs/vite/issues/5167 https://github.com/vitejs/vite/pull/6314

Kurtil commented 2 years ago

What about https://github.com/vitejs/vite/pull/6670 ? :P

bluwy commented 2 years ago

In #8754, I've updated so that minifyWhitespace would only be turned off (which is removing the pure annotations). minifySyntax and minifyIdentifiers are enabled so we have partial minification for es lib build.

Junior2Ran commented 2 years ago

is there any progress about this topic?

mindplay-dk commented 2 years ago

I don't understand, is minifying just disabled entirely for es library output?

I've tried for example this:

  build: {
    lib: {
      // ...
      formats: ["es"]
    },
    minify: "terser",
    terserOptions: {
      compress: true,
      mangle: true,
    },
  }

It doesn't minify or mangle at all - I have no control of the terser options at all?

I can understand having sensible defaults, so you don't accidentally break tree shaking - but blocking me from configuring terser entirely? And not even a warning - it just doesn't work. Very confusing.

At this time, minify: "esbuild" gives a significantly smaller file, because it actually compresses and minifies - with minify: "terser" it doesn't minify at all. How is this setting useful?

I was able to manually minify with terser after the fact, so it's not that this isn't possible.

npm exec terser -- -c -m --module dist/lib.js > dist/lib.min.js
Teaghy commented 1 year ago

Excuse me, has this problem been solved yet?

abarke commented 1 year ago

Any solution?

soerenmeier commented 1 year ago

As a workaround you can use a small plugin to minify the file:

import esbuild from 'esbuild';

const plugin = {
    name: 'minify',
    closeBundle: () => {
        esbuild.buildSync({
            entryPoints: ['./dist/lib.js'],
            minify: true,
            allowOverwrite: true,
            outfile: './dist/lib.js'
        })
    }
};
sinedied commented 1 year ago

Would love to see this implemented!

Currently this is my workaround:

Add an extra esm format to lib entry (don't mind the TS error):

    lib: {
      entry: './src/index.ts',
      formats: ['es', 'esm'],
      fileName: (format) => ({
        es: `${pkg.name}.js`,
        esm: `${pkg.name}.min.js`,
      })[format]

Then add this plugin to the build:

import { transform } from 'esbuild';

function minifyEs() {
  return {
    name: 'minifyEs',
    renderChunk: {
      order: 'post',
      async handler(code, chunk, outputOptions) {
        if (outputOptions.format === 'es' && chunk.fileName.endsWith('.min.js')) {
          return await transform(code, { minify: true });
        }
        return code;
      },
    }
  };
}

This will generate the ES amd ES minified variants.

maranomynet commented 1 year ago

@sinedied Thanks.

I've got //@ts-check at the top of my vite.config.js and to suppress the TS error I use this:

  formats: [
    'cjs',
    // @ts-expect-error
    'esm',
    // @ts-expect-error
    'system',
  ],

(BTW: 'system' format is supported by rollup and seems to work, despite vite not documenting it as an option.)

abarke commented 1 year ago

Please support https://github.com/vitejs/vite/pull/6585

YornQiu commented 1 year ago

so stupid, there is no way to minify 'es', terserOptions' compress and mangle doesn't work at all.

stfn00 commented 1 year ago

If it helps, I've made a custom plugin that implements terser on generateBundle phase, to minify.

import { resolve } from 'node:path'
import { defineConfig } from 'vite'
import { minify } from "terser";
import autoprefixer from 'autoprefixer'

function minifyBundles() {
  return {
    name: "minifyBundles",
    async generateBundle(options, bundle) {
      for (let key in bundle) {
        if (bundle[key].type == 'chunk' && key.endsWith('.js')) {
          const minifyCode = await minify(bundle[key].code, { sourceMap: false })
          bundle[key].code = minifyCode.code
        }
      }
      return bundle
    },
  }
}

export default defineConfig({
  appType: 'custom',
  css: {
    devSourcemap: true,
    postcss: {
      plugins: [
        autoprefixer
      ],
    }
  },
  build: {
    target: ['es2015'],
    outDir: 'dist',
    emptyOutDir: true,
    cssCodeSplit: true,
    sourcemap: false,
    lib: {
      formats: ['es'],
      entry: [
        resolve(__dirname, 'src/scripts/main.js'),
        resolve(__dirname, 'src/scripts/critical.js'),
      ],
      fileName: '[name]',
    },
  },
  plugins: [
    minifyBundles()
  ]
})
itssumitrai commented 1 year ago

Coming back end of 2023, this is a fairly important missing feature. For modern libraries esm is the way to go and no way to minify the output just makes it useless. Sticking to rollup for builds is the way to go atm

daraclare commented 6 months ago

Is there any plan to look at this does anyone know?

Kurtil commented 6 months ago

Is there any plan to look at this does anyone know?

No news. This is my npm run build command workaround :

vite build && esbuild my/lib/path.js --minify --outfile=my/lib/path.js --allow-overwrite

I build using vite then minify using esbuild separatly... :/

mindplay-dk commented 6 months ago

In the future, more users could be using ES builds over CDNs with native ES imports, so a minified ES build could be necessary for those cases.

2.5 years on, this is beginning to feel like a pressing matter.

stefanholzapfel commented 6 months ago

Maybe I got something wrong, but why not use the minify flag directly in the build options?

    build: {
        outDir: './dist/bundle-minified',
        target: ['es2015'],
        lib: {
            entry: 'src/index.ts',
            formats: ['es', 'amd'],
            fileName: (format) => ({
                es: `spotteron.ui.esm.min.js`,
                amd: `spotteron.ui.amd.min.js`,
            })[format]
        },
        rollupOptions: {
            output: {
                inlineDynamicImports: true
            }
        },
        sourcemap: false,
        minify: true,
        cssMinify: true
    }

I get a minified version. Is the configurability the problem?

krasevych commented 5 months ago

any update?

jmlee2k commented 4 months ago

This is yet another example of a small plugin which will minify the lib - I haven't tested it beyond my very simple use case.

benefits:

const minifyBundle = ():Plugin=>({
    name:"minify-bundle",
    async generateBundle(_,bundle)
    {
        for (const asset of Object.values(bundle))
        {
            if (asset.type == "chunk")
                asset.code = (await esbuild.transform(asset.code,{minify:true})).code;
        }
    }
});
Makio64 commented 2 months ago

Thanks @jmlee2k the code you provide works for me

This said : being allow to minify a lib file should be by default for a bundler ?