Skip to content
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

Generate independent JS bundles with no code sharing between bundles (service workers, multi-page apps, multiple library formats) #12203

Open
4 tasks done
jschaf opened this issue Feb 26, 2023 · 4 comments

Comments

@jschaf
Copy link

jschaf commented Feb 26, 2023

Description

As a developer using Vite, I want to be able to generate independent bundles for a service worker and the main app. I want the service worker bundle to be completely independent of the main bundle to avoid unnecessary imports. Code splitting is less beneficial when the bundles run in different scopes or pages.

Example

Let's say I have the following file tree:

  • main.js (entry point: depends on main_dep.js and shared_library.js)
  • main_dep.js
  • service_worker.js (entry point: depends on service_worker_dep.js and shared_library.js)
  • service_worker_dep.js
  • shared_library.js

In this case, Vite generates three chunks because a single invocation of Rollup ensures code is never duplicated:

  • main.hash.js: contains main.js and main_dep.js; imports shared_library.hash.js
  • service_worker.hash.js: contains service_worker.js and service_worker_dep.js; imports shared_library.hash.js
  • shared_library.hash.js

I want Vite to emit two independent bundles, duplicating shared_library.js in each chunk.

  • main.hash.js: contains main.js, main_dep.js, and shared_library.hash.js
  • service_worker.hash.js: contains service_worker.js, service_worker_dep.js, shared_library.hash.js

Related use cases

Independent (no code sharing) modules for library mode

Multiple Bundles

Build slightly different apps

Suggested solution

In the vite config object, support an array of Rollup options as requested in #2039.

In build mode, invoke Rollup once per array element.

In serve mode, I don't think Vite uses Rollup.

Pros

  • Keep a single vite.config.ts, a single build and serve command.
  • Increases flexibility of Vite to cover several requested use-cases.

Cons

  • May differ from the philosophical goals of Vite.
  • May add significant complexity to build command--I'm not familiar enough with Vite internals to know.

Alternative

  1. Add a separate script tag in index.html. A disadvantage is that it's unclear whether a separate module should be independent of the main entry point.

  2. Keep the status quo. A reasonable workaround is to use multiple Vite configs or accept code splitting when using multiple entry points. The main downside is that dealing with two Vite configs is significantly more awkward than a single config. Since a web worker is tightly coupled to the app it supports, it seems heavy-handed to require another Vite config.

Additional context

#2039 (Support multiple (array) input/output options in rollupOptions): Closed by Evan You

You can't because vite build runs a single Rollup build. If you want multiple builds, have multiple vite config files and run vite build -c different.config.js

Rollup tutorial: never duplicates code
Link to Rollup tutorial that declares that Rollup will never duplicate code.

StackOverflow: Prevent service-worker.js from being bundled with vite / rollup
Vite config to place service-worker.js at the top level of the directory. Shared code is split to a separate chunk to be imported by the main index.html entry point and service worker entry point.

How to add multiple inputs and outputs for Svelte rollup config
Blog post on how to emit multiple bundles in Rollup using an array of Rollup configurations instead of a single object. Another blog post on bundling into multiple formats hints that the bundles are likely independent.

Validations

@Tanimodori
Copy link

In my opinion, if two bundle go to same place for deployment, use multi-entry setup. Otherwise you can setup two different sets of vite config for completely independent bundles. Sharing the exact same chunk for independent bundles has marginal benefits. There are many monorepos that shares same modules but not the exact same chunks.

@pdamoc
Copy link

pdamoc commented Apr 4, 2023

What I had to do is

export default defineConfig(() => {
  let input =
    process.env.VITE_PART == "2"
      ? {
          "widget-3": resolve(__dirname, "widgets/widget-3.ts"),
        }
      : {
          "widget": resolve(__dirname, "widgets/widget.ts"), 
          "widget-2": resolve(__dirname, "widgets/widget-2.ts"), 
        };
  return {
    build: {
      emptyOutDir: false,
      rollupOptions: {
        input,
        output: {
          entryFileNames: "[name].js",
        },
      },
    },
  };
});

with vite build && VITE_PART=2 vite build because widget-2 shared enough code with widget-3. These are widgets that are designed to be dynamically loaded onto pages based on data and need to be self-contained.

I would love to not have to do this.

@aszenz
Copy link

aszenz commented Aug 28, 2023

A related issue in rollup

rollup/rollup#2756

@plasid
Copy link

plasid commented Sep 28, 2023

It might be related, please help me https://github.com/vitejs/vite/discussions/14494

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants